Metadata-Version: 2.4
Name: talent-whale
Version: 0.1.9
Summary: 一站式招聘自动化工具：简历邮件生成 | 邮件营销活动 | LinkedIn 自动化
Author-email: Chandler <275737875@qq.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/talent-whale/talent-whale
Project-URL: Repository, https://github.com/talent-whale/talent-whale
Keywords: recruitment,linkedin,email,llm,automation
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: typer>=0.15.0
Requires-Dist: rich>=13.0.0
Requires-Dist: python-dotenv>=1.0.0
Requires-Dist: pandas>=2.0.0
Requires-Dist: openpyxl>=3.1.0
Requires-Dist: requests>=2.28.0
Requires-Dist: tenacity>=8.0.0
Requires-Dist: llmdog>=0.0.1
Requires-Dist: larkfunc>=0.1.0
Requires-Dist: selenium>=4.25.0
Requires-Dist: diskcache>=5.6.0
Requires-Dist: browser-dog>=0.0.1
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Requires-Dist: black; extra == "dev"
Requires-Dist: isort; extra == "dev"

# talent-whale

一站式招聘自动化工具包：基于 LLM 的简历邮件生成、Zmail 邮件营销活动、LinkedIn Recruiter 自动化消息发送，以及邮件数据后处理。

---

## 功能特性

1. **简历邮件生成** (`email_gen`)
   - 读取候选人简历（`.txt` / `.json`），调用 LLM 匹配职位并生成销售推介邮件
   - 支持自定义 Prompt 模板文件
   - 批量模式（URL 列表）+ 单文件模式，支持断点续传

2. **邮件营销活动** (`campaign`)
   - 从 Excel 读取候选人与收件人信息，通过 Zmail API 批量发送邮件
   - 随机延迟、幂等发送（已发邮件自动跳过）
   - 可扩展的抽象接口（EmailSender / EmailRepository / CandidateSource）

3. **LinkedIn 自动化** (`linkedin`)
   - Selenium 驱动 LinkedIn Recruiter，自动发送 InMail
   - diskcache + JSON 双重去重，断点续传
   - 职位关键词过滤、忽略名单支持

4. **数据后处理** (`data`)
   - 批量读取 JSON 邮件文件，清洗签名，整合输出为 Excel

5. **统一 CLI**（Typer + Rich）
   - 彩色输出、进度显示、统计表格
   - 所有参数支持命令行覆盖

---

## 安装和环境配置

### 基础安装

```bash
pip install talent-whale
```

### 配置 LLM（推荐 .env 方式）

```bash
cp .env.example .env
# 编辑 .env，填写真实 API Key
```

`.env` 文件内容：

```env
TALENT_WHALE_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxx
TALENT_WHALE_API_URL=https://api.deepseek.com/v1/chat/completions
TALENT_WHALE_MODEL=deepseek-chat
TALENT_WHALE_TIMEOUT=60
```

---

## 使用示例和代码片段

### Python API

```python
from talent_whale import chat, load_config

# 方式一：通过 .env 文件自动加载（推荐）
reply = chat("用 Python 实现二叉树的层序遍历")
print(reply)

# 方式二：显式传入配置（覆盖 .env）
cfg = load_config(
    api_key="sk-xxxx",
    api_url="https://api.deepseek.com/v1/chat/completions",
    model="deepseek-chat",
    timeout=60,
)
reply = chat("解释 RAG 架构", config=cfg)
print(reply)
```

```python
from talent_whale import read_txt_data, parse_json_safely, clean_llm_response
from talent_whale.utils.io import read_txt_to_list, save_json_to_file, ensure_directory_exists
from talent_whale.utils.text import extract_linkedin_id, extract_filename_without_extension

# 读取文本文件
content = read_txt_data("data/resume.txt")

# 安全解析 JSON
data = parse_json_safely('{"name": "whale", "version": 1}')

# 清理 LLM 返回的代码块标记
raw   = '```json\n{"result": "ok"}\n```'
clean = clean_llm_response(raw)  # '{"result": "ok"}'

# 提取 LinkedIn 用户 ID
uid  = extract_linkedin_id("https://www.linkedin.com/in/johndoe/")
# 'johndoe'

# 按行读取文件
urls = read_txt_to_list("urls.txt")

# 确保目录存在并保存 JSON
ensure_directory_exists("output/emails")
save_json_to_file({"key": "value"}, "output/emails/result.json")
```

### CLI 命令

#### 1. 简历邮件生成（批量，使用默认模板）

```bash
# 无需 --template-file，自动使用内置 DEFAULT_PROMPT_TEMPLATE
whale email generate batch \
  urls.txt \
  ./email_output \
  --type json \
  --model deepseek-v3.1-terminus
```

#### 2. 简历邮件生成（批量，自定义模板）

```bash
whale email generate batch \
  urls.txt \
  ./email_output \
  --template-file my_prompt.txt \
  --type json \
  --model deepseek-v3.1-terminus
```

#### 3. 查看默认 Prompt 模板

```bash
# 查看完整模板内容（含职位列表）
whale email show-template

# 仅查看模板格式说明（跳过职位列表）
whale email show-template --compact
```

#### 4. 导出 Prompt 模板

将内置 `DEFAULT_PROMPT_TEMPLATE` 导出为本地文件，方便自定义编辑后配合 `generate` 命令使用。

```bash
# 导出到默认路径 ./prompt_template.txt
whale email export-template

# 导出到指定路径
whale email export-template -o my_template.txt

# 强制覆盖已有文件
whale email export-template -o my_template.txt -f

# 使用导出的自定义模板生成邮件
whale email generate batch urls.txt out/ -p my_template.txt
```

#### 5. 简历邮件生成（单文件）

```bash
whale email generate single \
  ./resume_json/johndoe.json \
  ./email_output
```

#### 6. 邮件营销活动

```bash
# 基础用法
whale campaign run \
  --email sender@example.com \
  --password YOUR_PASSWORD \
  --tag-filter agent \
  --excel email_list.xlsx \
  --json-path ./resume_json \
  --log-folder ./email_log \
  --delay-min 10 \
  --delay-max 30

# 自定义 Zmail API 地址
whale campaign run \
  --email sender@example.com \
  --password YOUR_PASSWORD \
  --api-url http://your-server:8080/api/send

# 自定义签名（含换行）
whale campaign run \
  --email sender@example.com \
  --signature $'祝颂商祺\nMichael\nWechat: mywechat'
```

#### 7. LinkedIn 自动化发消息

```bash
whale linkedin run \
  --excel ./lk_email_gen.xlsx \
  --tag-filter agent \
  --cache-dir ./cache_dir \
  --checkpoint ./urn/checkpoint.json \
  --recruiter Michael
```

#### 8. 邮件数据后处理

```bash
whale data process ./email_ms_lk_json output.xlsx
```

---

## API 接口说明

### `talent_whale.chat(prompt, model=None, config=None) -> str`

调用 LLM 对话接口。`config` 为 `None` 时自动从 `.env` 加载。

### `talent_whale.load_config(**kwargs) -> LLMConfig`

加载 LLM 配置，优先级：参数 > `.env` > 内置默认值。

| 参数         | 对应环境变量                   | 默认值                                             |
|------------|--------------------------|--------------------------------------------------|
| `api_key`  | `TALENT_WHALE_API_KEY`   | `""`                                             |
| `api_url`  | `TALENT_WHALE_API_URL`   | `https://api.deepseek.com/v1/chat/completions` |
| `model`    | `TALENT_WHALE_MODEL`     | `deepseek-chat`                                  |
| `timeout`  | `TALENT_WHALE_TIMEOUT`   | `60`                                             |

### `talent_whale.email_gen.gen_email_tool(...)`

批量生成邮件 JSON，可直接在 Python 脚本中调用，参数与 CLI `email generate batch` 一致。

### `talent_whale.campaign.EmailCampaignFactory.create_service(config) -> EmailCampaignService`

工厂方法，根据 `AppConfig` 对象组装完整的邮件营销服务。

---

## 依赖项清单

### 必需依赖

| 包              | 用途                  |
|----------------|---------------------|
| `typer`        | CLI 框架              |
| `rich`         | 终端彩色输出             |
| `python-dotenv` | `.env` 配置加载         |
| `pandas`       | Excel 读写            |
| `openpyxl`     | Excel 引擎            |
| `requests`     | HTTP 请求（Zmail API） |
| `tenacity`     | 重试机制               |
| `llmdog`       | LLM 调用封装           |
| `larkfunc`     | 文件 I/O 与文本工具函数    |
| `selenium`     | 浏览器自动化（LinkedIn）  |
| `diskcache`    | URN 与去重持久化缓存      |
| `browser-dog`  | LinkedIn Talent 登录会话管理 |


---

## 技术架构与设计原理

### 总体架构

```
talent_whale/
├── __init__.py          # 公开 API 入口，重导出核心函数
├── cli.py               # 根 CLI 入口，注册 4 个子命令组
├── config.py            # 配置管理：.env + CLI 参数双通道
├── output.py            # Rich 输出：全局 Console 实例 + 辅助函数
├── data_cli.py          # 数据处理子命令
├── llm/                 # LLM 调用抽象层
│   ├── client.py        # 封装 llmdog.chat + llmdog.config.load_config
├── utils/               # 工具函数层
│   ├── io.py            # 从 larkfunc 重导出：文件读写工具
│   ├── text.py          # 从 larkfunc 重导出：文本解析工具
│   └── data.py          # 自实现：邮件签名清洗 / JSON → Excel
├── email_gen/           # 简历邮件生成模块
│   ├── generator.py     # LLM 邮件生成核心逻辑（含重试）
│   └── cli.py           # CLI 子命令：batch / single
├── campaign/            # 邮件营销活动模块
│   ├── models.py        # 数据模型（frozen dataclass + 预设模板）
│   ├── service.py       # 抽象接口层 + EmailCampaignService 核心编排
│   ├── factory.py       # 具体实现 + EmailCampaignFactory
│   └── cli.py           # CLI 子命令：run
└── linkedin/            # LinkedIn 自动化模块
    ├── models.py        # 数据模型：候选人、消息、自动化配置
    ├── parser.py        # LinkedIn 页面解析器
    ├── navigator.py     # 页面导航 + 元素点击（Selenium）
    ├── sender.py        # 消息发送实现
    ├── checkers.py      # 去重检查器（diskcache / JSON / 组合）
    ├── orchestrator.py  # 核心编排器：9 步完整流程
    ├── factory.py       # 工厂函数：组装编排器
    └── cli.py           # CLI 子命令：run（BrowserDog 登录）
```

#### 模块依赖关系（单向无环）

```
            ┌─────────┐
            │  cli.py  │  (根入口，注册子命令)
            └────┬────┘
                 │
    ┌────────────┼────────────┬────────────┐
    ▼            ▼            ▼            ▼
  email_gen   campaign    linkedin      data
    │            │            │            │
    └────────────┼────────────┘            │
                 ▼                         │
              utils ───────────────────────┘
                 │
                 ▼
               llm
                 │
                 ▼
              config
                 │
                 ▼
              output   (所有模块依赖，全局 Console)
```

设计原则：**依赖只能向下** — CLI → 业务模块 → utils → llm → config → output。任何反向导入均视为违规。

---

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

#### 设计思路

采用 **python-dotenv + 函数参数双通道** 模式，消除对单一环境变量来源的依赖：

- `.env` 文件：适合本地开发，避免密钥硬编码
- CLI 参数：适合 CI/CD 或需要临时切换账号的场景
- 优先级链：`CLI 参数 > .env 文件 > 内置默认值`

#### 核心实现

```python
# config.py — 精简原理
from dotenv import load_dotenv
from dataclasses import dataclass

@dataclass
class LLMConfig:
    api_key:    str = ""
    api_url:    str = "https://api.deepseek.com/v1/chat/completions"
    model:      str = "deepseek-chat"
    timeout:    int = 60
    verify_ssl: bool = True

def load_config(api_key=None, api_url=None, model=None, ...) -> LLMConfig:
    _load_env(env_file)         # 1. 加载 .env
    return LLMConfig(
        api_key=api_key or os.getenv("TALENT_WHALE_API_KEY", ""),  # 2. 参数覆盖
        ...
    )
```

**关键设计决策**：
- `LLMConfig` 使用可变 `dataclass`（非 frozen），允许调用方在获取后局部覆盖 `model`
- `_load_env()` 仅在当前工作目录查找 `.env`，不干扰系统级环境变量
- 所有环境变量前缀 `TALENT_WHALE_` 防止命名冲突

---

### 2. LLM 客户端层 — `llm/client.py`

#### 设计思路

将 `llmdog` 作为底层 API 封装，`talent-whale` 作为业务适配层。两层职责清晰分离：

| 层级          | 职责                                      | 包名       |
|--------------|------------------------------------------|-----------|
| 底层 API      | HTTP 连接、重试、流式输出                   | `llmdog`  |
| 业务适配层     | 从 `.env` 加载配置、提供业务语义的 `chat()`   | `talent_whale` |

```python
from llmdog import chat as _llmdog_chat
from llmdog.config import load_config as _llmdog_load_config

def chat(prompt, model=None, config=None) -> str:
    if config is None:
        config = _load_tw_config()     # 自动从 .env 加载
    llm_cfg = _llmdog_load_config(     # 转换为 llmdog 格式
        api_key=config.api_key, api_url=config.api_url, ...
    )
    return _llmdog_chat(prompt, config=llm_cfg)
```

---

### 3. 简历邮件生成模块 — `email_gen/`

#### 架构设计

```
CLI: email generate batch/single
         │
         ▼
   gen_email_tool()      ← 批量入口：遍历 URL 列表，断点续传
         │
         ▼
  process_resume_file()  ← 单文件处理流水线
         │
    ┌────┼────┐
    ▼    ▼    ▼
  read  call  parse
  txt   LLM   JSON
```

#### 核心业务流程

1. **读取**：通过 `larkfunc.read_txt_data` 读取简历文件（支持 `.txt` / `.json`）
2. **选择 Prompt**：若调用方传入 `prompt_template` 则使用自定义模板；否则自动回退到 `DEFAULT_PROMPT_TEMPLATE`
3. **调用 LLM**：将简历文本 + Prompt 模板拼接，调用 `llm/client.chat()`（最多 3 次重试）
4. **解析 JSON**：`larkfunc.clean_llm_response` 去除 Markdown 代码块标记，`larkfunc.parse_json_safely` 安全解析
5. **保存**：`larkfunc.save_json_to_file` 输出到 `{output_dir}/{linkedin_id}.json`
6. **断点续传**：若输出文件已存在，自动跳过

#### 可扩展性

- **Prompt 模板独立**：`--template-file` 参数支持外部文件；未指定时自动使用内置 `DEFAULT_PROMPT_TEMPLATE`（来源 002），可通过 `email show-template` 查看
- **模型可切换**：`--model` 参数直接覆盖 LLM 模型，同一套代码可适配 DeepSeek / OpenAI / 本地模型
- **批量化设计**：`gen_email_tool` 接受 URL 列表文件，与 `process_resume_file`（单文件）解耦，二者可独立复用

---

### 4. 邮件营销活动模块 — `campaign/`

#### 设计思路

采用 **接口抽象 + 工厂模式**，将业务逻辑与具体实现彻底解耦：

```
┌──────────────────────────────────────────────┐
│            EmailCampaignService              │  ← 核心编排（依赖接口，不依赖实现）
│   run_campaign():                            │
│     1. candidate_source.get_candidates()     │
│     2. email_repository.is_sent() 去重       │
│     3. email_sender.send() 发送              │
│     4. email_repository.save_log() 记录      │
└───────┬──────────┬───────────┬──────────────┘
        │          │           │
   ┌────▼────┐ ┌───▼────┐ ┌───▼────────┐
   │Candidate│ │ Email  │ │  Email     │    ← 抽象接口（ABC）
   │ Source  │ │ Sender │ │ Repository │
   └────┬────┘ └───┬────┘ └───┬────────┘
        │          │           │
   ┌────▼────┐ ┌───▼────┐ ┌───▼────────┐
   │ Excel   │ │ Zmail  │ │ JsonFile   │    ← 具体实现（factory.py）
   │ Candidate│ │ REST   │ │ EmailRepo  │
   │ Source  │ │ API    │ │            │
   └─────────┘ └────────┘ └────────────┘
```

#### 四个抽象接口

| 接口               | 职责               | 当前实现                        |
|-------------------|-------------------|-------------------------------|
| `CandidateSource` | 获取候选人列表       | `ExcelCandidateSource` (pandas) |
| `EmailDataSource` | 从 LinkedIn ID 查邮箱 | `JsonFileEmailDataSource`    |
| `EmailSender`     | 发送邮件           | `ZmailEmailSender` (REST API) |
| `EmailRepository` | 发送日志存储/去重    | `JsonFileEmailRepository`    |

#### 领域模型（frozen dataclass）

所有配置类使用 `@dataclass(frozen=True)` 确保不可变，防止运行时意外修改：

```python
@dataclass(frozen=True)
class SenderConfig:
    email: str
    password: str
    api_base_url: str = "http://127.0.0.1:5000/api/zmail/send"

    def __post_init__(self):
        if "@" not in self.email:
            raise ValueError(f"邮箱格式无效: {self.email}")
```

`api_base_url` 支持通过 CLI 参数 `--api-url` 覆盖，无需修改源码即可切换邮件服务端点。

`AppConfig` 提供 `metatech()` / `deepresearch()` 两个类方法预设，减少重复配置代码。

#### 工厂模式

```python
class EmailCampaignFactory:
    @staticmethod
    def create_service(config: AppConfig) -> EmailCampaignService:
        """根据 AppConfig 组装完整服务。"""
        email_source = JsonFileEmailDataSource(config.data_source)
        candidate_src = ExcelCandidateSource(config.data_source, email_source)
        sender = ZmailEmailSender(config.sender)
        repo = JsonFileEmailRepository(config.repository)
        return EmailCampaignService(candidate_src, sender, repo, config.campaign)
```

#### 核心业务流程 — `run_campaign()`

```
遍历候选人
    │
    ├── 无邮箱 ──────────────→ 跳过 (skipped_no_email +1)
    │
    ├── 已发送 ──────────────→ 跳过 (skipped_already_sent +1)  ← Repository 去重
    │
    ├── 发送成功 ────────────→ 记录日志 (sent +1)              ← Sender + Repository
    │
    ├── 发送失败 ────────────→ 打印错误 (failed +1)
    │
    └── random.uniform(delay) 延迟（反爬虫）
```

#### 可扩展性

- **换邮件服务**：实现 `EmailSender` 接口即可切换到 SendGrid / AWS SES / SMTP
- **换数据源**：实现 `CandidateSource` 接口即可从数据库 / CSV / API 读取候选人
- **换存储**：实现 `EmailRepository` 接口即可切换到 MySQL / MongoDB / S3
- **配置预设**：在 `AppConfig` 上添加新的 `classmethod` 即可注册新的账号模板

---

### 5. LinkedIn 自动化模块 — `linkedin/`

#### 设计思路

将复杂的 LinkedIn Recruiter 自动化流程拆解为 **6 个独立组件**，通过编排器（Orchestrator）串联：

```
┌─────────────────────────────────────────────────────────┐
│            LinkedInAutomationOrchestrator                │
│                                                         │
│  process_candidate_urn() ──→ process_candidate()        │
│         │                        │                      │
│         └────────┬───────────────┘                      │
│                  ▼                                      │
│           _run_flow()  ← 9 步核心流程                   │
│                                                         │
│  1. navigate_to_profile()   ──────▶ navigator          │
│  2. parse_profile()         ──────▶ parser             │
│  3. name_evaluator          ──────▶ evaluator (可选)    │
│  4. title_evaluator         ──────▶ evaluator (可选)    │
│  5. extract_message_threads()  ───▶ parser             │
│  6. is_duplicate()          ──────▶ duplicate_checker  │
│  7. is_message_button_clickable() ─▶ navigator          │
│  8. open_message_dialog()   ──────▶ navigator          │
│  9. send_message()          ──────▶ message_sender      │
└─────────────────────────────────────────────────────────┘
```

#### 组件详解

**Navigator（页面导航器）**
- `navigate_to_profile()`：WebDriverWait + EC 等待页面加载
- `click_messages_tab()`：`tenacity` 指数退避重试（最多 5 次），JavaScript 点击绕过 Selenium 元素拦截
- `open_message_dialog()`：多定位器回退策略（XPATH → CSS_SELECTOR → data-control-name）
- `is_message_button_clickable()`：检查按钮 `disabled` 属性

**DuplicateChecker（去重检查器）**

采用 **策略模式 + 组合模式**：

```python
# 独立策略
DiskCacheDuplicateChecker      # 基于 diskcache，自动过期，进程内/跨进程
JsonCheckpointDuplicateChecker  # 基于 JSON 文件，仅依赖标准库

# 组合策略（同时写入多个检查器）
CompositeDuplicateChecker       # 任意命中即重复，写入时全量同步
```

**两种入口路径**

| 方法                      | 适用场景                     | 流程                             |
|--------------------------|-----------------------------|----------------------------------|
| `process_candidate_urn()` | URN 已缓存（二次访问）        | 读缓存 → 拼接 Talent URL → 发消息 |
| `process_candidate()`     | 首次访问普通 LinkedIn URL    | 导航主页 → 提取 Talent URL → 缓存 URN → 发消息 |

---

### 6. 数据后处理模块 — `data_cli.py` + `utils/data.py`

#### 设计思路

纯粹的管道式处理：

```
JSON 目录 → 遍历文件 → 提取字段 → 清洗签名 → 拼装 DataFrame → 输出 Excel
```

核心函数 `clean_email_signature()` 使用正则匹配中文签名变体：

```python
pattern = r"""\s*(祝颂商祺|祝商祺|祝好)[，,]?\s*\n?\s*Michael\s*$"""
cleaned = re.sub(pattern, "", content, flags=re.DOTALL | re.VERBOSE)
```

输出 Excel 按固定列顺序 `[url, match_job_title, recommend_title, email_content, filename]` 组织，适合后续导入邮件系统。

---

### 7. 输出层 — `output.py`

#### 设计约束

- **全局唯一 Console 实例**：`console = Console(theme=custom_theme)`，所有模块 `from talent_whale.output import console`
- **禁止裸 `print()`**：所有输出必须通过 `console.print()` 或快捷函数
- **统一主题**：`info=cyan`, `success=bold bright_green`, `warning=bold bright_yellow`, `error=bold bright_red`, `highlight=bold magenta`, `dim=dim white`

#### 辅助函数

| 函数            | 输出样式              |
|----------------|---------------------|
| `banner()`     | Panel 边框 + 标题     |
| `stats_table()` | 交替底色 Rich Table  |
| `rule()`       | 水平分隔线             |
| `info/success/warning/error/dim/highlight()` | 单行彩色文本 |

---

### 如何保证可扩展性与可维护性

1. **接口抽象 + 依赖注入**
   `campaign/` 和 `linkedin/` 均通过 ABC 定义契约，通过构造函数注入具体实现。新增邮件服务商或数据源只需实现接口，无需修改核心逻辑。

2. **工厂模式隔离组装复杂度**
   `EmailCampaignFactory.create_service()` 和 `create_default_orchestrator()` 将对象图的创建集中管理，调用方零感知内部依赖。

3. **单向依赖无环图**
   依赖方向严格从 CLI → 业务模块 → utils → llm → config → output，消除循环引用风险。

4. **延迟导入（Lazy Import）处理可选依赖**
   所有 Selenium / diskcache 导入均放在方法内部，模块顶层仅依赖纯 Python 包，确保基础功能（email_gen / campaign / data）在无浏览器环境下正常运行。

5. **配置文件外部化**
   `.env` 管理密钥，`pyproject.toml` 管理依赖，Prompt 模板通过 `--template-file` 外部传入，代码与配置彻底分离。

6. **frozen dataclass 确保数据不可变**
   `SenderConfig`、`DataSourceConfig`、`RepositoryConfig`、`CampaignConfig`、`AppConfig` 全部使用 `frozen=True`，`__post_init__` 中做格式校验，fail-fast 原则。

7. **组件化策略与组合优于继承**
   `CompositeDuplicateChecker` 组合多个检查器；`Orchestrator` 组合 Navigator / Parser / Sender / Checker，而非通过多层继承。

8. **统一输出主题**
   全局 `console` 实例 + 命名颜色规则，保证所有模块视觉一致，新增子命令只需遵循颜色规范即可。

---

### 核心 CLI 命令矩阵

| 命令组      | 子命令           | 必需参数                              | 关键可选参数                                     |
|------------|-----------------|--------------------------------------|-----------------------------------------------|
| `email`    | `generate batch` | urls_file, output_dir                | `--template-file`, `--type`, `--model`        |
| `email`    | `generate single`| resume_path, output_dir              | `--template-file`, `--model`                  |
| `email`    | `show-template`  | (无)                                  | `--compact`                                    |
| `campaign` | `run`           | `--email`, `--password`              | `--tag-filter`, `--excel`, `--delay-min/max`, `--api-url`, `--signature` |
| `linkedin` | `run`           | (无)                                  | `--excel`, `--tag-filter`, `--headless`, `--recruiter` |
| `data`     | `process`       | input_folder, output_excel           | (无)                                           |

---

## 免责声明

1）本工具（talent-whale）仅供个人或企业在合法招聘场景下使用，旨在提升招聘流程效率。

2）用户使用本工具时，必须遵守所在国家/地区的法律法规，以及所使用平台（如 LinkedIn、Zmail 等）的服务条款与使用政策。

3）开发者不对任何因滥用本工具而产生的后果承担责任，包括但不限于：
   - 违反平台服务条款导致的账号封禁
   - 违反数据保护法规（如 GDPR、个人信息保护法等）导致的法律风险
   - 因发送垃圾邮件、骚扰信息或进行未经授权的自动化操作而产生的任何损失

4）请在使用前充分了解目标平台关于自动化工具的规范，并确保所有操作已获得相关方的明确授权。

---

## 贡献指南与许可证

### 贡献指南

1. Fork 本仓库，创建 feature 分支
2. 遵循代码规范：CLI 使用 Typer，输出使用 Rich（禁止裸 `print()`）
3. 提交 Pull Request，描述改动原因与影响范围

### 许可证

MIT License © talent-whale contributors
