Metadata-Version: 2.4
Name: llmdog
Version: 0.1.0
Summary: 轻量级 LLM 命令行工具与 Python 库，支持兼容 OpenAI Chat Completions 格式的任意 API 端点。
Author-email: Chandler <275737875@qq.com>
License-Expression: MIT
Keywords: ai,chatbot,cli,llm,openai
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.9
Requires-Dist: pyyaml>=6.0
Requires-Dist: requests>=2.28.0
Requires-Dist: rich>=13.0.0
Requires-Dist: tenacity>=8.0.0
Requires-Dist: typer>=0.12.0
Requires-Dist: typing-extensions>=4.0.0
Provides-Extra: dev
Requires-Dist: black>=23.0; extra == 'dev'
Requires-Dist: isort>=5.0; extra == 'dev'
Requires-Dist: mypy>=1.0; extra == 'dev'
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: types-pyyaml; extra == 'dev'
Requires-Dist: types-requests; extra == 'dev'
Description-Content-Type: text/markdown

# llmdog

> 轻量级 LLM 命令行工具与 Python 库，支持兼容 OpenAI Chat Completions 格式的任意 API 端点。

---

## 一、项目概述

**llmdog** 是一个极简但生产可用的 LLM 调用框架，提供两种使用形态：

- **CLI 命令行工具**：`llmdog chat --content "你好"` 一行命令即可对话
- **Python 库**：`from llmdog import chat` 在代码中直接调用

### 核心特性

| 特性 | 说明 |
|------|------|
| **统一接口** | 兼容 OpenAI Chat Completions 格式的任意端点（OpenAI、DeepSeek、Qwen 等） |
| **多配置来源** | 环境变量、YAML/JSON 配置文件、运行时参数，优先级明确 |
| **可扩展后端** | 基于抽象基类 + 注册表模式，无需修改核心代码即可接入新后端 |
| **生产级重试** | 基于 tenacity 的指数退避重试机制，应对网络抖动 |
| **Rich 美化输出** | 彩色终端面板、旋转进度条、配置表格（未安装 Rich 时自动降级） |
| **结构化日志** | 详细请求/重试/错误日志，敏感信息（API Key）脱敏输出 |

### 技术栈

| 组件 | 用途 |
|------|------|
| Python ≥ 3.9 | 运行时 |
| `requests` | HTTP 请求 |
| `tenacity` | 指数退避重试 |
| `typer` | CLI 框架 |
| `rich` | 终端美化 |
| `pyyaml` | YAML 配置解析 |
| `hatchling` | 构建打包 |

---

## 二、项目架构说明

```
src/llmdog/
├── __init__.py          # 包入口，导出公开 API
├── cli.py               # Typer CLI 命令行入口
├── chat.py              # 统一调用层（注册表模式）
├── config.py            # 配置管理（多来源合并）
├── backends/
│   ├── __init__.py      # 后端子包导出
│   ├── base.py          # 抽象基类 BaseBackend
│   └── llmapi.py        # OpenAI 兼容格式通用后端
└── utils/
    ├── __init__.py      # 工具子包导出
    └── display.py       # Rich 终端美化工具
```

### 模块职责

#### `__init__.py` — 包入口与公开 API 导出

导出以下公开接口：

| 符号 | 类型 | 来源模块 |
|------|------|----------|
| `chat` | 函数 | `chat.py` |
| `Config` | 数据类 | `config.py` |
| `load_config` | 函数 | `config.py` |
| `register_backend` | 函数 | `chat.py` |
| `list_backends` | 函数 | `chat.py` |
| `__version__` | 字符串 | 内置（`"0.1.0"`） |

#### `chat.py` — 统一调用层

采用**注册表模式（Registry Pattern）**，维护一个 `_BACKEND_REGISTRY` 字典，将后端名称字符串映射到具体后端类。

- `chat(content, *, backend, model, config, **kwargs)` — 核心对话函数，支持零配置、运行时覆盖、Config 对象三种调用方式
- `register_backend(name, backend_cls)` — 注册自定义后端（须继承 `BaseBackend`）
- `list_backends()` — 返回已注册的所有后端名称列表

#### `config.py` — 配置管理

- `Config` 数据类：存储全部运行时参数（`api_key`、`api_url`、`model`、`timeout`、`max_retries`、`backoff_multiplier`、`verify_ssl`、`backend`）
- `load_config(config_file, **overrides)` — 工厂函数，按四级优先级合并配置
- 内置配置文件搜索路径：`./.llmdog.yaml` → `./.llmdog.yml` → `./.llmdog.json` → `~/.llmdog.yaml` → `~/.llmdog.yml` → `~/.llmdog.json`

#### `backends/base.py` — 抽象基类

`BaseBackend(abc.ABC)` 定义所有后端必须实现的接口：

- `name: str` — 后端唯一标识符（类属性）
- `chat(content, model, **kwargs) -> Optional[str]` — 抽象方法
- `validate_content(content) -> bool` — 输入合法性校验（具体方法）

#### `backends/llmapi.py` — 通用后端实现

`LlmApiBackend` 是内置的唯一后端，`name = "llmapi"`：

- 基于 `requests` 发送 POST 请求到 OpenAI 兼容端点
- 使用 `tenacity` 实现指数退避重试（`wait_exponential`，min=1s，max=10s）
- 支持运行时参数覆盖（`api_key`、`api_url`、`timeout`、`model`）
- 请求头包含 `Authorization: Bearer {api_key}` 和自定义 `User-Agent`
- API Key 缺失时返回 `None` 并记录错误日志

#### `utils/display.py` — 终端美化工具

基于 Rich 的输出工具集，未安装 Rich 时自动降级为普通 `print`：

| 函数 | 作用 |
|------|------|
| `print_header(msg)` | 标题面板 |
| `print_success(msg)` | 绿色成功提示 |
| `print_error(msg)` | 红色错误提示 |
| `print_info(msg)` | 黄色信息提示 |
| `print_result(msg)` | 蓝色面板展示模型回复（支持 Markdown 渲染） |
| `spinner(description)` | 上下文管理器，旋转进度条 |
| `print_config_table(data)` | 表格形式打印配置（API Key 自动脱敏） |

#### `cli.py` — 命令行入口

基于 Typer 构建，提供两个子命令：

- `llmdog chat` — 向 LLM 发送消息并打印回复
- `llmdog config show` — 展示当前生效配置（含优先级合并结果）

---

## 三、快速使用教程

### 1. 安装

```bash
pip install llmdog
```


### 2. 配置 API Key

最简方式 — 设置环境变量：

```bash
export LLM_API_KEY="sk-xxxxxxxxxxxxxxxxxxxxxxxx"
```

### 3. 首次调用

**CLI 方式：**

```bash
llmdog chat --content "你好，你是谁？"
```

**Python 方式：**

```python
from llmdog import chat

reply = chat("你好，你是谁？")
print(reply)
```

### 4. 指定模型和超时

```bash
# CLI
llmdog chat --content "帮我写一个快速排序算法" --model qwen3-72b-instruct --timeout 60
```

```python
# Python
from llmdog import chat

reply = chat("帮我写一个快速排序算法", model="qwen3-72b-instruct", timeout=60)
print(reply)
```

### 5. 查看当前生效配置

```bash
llmdog config show
```

### 6. 查看版本和帮助

```bash
llmdog --version
llmdog --help
llmdog chat --help
```

---

## 四、配置教程

### 配置优先级

llmdog 按以下优先级从高到低合并配置（高优先级覆盖低优先级）：

```
1. 运行时参数（函数调用 / CLI 选项显式传入）
       ↓ 覆盖
2. 系统环境变量
       ↓ 覆盖
3. 配置文件（~/.llmdog.yaml 或 ./.llmdog.yaml）
       ↓ 覆盖
4. 内置默认值
```

### 配置参数清单

| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `api_key` | `str \| None` | `None` | Bearer Token，用于 API 鉴权 |
| `api_url` | `str` | `http://api.openai.com/v1/chat/completions` | API 端点地址 |
| `model` | `str` | `qwen2.5-coder-32b-instruct` | 默认模型名称 |
| `timeout` | `int` | `120` | HTTP 请求超时秒数 |
| `max_retries` | `int` | `3` | 请求失败最大重试次数 |
| `backoff_multiplier` | `int` | `1` | 指数退避时间倍率（秒） |
| `verify_ssl` | `bool` | `False` | 是否验证 SSL 证书 |
| `backend` | `str` | `"llmapi"` | 后端标识符 |

### 配置来源详解

#### 来源 1：环境变量

| 环境变量 | 对应配置项 | 类型转换 |
|----------|------------|----------|
| `LLM_API_KEY` | `api_key` | 字符串 |
| `LLM_API_URL` | `api_url` | 字符串 |
| `LLM_MODEL` | `model` | 字符串 |
| `LLM_TIMEOUT` | `timeout` | 自动转 `int` |
| `LLM_MAX_RETRIES` | `max_retries` | 自动转 `int` |
| `LLM_VERIFY_SSL` | `verify_ssl` | `"1"`/`"true"`/`"yes"` → `True` |
| `LLM_BACKEND` | `backend` | 字符串 |

```bash
export LLM_API_KEY="sk-xxxxxxxxxxxxxxxxxxxxxxxx"
export LLM_API_URL="https://api.deepseek.com/v1/chat/completions"
export LLM_MODEL="deepseek-chat"
export LLM_TIMEOUT="60"
export LLM_VERIFY_SSL="true"
```

#### 来源 2：配置文件

支持 YAML（推荐）和 JSON 两种格式，搜索顺序：

1. `./.llmdog.yaml`（当前目录）
2. `./.llmdog.yml`
3. `./.llmdog.json`
4. `~/.llmdog.yaml`（家目录）
5. `~/.llmdog.yml`
6. `~/.llmdog.json`

**YAML 示例（`~/.llmdog.yaml`）：**

```yaml
api_key: sk-xxxxxxxxxxxxxxxxxxxxxxxx
api_url: https://api.deepseek.com/v1/chat/completions
model: deepseek-chat
timeout: 60
max_retries: 3
verify_ssl: true
```

**JSON 示例（`~/.llmdog.json`）：**

```json
{
  "api_key": "sk-xxxxxxxxxxxxxxxxxxxxxxxx",
  "api_url": "https://api.deepseek.com/v1/chat/completions",
  "model": "deepseek-chat",
  "timeout": 60,
  "verify_ssl": true
}
```

> YAML 解析依赖 `pyyaml`（已包含在安装依赖中）。若未安装则跳过 YAML 文件。

#### 来源 3：运行时参数

**CLI 选项：**

```bash
llmdog chat \
  --content "测试" \
  --api-key sk-xxxxxxxxxxxxxxxxxxxxxxxx \
  --api-url https://api.deepseek.com/v1/chat/completions \
  --model deepseek-chat \
  --timeout 60 \
  --config-file ~/.my-config.yaml
```

**Python 函数参数：**

```python
from llmdog import chat
from llmdog.config import load_config

cfg = load_config(
    api_key="sk-xxxxxxxxxxxxxxxxxxxxxxxx",
    api_url="https://api.deepseek.com/v1/chat/completions",
    model="deepseek-chat",
    timeout=60,
    verify_ssl=True,
)
reply = chat("测试", config=cfg)
```

### 常见服务商配置示例

#### DeepSeek

| 参数 | 值 |
|------|----|
| `api_url` | `https://api.deepseek.com/v1/chat/completions` |
| 模型 | `deepseek-chat`、`deepseek-reasoner` |

```yaml
# ~/.llmdog-deepseek.yaml
api_key: sk-xxxxxxxxxxxxxxxxxxxxxxxx
api_url: https://api.deepseek.com/v1/chat/completions
model: deepseek-chat
verify_ssl: true
```

#### 阿里云百炼（Qwen / 通义千问）

| 参数 | 值 |
|------|----|
| `api_url` | `https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions` |
| 模型 | `qwen-max`、`qwen-plus`、`qwen-turbo`、`qwen2.5-72b-instruct`、`qwen2.5-coder-32b-instruct` |

```yaml
# ~/.llmdog-qwen.yaml
api_key: sk-xxxxxxxxxxxxxxxxxxxxxxxx
api_url: https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions
model: qwen-max
verify_ssl: true
```

#### OpenAI

| 参数 | 值 |
|------|----|
| `api_url` | `https://api.openai.com/v1/chat/completions` |
| 模型 | `gpt-4o`、`gpt-4o-mini`、`gpt-4-turbo`、`o1`、`o3-mini` |

```yaml
# ~/.llmdog-openai.yaml
api_key: sk-xxxxxxxxxxxxxxxxxxxxxxxx
api_url: https://api.openai.com/v1/chat/completions
model: gpt-4o
verify_ssl: true
```

#### 多服务商配置切换

通过 `--config-file` 在不同服务商间快速切换：

```bash
# 使用 DeepSeek
llmdog chat --content "写一篇技术博客" --config-file ~/.llmdog-deepseek.yaml

# 使用 Qwen
llmdog chat --content "写一篇技术博客" --config-file ~/.llmdog-qwen.yaml

# 使用 OpenAI
llmdog chat --content "写一篇技术博客" --config-file ~/.llmdog-openai.yaml
```

---

## 五、API 接口说明

### `chat(content, *, backend=None, model=None, config=None, **kwargs)`

核心对话函数。

| 参数 | 类型 | 说明 |
|------|------|------|
| `content` | `str` | 用户输入文本（必填，不能为空） |
| `backend` | `str \| None` | 后端标识符，默认从配置读取（`"llmapi"`） |
| `model` | `str \| None` | 模型名称，覆盖配置中的默认值 |
| `config` | `Config \| None` | 配置对象，为 `None` 时自动调用 `load_config()` |
| `api_key` | `str`（kwargs） | API Key，覆盖环境变量 |
| `api_url` | `str`（kwargs） | API 端点地址 |
| `timeout` | `int`（kwargs） | 超时秒数 |

**返回值**：`str | None` — 模型回复文本；调用失败时返回 `None`。

**异常**：指定未注册的后端时抛出 `ValueError`。

### `load_config(config_file=None, **overrides)`

按优先级合并配置，返回 `Config` 实例。

**优先级**：`overrides` > 环境变量 > 配置文件 > 默认值

### `register_backend(name, backend_cls)`

注册自定义后端。`backend_cls` 必须是 `BaseBackend` 的子类，否则抛出 `ValueError`。

### `list_backends()`

返回当前已注册的所有后端名称列表。

### `Config`

配置数据类，字段见[配置参数清单](#配置参数清单)。提供 `as_dict()` 导出字典和 `validate()` 合法性校验方法。

---

## 六、自定义后端扩展

```python
from typing import Optional
from llmdog import chat, register_backend
from llmdog.backends.base import BaseBackend


class MyBackend(BaseBackend):
    """自定义后端示例。"""

    name = "my_service"  # 后端唯一标识

    def chat(self, content: str, model: Optional[str] = None, **kwargs) -> Optional[str]:
        # 你的实现逻辑
        return "custom reply"


# 注册后端
register_backend("my_service", MyBackend)

# 使用自定义后端
reply = chat("测试", backend="my_service")
print(reply)
```

---

## 七、开发与测试

### 运行测试

```bash
# 安装开发依赖
pip install -e ".[dev]"

# 运行全部测试
pytest tests/ -v

# 生成覆盖率报告
pytest tests/ --cov=llmdog --cov-report=term-missing
```

### 代码规范

| 工具 | 配置 |
|------|------|
| `black` | line-length=100，target py39-py312 |
| `isort` | profile=black，line_length=100 |
| `mypy` | python_version=3.9 |

---

## 八、依赖项清单

### 运行时依赖

| 依赖 | 最低版本 | 用途 |
|------|----------|------|
| `requests` | 2.28.0 | HTTP 请求 |
| `tenacity` | 8.0.0 | 指数退避重试 |
| `typer` | 0.12.0 | CLI 框架 |
| `rich` | 13.0.0 | 终端美化输出 |
| `pyyaml` | 6.0 | YAML 配置文件解析 |
| `typing-extensions` | 4.0.0 | Python 3.9 类型兼容 |

### 开发依赖（`pip install llmdog[dev]`）

| 依赖 | 用途 |
|------|------|
| `pytest` | 单元测试框架 |
| `pytest-cov` | 测试覆盖率报告 |
| `black` | 代码格式化 |
| `isort` | import 排序 |
| `mypy` | 静态类型检查 |
| `types-requests` | requests 类型存根 |
| `types-PyYAML` | PyYAML 类型存根 |

---

## 九、贡献指南

1. Fork 本仓库并创建特性分支：`git checkout -b feature/my-new-backend`
2. 为所有公开 API 添加 docstring（遵循 PEP 257）
3. 确保新增后端继承 `BaseBackend` 并覆盖 `name` 属性
4. 运行测试并确保通过：`pytest tests/ -v`
5. 提交 Pull Request，附上功能描述和测试结果

---

## 十、许可证

本项目使用 [MIT License](https://opensource.org/licenses/MIT)。

---

## 附录：集成提示词模板

以下提示词可供其他项目复用或集成 llmdog 模块时作为基础参考：

````markdown
# llmdog 集成指南

## 核心能力

llmdog 是一个轻量级 LLM 调用库，提供：
- 统一的 `chat(content)` 函数，兼容 OpenAI Chat Completions 格式的任意端点
- CLI 命令行工具（`llmdog chat`）和 Python 库两种调用方式
- 多配置来源合并（环境变量 > 配置文件 > 默认值）
- 基于 tenacity 的指数退避重试机制
- 注册表模式的后端扩展机制

## 接入步骤

### 1. 安装

```bash
pip install llmdog
```

### 2. 配置 API Key

```bash
export LLM_API_KEY="sk-xxxxxxxxxxxxxxxxxxxxxxxx"
```

### 3. 选择服务商

通过环境变量或配置文件指定 API 端点和模型：

```bash
# DeepSeek 示例
export LLM_API_URL="https://api.deepseek.com/v1/chat/completions"
export LLM_MODEL="deepseek-chat"
```

## 常用调用模式

### 模式一：CLI 命令行

```bash
llmdog chat --content "你好，你是谁？"
llmdog chat -c "写代码" -m qwen3-72b-instruct -t 60
llmdog config show
```

### 模式二：Python 库调用

```python
from llmdog import chat

# 零配置（依赖环境变量 LLM_API_KEY）
reply = chat("你好")

# 指定模型和超时
reply = chat("写代码", model="qwen3-72b-instruct", timeout=60)

# 传入完整 Config
from llmdog.config import load_config
cfg = load_config(api_key="sk-xxx", model="deepseek-chat")
reply = chat("测试", config=cfg)
```

### 模式三：自定义后端

```python
from llmdog import chat, register_backend
from llmdog.backends.base import BaseBackend

class MyBackend(BaseBackend):
    name = "my_backend"
    def chat(self, content, model=None, **kwargs):
        return "custom reply"

register_backend("my_backend", MyBackend)
reply = chat("测试", backend="my_backend")
```

## 配置参数清单

| 参数 | 环境变量 | 默认值 | 说明 |
|------|----------|--------|------|
| api_key | LLM_API_KEY | None | API Key |
| api_url | LLM_API_URL | http://api.openai.com/v1/chat/completions | 端点地址 |
| model | LLM_MODEL | qwen2.5-coder-32b-instruct | 模型名称 |
| timeout | LLM_TIMEOUT | 120 | 超时秒数 |
| max_retries | LLM_MAX_RETRIES | 3 | 最大重试次数 |
| verify_ssl | LLM_VERIFY_SSL | false | SSL 验证 |
| backend | LLM_BACKEND | llmapi | 后端标识 |

配置优先级：运行时参数 > 环境变量 > 配置文件 > 默认值

配置文件搜索路径：`./.llmdog.yaml` → `~/.llmdog.yaml`（支持 .yml / .json）

## 配置文件示例

```yaml
api_key: sk-xxxxxxxxxxxxxxxxxxxxxxxx
api_url: https://api.deepseek.com/v1/chat/completions
model: deepseek-chat
timeout: 60
max_retries: 3
verify_ssl: true
```
````

---

*本项目使用 [MIT License](https://opensource.org/licenses/MIT)。*
