# AI Bridge 🌉

**纯净的 AI 模型桥接库** — 透明、原生 SDK、多厂商支持、无主观侵入。

AI Bridge (`aib`) 是一个统一的 Python 接口，用于调用各大主流 AI 厂商的原生能力。核心理念是 **"透明桥接"**：我们只做搬运工，不做任何加工，让用户直接获得大模型的原始返回和错误信息。

---

## 目录

- [核心特性](#-核心特性)
- [支持厂商](#-支持厂商)
- [安装](#-安装)
- [快速开始](#-快速开始)
  - [SDK 使用](#1-sdk-使用)
  - [CLI 命令行](#2-cli-命令行使用)
- [配置指南](#️-配置指南)
  - [配置文件](#方式一配置文件-推荐)
  - [环境变量](#方式二环境变量)
  - [配置优先级](#配置优先级)
- [API 参考](#-api-参考)
  - [AIBridge 类](#aibridge-类)
  - [Response 对象](#response-对象)
  - [Usage 对象](#usage-对象)
- [多模态与文件处理](#-多模态与文件处理)
- [Batch API 批量处理](#-batch-api-批量处理)
- [各厂商配置示例](#-各厂商配置示例)
- [错误处理](#-错误处理)
- [项目结构](#-项目结构)
- [License](#-license)

---

## 🌟 核心特性

### 透明桥接 (Transparent Bridge)

- 🛡️ **无主观处理** — 不拦截错误，不吞噬异常，不修改响应内容
- 📦 **原生对象** — `Response.raw` 保留原始 SDK 响应对象，方便高级用户调试
- ⚡ **原生 SDK** — 底层直接调用官方 SDK（`google-genai`、`openai`、`dashscope`），能力零损耗

### 强大的文件与多模态

- 📂 **Native File API** — 优先使用厂商原生 File API 上传文件（PDF/视频/音频），而非粗暴的 Base64 转换
- 🖼️ **多模态支持** — 完美支持视觉问答、文档分析等场景
- 🔄 **智能路由** — 自动根据模型类型选择最佳的文件处理方式

### 独家功能

- 🚀 **Batch API** — 集成 Qwen 和 Gemini 的批量处理接口，成本降低 50%
- ⏱️ **超时控制** — 支持全局、厂商级、单次请求三级 Timeout 设置
- 🔌 **中转站支持** — 完美支持自定义 `base_url`，适配各类 API 代理

---

## 🏢 支持厂商

| 厂商 | 底层 SDK | 默认模型 | File API | Batch API |
|------|----------|----------|:--------:|:---------:|
| **Google Gemini** | `google-genai` | `gemini-2.0-flash` | ✅ 原生 | ✅ |
| **Moonshot Kimi** | `openai` (兼容) | `moonshot-v1-auto` | ✅ 原生 | ❌ |
| **Aliyun Qwen** | `dashscope` | `qwen-plus` | ✅ 原生 / Base64 (VL) | ✅ |
| **OpenAI** | `openai` | `gpt-4o` | ⚡ Base64 | ❌ |

---

## 📦 安装

### 基础安装

```bash
pip install ai-abridge
```

### 依赖说明

以下依赖会自动安装：

| 依赖 | 版本 | 用途 |
|------|------|------|
| `openai` | `>=1.0.0` | OpenAI / Kimi / Qwen Batch |
| `google-genai` | `>=1.0.0` | Google Gemini |
| `dashscope` | `>=1.0.0` | Aliyun Qwen |
| `typer` | `>=0.9.0` | CLI 命令行工具 |
| `pyyaml` | `>=6.0` | 配置文件解析 |

> **要求**: Python >= 3.9

---

## 🚀 快速开始

### 1. SDK 使用

```python
from aib import AIBridge

# 初始化 (自动读取环境变量或配置文件，也可以显式传入)
bridge = AIBridge(
    vendor="gemini",
    api_key="YOUR_API_KEY",
    model="gemini-2.0-flash",
    timeout=60  # 可选：60 秒超时
)

# 简单对话
response = bridge.chat("你好，请介绍一下你自己")
print(response.content)       # AI 原始返回内容
print(response.usage)         # Token 用量统计

# 带文件的多模态对话 (自动通过厂商 File API 上传)
response = bridge.chat(
    prompt="请总结这份文档主要讲了什么，并分析第二张图表",
    files=["./report.pdf", "./chart.png"]
)
print(response.content)

# 查看 Token 消耗
print(f"输入: {response.usage.prompt_tokens}")
print(f"输出: {response.usage.completion_tokens}")
print(f"总计: {response.usage.total_tokens}")

# 访问原始 SDK 响应 (高级用法)
print(response.raw)
```

### 2. CLI 命令行使用

AI Bridge 提供了命令行工具 `ab`，安装后即可直接使用。

```bash
# 简单对话 (默认使用配置中的 default_vendor)
ab chat "你好！"

# 指定厂商和模型
ab chat "写首诗" -v kimi -m moonshot-v1-8k

# 带文件分析 (支持多个 -f)
ab chat "解释这段代码" -v gemini -f main.py
ab chat "对比这两张图" -v openai -f img1.png -f img2.jpg

# 指定 API Key (覆盖配置)
ab chat "Hello" -v openai -k "sk-your-key"

# 设置超时
ab chat "生成长文章..." -v qwen --timeout 120

# 设置采样温度和最大 Token
ab chat "创意写作" -v gemini -t 0.9 --max-tokens 2000

# 查看 Token 使用情况
ab chat "你好" -v gemini --usage

# 使用自定义中转站
ab chat "Hello" -v openai --base-url "https://api.proxy.com/v1"
```

#### CLI 完整参数一览

| 参数 | 短选项 | 说明 |
|------|--------|------|
| `prompt` | (位置参数) | 发送给 AI 的提示词 |
| `--vendor` | `-v` | 厂商名称：`gemini` / `kimi` / `qwen` / `openai` |
| `--model` | `-m` | 模型名称 |
| `--api-key` | `-k` | API 密钥（覆盖配置文件/环境变量） |
| `--base-url` | `-u` | 自定义 API 端点（中转站） |
| `--timeout` | | 请求超时时间（秒） |
| `--file` | `-f` | 附带的文件路径（可多次指定） |
| `--config` | `-c` | 配置文件路径 |
| `--temperature` | `-t` | 采样温度 |
| `--max-tokens` | | 最大输出 Token 数 |
| `--usage` | | 显示 Token 用量统计 |

#### 其他 CLI 命令

```bash
# 查看当前配置信息
ab config
ab config -p ./my-config.yaml    # 指定配置文件路径

# 查看版本
ab version
```

---

## ⚙️ 配置指南

支持 **YAML 配置文件** 和 **环境变量** 两种方式管理 API Key 和默认设置。

### 方式一：配置文件 (推荐)

创建 `~/.aib/config.yaml` 或项目目录下的 `config.yaml`：

```yaml
# 默认使用的厂商
default_vendor: gemini

# 可选：全局超时时间 (秒)，所有厂商生效
timeout: 60

vendors:
  gemini:
    api_key: "AIzaSy..."
    model: "gemini-2.0-flash"
    timeout: 120               # 厂商特定超时，覆盖全局
    # base_url: "https://custom-proxy.com"  # 可选：自定义代理

  kimi:
    api_key: "sk-..."
    model: "moonshot-v1-auto"
    # base_url: "https://api.moonshot.cn/v1"  # 默认值

  qwen:
    api_key: "sk-..."
    model: "qwen-plus"
    # base_url: "https://dashscope.aliyuncs.com/compatible-mode/v1"  # 默认值

  openai:
    api_key: "sk-..."
    model: "gpt-4o"
    base_url: "https://api.openai.com/v1"  # 支持自定义代理地址
```

### 方式二：环境变量

```bash
# 默认厂商
export AIB_DEFAULT_VENDOR="gemini"

# API Key（各厂商）
export AIB_GEMINI_API_KEY="AIza..."
export AIB_KIMI_API_KEY="sk-..."
export AIB_QWEN_API_KEY="sk-..."
export AIB_OPENAI_API_KEY="sk-..."

# 自定义模型
export AIB_GEMINI_MODEL="gemini-2.0-flash"
export AIB_OPENAI_MODEL="gpt-4o"

# 自定义 Base URL (中转站)
export AIB_OPENAI_BASE_URL="https://api.proxy.com/v1"

# 超时设置 (秒)
export AIB_GEMINI_TIMEOUT="120"
```

### 配置优先级

配置项按以下优先级生效（从高到低）：

1. **代码显式传入** — `AIBridge(api_key="...", model="...")`
2. **环境变量** — `AIB_GEMINI_API_KEY` 等
3. **指定配置文件** — `AIBridge(config_path="./my-config.yaml")`
4. **用户配置文件** — `~/.aib/config.yaml`
5. **项目配置文件** — `./config.yaml`
6. **内置默认值**

---

## � API 参考

### AIBridge 类

```python
from aib import AIBridge

bridge = AIBridge(
    vendor="gemini",          # 厂商名称: gemini / kimi / qwen / openai
    api_key="YOUR_KEY",       # API 密钥 (可选，从配置/环境变量读取)
    model="gemini-2.0-flash", # 模型名称 (可选，使用厂商默认模型)
    base_url=None,            # 自定义 API 端点 (可选，用于中转站)
    timeout=60,               # 请求超时秒数 (可选)
    config_path=None,         # 配置文件路径 (可选)
    **kwargs                  # 其他厂商特定参数
)
```

#### `bridge.chat(prompt, files=None, **kwargs) → Response`

发送对话请求。

| 参数 | 类型 | 说明 |
|------|------|------|
| `prompt` | `str` | 必须。用户提示词 |
| `files` | `List[str \| Path]` | 可选。文件路径列表，自动通过 File API 上传 |
| `temperature` | `float` | 可选。采样温度 (通过 `**kwargs` 传入) |
| `max_tokens` | `int` | 可选。最大输出 Token 数 (通过 `**kwargs` 传入) |

#### `bridge.upload_file(file_path) → str`

手动上传文件到厂商 File API。适用于需要在多次请求中引用同一文件的场景。

```python
file_id = bridge.upload_file("./large_document.pdf")
```

#### `bridge.adapter → VendorAdapter`

获取底层厂商适配器实例，用于高级操作。

### Response 对象

```python
response = bridge.chat("Hello")

response.content            # str   - AI 原始返回内容（未做任何修改）
response.usage              # Usage - Token 用量统计
response.usage.prompt_tokens       # int | None - 输入 Token 数
response.usage.completion_tokens   # int | None - 输出 Token 数
response.usage.total_tokens        # int | None - 总 Token 数
response.raw                # Any   - 原始 SDK 响应对象

str(response)               # 等同于 response.content
```

### Usage 对象

`Usage` 会自动适配各厂商的不同命名：

| 属性 | Gemini | OpenAI / Kimi | Qwen (Dashscope) |
|------|--------|---------------|-------------------|
| `prompt_tokens` | `prompt_token_count` | `prompt_tokens` | `input_tokens` |
| `completion_tokens` | `candidates_token_count` | `completion_tokens` | `output_tokens` |
| `total_tokens` | 计算得出 | `total_tokens` | `total_tokens` |

---

## 📂 多模态与文件处理

AI Bridge 根据厂商和模型自动选择最佳的文件处理方式：

| 厂商 | 处理方式 | 支持格式 | 说明 |
|------|----------|----------|------|
| **Gemini** | 原生 Files API 上传 | PDF、图片、视频、音频 | 上传后自动轮询等待处理完成 |
| **Kimi** | 原生 Files API 上传 | 文档、图片 | 通过 `fileid://` 协议引用 |
| **Qwen** (VL 模型) | Base64 编码 | 图片 | 模型名含 `vl` 时使用多模态 API |
| **Qwen** (文本模型) | 原生 Files API 上传 | 文档 | 通过 `fileid://` 协议引用 |
| **OpenAI** | Base64 编码 | 图片 | 自动检测 MIME 类型 |

```python
# Gemini 多模态 - 分析 PDF 和图片
bridge = AIBridge(vendor="gemini")
response = bridge.chat(
    prompt="总结文档内容并描述图片",
    files=["report.pdf", "photo.jpg"]
)

# Qwen VL 模型 - 视觉问答
bridge = AIBridge(vendor="qwen", model="qwen-vl-plus")
response = bridge.chat(
    prompt="这张图片里有什么？",
    files=["scene.png"]
)
```

---

## 🚀 Batch API 批量处理

对于不着急（24 小时内完成）的大批量任务，使用 Batch API 可节省 **50% 成本**。

目前支持 **Qwen** 和 **Gemini** 两个厂商。

### Qwen Batch

```python
from aib.batch import QwenBatchManager

manager = QwenBatchManager(api_key="sk-...")

# 提交批量任务
job = manager.submit(
    requests=[
        {"prompt": "分析用户评论: 这个产品真好用！"},
        {"prompt": "翻译这段话: Hello World"},
        {"prompt": "总结文章要点: ...",  "files": ["article.txt"]},
        # ... 支持上千条请求
    ],
    model="qwen-plus"
)
print(f"任务已提交，ID: {job.id}, 状态: {job.status}")

# 查询状态
status = manager.get_status(job.id)
print(f"进度: {status.completed_requests}/{status.total_requests}")

# 获取结果 (任务完成后)
results = manager.get_results(job.id)
for request_id, content in results.items():
    print(f"{request_id}: {content}")

# 取消任务
manager.cancel(job.id)
```

### Gemini Batch

```python
from aib.batch import GeminiBatchManager

manager = GeminiBatchManager(api_key="AIza...")

job = manager.submit(
    requests=[
        {"prompt": "分析数据: ...", "files": ["data.csv"]},
        {"prompt": "翻译文本: ..."},
    ],
    model="gemini-2.0-flash"
)

# 查询 / 获取结果 / 取消 — 接口与 QwenBatchManager 完全一致
```

### BatchJob 对象

```python
job.id                  # str         - 任务 ID
job.vendor              # str         - 厂商名称
job.model               # str         - 使用的模型
job.status              # BatchStatus - 状态枚举
job.total_requests      # int         - 总请求数
job.completed_requests  # int         - 已完成请求数
job.output_file_id      # str | None  - 输出文件 ID
job.error               # str | None  - 错误信息
```

### BatchStatus 枚举

| 值 | 说明 |
|---|---|
| `PENDING` | 等待中 |
| `VALIDATING` | 验证中 |
| `RUNNING` | 执行中 |
| `COMPLETED` | 已完成 |
| `FAILED` | 失败 |
| `CANCELLED` | 已取消 |
| `EXPIRED` | 已过期 |

---

## 🏢 各厂商配置示例

### Google Gemini

```python
bridge = AIBridge(
    vendor="gemini",
    api_key="AIzaSy...",
    model="gemini-2.0-flash",       # 或 gemini-2.0-pro 等
    timeout=120,
    # base_url="https://proxy.example.com"  # 可选：自定义代理
)
```

### Moonshot Kimi

```python
bridge = AIBridge(
    vendor="kimi",
    api_key="sk-...",
    model="moonshot-v1-auto",       # 或 moonshot-v1-8k / 32k / 128k
    # base_url="https://api.moonshot.cn/v1"  # 默认值
)
```

### Aliyun Qwen

```python
bridge = AIBridge(
    vendor="qwen",
    api_key="sk-...",
    model="qwen-plus",             # 或 qwen-turbo / qwen-max / qwen-vl-plus
    # base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"  # 默认值
)
```

### OpenAI

```python
bridge = AIBridge(
    vendor="openai",
    api_key="sk-...",
    model="gpt-4o",                # 或 gpt-4o-mini / gpt-3.5-turbo 等
    base_url="https://api.openai.com/v1",  # 支持自定义代理
)
```

---

## ❌ 错误处理

遵循**透明桥接**原则，API 调用失败时库会直接抛出厂商 SDK 的**原始异常**，而非通用的封装异常。这有助于根据具体错误码进行精确处理。

```python
from aib import AIBridge

bridge = AIBridge(vendor="openai", api_key="sk-...")

try:
    response = bridge.chat("Hello")
except Exception as e:
    # e 是原始异常:
    #   OpenAI  → openai.APIError / openai.RateLimitError
    #   Gemini  → google.api_core.exceptions.GoogleAPICallError
    #   Qwen    → dashscope 原生异常
    #   Kimi    → openai.APIError (使用 OpenAI SDK)
    print(f"API 调用失败: {type(e).__name__}: {e}")
```

### 常见异常场景

| 场景 | 异常类型 | 说明 |
|------|----------|------|
| API Key 未配置 | `ValueError` | AIBridge 初始化时检查 |
| 无效厂商名 | `ValueError` | AIBridge 初始化时检查 |
| 文件不存在 | `FileNotFoundError` | 调用 `chat()` 或 `upload_file()` 时检查 |
| API 调用失败 | 厂商原生异常 | 透明传递，不做封装 |
| 文件上传超时 | `RuntimeError` | Gemini 文件处理超时 (60s) |

---

## 🗂️ 项目结构

```
aib_project/
├── pyproject.toml              # 项目配置与依赖
├── config.example.yaml         # 配置文件示例
├── README.md                   # 本文档
├── test_sdk.py                 # SDK 使用示例
└── src/aib/
    ├── __init__.py             # 包入口，导出 AIBridge / Response / VendorType
    ├── bridge.py               # AIBridge 门面类 (统一入口)
    ├── models.py               # 数据模型: Response / Usage / VendorType
    ├── config.py               # 配置加载 (YAML + 环境变量)
    ├── cli.py                  # CLI 命令行工具 (Typer)
    ├── vendors/                # 厂商适配器
    │   ├── base.py             # VendorAdapter 抽象基类
    │   ├── gemini.py           # Google Gemini 适配器
    │   ├── kimi.py             # Moonshot Kimi 适配器
    │   ├── openai.py           # OpenAI 适配器
    │   └── qwen.py             # Aliyun Qwen 适配器
    └── batch/                  # 批量处理
        ├── base.py             # BaseBatchManager 抽象基类
        ├── gemini.py           # Gemini Batch 管理器
        └── qwen.py             # Qwen Batch 管理器
```

---

## 📄 License

MIT License
