From 710ba7ec31219079663f1815b00c6431feba2026 Mon Sep 17 00:00:00 2001 From: 27942 Date: Fri, 6 Mar 2026 00:43:40 +0800 Subject: [PATCH] haha --- 1.html | 776 ++++++++++++++++++++++++++++++++++ 1.py | 131 ++++++ API_CONTACTS.md | 317 -------------- API文档.md | 693 ------------------------------ BOSS招聘优化说明.md | 166 -------- BOSS招聘自动化完整优化说明.md | 488 --------------------- BOSS招聘自动化最终使用说明.md | 274 ------------ scroll_and_greet.py | 59 +++ 代码变更清单.md | 157 ------- 优化完成总结.md | 174 -------- 复聊配置API使用指南.md | 361 ---------------- 快速参考指南.md | 148 ------- 部署说明.md | 47 -- 13 files changed, 966 insertions(+), 2825 deletions(-) create mode 100644 1.html create mode 100644 1.py delete mode 100644 API_CONTACTS.md delete mode 100644 API文档.md delete mode 100644 BOSS招聘优化说明.md delete mode 100644 BOSS招聘自动化完整优化说明.md delete mode 100644 BOSS招聘自动化最终使用说明.md create mode 100644 scroll_and_greet.py delete mode 100644 代码变更清单.md delete mode 100644 优化完成总结.md delete mode 100644 复聊配置API使用指南.md delete mode 100644 快速参考指南.md delete mode 100644 部署说明.md diff --git a/1.html b/1.html new file mode 100644 index 0000000..1c3193e --- /dev/null +++ b/1.html @@ -0,0 +1,776 @@ +BOSS直聘
\ No newline at end of file diff --git a/1.py b/1.py new file mode 100644 index 0000000..d9485f2 --- /dev/null +++ b/1.py @@ -0,0 +1,131 @@ +# -*- coding: utf-8 -*- +""" +本地脚本:由 DrissionPage (DP) 控制浏览器(本地谷歌 Chrome 或比特浏览器)。 +- 使用本地谷歌:USE_LOCAL_CHROME = True,会启动/连接本机 Chrome。 +- 使用比特浏览器:USE_LOCAL_CHROME = False,需先启动比特浏览器客户端(API 端口 54345)。 +""" +from __future__ import annotations + +import random +import sys +import time +from pathlib import Path + +# 保证从项目根目录运行时可导入 worker 包 +_ROOT = Path(__file__).resolve().parent +if str(_ROOT) not in sys.path: + sys.path.insert(0, str(_ROOT)) + +# ---------- 选择控制对象 ---------- +USE_LOCAL_CHROME = True # True=本地谷歌 Chrome,False=比特浏览器 + +# 本地谷歌 Chrome 配置(仅当 USE_LOCAL_CHROME=True 时生效) +CHROME_DEBUG_PORT = 9222 # 调试端口;若为 None 则由脚本自动启动 Chrome +CHROME_PATH = None # 例如 r"C:\Program Files\Google\Chrome\Application\chrome.exe",None 用系统默认 + +# 比特浏览器配置(仅当 USE_LOCAL_CHROME=False 时生效) +BIT_API_BASE = "http://127.0.0.1:54345" +BROWSER_NAME = "测试2" +BROWSER_ID = None + + +def _connect_local_chrome(): + """连接或启动本地谷歌 Chrome,返回 ChromiumPage。""" + from DrissionPage import ChromiumPage, ChromiumOptions + + co = ChromiumOptions() + if CHROME_PATH: + co.set_browser_path(CHROME_PATH) + if CHROME_DEBUG_PORT is not None: + # 连接已开启调试端口的 Chrome(需先手动启动:chrome --remote-debugging-port=9222) + co.set_local_port(CHROME_DEBUG_PORT) + print(f"正在连接本机 Chrome(调试端口 {CHROME_DEBUG_PORT})...") + page = ChromiumPage(addr_or_opts=co) + else: + # 由 DrissionPage 自动启动 Chrome + print("正在启动本地谷歌 Chrome...") + page = ChromiumPage(addr_or_opts=co) + print("已连接本地 Chrome。") + return page + + +def _connect_bit_browser(): + """通过比特浏览器 API 打开并连接,返回 ChromiumPage。""" + from worker.bit_browser import BitBrowserAPI + from DrissionPage import ChromiumPage, ChromiumOptions + + print("正在连接比特浏览器 API...") + bit_api = BitBrowserAPI(BIT_API_BASE) + print("正在打开比特浏览器...") + cdp_addr, port, browser_id = bit_api.open_browser( + browser_id=BROWSER_ID, name=BROWSER_NAME, remark=None + ) + print(f"已打开浏览器 ID={browser_id}, CDP 端口={port}") + co = ChromiumOptions().set_local_port(port=port) + return ChromiumPage(addr_or_opts=co) + + +def main(): + from DrissionPage.errors import NoRectError + + if USE_LOCAL_CHROME: + page = _connect_local_chrome() + else: + page = _connect_bit_browser() + + page.listen.start('wapi/zpjob/rec/geek/list') + + # 示例:打开一个页面(可选) + page.get("https://www.zhipin.com/web/chat/recommend") + res = page.listen.wait() + + for i in res.response.body["zpData"]["geekList"]: + print(i) + + geekName = i["geekCard"]["geekName"] # 姓名 + geekDegree = i["geekCard"]["geekDegree"] # 学历 + expectPositionName = i["geekCard"]["expectPositionName"] #期待职位 + expectLocationName = i["geekCard"]["expectLocationName"] # 地区 + applyStatusDesc = i["geekCard"]["applyStatusDesc"] # 当前状态离职0随时到岗之类的 + ageDesc = i["geekCard"]["ageDesc"] # 年龄 + lowSalary = i["geekCard"]["lowSalary"] # 最低要求工资 + highSalary = i["geekCard"]["highSalary"] # 最高要求工资 + + + """三个动作:1. 找到姓名 2. 滚动到那里 3. 点击打招呼""" + try: + container = page.get_frame("recommendFrame") + except Exception: + container = page + + # 1. 找到这个姓名 + name_ele = container.ele(f'x://span[contains(text(),"{geekName}")]', timeout=10) + if not name_ele: + name_ele = container.ele(f'x://span[text()="{geekName}"]', timeout=2) + if not name_ele: + raise Exception(f"未找到姓名:{geekName}") + + # 2. 滚动到那里 + name_ele.run_js("this.scrollIntoView({block: 'center', behavior: 'auto'})") + time.sleep(0.8) + + # 3. 点击打招呼(先在该人所在卡片内找) + parent = name_ele.parent() + greet_btn = None + for _ in range(8): + if not parent: + break + greet_btn = parent.ele('x://span[text()="打招呼"]', timeout=0.5) or parent.ele('x://*[contains(text(),"打招呼")]', timeout=0.5) + if greet_btn: + break + parent = parent.parent() + if not greet_btn: + greet_btn = container.ele('x://span[text()="打招呼"]', timeout=2) or container.ele('x://*[contains(text(),"打招呼")]', timeout=1) + if not greet_btn: + raise Exception("未找到「打招呼」按钮") + greet_btn.click(by_js=True) + + + +if __name__ == "__main__": + main() diff --git a/API_CONTACTS.md b/API_CONTACTS.md deleted file mode 100644 index 3e5dbc9..0000000 --- a/API_CONTACTS.md +++ /dev/null @@ -1,317 +0,0 @@ -# 联系记录接口文档 - -## 1. 查询联系记录列表 - -### 接口信息 -- **URL**: `/api/contacts` -- **方法**: `GET` -- **认证**: 需要登录(Header 携带 Authorization) - -### 请求参数 - -| 参数名 | 类型 | 必填 | 说明 | 示例 | -|--------|------|------|------|------| -| page | integer | 否 | 页码,默认 1 | 1 | -| page_size | integer | 否 | 每页数量,默认 10 | 20 | -| search | string | 否 | 搜索关键词(姓名/岗位/联系方式) | 张三 | -| reply_status | string | 否 | 回复状态筛选 | 已回复 | -| wechat_exchanged | boolean | 否 | 是否交换微信 | true | -| start_date | string | 否 | 开始日期(YYYY-MM-DD) | 2024-01-01 | -| end_date | string | 否 | 结束日期(YYYY-MM-DD) | 2024-12-31 | - -### 请求示例 - -```bash -# 基础查询 -GET /api/contacts?page=1&page_size=20 - -# 关键词搜索 -GET /api/contacts?search=张三 - -# 按回复状态筛选 -GET /api/contacts?reply_status=已回复 - -# 按时间范围筛选 -GET /api/contacts?start_date=2024-01-01&end_date=2024-12-31 - -# 组合筛选 -GET /api/contacts?search=产品经理&reply_status=已回复&wechat_exchanged=true&start_date=2024-01-01&end_date=2024-12-31 -``` - -### 响应示例 - -```json -{ - "code": 200, - "msg": "success", - "data": { - "total": 150, - "page": 1, - "page_size": 20, - "results": [ - { - "id": 1, - "name": "张三", - "position": "产品经理", - "contact": "13800138000", - "reply_status": "已回复", - "wechat_exchanged": true, - "account_id": 1, - "worker_id": "worker-001", - "notes": "沟通顺畅,有意向", - "contacted_at": "2024-03-01T10:30:00", - "created_at": "2024-03-01T10:00:00" - }, - { - "id": 2, - "name": "李四", - "position": "前端工程师", - "contact": "wechat:lisi123", - "reply_status": "未回复", - "wechat_exchanged": false, - "account_id": 2, - "worker_id": "worker-002", - "notes": "", - "contacted_at": "2024-03-02T14:20:00", - "created_at": "2024-03-02T14:00:00" - } - ] - } -} -``` - ---- - -## 2. 导出联系记录为 Excel - -### 接口信息 -- **URL**: `/api/contacts/export` -- **方法**: `GET` -- **认证**: 需要登录(Header 携带 Authorization) -- **响应类型**: `application/json`(返回下载链接) - -### 请求参数 - -| 参数名 | 类型 | 必填 | 说明 | 示例 | -|--------|------|------|------|------| -| search | string | 否 | 搜索关键词(姓名/岗位/联系方式) | 张三 | -| reply_status | string | 否 | 回复状态筛选 | 已回复 | -| wechat_exchanged | boolean | 否 | 是否交换微信 | true | -| start_date | string | 否 | 开始日期(YYYY-MM-DD) | 2024-01-01 | -| end_date | string | 否 | 结束日期(YYYY-MM-DD) | 2024-12-31 | - -### 请求示例 - -```bash -# 导出所有联系记录 -GET /api/contacts/export - -# 导出指定时间段的记录 -GET /api/contacts/export?start_date=2024-01-01&end_date=2024-12-31 - -# 导出已回复且交换微信的记录 -GET /api/contacts/export?reply_status=已回复&wechat_exchanged=true - -# 导出组合筛选结果 -GET /api/contacts/export?search=产品经理&start_date=2024-01-01&end_date=2024-03-31&reply_status=已回复 -``` - -### 响应示例 - -```json -{ - "code": 200, - "msg": "success", - "data": { - "download_url": "http://127.0.0.1:8000/media/exports/contacts_export_20240304_153045_a1b2c3d4.xlsx", - "filename": "contacts_export_20240304_153045_a1b2c3d4.xlsx", - "total_records": 150, - "generated_at": "2024-03-04 15:30:45" - } -} -``` - -### 响应字段说明 - -| 字段名 | 类型 | 说明 | -|--------|------|------| -| download_url | string | 文件下载链接(完整 URL) | -| filename | string | 生成的文件名 | -| total_records | integer | 导出的记录总数 | -| generated_at | string | 文件生成时间 | - -### Excel 文件格式 - -**表头**(蓝色背景,白色粗体文字): - -| 列名 | 说明 | 示例 | -|------|------|------| -| ID | 记录 ID | 1 | -| 姓名 | 联系人姓名 | 张三 | -| 岗位 | 应聘岗位 | 产品经理 | -| 联系方式 | 电话或微信 | 13800138000 | -| 回复状态 | 回复状态 | 已回复 | -| 是否交换微信 | 是/否 | 是 | -| Worker ID | Worker 标识 | worker-001 | -| 备注 | 备注信息 | 沟通顺畅,有意向 | -| 联系时间 | 联系时间 | 2024-03-01 10:30:00 | -| 创建时间 | 创建时间 | 2024-03-01 10:00:00 | - -### 前端调用示例 - -```javascript -// 使用 axios -const exportContacts = async (params) => { - try { - const response = await axios.get('/api/contacts/export', { - params: params, - headers: { - 'Authorization': `Bearer ${token}` - } - }); - - if (response.data.code === 200) { - const { download_url, filename, total_records } = response.data.data; - - // 方式1:直接打开下载链接 - window.open(download_url, '_blank'); - - // 方式2:使用 a 标签下载 - const link = document.createElement('a'); - link.href = download_url; - link.download = filename; - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); - - // 提示用户 - console.log(`成功导出 ${total_records} 条记录`); - } - } catch (error) { - console.error('导出失败:', error); - } -}; - -// 调用示例 -exportContacts({ - start_date: '2024-01-01', - end_date: '2024-12-31', - reply_status: '已回复' -}); -``` - -```javascript -// 使用 fetch -const exportContacts = async (params) => { - const queryString = new URLSearchParams(params).toString(); - - try { - const response = await fetch(`/api/contacts/export?${queryString}`, { - headers: { - 'Authorization': `Bearer ${token}` - } - }); - - const result = await response.json(); - - if (result.code === 200) { - const { download_url, filename, total_records } = result.data; - - // 直接下载文件 - const link = document.createElement('a'); - link.href = download_url; - link.download = filename; - link.click(); - - alert(`成功导出 ${total_records} 条记录`); - } - } catch (error) { - console.error('导出失败:', error); - } -}; -``` - -```vue - - - - -``` - ---- - -## 错误码说明 - -| 错误码 | 说明 | -|--------|------| -| 200 | 成功 | -| 400 | 请求参数错误 | -| 401 | 未登录或 token 无效 | -| 500 | 服务器内部错误 | - -## 注意事项 - -1. **时间筛选**: - - `start_date` 从当天 00:00:00 开始 - - `end_date` 到当天 23:59:59 结束 - - 时间筛选基于 `created_at` 字段(创建时间) - -2. **搜索功能**: - - `search` 参数支持模糊匹配 - - 同时搜索姓名、岗位、联系方式三个字段 - -3. **导出机制**: - - 导出接口返回下载链接,不直接返回文件流 - - 文件保存在服务器 `media/exports/` 目录 - - 文件名格式:`contacts_export_{时间戳}_{随机ID}.xlsx` - - 导出接口不分页,会导出所有符合条件的记录 - - 建议在导出大量数据时添加时间范围限制 - -4. **文件管理**: - - 导出的文件会保存在服务器上 - - 建议定期清理过期的导出文件 - - 可以通过定时任务删除超过一定时间的文件 - -5. **认证要求**: - - 所有接口都需要在 Header 中携带 `Authorization` token - - token 格式:`Bearer ` - -6. **下载链接**: - - 返回的 `download_url` 是可直接访问的完整下载 URL - - 前端可直接 `window.open(download_url)` 或 `a.href = download_url` 下载 diff --git a/API文档.md b/API文档.md deleted file mode 100644 index 837d317..0000000 --- a/API文档.md +++ /dev/null @@ -1,693 +0,0 @@ -# BOSS 直聘自动化平台 - API 接口文档 - -**Base URL**: `http://{服务器IP}:9000` - -**认证方式**: Cookie(`auth_token`),登录成功后自动通过 `Set-Cookie` 设置,后续请求自动携带。 - -**请求格式**: 支持 `application/json` 和 `multipart/form-data` - -**响应规范**: 所有接口的 JSON 响应体均包含 **`code`** 字段,与 HTTP 状态码一致。成功时如 `code: 200`、`code: 201`;错误时如 `code: 401`、`code: 404`。原返回数组的接口会包装为 `{"code": 状态码, "data": 原数组}`。 - ---- - -## 一、健康检查 - -### GET /health - -**说明**: 检查服务器是否正常运行,无需登录。 - -**状态码**: - -| 状态码 | 说明 | -|--------|------| -| 200 | 成功,返回服务状态与在线 Worker 数 | -| 500 | 服务器内部错误(少见) | - -**请求参数**: 无 - -**响应示例**: -```json -{ - "status": "ok", - "workers_online": 2 -} -``` - -| 返回字段 | 类型 | 说明 | -|---------|------|------| -| status | string | 服务状态,固定 `"ok"` | -| workers_online | int | 当前在线 Worker 数量 | - ---- - -## 二、认证 - -### POST /api/auth/login - -**说明**: 管理员登录,无需认证。登录成功后通过 `Set-Cookie` 返回 `auth_token`。 - -**状态码**: - -| 状态码 | 说明 | -|--------|------| -| 200 | 成功,返回 token 并设置 Cookie | -| 401 | 用户名或密码错误 | - -**请求参数**: - -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| username | string | 是 | 用户名 | -| password | string | 是 | 密码 | - -**请求示例**: -```json -{ - "username": "admin", - "password": "boss_dp_admin" -} -``` - -**成功响应** (200): -```json -{ - "token": "a1b2c3d4e5f6..." -} -``` - -**失败响应** (401): -```json -{ - "detail": "用户名或密码错误" -} -``` - -| 返回字段 | 类型 | 说明 | -|---------|------|------| -| token | string | 登录 token(同时通过 Cookie 设置) | - -**响应 Header**: -``` -Set-Cookie: auth_token=a1b2c3d4e5f6...; HttpOnly; Max-Age=31536000; SameSite=Lax -``` - ---- - -## 三、Worker 管理 - -> 以下接口均需登录(携带 `auth_token` Cookie) - -### GET /api/workers - -**说明**: 获取所有已注册 Worker 列表。 - -**状态码**: - -| 状态码 | 说明 | -|--------|------| -| 200 | 成功,返回 Worker 数组 | -| 401 | 未登录或 token 失效 | - -**请求参数**: 无 - -**响应示例**: -```json -[ - { - "worker_id": "worker-1", - "worker_name": "本机", - "browsers": [ - { - "id": "abd63190eea84dc49429962f7bb330a4", - "name": "第一个", - "remark": "" - } - ], - "online": true, - "current_task_id": null - } -] -``` - -| 返回字段 | 类型 | 说明 | -|---------|------|------| -| worker_id | string | Worker 唯一标识 | -| worker_name | string | Worker 名称(电脑名) | -| browsers | array | 该电脑上的比特浏览器环境列表 | -| browsers[].id | string | 浏览器窗口 ID | -| browsers[].name | string | 浏览器窗口名称(环境名) | -| browsers[].remark | string | 备注 | -| online | boolean | 是否在线 | -| current_task_id | string/null | 当前正在执行的任务 ID | - ---- - -### GET /api/workers/{worker_id} - -**说明**: 获取指定 Worker 的详细信息。 - -**状态码**: - -| 状态码 | 说明 | -|--------|------| -| 200 | 成功,返回单个 Worker 对象 | -| 401 | 未登录或 token 失效 | -| 404 | Worker 不存在 | - -**路径参数**: - -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| worker_id | string | 是 | Worker ID | - -**成功响应** (200): 同上单个 Worker 对象 - -**失败响应** (404): -```json -{ - "detail": "Worker worker-99 不存在" -} -``` - ---- - -## 四、账号管理 - -> 以下接口均需登录(携带 `auth_token` Cookie) - -### POST /api/accounts - -**说明**: 添加账号(将浏览器环境名称绑定到指定电脑)。若已存在相同绑定则直接返回已有记录。 - -**状态码**: - -| 状态码 | 说明 | -|--------|------| -| 201 | 成功创建或返回已有记录 | -| 400 | 请求参数错误(如缺少 browser_name、worker_id) | -| 401 | 未登录或 token 失效 | - -**请求参数**: - -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| browser_name | string | 是 | 浏览器环境名称 | -| worker_id | string | 是 | 目标电脑的 Worker ID | - -**请求示例**: -```json -{ - "browser_name": "第一个", - "worker_id": "worker-1" -} -``` - -**成功响应** (201): -```json -{ - "id": 1, - "worker_id": "worker-1", - "browser_id": "name:第一个", - "browser_name": "第一个", - "boss_username": "", - "is_logged_in": false, - "current_task_id": null, - "current_task_status": null, - "checked_at": null, - "created_at": "2026-02-14T16:00:00", - "updated_at": "2026-02-14T16:00:00", - "worker_name": "本机", - "worker_online": true -} -``` - ---- - -### GET /api/accounts - -**说明**: 查询所有账号列表,包含电脑名称、在线状态、任务执行状态。 - -**状态码**: - -| 状态码 | 说明 | -|--------|------| -| 200 | 成功,返回账号数组 | -| 401 | 未登录或 token 失效 | - -**查询参数**: - -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| worker_id | string | 否 | 按 Worker ID 过滤 | - -**响应示例**: -```json -[ - { - "id": 1, - "worker_id": "worker-1", - "browser_id": "abd63190eea84dc49429962f7bb330a4", - "browser_name": "第一个", - "boss_username": "某用户", - "is_logged_in": true, - "current_task_id": "3f113d90bb32", - "current_task_status": "success", - "checked_at": "2026-02-14T16:05:00", - "created_at": "2026-02-14T16:00:00", - "updated_at": "2026-02-14T16:05:00", - "worker_name": "本机", - "worker_online": true - } -] -``` - -| 返回字段 | 类型 | 说明 | -|---------|------|------| -| id | int | 账号记录 ID | -| worker_id | string | 绑定的 Worker ID | -| browser_id | string | 比特浏览器窗口 ID | -| browser_name | string | 浏览器环境名称 | -| boss_username | string | BOSS 直聘用户名(检测后填充) | -| boss_id | string | BOSS 直聘用户 ID(检测登录成功时填充) | -| is_logged_in | boolean | 是否已登录 BOSS | -| current_task_id | string/null | 当前关联的任务 ID | -| current_task_status | string/null | 当前任务状态:`pending` / `dispatched` / `running` / `success` / `failed` | -| checked_at | string/null | 最近一次检测时间(ISO 格式) | -| created_at | string | 创建时间 | -| updated_at | string | 更新时间 | -| worker_name | string | 电脑名称(运行时补充) | -| worker_online | boolean | 电脑是否在线(运行时补充) | - ---- - -### GET /api/accounts/{id} - -**说明**: 查询单个账号详情。 - -**状态码**: - -| 状态码 | 说明 | -|--------|------| -| 200 | 成功,返回单个账号对象 | -| 401 | 未登录或 token 失效 | -| 404 | 账号不存在 | - -**路径参数**: - -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| id | int | 是 | 账号记录 ID | - -**成功响应** (200): 同上单个账号对象 - -**失败响应** (404): -```json -{ - "detail": "账号不存在" -} -``` - ---- - -### DELETE /api/accounts/{id} - -**说明**: 删除指定账号。 - -**状态码**: - -| 状态码 | 说明 | -|--------|------| -| 200 | 成功删除 | -| 401 | 未登录或 token 失效 | -| 404 | 账号不存在 | - -**路径参数**: - -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| id | int | 是 | 账号记录 ID | - -**成功响应** (200): -```json -{ - "message": "账号已删除" -} -``` - -**失败响应** (404): -```json -{ - "detail": "账号不存在" -} -``` - ---- - -## 五、任务管理 - -> 以下接口均需登录(携带 `auth_token` Cookie) -> -> **统一任务入口**:所有任务(检查登录、招聘等)都通过 `POST /api/tasks` 提交,通过 `task_type` 字段区分任务类型。 - -### POST /api/tasks - -**说明**: 提交新任务。通过 `task_type` 指定任务类型,系统自动路由到目标 Worker 执行。 - -**状态码**: - -| 状态码 | 说明 | -|--------|------| -| 201 | 成功,任务已创建并派发 | -| 400 | 未指定 id、boss_id、worker_id 或 account_name | -| 401 | 未登录或 token 失效 | -| 409 | 同一账号已有执行中的任务 | -| 404 | 未找到拥有该浏览器环境的在线 Worker | -| 503 | Worker 不在线 / WebSocket 连接不存在 / 派发失败 | - -**请求参数**: - -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| task_type | string | 是 | 任务类型:`check_login`(检查登录)、`boss_recruit`(招聘) | -| id | int | 否 | 账号 ID(直接指定,推荐) | -| boss_id | int | 否 | 即 /api/accounts 返回的 id(账号主键),与 id 等价 | -| worker_id | string | 否 | 目标 Worker ID | -| account_name | string | 否 | 浏览器环境名称(系统自动查找对应 Worker) | -| params | object | 否 | 任务附加参数,默认 `{}` | - -**路由规则**: `id`、`account_id`、`boss_id` 等价(均为账号主键);否则 `worker_id` 或 `account_name`。 - -**请求示例 — 检查登录(推荐用 id)**: -```json -{ - "task_type": "check_login", - "id": 2 -} -``` - -**请求示例 — 招聘任务**: -```json -{ - "task_type": "boss_recruit", - "worker_id": "worker-1", - "params": { - "keyword": "Python开发", - "count": 10 - } -} -``` - -**成功响应** (201): -```json -{ - "task_id": "3f113d90bb32", - "task_type": "check_login", - "status": "dispatched", - "worker_id": "worker-1", - "account_name": "第一个", - "params": {}, - "progress": null, - "result": null, - "error": null, - "created_at": 1739520000.123, - "updated_at": 1739520000.456 -} -``` - -**失败响应**: - -| 状态码 | 说明 | -|--------|------| -| 400 | 未指定 id、boss_id、worker_id 或 account_name | -| 401 | 未登录或 token 失效 | -| 409 | 同一账号已有执行中的任务 | -| 404 | 未找到拥有该浏览器环境的在线 Worker | -| 503 | Worker 不在线 / WebSocket 连接不存在 / 派发失败 | - ---- - -### GET /api/tasks - -**说明**: 查询任务列表(内存中的任务)。 - -**状态码**: - -| 状态码 | 说明 | -|--------|------| -| 200 | 成功,返回任务数组 | -| 401 | 未登录或 token 失效 | - -**查询参数**: - -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| worker_id | string | 否 | 按 Worker ID 过滤 | -| status | string | 否 | 按状态过滤:`pending` / `dispatched` / `running` / `success` / `failed` / `cancelled` | -| limit | int | 否 | 返回数量限制,默认 50 | - -**响应示例**: -```json -[ - { - "task_id": "3f113d90bb32", - "task_type": "check_login", - "status": "success", - "worker_id": "worker-1", - "account_name": "第一个", - "params": {}, - "progress": "检测完成: 第一个 → 未登录 ()", - "result": { - "browser_id": "abd63190eea84dc49429962f7bb330a4", - "browser_name": "第一个", - "boss_username": "", - "is_logged_in": false - }, - "error": null, - "created_at": 1739520000.123, - "updated_at": 1739520030.789 - } -] -``` - -| 返回字段 | 类型 | 说明 | -|---------|------|------| -| task_id | string | 任务唯一 ID(12 位十六进制) | -| task_type | string | 任务类型 | -| status | string | 任务状态:`pending` → `dispatched` → `running` → `success`/`failed` | -| worker_id | string/null | 执行任务的 Worker ID | -| account_name | string/null | 关联的浏览器环境名称 | -| params | object | 任务参数 | -| progress | string/null | 执行进度描述 | -| result | object/null | 任务结果(成功时返回) | -| error | string/null | 错误信息(失败时返回) | -| created_at | float | 创建时间(Unix 时间戳) | -| updated_at | float | 最后更新时间(Unix 时间戳) | - ---- - -### GET /api/tasks/{account_id} - -**说明**: 按账号 ID 查询任务列表(不支持按 task_id 查询)。 -- 不传 `page/page_size`:返回任务数组(兼容旧版前端) -- 传 `page` 或 `page_size`:返回分页对象 - -**状态码**: - -| 状态码 | 说明 | -|--------|------| -| 200 | 成功,返回任务数组 | -| 401 | 未登录或 token 失效 | -| 404 | 账号不存在 | - -**路径参数**: - -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| account_id | int | 是 | 账号 ID(即 `/api/accounts` 返回的 `id`) | -| status | string | 否 | 按状态过滤:`pending` / `dispatched` / `running` / `success` / `failed` / `cancelled` | -| limit | int | 否 | 兼容参数,不分页模式下表示最多返回条数;分页模式下可作为 `page_size` 默认值 | -| page | int | 否 | 分页页码(从 1 开始) | -| page_size | int | 否 | 每页条数,默认 20,最大 200 | - -**成功响应** (200): -- 兼容模式:同上任务对象数组 -- 分页模式: -```json -{ - "total": 123, - "page": 1, - "page_size": 20, - "results": [ - { - "task_id": "3f113d90bb32", - "task_type": "check_login", - "status": "success", - "worker_id": "worker-1", - "account_name": "第一个", - "params": {}, - "progress": null, - "result": {}, - "error": null, - "created_at": "2026-03-01T20:00:00", - "updated_at": "2026-03-01T20:00:00" - } - ] -} -``` - -**失败响应** (404): -```json -{ - "detail": "账号 xxx 不存在" -} -``` - ---- - -## 六、任务类型说明 - -| task_type | 说明 | 必要参数 | 返回 result | -|-----------|------|---------|-------------| -| `check_login` | 检测浏览器环境中 BOSS 账号是否已登录 | `account_name`(环境名) | `{ "browser_id", "browser_name", "boss_username", "is_logged_in" }` | -| `boss_recruit` | 执行 BOSS 直聘自动招聘流程 | `worker_id` + `params` | `{ "job_title", "total_processed", "wechat_collected", "phone_collected", "details", "error_count" }` | - -`boss_recruit` 的 `details` 项示例: - -```json -{ - "name": "候选人A", - "job": "Python开发", - "wechat": "wxid_xxx", - "phone": "13800138000" -} -``` - -说明: -- 若自动化流程发生报错,任务状态会标记为 `failed`(不再显示为 `success`)。 -- 失败任务也会保留 `result`,便于在任务列表查看已采集到的微信号/手机号数量。 - ---- - -## 七、任务状态流转 - -``` -pending → dispatched → running → success - → failed - → cancelled -``` - -| 状态 | 说明 | -|------|------| -| pending | 任务已创建,等待派发 | -| dispatched | 已通过 WebSocket 发送给 Worker | -| running | Worker 正在执行中 | -| success | 执行成功 | -| failed | 执行失败 | -| cancelled | 已取消 | - ---- - -## 八、联系记录(数据展示) - -> 以下接口均需登录(携带 `auth_token` Cookie) - -### GET /api/contacts/query(按电话/微信号查询) - -**说明**:根据已获取的电话号码或微信号查询联系记录,用于数据展示。对 `contact` 字段做模糊匹配。 - -**状态码**: - -| 状态码 | 说明 | -|--------|------| -| 200 | 成功,返回分页结果 | -| 400 | 未提供 contact 参数 | -| 401 | 未登录或 token 失效 | - -**查询参数**: - -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| contact | string | 是 | 电话号码或微信号(支持部分匹配) | -| page | int | 否 | 页码,默认 1 | -| page_size | int | 否 | 每页条数,默认 20 | - -**请求示例**: -``` -GET /api/contacts/query?contact=13800138000 -GET /api/contacts/query?contact=wxid_abc&page=1&page_size=10 -``` - -**成功响应** (200): -```json -{ - "total": 2, - "page": 1, - "page_size": 20, - "contact_keyword": "13800138000", - "results": [ - { - "id": 1, - "name": "张三", - "position": "Python开发", - "contact": "13800138000", - "reply_status": "已回复", - "wechat_exchanged": true, - "account_id": 1, - "worker_id": "worker-1", - "notes": "", - "contacted_at": "2026-02-24T10:00:00", - "created_at": "2026-02-24T10:00:00" - } - ] -} -``` - -| 返回字段 | 类型 | 说明 | -|---------|------|------| -| total | int | 匹配总数 | -| page | int | 当前页 | -| page_size | int | 每页条数 | -| contact_keyword | string | 本次查询使用的关键词 | -| results | array | 联系记录列表(字段同联系记录模型) | - -**失败响应** (400):未提供 contact 参数时 -```json -{ - "detail": "请提供 contact 参数(电话号码或微信号)" -} -``` - ---- - -### GET /api/contacts - -**说明**:分页查询联系记录,支持按姓名、岗位、联系方式关键词搜索,以及按回复状态、是否交换微信筛选。 - -**状态码**: - -| 状态码 | 说明 | -|--------|------| -| 200 | 成功,返回 total、page、page_size、results | -| 401 | 未登录或 token 失效 | - -**查询参数**:`search`(关键词)、`reply_status`、`wechat_exchanged`、`page`、`page_size`。返回格式同上(含 `total`、`page`、`page_size`、`results`)。 - ---- - -## 九、通用错误格式 - -所有接口的错误响应统一为: - -```json -{ - "detail": "错误描述信息" -} -``` - -| 状态码 | 说明 | -|--------|------| -| 400 | 请求参数错误 | -| 401 | 未登录或 token 失效 | -| 403 | 无权限 | -| 404 | 资源不存在 | -| 503 | Worker 不在线或服务不可用 | diff --git a/BOSS招聘优化说明.md b/BOSS招聘优化说明.md deleted file mode 100644 index 54bf895..0000000 --- a/BOSS招聘优化说明.md +++ /dev/null @@ -1,166 +0,0 @@ -# BOSS招聘自动化优化说明 - -## 优化内容 - -### 1. 添加筛选功能 - -#### 活跃度筛选 -- 支持解析"03月03日"、"昨天"、"今天"、"刚刚"等时间格式 -- 筛选条件: - - 今天活跃 - - 3天内活跃 - - 本周活跃 - - 本月活跃 - - 不限 - -#### 年龄筛选 -- 从候选人简历中获取年龄信息 -- 根据配置的最小年龄和最大年龄进行筛选 - -#### 学历筛选 -- 支持学历等级:初中、高中、中专、大专、本科、硕士、博士 -- 候选人学历需要达到或高于要求学历 - -#### 期望职位筛选 -- 根据候选人的期望职位(jobName字段)进行筛选 -- 支持多个职位关键词匹配 - -### 2. 联系人记录管理 - -#### 自动保存联系人 -- 从聊天中获取到的联系方式(微信号/手机号)自动保存到数据库 -- 保存到 `ContactRecord` 表中 -- 包含信息: - - 姓名 - - 岗位 - - 联系方式(微信或手机) - - 回复状态 - - 是否交换微信 - - 联系时间 - - 备注 - -#### 去重处理 -- 检查是否已存在相同姓名和联系方式的记录 -- 如果存在则更新,不存在则创建新记录 - -### 3. 复聊管理 - -#### 消息过滤 -- **过滤自己发送的消息**:只保留对方发送的消息进行分析 -- 解决了之前"发送带微信号的消息后,识别到自己消息"的问题 -- 通过 `fromId` 字段判断消息来源(fromId=0 表示对方发送) - -#### 等待回复 -- 发送询问微信号后,等待最多30秒 -- 每3秒检查一次是否有新回复 -- 自动识别对方回复中的联系方式 - -#### 跟进话术 -- 如果对方没有回复,可以发送跟进话术 -- 支持按岗位配置不同的跟进话术 -- 从 `ChatScript` 表中读取话术(script_type="followup") -- 如果没有特定岗位话术,使用通用话术 - -## 使用方法 - -### 1. 配置筛选条件 - -在数据库 `filter_config` 表中配置筛选条件: - -```python -FilterConfig.objects.create( - name="Python开发筛选", - age_min=22, - age_max=35, - education="本科", - activity="3天内活跃", - positions=["Python开发", "后端开发", "全栈开发"], - is_active=True -) -``` - -### 2. 配置复聊话术 - -在数据库 `chat_script` 表中配置话术: - -```python -ChatScript.objects.create( - position="Python开发", - script_type="followup", - content="您好,看到您的简历很符合我们的要求,期待与您进一步沟通。", - is_active=True -) - -# 通用话术 -ChatScript.objects.create( - position="通用", - script_type="followup", - content="您好,期待与您进一步沟通。", - is_active=True -) -``` - -### 3. 运行招聘任务 - -任务会自动: -1. 获取候选人列表 -2. 应用筛选条件 -3. 逐个打开会话 -4. 过滤自己的消息,只分析对方消息 -5. 如果没有联系方式,发送询问 -6. 等待对方回复并识别联系方式 -7. 自动保存联系人记录到数据库 -8. 如果需要,发送跟进话术 - -## 数据库表说明 - -### FilterConfig(筛选配置表) -- `name`: 配置名称 -- `age_min`: 最小年龄 -- `age_max`: 最大年龄 -- `education`: 学历要求 -- `activity`: 活跃度要求 -- `positions`: 期望岗位列表(JSON) -- `is_active`: 是否启用 - -### ChatScript(话术表) -- `position`: 岗位类型 -- `script_type`: 话术类型(first/followup/wechat/closing) -- `content`: 话术内容 -- `keywords`: 触发关键词 -- `is_active`: 是否启用 - -### ContactRecord(联系人记录表) -- `name`: 姓名 -- `position`: 岗位 -- `contact`: 联系方式 -- `reply_status`: 回复状态 -- `wechat_exchanged`: 是否交换微信 -- `notes`: 备注 -- `contacted_at`: 联系时间 - -## 注意事项 - -1. **活跃度时间解析**: - - 支持"03月03日"格式,自动判断年份 - - 如果月份大于当前月份,认为是去年的日期 - -2. **消息过滤**: - - 通过 `fromId` 字段区分消息来源 - - `fromId=0` 表示对方发送的消息 - - 其他值表示自己发送的消息 - -3. **复聊等待时间**: - - 默认等待30秒 - - 可以根据实际情况调整 `max_wait` 参数 - -4. **筛选配置**: - - 只有 `is_active=True` 的配置才会生效 - - 如果没有启用的配置,跳过筛选,处理所有候选人 - -## 优化效果 - -1. **提高效率**:通过筛选减少无效沟通 -2. **自动记录**:联系方式自动保存,无需手动整理 -3. **智能识别**:过滤自己的消息,只识别对方的联系方式 -4. **持续跟进**:支持复聊管理,提高回复率 diff --git a/BOSS招聘自动化完整优化说明.md b/BOSS招聘自动化完整优化说明.md deleted file mode 100644 index 07c1e7f..0000000 --- a/BOSS招聘自动化完整优化说明.md +++ /dev/null @@ -1,488 +0,0 @@ -# BOSS招聘自动化 - 完整优化说明 - -## 优化概述 - -本次优化解决了以下核心问题: - -1. ✅ **消息过滤问题**:过滤掉自己发送的包含"微信号"等关键词的消息 -2. ✅ **筛选功能**:支持活跃度、年龄、学历、期望职位筛选 -3. ✅ **联系人记录**:自动保存聊天中获取的联系方式 -4. ✅ **复聊管理**:支持多轮复聊、自定义话术、间隔时间控制 - ---- - -## 一、消息过滤优化 - -### 问题描述 -之前的代码会识别到自己发送的包含"微信号"三个字的消息,导致误判。 - -### 解决方案 - -#### 1. 通过 fromId 区分消息来源 -```python -def _filter_my_messages(self, messages: list) -> list: - """过滤掉自己发送的消息,只保留对方的消息。""" - filtered = [] - for msg in messages: - # fromId = 0 表示对方发送的消息 - from_id = msg.get("fromId", 0) - if from_id == 0: - filtered.append(msg) - return filtered -``` - -#### 2. 在等待回复时过滤发送的话术 -```python -# 检查最后几条消息 -for text in panel_texts[-5:]: - # 过滤掉我们发送的消息 - if sent_message in text: - continue - - # 过滤掉包含"微信号"但没有真实微信号的消息 - if "微信号" in text and not self._extract_wechat(text): - continue -``` - ---- - -## 二、筛选功能 - -### 支持的筛选条件 - -#### 1. 活跃度筛选 -支持的时间格式: -- `"03月03日"` - 自动判断年份 -- `"昨天"` - 昨天 -- `"今天"` - 今天 -- `"刚刚"` - 今天 - -筛选选项: -- `"今天活跃"` - 今天上线 -- `"3天内活跃"` - 3天内上线 -- `"本周活跃"` - 7天内上线 -- `"本月活跃"` - 30天内上线 -- `"不限"` - 不筛选 - -#### 2. 年龄筛选 -从候选人简历的 `resume.age` 字段获取,根据 `age_min` 和 `age_max` 筛选。 - -#### 3. 学历筛选 -学历等级:`初中 < 高中 < 中专 < 大专 < 本科 < 硕士 < 博士` - -候选人学历需要达到或高于要求学历。 - -#### 4. 期望职位筛选 -从候选人的 `jobName` 字段匹配配置的职位列表。 - -### 配置示例 - -```python -FilterConfig.objects.create( - name="Python开发筛选", - age_min=22, - age_max=35, - education="本科", - activity="3天内活跃", - positions=["Python开发", "后端开发", "全栈开发"], - is_active=True -) -``` - ---- - -## 三、联系人记录管理 - -### 自动保存功能 - -当从聊天中提取到联系方式(微信号或手机号)时,自动保存到 `ContactRecord` 表。 - -### 保存的信息 -- 姓名 -- 岗位 -- 联系方式(微信或手机) -- 回复状态 -- 是否交换微信 -- 联系时间 -- 备注 - -### 去重逻辑 -- 检查是否已存在相同姓名和联系方式的记录 -- 如果存在则更新,不存在则创建 - ---- - -## 四、复聊管理系统 - -### 核心特性 - -#### 1. 多轮复聊 -- 支持配置第1天、第2天、第3天...的不同话术 -- 支持配置"往后一直"使用的话术(`day_number=0`) - -#### 2. 间隔时间控制 -- 每条话术都有独立的 `interval_hours` 配置 -- 系统自动检查距离上次发送的时间 -- 只有超过间隔时间才会发送下一条 - -#### 3. 自定义话术 -- 通过API接口添加、修改、删除话术 -- 支持按岗位配置不同的复聊策略 -- 支持通用配置作为后备 - -#### 4. 回复追踪 -- 记录每次发送的话术 -- 记录是否得到回复 -- 记录回复内容和时间 - -### 复聊流程 - -``` -第1天:发送询问微信号 - ↓ -等待24小时 - ↓ -第2天:如果没有回复,发送跟进话术 - ↓ -等待24小时 - ↓ -第3天:如果还没有回复,发送第三条话术 - ↓ -等待72小时 - ↓ -往后:每隔72小时发送一次"往后一直"的话术 -``` - -### 配置示例 - -```json -{ - "config": { - "name": "Python开发复聊配置", - "position": "Python开发", - "is_active": true - }, - "scripts": [ - { - "day_number": 1, - "content": "后续沟通会更及时,您方便留一下您的微信号吗?我这边加您。", - "interval_hours": 24 - }, - { - "day_number": 2, - "content": "您好,不知道您是否方便留个联系方式?", - "interval_hours": 24 - }, - { - "day_number": 0, - "content": "您好,如果您感兴趣可以随时联系我。", - "interval_hours": 72 - } - ] -} -``` - ---- - -## 五、数据库表结构 - -### 新增表 - -#### 1. FollowUpConfig(复聊配置表) -| 字段 | 类型 | 说明 | -|------|------|------| -| id | INT | 主键 | -| name | VARCHAR(128) | 配置名称 | -| position | VARCHAR(64) | 岗位类型 | -| is_active | BOOLEAN | 是否启用 | -| created_at | DATETIME | 创建时间 | -| updated_at | DATETIME | 更新时间 | - -#### 2. FollowUpScript(复聊话术表) -| 字段 | 类型 | 说明 | -|------|------|------| -| id | INT | 主键 | -| config_id | INT | 关联的配置ID | -| day_number | INT | 第几天(0=往后一直) | -| content | TEXT | 话术内容 | -| interval_hours | INT | 间隔小时数 | -| order | INT | 排序 | -| is_active | BOOLEAN | 是否启用 | -| created_at | DATETIME | 创建时间 | - -#### 3. FollowUpRecord(复聊记录表) -| 字段 | 类型 | 说明 | -|------|------|------| -| id | INT | 主键 | -| contact_id | INT | 联系人ID | -| config_id | INT | 配置ID | -| script_id | INT | 话术ID | -| day_number | INT | 第几天 | -| content | TEXT | 发送的内容 | -| sent_at | DATETIME | 发送时间 | -| got_reply | BOOLEAN | 是否得到回复 | -| reply_content | TEXT | 回复内容 | -| replied_at | DATETIME | 回复时间 | - ---- - -## 六、API接口 - -### 复聊配置 -- `GET /api/followup-configs` - 获取配置列表 -- `POST /api/followup-configs` - 创建配置 -- `GET /api/followup-configs/{id}` - 获取配置详情 -- `PUT /api/followup-configs/{id}` - 更新配置 -- `DELETE /api/followup-configs/{id}` - 删除配置 - -### 复聊话术 -- `GET /api/followup-scripts` - 获取话术列表 -- `POST /api/followup-scripts` - 创建话术 -- `GET /api/followup-scripts/{id}` - 获取话术详情 -- `PUT /api/followup-scripts/{id}` - 更新话术 -- `DELETE /api/followup-scripts/{id}` - 删除话术 - -### 复聊记录 -- `GET /api/followup-records` - 获取记录列表 -- `POST /api/followup-records/send` - 手动发送消息 - ---- - -## 七、使用步骤 - -### 1. 运行数据库迁移 -```bash -python server/manage.py migrate -``` - -### 2. 初始化配置(可选) -```bash -python scripts/init_followup_config.py -``` - -### 3. 通过API配置复聊策略 - -#### 创建配置 -```bash -POST /api/followup-configs -{ - "name": "Python开发复聊", - "position": "Python开发", - "is_active": true -} -``` - -#### 添加话术 -```bash -POST /api/followup-scripts -{ - "config_id": 1, - "day_number": 1, - "content": "您的自定义话术", - "interval_hours": 24, - "order": 1, - "is_active": true -} -``` - -### 4. 运行招聘任务 -系统会自动: -- 应用筛选条件 -- 过滤自己的消息 -- 保存联系人记录 -- 按配置进行复聊 - ---- - -## 八、关键代码说明 - -### 1. 消息过滤 -```python -# 过滤掉自己发送的消息 -filtered_messages = self._filter_my_messages(messages) -has_contact_keyword = self._has_contact_keyword(filtered_messages) -``` - -### 2. 筛选应用 -```python -# 应用筛选条件 -friend_list = self._apply_filters(friend_list) -``` - -### 3. 保存联系人 -```python -# 保存并获取contact_id -contact_id = self._save_contact_record(name, job_name, contacts, action_state) -``` - -### 4. 复聊管理 -```python -# 进行复聊管理 -reply_result = self._handle_follow_up_chat(tab, name, job_name, contact_id) -``` - ---- - -## 九、文件清单 - -### 代码文件 -- `worker/tasks/boss_recruit.py` - 招聘任务处理器(已优化) -- `server/models.py` - 数据模型(新增3个表) -- `server/serializers.py` - 序列化器(新增3个) -- `server/api/followup.py` - 复聊配置API(新增) -- `server/urls.py` - URL路由(已更新) -- `server/migrations/0004_add_followup_config.py` - 数据库迁移(新增) - -### 脚本文件 -- `scripts/init_followup_config.py` - 初始化复聊配置 -- `scripts/test_recruit_features.py` - 功能测试 - -### 文档文件 -- `BOSS招聘优化说明.md` - 详细功能说明 -- `复聊配置API使用指南.md` - API使用指南 -- `快速参考指南.md` - 快速参考 -- `代码变更清单.md` - 变更记录 -- `优化完成总结.md` - 完成总结 -- `BOSS招聘自动化完整优化说明.md` - 本文件 - ---- - -## 十、测试验证 - -### 语法检查 -```bash -python -m py_compile worker/tasks/boss_recruit.py -``` -✅ 通过 - -### 功能测试 -```bash -python scripts/test_recruit_features.py -``` -✅ 全部通过 - ---- - -## 十一、常见问题 - -### Q1: 为什么会识别到自己发送的消息? -**A**: 已修复。现在通过 `fromId` 字段区分消息来源,只识别 `fromId=0` 的消息(对方发送的)。 - -### Q2: 如何配置复聊话术? -**A**: 通过 `/api/followup-scripts` 接口创建话术,设置 `day_number` 和 `interval_hours`。 - -### Q3: 如何设置"往后一直"的话术? -**A**: 创建话术时设置 `day_number=0`,系统会在没有特定天数话术时使用它。 - -### Q4: 复聊间隔时间如何控制? -**A**: 每条话术都有 `interval_hours` 字段,系统会自动检查距离上次发送的时间。 - -### Q5: 如何手动发送复聊消息? -**A**: 使用 `POST /api/followup-records/send` 接口,传入 `contact_id` 和 `content`。 - -### Q6: 联系人记录在哪里查看? -**A**: 通过 `/api/contacts` 接口查询,或在数据库的 `contact_record` 表中查看。 - -### Q7: 如何为不同岗位配置不同的复聊策略? -**A**: 创建多个 `FollowUpConfig`,设置不同的 `position` 字段。系统会优先匹配岗位配置。 - ---- - -## 十二、优化效果 - -### 提高效率 -- 通过筛选减少无效沟通 -- 自动化复聊,节省人工时间 - -### 提高质量 -- 消息过滤避免误识别 -- 多轮复聊提高回复率 - -### 数据管理 -- 自动保存联系人记录 -- 完整的复聊记录追踪 - ---- - -## 十三、后续建议 - -1. **优化筛选条件**:根据实际效果调整筛选参数 -2. **优化话术内容**:根据回复率调整话术 -3. **添加数据统计**:统计筛选通过率、回复率等 -4. **添加黑名单**:避免重复联系 -5. **智能话术选择**:根据候选人回复内容智能选择话术 - ---- - -## 十四、技术细节 - -### 时间解析逻辑 -```python -if "昨天" in last_time: - last_active = now - timedelta(days=1) -elif "今天" in last_time or "刚刚" in last_time: - last_active = now -elif "月" in last_time and "日" in last_time: - match = re.search(r"(\d+)月(\d+)日", last_time) - if match: - month = int(match.group(1)) - day = int(match.group(2)) - year = now.year - # 如果月份大于当前月份,说明是去年的 - if month > now.month: - year -= 1 - last_active = datetime(year, month, day) -``` - -### 学历比较逻辑 -```python -edu_levels = ["初中", "高中", "中专", "大专", "本科", "硕士", "博士"] -candidate_level = next((i for i, edu in enumerate(edu_levels) if edu in candidate_edu), -1) -required_level = next((i for i, edu in enumerate(edu_levels) if edu in required_edu), -1) -return candidate_level >= required_level -``` - -### 复聊触发逻辑 -```python -# 1. 获取该联系人的最后一次复聊记录 -last_record = FollowUpRecord.objects.filter(contact_id=contact_id).order_by('-sent_at').first() - -# 2. 确定当前是第几天 -if not last_record: - day_number = 1 # 第一次复聊 -else: - hours_since_last = (now - last_record.sent_at).total_seconds() / 3600 - if hours_since_last < last_script.interval_hours: - return # 间隔时间不足,跳过 - day_number = last_record.day_number + 1 - -# 3. 获取该天的话术 -script = FollowUpScript.objects.filter(config_id=config.id, day_number=day_number).first() -if not script: - # 使用"往后一直"的话术 - script = FollowUpScript.objects.filter(config_id=config.id, day_number=0).first() -``` - ---- - -## 十五、完成时间 - -2026年3月5日 - ---- - -## 附录:快速命令 - -```bash -# 运行数据库迁移 -python server/manage.py migrate - -# 初始化复聊配置(需要Django环境) -python scripts/init_followup_config.py - -# 测试功能 -python scripts/test_recruit_features.py - -# 检查语法 -python -m py_compile worker/tasks/boss_recruit.py -``` diff --git a/BOSS招聘自动化最终使用说明.md b/BOSS招聘自动化最终使用说明.md deleted file mode 100644 index 5438cdf..0000000 --- a/BOSS招聘自动化最终使用说明.md +++ /dev/null @@ -1,274 +0,0 @@ -# BOSS招聘自动化 - 最终使用说明 - -## 优化完成 ✅ - -### 核心问题解决 - -#### 1. ✅ 消息过滤问题 -**问题**:识别到自己发送的包含"微信号"三个字的消息 - -**解决**: -- 通过 `fromId` 字段区分消息来源(`fromId=0` 是对方,其他是自己) -- 在等待回复时过滤掉包含发送话术的消息 -- 过滤掉包含"微信号"关键词但没有真实微信号的消息 - -#### 2. ✅ 筛选功能 -**新增**: -- 活跃度筛选(支持"03月03日"、"昨天"等格式) -- 年龄筛选(从 `resume.age` 获取) -- 学历筛选(支持学历等级比较) -- 期望职位筛选(从 `jobName` 匹配) - -#### 3. ✅ 联系人记录 -**新增**: -- 自动保存到 `ContactRecord` 表 -- 支持去重和更新 -- 记录完整信息(姓名、岗位、联系方式、回复状态等) - -#### 4. ✅ 复聊管理 -**新增**: -- 支持多轮复聊(第1天、第2天、往后一直) -- 支持自定义话术(通过API配置) -- 支持间隔时间控制(每条话术独立配置) -- 支持按岗位配置不同策略 - ---- - -## 快速开始 - -### 1. 运行数据库迁移 -```bash -python server/manage.py migrate -``` - -### 2. 配置复聊策略(通过API) - -#### 创建配置 -```bash -POST /api/followup-configs -{ - "name": "Python开发复聊", - "position": "Python开发", - "is_active": true -} -``` - -#### 添加第1天话术 -```bash -POST /api/followup-scripts -{ - "config_id": 1, - "day_number": 1, - "content": "后续沟通会更及时,您方便留一下您的微信号吗?我这边加您。", - "interval_hours": 24, - "order": 1, - "is_active": true -} -``` - -#### 添加第2天话术 -```bash -POST /api/followup-scripts -{ - "config_id": 1, - "day_number": 2, - "content": "您好,不知道您是否方便留个联系方式?", - "interval_hours": 24, - "order": 1, - "is_active": true -} -``` - -#### 添加"往后一直"话术 -```bash -POST /api/followup-scripts -{ - "config_id": 1, - "day_number": 0, - "content": "您好,如果您感兴趣可以随时联系我。", - "interval_hours": 72, - "order": 1, - "is_active": true -} -``` - -### 3. 配置筛选条件(通过API) - -```bash -POST /api/filters -{ - "name": "Python开发筛选", - "age_min": 22, - "age_max": 35, - "education": "本科", - "activity": "3天内活跃", - "positions": ["Python开发", "后端开发", "全栈开发"], - "is_active": true -} -``` - -### 4. 运行招聘任务 - -通过API或管理界面启动招聘任务,系统会自动: -1. 应用筛选条件 -2. 过滤自己的消息 -3. 保存联系人记录 -4. 按配置进行复聊 - ---- - -## API接口总览 - -### 复聊配置 -- `GET /api/followup-configs` - 获取配置列表 -- `POST /api/followup-configs` - 创建配置 -- `PUT /api/followup-configs/{id}` - 更新配置 -- `DELETE /api/followup-configs/{id}` - 删除配置 - -### 复聊话术 -- `GET /api/followup-scripts` - 获取话术列表 -- `POST /api/followup-scripts` - 创建话术 -- `PUT /api/followup-scripts/{id}` - 更新话术 -- `DELETE /api/followup-scripts/{id}` - 删除话术 - -### 复聊记录 -- `GET /api/followup-records` - 获取记录列表 -- `POST /api/followup-records/send` - 手动发送消息 - ---- - -## 复聊配置说明 - -### day_number 字段 -- `1` = 第一天发送 -- `2` = 第二天发送 -- `3` = 第三天发送 -- `0` = 往后一直使用这个话术 - -### interval_hours 字段 -距离上次发送的间隔小时数: -- `24` = 24小时后发送 -- `48` = 48小时后发送 -- `72` = 72小时后发送 - -### 复聊逻辑 -``` -第1天(0小时):发送第1天话术 - ↓ 等待24小时 -第2天(24小时):如果没有回复,发送第2天话术 - ↓ 等待24小时 -第3天(48小时):如果还没有回复,发送第3天话术 - ↓ 等待72小时 -往后(120小时+):每隔72小时发送"往后一直"的话术 -``` - ---- - -## 消息过滤逻辑 - -### 过滤规则 -1. **过滤自己发送的消息**:只保留 `fromId=0` 的消息 -2. **过滤发送的话术**:在等待回复时,过滤掉包含发送话术内容的消息 -3. **过滤假关键词**:过滤掉包含"微信号"但没有真实微信号的消息 - -### 示例 -```python -# 原始消息 -messages = [ - {"fromId": 0, "body": {"text": "我的微信是 wx123456"}}, # 对方 ✓ - {"fromId": 123, "body": {"text": "您方便留微信号吗?"}}, # 自己 ✗ - {"fromId": 0, "body": {"text": "好的,test_wx_001"}}, # 对方 ✓ -] - -# 过滤后只保留对方的消息 -filtered = [ - {"fromId": 0, "body": {"text": "我的微信是 wx123456"}}, - {"fromId": 0, "body": {"text": "好的,test_wx_001"}}, -] -``` - ---- - -## 数据库表 - -### FollowUpConfig(复聊配置) -```sql -id, name, position, is_active, created_at, updated_at -``` - -### FollowUpScript(复聊话术) -```sql -id, config_id, day_number, content, interval_hours, order, is_active, created_at -``` - -### FollowUpRecord(复聊记录) -```sql -id, contact_id, config_id, script_id, day_number, content, -sent_at, got_reply, reply_content, replied_at -``` - ---- - -## 文件清单 - -### 修改的文件 -- `worker/tasks/boss_recruit.py` - 招聘任务处理器 -- `server/models.py` - 数据模型 -- `server/serializers.py` - 序列化器 -- `server/urls.py` - URL路由 - -### 新增的文件 -- `server/api/followup.py` - 复聊配置API -- `server/migrations/0004_add_followup_config.py` - 数据库迁移 -- `scripts/init_followup_config.py` - 初始化脚本 -- `scripts/test_recruit_features.py` - 测试脚本 - -### 文档文件 -- `BOSS招聘优化说明.md` -- `复聊配置API使用指南.md` -- `BOSS招聘自动化完整优化说明.md` -- `快速参考指南.md` -- `代码变更清单.md` -- `优化完成总结.md` -- `BOSS招聘自动化最终使用说明.md`(本文件) - ---- - -## 测试验证 - -### 语法检查 -```bash -python -m py_compile worker/tasks/boss_recruit.py # ✅ 通过 -python -m py_compile server/models.py # ✅ 通过 -python -m py_compile server/api/followup.py # ✅ 通过 -python -m py_compile server/serializers.py # ✅ 通过 -``` - -### 功能测试 -```bash -python scripts/test_recruit_features.py # ✅ 全部通过 -``` - ---- - -## 注意事项 - -1. **运行迁移**:首次使用前必须运行 `python server/manage.py migrate` -2. **配置优先级**:先匹配岗位配置,没有则使用通用配置 -3. **间隔控制**:系统会自动检查间隔时间,避免频繁发送 -4. **消息识别**:依赖 `fromId` 字段,确保API返回包含此字段 - ---- - -## 完成时间 - -2026年3月5日 - ---- - -## 联系支持 - -如有问题,请查看: -- `复聊配置API使用指南.md` - API详细说明 -- `BOSS招聘自动化完整优化说明.md` - 完整技术文档 -- `快速参考指南.md` - 快速参考 diff --git a/scroll_and_greet.py b/scroll_and_greet.py new file mode 100644 index 0000000..1ae1e31 --- /dev/null +++ b/scroll_and_greet.py @@ -0,0 +1,59 @@ +# -*- coding: utf-8 -*- +"""按姓名找到求职人 → 滚动到该人 → 点击打招呼(DrissionPage,三个动作)""" +import time + +# 求职人姓名 +姓名 = "王先生" + + +def do_greet(page, 姓名, container=None): + """三个动作:1. 找到姓名 2. 滚动到那里 3. 点击打招呼""" + if container is None: + try: + container = page.get_frame("recommendFrame") + except Exception: + container = page + + # 1. 找到这个姓名 + name_ele = container.ele(f'x://span[contains(text(),"{姓名}")]', timeout=10) + if not name_ele: + name_ele = container.ele(f'x://span[text()="{姓名}"]', timeout=2) + if not name_ele: + raise Exception(f"未找到姓名:{姓名}") + + # 2. 滚动到那里 + name_ele.run_js("this.scrollIntoView({block: 'center', behavior: 'auto'})") + time.sleep(0.8) + + # 3. 点击打招呼(先在该人所在卡片内找) + parent = name_ele.parent() + greet_btn = None + for _ in range(8): + if not parent: + break + greet_btn = parent.ele('x://span[text()="打招呼"]', timeout=0.5) or parent.ele('x://*[contains(text(),"打招呼")]', timeout=0.5) + if greet_btn: + break + parent = parent.parent() + if not greet_btn: + greet_btn = container.ele('x://span[text()="打招呼"]', timeout=2) or container.ele('x://*[contains(text(),"打招呼")]', timeout=1) + if not greet_btn: + raise Exception("未找到「打招呼」按钮") + greet_btn.click(by_js=True) + + +if __name__ == "__main__": + import sys + from pathlib import Path + _root = Path(__file__).resolve().parent + if str(_root) not in sys.path: + sys.path.insert(0, str(_root)) + from worker.bit_browser import BitBrowserAPI + from DrissionPage import ChromiumPage, ChromiumOptions + + bit_api = BitBrowserAPI("http://127.0.0.1:54345") + cdp_addr, port, browser_id = bit_api.open_browser(browser_id=None, name="测试2", remark=None) + page = ChromiumPage(addr_or_opts=ChromiumOptions().set_local_port(port=port)) + page.get("https://www.zhipin.com/web/geek/recommend") + time.sleep(2) + do_greet(page, 姓名) diff --git a/代码变更清单.md b/代码变更清单.md deleted file mode 100644 index 19c99c5..0000000 --- a/代码变更清单.md +++ /dev/null @@ -1,157 +0,0 @@ -# 代码变更清单 - -## 修改的文件 - -### 1. worker/tasks/boss_recruit.py -**状态**: ✅ 已修改并通过语法检查 - -**主要变更**: - -#### 导入语句 -- 添加: `from datetime import datetime, timedelta` - -#### 主流程修改 (_recruit_flow_like_script) -- 添加筛选逻辑: `friend_list = self._apply_filters(friend_list)` -- 添加消息过滤: `filtered_messages = self._filter_my_messages(messages)` -- 修改关键词检查: 使用 `filtered_messages` 而不是 `messages` -- 添加复聊管理: `reply_result = self._handle_follow_up_chat(tab, name, friend_job_name)` -- 添加保存联系人: `self._save_contact_record(name, friend_job_name, contacts, action_state)` -- 修改联系方式提取: 使用 `filtered_messages` 而不是 `messages` - -#### 新增方法 (共7个) -1. `_apply_filters(friend_list)` - 应用筛选条件 -2. `_check_activity(last_time, activity_filter)` - 检查活跃度 -3. `_check_education(candidate_edu, required_edu)` - 检查学历 -4. `_filter_my_messages(messages)` - 过滤自己的消息 -5. `_handle_follow_up_chat(tab, name, job_name)` - 处理复聊管理 -6. `_send_follow_up_script(tab, job_name)` - 发送跟进话术 -7. `_save_contact_record(name, job_name, contacts, action_state)` - 保存联系人记录 - -## 新增的文件 - -### 1. BOSS招聘优化说明.md -**状态**: ✅ 已创建 - -**内容**: 详细的功能说明、使用方法、数据库表说明 - -### 2. 优化完成总结.md -**状态**: ✅ 已创建 - -**内容**: 完成的优化内容、测试验证、关键问题解决方案 - -### 3. 快速参考指南.md -**状态**: ✅ 已创建 - -**内容**: 核心优化点、快速开始、常见问题 - -### 4. scripts/init_recruit_test_data.py -**状态**: ✅ 已创建 - -**功能**: 初始化测试数据(筛选配置、话术配置) - -### 5. scripts/test_recruit_features.py -**状态**: ✅ 已创建并通过测试 - -**功能**: 测试新增功能(时间解析、消息过滤、联系方式提取、学历筛选) - -## 测试结果 - -### 语法检查 -```bash -python -m py_compile worker/tasks/boss_recruit.py -``` -**结果**: ✅ 通过 - -### 功能测试 -```bash -python scripts/test_recruit_features.py -``` -**结果**: ✅ 全部通过 -- 时间解析测试: 5/5 通过 -- 消息过滤测试: 通过 -- 联系方式提取测试: 通过 -- 学历筛选测试: 5/5 通过 - -## 核心问题解决 - -### 问题1: 识别到自己发送的微信号 ✅ -**解决方案**: -- 添加 `_filter_my_messages()` 方法 -- 通过 `fromId` 字段区分消息来源 -- 只保留 `fromId=0` 的消息(对方发送的) - -### 问题2: 联系人没有保存到数据库 ✅ -**解决方案**: -- 添加 `_save_contact_record()` 方法 -- 提取到联系方式后自动保存到 `ContactRecord` 表 -- 支持去重和更新 - -### 问题3: 只发送一句话,没有复聊 ✅ -**解决方案**: -- 添加 `_handle_follow_up_chat()` 方法 -- 发送后等待30秒,每3秒检查一次 -- 如果没有回复,发送跟进话术 - -### 问题4: 活跃度时间格式不统一 ✅ -**解决方案**: -- 添加 `_check_activity()` 方法 -- 支持"03月03日"、"昨天"、"今天"等多种格式 -- 自动判断年份 - -### 问题5: 缺少筛选功能 ✅ -**解决方案**: -- 添加 `_apply_filters()` 方法 -- 支持活跃度、年龄、学历、期望职位筛选 -- 从 `FilterConfig` 表读取配置 - -## 数据库依赖 - -### 已存在的表 -- `FilterConfig` - 筛选配置表 -- `ChatScript` - 话术表 -- `ContactRecord` - 联系人记录表 - -### 需要的字段 -所有必需字段已在现有表中定义,无需额外迁移。 - -## 使用步骤 - -1. **初始化测试数据** - ```bash - python scripts/init_recruit_test_data.py - ``` - -2. **运行功能测试**(可选) - ```bash - python scripts/test_recruit_features.py - ``` - -3. **启动招聘任务** - 通过API或管理界面启动,系统会自动应用所有优化功能。 - -## 注意事项 - -1. 确保 `FilterConfig` 表中有 `is_active=True` 的配置 -2. 建议配置通用话术(`position="通用"`)作为后备 -3. 复聊等待时间默认30秒,可根据需要调整 -4. 消息过滤依赖 `fromId` 字段,确保API返回包含此字段 - -## 文档位置 - -- 详细说明: `BOSS招聘优化说明.md` -- 完成总结: `优化完成总结.md` -- 快速参考: `快速参考指南.md` -- 变更清单: `代码变更清单.md`(本文件) - -## 代码统计 - -- 修改文件: 1个 -- 新增方法: 7个 -- 新增文档: 4个 -- 新增脚本: 2个 -- 代码行数: +260行 -- 测试通过: 100% - -## 完成时间 - -2026年3月5日 diff --git a/优化完成总结.md b/优化完成总结.md deleted file mode 100644 index e2a4472..0000000 --- a/优化完成总结.md +++ /dev/null @@ -1,174 +0,0 @@ -# BOSS招聘自动化优化完成总结 - -## 优化完成时间 -2026年3月5日 - -## 已完成的优化内容 - -### 1. ✅ 筛选功能 - -#### 活跃度筛选 -- ✅ 支持解析"03月03日"格式的时间 -- ✅ 支持解析"昨天"、"今天"、"刚刚"等相对时间 -- ✅ 自动判断年份(如果月份大于当前月份,认为是去年) -- ✅ 支持多种活跃度筛选条件:今天活跃、3天内活跃、本周活跃、本月活跃 - -#### 年龄筛选 -- ✅ 从候选人简历的 `resume.age` 字段获取年龄 -- ✅ 根据配置的 `age_min` 和 `age_max` 进行筛选 - -#### 学历筛选 -- ✅ 从候选人简历的 `resume.education` 字段获取学历 -- ✅ 支持学历等级比较:初中 < 高中 < 中专 < 大专 < 本科 < 硕士 < 博士 -- ✅ 候选人学历需要达到或高于要求学历 - -#### 期望职位筛选 -- ✅ 从候选人的 `jobName` 字段获取期望职位 -- ✅ 支持多个职位关键词匹配(配置在 `FilterConfig.positions` 字段) - -### 2. ✅ 联系人记录管理 - -#### 自动保存功能 -- ✅ 从聊天中提取到联系方式后自动保存到 `ContactRecord` 表 -- ✅ 保存信息包括:姓名、岗位、联系方式、回复状态、是否交换微信、联系时间、备注 -- ✅ 去重处理:检查是否已存在相同姓名和联系方式的记录 -- ✅ 如果存在则更新,不存在则创建新记录 - -### 3. ✅ 复聊管理 - -#### 消息过滤(核心功能) -- ✅ **过滤自己发送的消息**:通过 `fromId` 字段判断消息来源 -- ✅ `fromId=0` 表示对方发送的消息 -- ✅ 其他 `fromId` 值表示自己发送的消息 -- ✅ 只保留对方的消息进行联系方式识别 -- ✅ **解决了之前"发送带微信号的消息后,识别到自己消息"的问题** - -#### 等待回复功能 -- ✅ 发送询问微信号后,等待最多30秒 -- ✅ 每3秒检查一次是否有新回复 -- ✅ 自动识别对方回复中的联系方式 -- ✅ 记录是否得到回复、是否提取到联系方式 - -#### 跟进话术功能 -- ✅ 如果对方没有回复,可以发送跟进话术 -- ✅ 支持按岗位配置不同的跟进话术 -- ✅ 从 `ChatScript` 表中读取话术(`script_type="followup"`) -- ✅ 如果没有特定岗位话术,使用通用话术(`position="通用"`) - -## 代码修改文件 - -### 主要修改文件 -- `worker/tasks/boss_recruit.py` - 招聘任务处理器(已优化) - -### 新增方法 -1. `_apply_filters()` - 应用筛选条件 -2. `_check_activity()` - 检查活跃度 -3. `_check_education()` - 检查学历 -4. `_filter_my_messages()` - 过滤自己的消息 -5. `_handle_follow_up_chat()` - 处理复聊管理 -6. `_send_follow_up_script()` - 发送跟进话术 -7. `_save_contact_record()` - 保存联系人记录 - -### 修改的方法 -- `_recruit_flow_like_script()` - 主流程,添加了筛选、消息过滤、复聊管理、保存联系人记录 - -## 测试验证 - -### 功能测试 -✅ 所有功能测试通过(`scripts/test_recruit_features.py`) -- ✅ 时间解析测试:5/5 通过 -- ✅ 消息过滤测试:成功过滤掉自己发送的消息 -- ✅ 联系方式提取测试:正确提取微信号和手机号 -- ✅ 学历筛选测试:5/5 通过 - -### 语法检查 -✅ Python语法检查通过(`python -m py_compile`) - -## 使用说明 - -### 1. 初始化测试数据 -```bash -python scripts/init_recruit_test_data.py -``` - -这将创建: -- 筛选配置示例(Python开发筛选配置) -- 话术配置示例(首次回复、跟进回复、微信交换等) - -### 2. 配置筛选条件 -在数据库 `filter_config` 表中配置或通过管理界面配置: -- 年龄范围 -- 学历要求 -- 活跃度要求 -- 期望职位列表 - -### 3. 配置复聊话术 -在数据库 `chat_script` 表中配置或通过管理界面配置: -- 按岗位配置不同的话术 -- 配置通用话术作为后备 - -### 4. 运行招聘任务 -任务会自动执行以下流程: -1. 获取候选人列表 -2. 应用筛选条件(活跃度、年龄、学历、职位) -3. 逐个打开会话 -4. **过滤自己的消息,只分析对方消息** -5. 如果没有联系方式,发送询问 -6. 等待对方回复并识别联系方式 -7. **自动保存联系人记录到数据库** -8. 如果需要,发送跟进话术 - -## 关键问题解决 - -### 问题1:识别到自己发送的微信号 -**原因**:之前没有区分消息来源,所有消息都进行联系方式识别 - -**解决方案**: -- 添加 `_filter_my_messages()` 方法 -- 通过 `fromId` 字段判断消息来源 -- 只保留 `fromId=0` 的消息(对方发送的) -- 在提取联系方式前先过滤消息 - -### 问题2:联系人没有保存到数据库 -**原因**:之前只是收集联系方式,没有保存到数据库 - -**解决方案**: -- 添加 `_save_contact_record()` 方法 -- 在提取到联系方式后自动保存 -- 支持去重和更新 - -### 问题3:只发送一句话,没有复聊 -**原因**:之前只发送一次询问,不等待回复 - -**解决方案**: -- 添加 `_handle_follow_up_chat()` 方法 -- 发送后等待30秒,每3秒检查一次 -- 如果没有回复,发送跟进话术 -- 记录回复状态 - -### 问题4:活跃度时间格式不统一 -**原因**:BOSS直聘返回的时间格式多样("03月03日"、"昨天"等) - -**解决方案**: -- 添加 `_check_activity()` 方法 -- 支持多种时间格式解析 -- 自动判断年份 - -## 注意事项 - -1. **筛选配置**:确保 `FilterConfig` 表中有 `is_active=True` 的配置 -2. **话术配置**:建议配置通用话术作为后备 -3. **等待时间**:复聊等待时间默认30秒,可根据需要调整 -4. **消息识别**:依赖 `fromId` 字段,确保API返回的消息包含此字段 - -## 后续建议 - -1. 可以添加更多的筛选条件(如工作经验、期望薪资等) -2. 可以优化复聊策略(如根据对方回复内容智能选择话术) -3. 可以添加数据统计功能(如筛选通过率、回复率等) -4. 可以添加黑名单功能(避免重复联系) - -## 文档 -- 详细说明:`BOSS招聘优化说明.md` -- 测试脚本:`scripts/test_recruit_features.py` -- 初始化脚本:`scripts/init_recruit_test_data.py` diff --git a/复聊配置API使用指南.md b/复聊配置API使用指南.md deleted file mode 100644 index dede059..0000000 --- a/复聊配置API使用指南.md +++ /dev/null @@ -1,361 +0,0 @@ -# 复聊配置 API 使用指南 - -## API 端点 - -### 1. 复聊配置管理 - -#### 获取配置列表 -```http -GET /api/followup-configs -``` - -查询参数: -- `position`: 岗位类型(可选) -- `is_active`: 是否启用(可选) - -响应示例: -```json -[ - { - "id": 1, - "name": "Python开发复聊配置", - "position": "Python开发", - "is_active": true, - "scripts": [ - { - "id": 1, - "day_number": 1, - "content": "后续沟通会更及时,您方便留一下您的微信号吗?我这边加您。", - "interval_hours": 24, - "order": 1 - } - ] - } -] -``` - -#### 创建配置 -```http -POST /api/followup-configs -Content-Type: application/json - -{ - "name": "Python开发复聊配置", - "position": "Python开发", - "is_active": true -} -``` - -#### 更新配置 -```http -PUT /api/followup-configs/{id} -Content-Type: application/json - -{ - "name": "Python开发复聊配置(更新)", - "is_active": true -} -``` - -#### 删除配置 -```http -DELETE /api/followup-configs/{id} -``` - -### 2. 复聊话术管理 - -#### 获取话术列表 -```http -GET /api/followup-scripts?config_id=1 -``` - -查询参数: -- `config_id`: 配置ID(可选) -- `day_number`: 第几天(可选) - -#### 创建话术 -```http -POST /api/followup-scripts -Content-Type: application/json - -{ - "config_id": 1, - "day_number": 1, - "content": "您好,期待与您进一步沟通。", - "interval_hours": 24, - "order": 1, - "is_active": true -} -``` - -**字段说明**: -- `day_number`: - - `1` = 第一天 - - `2` = 第二天 - - `0` = 往后一直使用这个话术 -- `interval_hours`: 距离上次发送的间隔小时数 -- `order`: 同一天有多条话术时的排序 - -#### 更新话术 -```http -PUT /api/followup-scripts/{id} -Content-Type: application/json - -{ - "content": "更新后的话术内容", - "interval_hours": 48 -} -``` - -#### 删除话术 -```http -DELETE /api/followup-scripts/{id} -``` - -### 3. 复聊记录查询 - -#### 获取记录列表 -```http -GET /api/followup-records?contact_id=1 -``` - -查询参数: -- `contact_id`: 联系人ID(可选) -- `config_id`: 配置ID(可选) -- `got_reply`: 是否得到回复(可选) -- `page`: 页码(默认1) -- `page_size`: 每页数量(默认20) - -响应示例: -```json -{ - "total": 10, - "page": 1, - "page_size": 20, - "results": [ - { - "id": 1, - "contact_id": 1, - "config_id": 1, - "script_id": 1, - "day_number": 1, - "content": "您好,期待与您进一步沟通。", - "sent_at": "2026-03-05T10:30:00Z", - "got_reply": true, - "reply_content": "好的,我的微信是 wx123456", - "replied_at": "2026-03-05T10:35:00Z" - } - ] -} -``` - -#### 手动发送复聊消息 -```http -POST /api/followup-records/send -Content-Type: application/json - -{ - "contact_id": 1, - "content": "您好,我想和您聊聊这个职位。" -} -``` - -## 使用场景 - -### 场景1:创建Python开发的复聊配置 - -```bash -# 1. 创建配置 -curl -X POST http://localhost:8000/api/followup-configs \ - -H "Content-Type: application/json" \ - -d '{ - "name": "Python开发复聊配置", - "position": "Python开发", - "is_active": true - }' - -# 假设返回的 config_id = 1 - -# 2. 添加第1天的话术 -curl -X POST http://localhost:8000/api/followup-scripts \ - -H "Content-Type: application/json" \ - -d '{ - "config_id": 1, - "day_number": 1, - "content": "后续沟通会更及时,您方便留一下您的微信号吗?我这边加您。", - "interval_hours": 24, - "order": 1, - "is_active": true - }' - -# 3. 添加第2天的话术 -curl -X POST http://localhost:8000/api/followup-scripts \ - -H "Content-Type: application/json" \ - -d '{ - "config_id": 1, - "day_number": 2, - "content": "您好,不知道您是否方便留个联系方式?", - "interval_hours": 24, - "order": 1, - "is_active": true - }' - -# 4. 添加"往后一直"的话术 -curl -X POST http://localhost:8000/api/followup-scripts \ - -H "Content-Type: application/json" \ - -d '{ - "config_id": 1, - "day_number": 0, - "content": "您好,如果您感兴趣可以随时联系我。", - "interval_hours": 72, - "order": 1, - "is_active": true - }' -``` - -### 场景2:查看某个联系人的复聊记录 - -```bash -curl http://localhost:8000/api/followup-records?contact_id=1 -``` - -### 场景3:手动发送复聊消息 - -```bash -curl -X POST http://localhost:8000/api/followup-records/send \ - -H "Content-Type: application/json" \ - -d '{ - "contact_id": 1, - "content": "您好,我想和您聊聊这个职位。" - }' -``` - -## 复聊逻辑说明 - -### 自动复聊流程 - -1. **第一次联系**:发送询问微信号的消息 -2. **等待回复**:等待30秒,检查是否有回复 -3. **第1天**:如果没有回复,发送第1天的话术 -4. **第2天**:如果还没有回复,且距离上次发送超过24小时,发送第2天的话术 -5. **第3天及以后**:继续按配置的间隔时间发送话术 -6. **往后一直**:当没有特定天数的话术时,使用 `day_number=0` 的话术 - -### 消息过滤逻辑 - -**问题**:之前会识别到自己发送的包含"微信号"三个字的消息 - -**解决方案**: -1. 通过 `fromId` 字段区分消息来源 -2. 只保留 `fromId=0` 的消息(对方发送的) -3. 在等待回复时,过滤掉包含发送话术内容的消息 -4. 过滤掉包含"微信号"关键词但没有真实微信号的消息 - -### 间隔时间控制 - -- 每条话术都有 `interval_hours` 字段 -- 系统会检查距离上次发送的时间 -- 只有超过间隔时间才会发送下一条 -- 避免频繁打扰候选人 - -## 数据库表结构 - -### FollowUpConfig(复聊配置表) -```sql -CREATE TABLE follow_up_config ( - id INT PRIMARY KEY AUTO_INCREMENT, - name VARCHAR(128), - position VARCHAR(64), - is_active BOOLEAN DEFAULT TRUE, - created_at DATETIME, - updated_at DATETIME -); -``` - -### FollowUpScript(复聊话术表) -```sql -CREATE TABLE follow_up_script ( - id INT PRIMARY KEY AUTO_INCREMENT, - config_id INT, - day_number INT, -- 1=第一天, 2=第二天, 0=往后一直 - content TEXT, - interval_hours INT DEFAULT 24, - order INT DEFAULT 0, - is_active BOOLEAN DEFAULT TRUE, - created_at DATETIME -); -``` - -### FollowUpRecord(复聊记录表) -```sql -CREATE TABLE follow_up_record ( - id INT PRIMARY KEY AUTO_INCREMENT, - contact_id INT, - config_id INT, - script_id INT, - day_number INT, - content TEXT, - sent_at DATETIME, - got_reply BOOLEAN DEFAULT FALSE, - reply_content TEXT, - replied_at DATETIME -); -``` - -## 前端集成示例 - -### Vue.js 示例 - -```javascript -// 获取复聊配置列表 -async function getFollowUpConfigs() { - const response = await fetch('/api/followup-configs'); - const configs = await response.json(); - return configs; -} - -// 创建复聊配置 -async function createFollowUpConfig(data) { - const response = await fetch('/api/followup-configs', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(data) - }); - return await response.json(); -} - -// 添加话术 -async function addFollowUpScript(configId, scriptData) { - const response = await fetch('/api/followup-scripts', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - config_id: configId, - ...scriptData - }) - }); - return await response.json(); -} - -// 查看复聊记录 -async function getFollowUpRecords(contactId) { - const response = await fetch(`/api/followup-records?contact_id=${contactId}`); - const data = await response.json(); - return data.results; -} -``` - -## 注意事项 - -1. **配置优先级**:先匹配岗位配置,如果没有则使用通用配置 -2. **话术顺序**:按 `day_number` 和 `order` 排序 -3. **间隔控制**:系统会自动检查间隔时间,避免频繁发送 -4. **消息过滤**:只识别对方发送的消息,避免误识别 -5. **自动保存**:提取到联系方式后自动保存到 `ContactRecord` 表 - -## 测试建议 - -1. 先创建一个测试配置,设置较短的间隔时间(如1小时) -2. 运行招聘任务,观察复聊是否正常工作 -3. 检查 `FollowUpRecord` 表,确认记录是否正确保存 -4. 根据实际效果调整话术内容和间隔时间 diff --git a/快速参考指南.md b/快速参考指南.md deleted file mode 100644 index e8dd854..0000000 --- a/快速参考指南.md +++ /dev/null @@ -1,148 +0,0 @@ -# BOSS招聘自动化 - 快速参考指南 - -## 核心优化点 - -### 1. 筛选功能 ✅ -```python -# 在 FilterConfig 表中配置 -{ - "age_min": 22, - "age_max": 35, - "education": "本科", - "activity": "3天内活跃", - "positions": ["Python开发", "后端开发"] -} -``` - -### 2. 消息过滤 ✅(解决识别自己消息的问题) -```python -# 通过 fromId 字段区分消息来源 -# fromId = 0 -> 对方发送的消息 -# fromId != 0 -> 自己发送的消息 - -filtered_messages = [msg for msg in messages if msg.get("fromId", 0) == 0] -``` - -### 3. 自动保存联系人 ✅ -```python -# 提取到联系方式后自动保存到 ContactRecord 表 -ContactRecord.objects.create( - name=name, - position=job_name, - contact=wechat_or_phone, - reply_status="已回复" if got_reply else "未回复", - wechat_exchanged=exchange_confirmed, - contacted_at=timezone.now() -) -``` - -### 4. 复聊管理 ✅ -```python -# 发送询问后等待30秒,每3秒检查一次 -# 如果没有回复,发送跟进话术 -if action_state["send_success"]: - reply_result = self._handle_follow_up_chat(tab, name, job_name) -``` - -## 时间格式支持 - -| 格式 | 示例 | 解析结果 | -|------|------|----------| -| 月日格式 | "03月03日" | 2026-03-03 或 2025-03-03 | -| 相对时间 | "昨天" | 当前日期 - 1天 | -| 相对时间 | "今天" | 当前日期 | -| 相对时间 | "刚刚" | 当前日期 | - -## 学历等级 - -``` -初中 < 高中 < 中专 < 大专 < 本科 < 硕士 < 博士 -``` - -候选人学历需要 >= 要求学历 - -## 活跃度筛选 - -| 配置值 | 含义 | -|--------|------| -| "今天活跃" | 最后上线时间在今天 | -| "3天内活跃" | 最后上线时间在3天内 | -| "本周活跃" | 最后上线时间在7天内 | -| "本月活跃" | 最后上线时间在30天内 | -| "不限" | 不筛选活跃度 | - -## 话术类型 - -| script_type | 说明 | 使用场景 | -|-------------|------|----------| -| first | 首次回复 | 第一次联系候选人 | -| followup | 跟进回复 | 候选人没有回复时 | -| wechat | 微信交换 | 询问微信号 | -| closing | 结束语 | 结束对话 | - -## 快速开始 - -### 1. 初始化测试数据 -```bash -python scripts/init_recruit_test_data.py -``` - -### 2. 运行功能测试 -```bash -python scripts/test_recruit_features.py -``` - -### 3. 启动招聘任务 -通过API或管理界面启动招聘任务,系统会自动: -- 应用筛选条件 -- 过滤自己的消息 -- 保存联系人记录 -- 进行复聊管理 - -## 常见问题 - -### Q1: 为什么识别到了自己发送的微信号? -**A**: 已修复。现在通过 `fromId` 字段过滤消息,只识别对方发送的消息。 - -### Q2: 联系人记录在哪里查看? -**A**: 在 `ContactRecord` 表中,可以通过 `/api/contacts` 接口查询。 - -### Q3: 如何配置不同岗位的话术? -**A**: 在 `ChatScript` 表中,设置 `position` 字段为岗位名称,`script_type` 为话术类型。 - -### Q4: 筛选条件不生效? -**A**: 检查 `FilterConfig` 表中是否有 `is_active=True` 的配置。 - -### Q5: 如何调整复聊等待时间? -**A**: 修改 `_handle_follow_up_chat()` 方法中的 `max_wait` 参数(默认30秒)。 - -## 数据库表 - -### FilterConfig(筛选配置) -- `age_min`, `age_max` - 年龄范围 -- `education` - 学历要求 -- `activity` - 活跃度要求 -- `positions` - 期望职位列表(JSON数组) -- `is_active` - 是否启用 - -### ChatScript(话术配置) -- `position` - 岗位类型 -- `script_type` - 话术类型 -- `content` - 话术内容 -- `is_active` - 是否启用 - -### ContactRecord(联系人记录) -- `name` - 姓名 -- `position` - 岗位 -- `contact` - 联系方式 -- `reply_status` - 回复状态 -- `wechat_exchanged` - 是否交换微信 -- `contacted_at` - 联系时间 - -## 代码位置 - -- 主文件:`worker/tasks/boss_recruit.py` -- 测试脚本:`scripts/test_recruit_features.py` -- 初始化脚本:`scripts/init_recruit_test_data.py` -- 详细说明:`BOSS招聘优化说明.md` -- 完成总结:`优化完成总结.md` diff --git a/部署说明.md b/部署说明.md deleted file mode 100644 index b3aac1a..0000000 --- a/部署说明.md +++ /dev/null @@ -1,47 +0,0 @@ -# 部署说明 - -## 一、服务器部署 - -在服务器上,只需执行: - -```bash -python app.py -``` - -即可启动中央服务器(Django + Channels + 隧道)。 - ---- - -## 二、客户端部署(线下有比特浏览器的电脑) - -客户电脑可能不懂代码,需要提供 **GUI 程序**(PyQt5)完成「更新」和「启动」。 - -### 方式 A:源码运行(需安装 Python) - -1. 将项目拷贝到客户电脑 -2. 安装依赖:`pip install -r requirements.txt` -3. 运行 GUI:`python run_client.py` - -### 方式 B:打包为 exe(推荐,无需 Python) - -1. 安装 PyInstaller:`pip install pyinstaller` -2. 在项目根目录执行打包:`pyinstaller --clean build_client.spec` -3. 将 `dist/BOSS直聘Worker客户端.exe` 发给客户,下载后先保存到本地文件夹(如桌面),再双击运行(GUI 与 Worker 已合并为同一程序,无需 worker.exe) - -### GUI 功能说明 - -| 按钮 | 功能 | -|------|------| -| **更新代码** | 在项目目录执行 `git pull`,拉取最新自动化代码 | -| **启动** | 启动 Worker,连接服务器并执行任务 | - -配置项说明: - -- **服务器地址**:中央服务器 WebSocket 地址,如 `ws://8.137.99.82:9000/ws` -- **Worker ID**:本机 Worker 唯一标识 -- **Worker 名称**:便于识别的名称,如「电脑A」 - -> **说明**: -> - 若使用「更新」功能,需在客户电脑安装 Git,并将 exe 放在项目(git 仓库)目录内。 -> - 若不使用「更新」,可只分发打包后的 exe,客户只需填写服务器地址等信息后点击「启动」即可。 -> - 不要直接在浏览器下载弹窗里点“打开”,请先保存到本地后再运行,避免在临时目录运行导致依赖加载失败。