Metadata-Version: 2.4
Name: profile-claw
Version: 0.1.0
Summary: 大模型简历处理工具：格式化、评估、邮件生成、总结概括
License-Expression: MIT
Keywords: cli,formatter,llm,profile,resume
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Text Processing
Requires-Python: >=3.10
Requires-Dist: fastapi>=0.100.0
Requires-Dist: jinja2>=3.1.0
Requires-Dist: llmdog>=0.0.3
Requires-Dist: python-multipart>=0.0.5
Requires-Dist: rich>=13.0.0
Requires-Dist: typer>=0.9.0
Requires-Dist: uvicorn>=0.20.0
Description-Content-Type: text/markdown

# profile-claw

**大模型简历处理工具** - 基于大语言模型的简历格式化、评估、邮件生成与总结概括命令行工具。

profile-claw 是一个 PyPI 可安装的 Python 模块，通过 [llmdog](https://pypi.org/project/llmdog/) 库调用大语言模型，支持兼容 OpenAI Chat Completions 格式的任意 API 端点。CLI 命令为 `profile`，同时提供 Python API 两种使用方式。

---

## 功能特性

- **格式化（format）**：将非结构化简历文本转换为标准 JSON 格式
- **评估（eval）**：对简历进行完整性、专业性、技能匹配度、呈现效果四维度评分分析
- **邮件生成（email）**：基于候选人简历生成招聘 outreach 邮件
- **总结概括（summary）**：提取简历核心信息，生成精炼总结
- **初始化（init）**：一键初始化本地 prompt 模板文件，支持自定义
- **批量处理**：支持单文件和目录批量处理
- **双重使用方式**：CLI 命令行 + Python 函数调用
- **Web 管理界面**：基于 FastAPI + Alpine.js 的 prompt 模板和 LLM 配置管理
- **灵活配置**：支持多种 LLM 模型、自定义 prompt 模板

---

## 安装和环境配置

### 前置要求

- Python >= 3.10
- pip 包管理器

### 方式一：直接安装（推荐用于生产）

```bash
pip install profile-claw
```

### 方式二：开发模式安装

1. **克隆或下载项目**

```bash
cd /path/to/profile-claw
```

2. **创建虚拟环境**

```bash
# 在项目根目录创建名为 venv 的虚拟环境
python -m venv venv

# 激活虚拟环境
# macOS / Linux:
source venv/bin/activate

# Windows:
venv\Scripts\activate
```

3. **安装依赖并以开发模式安装**

```bash
pip install -e .
```

4. **验证安装**

```bash
# 验证 CLI 命令
profile --version
# 输出: profile 0.1.0

# 验证 Python 导入
python -c "import profile_claw; print(profile_claw.__version__)"
# 输出: 0.1.0
```

### 虚拟环境说明

虚拟环境（venv）会将 Python 解释器和所有依赖项隔离在项目目录中，不影响系统全局环境。

```
project-root/
├── venv/              # 虚拟环境目录（隔离的 Python 环境）
├── src/
│   └── profile_claw/  # 源代码
└── pyproject.toml     # 项目配置
```

**常用虚拟环境操作：**

| 操作 | 命令 |
|------|------|
| 激活 | `source venv/bin/activate` (macOS/Linux) 或 `venv\Scripts\activate` (Windows) |
| 退出 | `deactivate` |
| 运行命令 | `venv/bin/profile --version`（无需激活） |
| 安装包 | `venv/bin/pip install <package>` |

---

## 使用示例

### CLI 命令行使用

#### 查看帮助信息

```bash
profile --help
```

输出：
```
Usage: profile [OPTIONS] COMMAND [ARGS]...

大模型简历处理工具：格式化、评估、邮件生成、总结概括

Options:
  --version, -v  显示版本号
  --help         Show this message and exit.

Commands:
  init      初始化本地 prompt 模板文件到 profile-prompts/ 目录
  format    格式化简历：将简历文本转换为标准 JSON 格式
  eval      评估简历：对简历进行多维度评分和分析
  email     生成招聘邮件：基于简历内容生成招聘 outreach 邮件
  summary   总结简历：提取核心信息生成精炼总结
```

#### 初始化本地 prompt 模板

```bash
# 在当前目录创建 profile-prompts/ 目录
profile init

# 指定目标目录
profile init --dir /path/to/project
```

执行后会在目标目录创建 `profile-prompts/` 子目录，包含四个 prompt 模板文件：
- `format_prompt.md`
- `eval_prompt.md`
- `email_prompt.md`
- `summary_prompt.md`

#### 格式化简历

```bash
# 处理单个文件（输出到同目录：resume_format.json）
profile format resume.txt

# 处理目录（输出到同级 resume_format/ 目录）
profile format resume_dir/

# 指定输出目录
profile format resume.txt --output output/

# 使用自定义 prompt
profile format resume.txt --prompt "请将以下简历转为JSON格式：{content}"

# 使用自定义 prompt 文件
profile format resume.txt --prompt-file my_prompt.md

# 指定 LLM 模型
profile format resume.txt --model gpt-4
```

#### 评估简历

```bash
profile eval resume.txt
profile eval resume_dir/ --output eval_results/
profile eval resume.txt --model gpt-4
```

#### 生成招聘邮件

```bash
profile email resume.txt
profile email resume.txt --output emails/
```

#### 总结简历

```bash
profile summary resume.txt
profile summary resume_dir/ --output summaries/
```

### Python API 使用

```python
import profile_claw

# 初始化本地 prompt 模板
profile_claw.init()
profile_claw.init(dir="/path/to/project")

# 格式化简历
output_files = profile_claw.format_resume("resume.txt")
output_files = profile_claw.format_resume("resume.txt", output_dir="output/")
output_files = profile_claw.format_resume("resume.txt", model="gpt-4")
output_files = profile_claw.format_resume("resume.txt", prompt="自定义prompt...{content}")

# 评估简历
output_files = profile_claw.eval_resume("resume.txt")

# 生成招聘邮件
output_files = profile_claw.generate_email("resume.txt")

# 总结简历
output_files = profile_claw.summary("resume.txt")

# 批量处理目录
output_files = profile_claw.format_resume("resume_dir/")
```

**函数签名：**

```python
def format_resume(
    input_path: str | Path,
    output_dir: str | Path | None = None,
    prompt: str | None = None,
    prompt_file: str | Path | None = None,
    model: str | None = None,
) -> list[Path]:
    """格式化简历，返回输出文件路径列表。"""
```

其他函数（`eval_resume`、`generate_email`、`summary`）签名相同。

### Web 管理界面使用

启动 Web 管理界面：

```bash
# 默认 127.0.0.1:7070
profile web

# 自定义地址和端口
profile web --host 0.0.0.0 --port 8080
```

打开浏览器访问 `http://127.0.0.1:7070`，界面提供：

| 功能 | 说明 |
|------|------|
| Prompt 模板管理 | 查看/编辑/新建/删除/重置 prompt 模板 |
| 内置模板 | 查看包内默认模板，可一键复制到本地 |
| 本地模板 | 管理 `profile-prompts/` 目录下的自定义模板 |
| LLM 配置 | 设置 API Key、URL、模型、超时时间、SSL 验证 |

**提示：** Web 界面配置的 LLM 参数仅在当前会话有效，重启后需重新设置。持久化配置请使用环境变量。

---

## API 接口说明

### 公共 API

| 函数 | 说明 |
|------|------|
| `profile_claw.__version__` | 版本号字符串 |
| `profile_claw.init(dir=None)` | 初始化本地 prompt 模板，返回 prompt 目录路径 |
| `profile_claw.format_resume(input_path, ...)` | 格式化简历，返回输出文件路径列表 |
| `profile_claw.eval_resume(input_path, ...)` | 评估简历，返回输出文件路径列表 |
| `profile_claw.generate_email(input_path, ...)` | 生成招聘邮件，返回输出文件路径列表 |
| `profile_claw.summary(input_path, ...)` | 总结简历，返回输出文件路径列表 |

### 参数说明

| 参数 | 类型 | 说明 |
|------|------|------|
| `input_path` | `str \| Path` | 输入文件或目录路径（必填） |
| `output_dir` | `str \| Path \| None` | 输出目录，默认自动计算 |
| `prompt` | `str \| None` | 自定义 prompt 内容（优先级最高） |
| `prompt_file` | `str \| Path \| None` | 自定义 prompt 文件路径 |
| `model` | `str \| None` | 指定 LLM 模型名称 |

### 输出格式

**格式化输出（`*_format.json`）：**
```json
{
  "basic_info": { "name": "张三", "gender": "男", "age": 28, ... },
  "education": [...],
  "work_experience": [...],
  "project_experience": [...],
  "skills": { "technical": [...], "languages": [...], ... },
  "self_evaluation": "..."
}
```

**评估输出（`*_eval.json`）：**
```json
{
  "overall_score": 85,
  "overall_level": "良好",
  "dimensions": {
    "completeness": { "score": 80, "comment": "..." },
    "professionalism": { "score": 85, "comment": "..." },
    "skill_match": { "score": 90, "comment": "..." },
    "presentation": { "score": 80, "comment": "..." }
  },
  "highlights": [...],
  "weaknesses": [...],
  "suggestions": [...],
  "summary": "..."
}
```

**邮件输出（`*_email.json`）：**
```json
{
  "subject": "高级Python工程师机会 - [公司名称]",
  "greeting": "尊敬的张三：",
  "body": {
    "introduction": "我是XX公司技术招聘负责人...",
    "highlights": ["您在Python后端开发方面的5年经验", "主导的高并发项目成果", "开源社区贡献"],
    "motivation": "我们正在寻找...",
    "closing": "期待与您进一步交流..."
  },
  "signature": "此致\n敬礼\n\n李四\n技术招聘经理",
  "full_text": "完整邮件文本..."
}
```

**总结输出（`*_summary.json`）：**
```json
{
  "name": "张三",
  "one_line_summary": "5年经验的Python后端工程师...",
  "years_of_experience": 5,
  "core_skills": ["Python", "Django", ...],
  "key_achievements": [...],
  "summary_paragraph": "综合总结..."
}
```

---

## 依赖项清单

| 依赖 | 版本要求 | 用途 |
|------|----------|------|
| `typer` | >= 0.9.0 | CLI 命令行框架 |
| `llmdog` | >= 0.0.3 | LLM 调用库，支持 OpenAI 兼容格式 |
| `rich` | >= 13.0.0 | 终端美化和格式化输出 |
| `fastapi` | >= 0.100.0 | Web 框架 |
| `uvicorn` | >= 0.20.0 | ASGI 服务器 |
| `jinja2` | >= 3.1.0 | HTML 模板引擎 |
| `python-multipart` | >= 0.0.5 | 表单数据解析 |

**间接依赖（由 llmdog 和 typer 引入）：**
- `requests` - HTTP 请求
- `tenacity` - 重试策略
- `pyyaml` - YAML 配置解析
- `typing-extensions` - 类型扩展

---

## 配置方法详解

### LLM API 配置

profile-claw 通过 [llmdog](https://pypi.org/project/llmdog/) 库与 LLM API 通信。配置方式：

#### 1. 环境变量（推荐）

```bash
# 必填：API Key
export LLM_API_KEY="your-api-key-here"

# 可选：API URL（默认为 OpenAI 端点）
export LLM_API_URL="https://api.openai.com/v1"

# 可选：默认模型名称
export LLM_MODEL="gpt-4"

# 可选：请求超时时间（秒，默认 60）
export LLM_TIMEOUT=60

# 可选：SSL 证书验证（默认 true）
export LLM_VERIFY_SSL=true
```

#### 2. 命令行参数

```bash
# 逐次指定模型
profile format resume.txt --model gpt-4
profile eval resume.txt -m claude-3-sonnet
```

#### 3. llmdog 配置文件

llmdog 支持 YAML 配置文件，详见 [llmdog 文档](https://pypi.org/project/llmdog/)。

#### 支持的 LLM 提供商

任何兼容 OpenAI Chat Completions 格式的 API 端点均可使用：
- OpenAI (GPT-4, GPT-3.5)
- Anthropic Claude（通过兼容层）
- Azure OpenAI
- 本地部署的兼容模型（如 Ollama、LM Studio）
- 其他兼容提供商

### 自定义 Prompt 模板

#### 方式一：使用 init 命令初始化后修改

```bash
# 1. 初始化本地 prompt 模板
profile init

# 2. 编辑生成的模板文件
# 修改 profile-prompts/format_prompt.md 等文件

# 3. 后续执行会自动使用本地模板
profile format resume.txt
```

**Prompt 优先级（从高到低）：**
1. 显式指定：`--prompt` 或 `--prompt-file` 参数
2. 本地文件：`profile-prompts/{action}_prompt.md`
3. 内置默认：包内 `profile_claw/prompts/` 目录

#### 方式二：命令行直接传入

```bash
# 直接传入 prompt 内容
profile format resume.txt --prompt "请将简历转为JSON：{content}"

# 传入 prompt 文件
profile format resume.txt --prompt-file my_custom_prompt.md
```

**注意：** prompt 模板必须包含 `{content}` 占位符，运行时会被替换为实际简历内容。

---

## 扩展性说明

### 项目架构

```
src/profile_claw/
├── __init__.py          # 公共 API 导出
├── cli.py               # Typer CLI 命令行界面
├── core.py              # 核心处理逻辑
├── web.py               # FastAPI Web 管理界面后端
├── templates/
│   └── index.html       # Web 管理界面前端（Alpine.js + Tailwind CSS）
└── prompts/
    ├── __init__.py
    ├── format_prompt.md # 内置格式化 prompt
    ├── eval_prompt.md   # 内置评估 prompt
    ├── email_prompt.md  # 内置邮件生成 prompt
    └── summary_prompt.md # 内置总结 prompt
```

**核心模块职责：**
- `core.py`：文件读写、prompt 解析、LLM 调用、JSON 清理、输出路径计算
- `cli.py`：命令行参数解析、命令注册、用户交互
- `web.py`：FastAPI 后端，prompt CRUD 和 LLM 配置管理 API
- `templates/`：Web 管理界面 HTML 页面
- `prompts/`：内置 prompt 模板，与代码逻辑分离

### Web API 接口

启动 Web 服务后，可通过以下 API 进行编程管理：

| 方法 | 路径 | 说明 |
|------|------|------|
| `GET` | `/api/prompts` | 列出所有 prompt 模板（内置 + 本地） |
| `GET` | `/api/prompts/builtin/{action}` | 获取内置 prompt |
| `GET` | `/api/prompts/local/{filename}` | 获取本地 prompt |
| `POST` | `/api/prompts/local` | 创建本地 prompt |
| `PUT` | `/api/prompts/local/{filename}` | 更新本地 prompt |
| `DELETE` | `/api/prompts/local/{filename}` | 删除本地 prompt |
| `POST` | `/api/prompts/local/{filename}/reset` | 从内置模板重置 |
| `GET` | `/api/config/llm` | 获取 LLM 配置 |
| `PUT` | `/api/config/llm` | 更新 LLM 配置 |
| `DELETE` | `/api/config/llm` | 清除 LLM 配置 |

**请求示例：**

```bash
# 获取所有 prompt
curl http://127.0.0.1:7070/api/prompts

# 创建本地 prompt
curl -X POST http://127.0.0.1:7070/api/prompts/local \
  -H 'Content-Type: application/json' \
  -d '{"name": "translate", "filename": "translate_prompt.md", "content": "翻译以下简历：{content}"}'

# 更新 LLM 配置
curl -X PUT http://127.0.0.1:7070/api/config/llm \
  -H 'Content-Type: application/json' \
  -d '{"api_key": "sk-...", "api_url": "https://api.openai.com/v1", "model": "gpt-4", "timeout": 60, "verify_ssl": true}'
```

### 添加新的处理功能

以添加"翻译（translate）"功能为例：

1. **创建 prompt 模板**

在 `src/profile_claw/prompts/` 目录创建 `translate_prompt.md`：

```markdown
# 简历翻译

请将以下简历翻译成英文，保持专业术语的准确性。

## 简历内容

{content}
```

2. **注册到 PROMPT_FILES**

编辑 `src/profile_claw/core.py`：

```python
PROMPT_FILES = {
    "format": "format_prompt.md",
    "eval": "eval_prompt.md",
    "email": "email_prompt.md",
    "summary": "summary_prompt.md",
    "translate": "translate_prompt.md",  # 新增
}
ACTIONS = {"format", "eval", "email", "summary", "translate"}  # 新增
```

3. **添加 API 函数**

在 `src/profile_claw/core.py` 中添加：

```python
def translate_resume(
    input_path: str | Path,
    output_dir: str | Path | None = None,
    prompt: str | None = None,
    prompt_file: str | Path | None = None,
    model: str | None = None,
) -> list[Path]:
    """翻译简历，返回输出文件路径列表。"""
    return process_resume("translate", input_path, output_dir, prompt, prompt_file, model)
```

4. **添加 CLI 命令**

在 `src/profile_claw/cli.py` 中添加：

```python
from profile_claw.core import translate_resume  # 导入新函数

@app.command()
def translate(
    input_path: Path = typer.Argument(..., help="输入文件或目录路径"),
    output: Optional[Path] = typer.Option(None, "--output", "-o", help="输出目录"),
    prompt: Optional[str] = typer.Option(None, "--prompt", "-p", help="自定义 prompt 内容"),
    prompt_file: Optional[Path] = typer.Option(None, "--prompt-file", "-P", help="自定义 prompt 文件路径"),
    model: Optional[str] = typer.Option(None, "--model", "-m", help="指定 LLM 模型"),
) -> None:
    """翻译简历：将简历翻译成目标语言"""
    _process_action("translate", input_path, output, prompt, prompt_file, model)
```

5. **导出新函数**

在 `src/profile_claw/__init__.py` 中添加导出：

```python
from profile_claw.core import translate_resume

__all__ = [
    # ... 其他导出
    "translate_resume",
]
```

### 修改现有 prompt 模板

**方式一：修改内置模板（需要重新安装包）**

直接编辑 `src/profile_claw/prompts/` 目录下的 `.md` 文件，然后重新安装：

```bash
pip install -e .
```

**方式二：使用本地模板（推荐）**

```bash
# 1. 初始化本地模板
profile init

# 2. 修改本地模板
# 编辑 profile-prompts/format_prompt.md

# 3. 后续执行自动使用本地模板
profile format resume.txt
```

---

## 贡献指南与许可证信息

### 贡献指南

欢迎贡献代码、报告问题或提出改进建议！

1. **Fork 项目** 并创建功能分支
2. **编写代码** 遵循项目代码风格
3. **添加测试** 确保新功能有相应测试覆盖
4. **提交 PR** 描述清楚改动内容和原因

**开发环境设置：**

```bash
# 克隆项目
git clone <repo-url>
cd profile-claw

# 创建虚拟环境
python -m venv venv
source venv/bin/activate

# 开发模式安装
pip install -e .

# 运行测试（如有）
pytest
```

### 许可证

本项目采用 MIT 许可证 - 详见 [LICENSE](LICENSE) 文件。

---

## 常见问题

**Q: LLM 调用失败怎么办？**

检查 `LLM_API_KEY` 环境变量是否正确设置，以及 API URL 是否可访问。

```bash
echo $LLM_API_KEY
curl $LLM_API_URL/models -H "Authorization: Bearer $LLM_API_KEY"
```

**Q: 如何查看当前使用的 prompt？**

使用 `init` 命令导出内置 prompt 到本地查看：

```bash
profile init
cat profile-prompts/format_prompt.md
```

**Q: 支持哪些文件格式？**

输入支持：`.txt`、`.json`、`.md`、`.markdown`
输出格式：JSON（2 空格缩进，中文不转义）
