haha
This commit is contained in:
131
1.py
Normal file
131
1.py
Normal file
@@ -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()
|
||||
317
API_CONTACTS.md
317
API_CONTACTS.md
@@ -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
|
||||
<!-- Vue 3 组件示例 -->
|
||||
<template>
|
||||
<button @click="handleExport" :loading="exporting">
|
||||
导出 Excel
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import axios from 'axios';
|
||||
|
||||
const exporting = ref(false);
|
||||
|
||||
const handleExport = async () => {
|
||||
exporting.value = true;
|
||||
|
||||
try {
|
||||
const response = await axios.get('/api/contacts/export', {
|
||||
params: {
|
||||
start_date: '2024-01-01',
|
||||
end_date: '2024-12-31'
|
||||
}
|
||||
});
|
||||
|
||||
if (response.data.code === 200) {
|
||||
const { download_url, total_records } = response.data.data;
|
||||
|
||||
// 下载文件
|
||||
window.open(download_url, '_blank');
|
||||
|
||||
// 显示成功提示
|
||||
ElMessage.success(`成功导出 ${total_records} 条记录`);
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error('导出失败,请重试');
|
||||
} finally {
|
||||
exporting.value = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 错误码说明
|
||||
|
||||
| 错误码 | 说明 |
|
||||
|--------|------|
|
||||
| 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 <token>`
|
||||
|
||||
6. **下载链接**:
|
||||
- 返回的 `download_url` 是可直接访问的完整下载 URL
|
||||
- 前端可直接 `window.open(download_url)` 或 `a.href = download_url` 下载
|
||||
693
API文档.md
693
API文档.md
@@ -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 不在线或服务不可用 |
|
||||
166
BOSS招聘优化说明.md
166
BOSS招聘优化说明.md
@@ -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. **持续跟进**:支持复聊管理,提高回复率
|
||||
@@ -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
|
||||
```
|
||||
@@ -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` - 快速参考
|
||||
59
scroll_and_greet.py
Normal file
59
scroll_and_greet.py
Normal file
@@ -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, 姓名)
|
||||
157
代码变更清单.md
157
代码变更清单.md
@@ -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日
|
||||
174
优化完成总结.md
174
优化完成总结.md
@@ -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`
|
||||
361
复聊配置API使用指南.md
361
复聊配置API使用指南.md
@@ -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. 根据实际效果调整话术内容和间隔时间
|
||||
148
快速参考指南.md
148
快速参考指南.md
@@ -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`
|
||||
47
部署说明.md
47
部署说明.md
@@ -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,客户只需填写服务器地址等信息后点击「启动」即可。
|
||||
> - 不要直接在浏览器下载弹窗里点“打开”,请先保存到本地后再运行,避免在临时目录运行导致依赖加载失败。
|
||||
Reference in New Issue
Block a user