Skip to main content

A CLI and Web-based job position management tool with full-text search, Excel import/export, and LLM-assisted entry.

Project description

JobDeer - 智能职位管理系统

一个基于 CLI 和 Web 双界面的职位管理工具,集成 Tantivy 全文检索、向量语义搜索、Excel 导入导出,以及 LLM 辅助录入功能。

📖 项目简介

JobDeer 是一个专为 HR 和技术团队设计的职位管理工具,支持通过命令行Web 浏览器两种方式进行职位信息的录入、查询、搜索和管理。

为什么选择 JobDeer?

  • 零配置启动:无需安装数据库,基于 JSON 文件存储,开箱即用
  • 双界面操作:技术人员用 CLI,HR 用 Web 界面,各取所需
  • 智能搜索:支持关键词、正则表达式、语义相似度三种搜索模式
  • AI 辅助:集成 LLM 自动从 JD 文本中提取结构化字段
  • 数据便携:支持 Excel 导入导出,便于数据迁移和报表生成

✨ 功能特性

功能 说明
🔍 关键词搜索 基于 Tantivy BM25 算法的全文检索,支持中文分词
🔎 正则搜索 使用 Python re 模块进行正则表达式匹配
🧠 语义搜索 基于 Embedding 向量的语义相似度检索(可选)
🎯 按字段精确检索 支持 26 个字段的组合 AND 查询
➕ 职位增删改查 完整的 CRUD 操作,自动备份数据
📊 Excel 导入导出 支持 .xlsx 格式的批量导入导出
🤖 LLM 辅助录入 粘贴原始 JD 文本,AI 自动提取结构化数据
⚙️ LLM 配置管理 交互式配置向导、API 连接测试、多种配置方式
🌐 Web 管理界面 基于 Alpine.js + TailwindCSS 的现代化 UI
💻 CLI 命令行工具 基于 Typer + Rich 的交互式终端
🔄 数据自动备份 每次修改自动创建备份文件
🔒 并发安全 使用文件锁保证多进程写入安全

🏗️ 项目架构

整体架构设计

┌─────────────────────────────────────────────────────────┐
│                    JobDeer 应用层                        │
├──────────────────────┬──────────────────────────────────┤
│   CLI 命令行界面      │      Web Web 界面                │
│   (Typer + Rich)     │   (Flask + Alpine.js + Tailwind) │
├──────────────────────┴──────────────────────────────────┤
│                    核心业务层                            │
├──────────────┬──────────────┬──────────────┬────────────┤
│ models.py    │ search.py    │ excel_io.py  │ llm_helper │
│ (数据模型)   │ (搜索引擎)   │ (Excel处理)  │ (AI辅助)   │
├──────────────┴──────────────┴──────────────┴────────────┤
│                    数据存储层                            │
├─────────────────────────────────────────────────────────┤
│  joblist.json  │  tantivy_index/  │  vector_index/      │
│  (JSON文件)    │  (全文索引)      │  (向量索引)          │
└─────────────────────────────────────────────────────────┘

模块划分说明

模块文件 职责 技术栈
jobdeer/models.py 数据模型定义、JSON 文件存储、CRUD 操作 filelock (并发锁)
jobdeer/search.py 全文检索、向量语义搜索、按字段搜索 Tantivy-py、jieba、sentence-transformers
jobdeer/excel_io.py Excel 文件导入导出、字段映射 openpyxl
jobdeer/llm_helper.py LLM 辅助文本提取 llmdog、larkfunc
jobdeer/cli.py 命令行入口、交互式命令 Typer、Rich
jobdeer/web.py Web 服务端、RESTful API Flask
jobdeer/templates/index.html Web 前端页面模板 HTML + TailwindCSS
jobdeer/static/app.js 前端交互逻辑 Alpine.js
jobdeer/static/style.css 自定义样式 CSS

技术栈选型原因

  1. Flask:轻量级 Web 框架,适合内部工具开发,易于部署
  2. Typer + Rich:现代化的 CLI 框架,自动生成 help 文档,输出美观
  3. Tantivy-py:Rust 实现的全文检索引擎,性能比 Whoosh 高 5-10x,活跃维护
  4. jieba:成熟的中文分词库,与 Tantivy 预分词策略完美配合
  5. sentence-transformers:提供轻量中文 Embedding 模型,支持语义搜索
  6. Alpine.js:轻量级前端框架,无需构建工具,直接浏览器运行
  7. TailwindCSS:实用优先的 CSS 框架,快速构建现代化 UI
  8. openpyxl:Python 处理 Excel 的标准库,支持 .xlsx 格式
  9. filelock:保证多进程并发写入 JSON 文件时的数据安全

🚀 安装与配置

环境要求

  • Python 3.8+(推荐 3.10+)
  • macOS / Linux / Windows

快速安装

# 1. 从 PyPI 安装(推荐)
pip install jobdeer

# 2. 或从源码安装
git clone https://github.com/jobdeer/jobdeer.git
cd jobdeer
pip install -e .

安装语义搜索支持(可选)

语义搜索功能需要额外安装 sentence-transformers 依赖(约 400MB 模型文件):

pip install "jobdeer[semantic]"

验证安装

# 查看版本
jobdeer --help

# 测试搜索功能
jobdeer search "测试" --limit 5

数据目录配置

默认情况下,数据存储在运行目录:

./
├── joblist.json          # 职位数据文件
├── joblist_backup_*.json # 自动备份文件
├── tantivy_index/        # 全文检索索引
└── vector_index/         # 向量索引(使用语义搜索时)

可通过环境变量自定义数据目录:

export JOBDEER_DATA_DIR="/path/to/your/data"

📖 使用指南

CLI 命令行使用

添加职位

jobdeer add \
  --title "Python后端开发工程师" \
  --department "技术部" \
  --description "负责公司后端系统开发" \
  --company "某某科技" \
  --location "北京" \
  --requirements "熟悉Python, Django, Redis" \
  --category "后端开发" \
  --tech-stack "Python,Django,Redis" \
  --priority "高" \
  --urgency "紧急" \
  --job-level "高级" \
  --salary-range "20k,30k" \
  --contact-person "张三" \
  --contact-email "hr@example.com"

查询职位

# 按 ID 查询
jobdeer get <job_id>

# 列表分页查看
jobdeer list --page 1 --per-page 20

搜索功能

关键词搜索(默认):

jobdeer search "Python后端"
jobdeer search "Python" --limit 10

正则表达式搜索

# 使用 --regex 快捷参数
jobdeer search "Python|Java" --regex

# 或使用 --mode regex(等效)
jobdeer search "Python|Java" --mode regex --ignore-case

语义搜索(需安装 semantic 依赖):

jobdeer search "做AI应用的后端开发" --mode semantic

按指定字段搜索

# 仅搜索职位名称
jobdeer search "Python" --field title

# 仅搜索技术栈
jobdeer search "React" --field tech_stack

更新职位

# 使用 --field 参数指定字段和值
jobdeer update <job_id> \
  --field "priority=非常高" \
  --field "urgency=紧急" \
  --field "salary_range=25k,35k"

删除职位

# 交互式确认
jobdeer delete <job_id>

# 跳过确认
jobdeer delete <job_id> --yes

重建索引

每次添加/删除大量职位后,建议重建索引:

jobdeer rebuild-index

启动 Web 界面

jobdeer web --port 5000 --host 127.0.0.1

然后在浏览器访问:http://127.0.0.1:5000

Excel 导入导出

# 导出所有职位到 Excel
jobdeer export jobs.xlsx

# 从 Excel 导入职位
jobdeer import_excel jobs.xlsx --conflict skip

LLM 辅助录入

# 交互模式:粘贴原始 JD 文本,AI 自动提取
jobdeer llm-add

# 使用自定义 API 配置
jobdeer llm-add --api-url "https://api.example.com/v1" --api-key "sk-xxx" --model "gpt-3.5-turbo"

系统会提示你粘贴职位描述文本,按 Ctrl+D(Unix)或 Ctrl+Z + Enter(Windows)结束输入。

LLM 配置管理

JobDeer 提供了完整的 LLM API 配置管理命令 jobdeer llm-config,支持多种配置方式。

命令功能

1. --show - 显示当前配置

jobdeer llm-config --show

显示内容:

  • 配置文件位置(~/.llmdog.yaml./.llmdog.yaml
  • 环境变量设置状态(LLM_API_KEYLLM_API_URL
  • 当前所有配置项(API Key 自动脱敏,只显示前 8 位)
  • 配置完整性验证提示

2. --test - 测试 API 连接

jobdeer llm-config --test

功能:

  • 使用 test_llm_api() 函数验证 API 连接
  • 显示测试结果和详细的错误诊断信息
  • 提供故障排除建议(API Key 无效、URL 错误、网络问题等)

3. --create - 创建配置文件模板

jobdeer llm-config --create

功能:

  • 复制 .llmdog.yaml.example 到当前目录
  • 检查文件是否已存在,避免意外覆盖
  • 提供下一步操作指引

4. --wizard - 交互式配置向导(推荐新用户)

jobdeer llm-config --wizard

功能:

  • 逐步引导配置 API URL、API Key、Model、Timeout
  • 显示常用配置示例(OpenAI、Azure、Ollama)
  • 支持使用默认值(按 Enter 键)
  • 配置摘要确认
  • 自动保存为 YAML 格式配置文件
  • 可选的 API 连接测试

5. 快速设置 - 命令行参数直接配置

jobdeer llm-config --api-url "https://api.example.com/v1" \
                   --api-key "sk-xxx" \
                   --model "gpt-3.5-turbo"

功能:

  • 自动读取现有配置并更新指定字段
  • 保存为 YAML 格式配置文件
  • 支持部分更新(只传需要的参数)
# 查看当前生效的配置
jobdeer llm-config --show

# 测试 API 连接
jobdeer llm-config --test

# 创建示例配置文件到当前目录
jobdeer llm-config --create

# 启动交互式配置向导(推荐新用户)
jobdeer llm-config --wizard

# 快速设置配置
jobdeer llm-config --api-url "https://api.example.com/v1" --api-key "sk-xxx" --model "gpt-3.5-turbo"

使用场景示例

场景 1:新用户快速开始

# 方式 1:使用交互式向导(推荐)
jobdeer llm-config --wizard

# 方式 2:创建配置文件后手动编辑
jobdeer llm-config --create
vim .llmdog.yaml

# 方式 3:直接通过命令行设置
jobdeer llm-config --api-url "https://api.openai.com/v1" \
                   --api-key "sk-xxx" \
                   --model "gpt-3.5-turbo"

场景 2:日常使用

# 查看当前配置
jobdeer llm-config --show

# 测试配置是否有效
jobdeer llm-config --test

# 使用 LLM 辅助录入(自动使用已配置的 API)
jobdeer llm-add

场景 3:高级用法

# 临时使用不同的 API(不修改配置文件)
jobdeer llm-add --api-url "http://localhost:11434/v1" \
                --api-key "ollama" \
                --model "qwen2.5:32b"

# 使用环境变量覆盖配置
LLM_API_KEY="sk-different-key" jobdeer llm-config --show

# 测试不同的 API 提供商
jobdeer llm-config --api-url "https://api.anthropic.com/v1" --api-key "sk-ant-xxx"
jobdeer llm-config --test

配置优先级

llmdog 的配置加载遵循以下优先级(从高到低):

1. 命令行参数 (--api-url, --api-key, --model)
   ↓
2. 环境变量 (LLM_API_URL, LLM_API_KEY, LLM_MODEL)
   ↓
3. 配置文件 (~/.llmdog.yaml 或 ./.llmdog.yaml)
   ↓
4. 内置默认值

重要说明

  • 环境变量优先级高于配置文件
  • 命令行参数优先级最高,可临时覆盖所有配置
  • 配置文件支持 YAML 和 JSON 格式

配置文件格式

使用 YAML 格式(通过 PyYAML 库):

# API 配置(必填)
api_key: "sk-your-api-key-here"
api_url: "https://api.openai.com/v1/chat/completions"
model: "gpt-3.5-turbo"

# 可选配置
timeout: 120          # 请求超时(秒)
max_retries: 3        # 最大重试次数
backoff_multiplier: 1 # 指数退避倍率(秒)
verify_ssl: false     # 是否验证 SSL 证书
backend: "llmapi"     # 后端标识符

最佳实践建议

  1. 开发环境:使用 .llmdog.yaml 配置文件,方便管理
  2. 生产环境:使用环境变量,避免敏感信息泄露
  3. 团队协作:提供 .llmdog.yaml.example 模板,每个人复制后填写自己的配置
  4. 安全注意永远不要将包含真实 API Key 的配置文件提交到 Git 仓库(已自动添加到 .gitignore

技术实现细节

核心函数

  • _print_llm_config_help() - 显示帮助信息(支持 Rich Markdown)
  • _show_current_config(config) - 显示当前配置
  • _test_api_connection(config) - 测试 API 连接
  • _create_config_file() - 创建配置文件
  • _quick_set_config(config, api_url, api_key, model) - 快速设置
  • _run_config_wizard() - 交互式向导

设计特点

  • 遵循 Typer CLI 规范,使用 @app.command()Annotated 类型提示
  • 复用现有的 test_llm_api() 函数,保持一致性
  • 使用 print_infoprint_successprint_error 等输出函数
  • API Key 显示时自动脱敏(只显示前 8 位)
  • 错误提示包含详细的解决建议

扩展功能(未来计划)

  1. 支持多配置配置文件(如 --config-file 参数)
  2. 支持配置导入/导出
  3. 支持配置历史记录
  4. 支持配置验证规则自定义
  5. 集成到 Web 界面的配置管理

Web 界面使用

搜索功能

Web 界面提供两种搜索方式:

1. 全局搜索(顶部搜索栏)

  • 关键词模式:输入关键词,使用 Tantivy BM25 算法全文检索
  • 正则模式:输入正则表达式,使用 Python re 模块匹配
  • 语义模式:输入自然语言描述,基于向量相似度匹配

2. 高级搜索(点击"高级搜索"按钮展开)

  • 列出 26 个可搜索字段,按 5 组分类排列:

    • 基本信息:职位名称、所属部门、公司名称、工作地点、职位描述、任职要求
    • 分类标签:职位类别、标签、技术栈、级别、聘用年份
    • 薪酬福利:薪酬范围、福利
    • 目标画像:目标公司、目标职位、目标产品、目标项目、目标部门、目标角色、目标论文、目标GitHub、目标关键词、目标候选人
    • 联系信息:联系人、联系邮箱、面试官
  • 可填写多个字段,之间为 AND 逻辑(必须同时满足)

  • 高级搜索与全局搜索互斥:展开高级搜索时,全局搜索框自动禁用

职位管理

  • 新增职位:点击"+ 新增职位"按钮,填写表单后保存
  • 编辑职位:点击每行的"编辑"按钮,修改后保存
  • 删除职位:点击每行的"删除"按钮,确认后删除
  • 重建索引:点击"重建索引"按钮,重建搜索索引

🔌 API 接口说明

RESTful API

Web 界面基于以下 RESTful API:

获取职位列表

GET /api/jobs?page=1&per_page=20

响应示例

{
  "jobs": [...],
  "page": 1,
  "per_page": 20,
  "total": 100
}

创建职位

POST /api/jobs
Content-Type: application/json

{
  "title": "Python后端开发工程师",
  "department": "技术部",
  "description": "负责公司后端系统开发",
  "company": "某某科技",
  "location": "北京"
}

响应:返回创建的职位对象(HTTP 201)

获取单个职位

GET /api/jobs/<job_id>

更新职位

PUT /api/jobs/<job_id>
Content-Type: application/json

{
  "priority": "非常高",
  "urgency": "紧急"
}

删除职位

DELETE /api/jobs/<job_id>

搜索职位

GET /api/search?q=Python&mode=keyword&field=title&limit=100

参数说明

参数 类型 必填 默认值 说明
q string - 搜索关键词/正则/语义查询文本
mode string keyword 搜索模式:keyword / regex / semantic
field string 无(全字段) 指定搜索字段名(仅 keyword/regex 模式有效)
ignore_case bool true 大小写不敏感(仅 regex 模式有效)
limit int 100 最大返回数

向后兼容regex=true 参数仍然生效(等价于 mode=regex

响应示例

{
  "jobs": [...],
  "total": 10,
  "mode": "keyword"
}

语义模式下,每个 job 额外包含 _score 字段(相似度分数 0-1)。

高级搜索(多字段组合)

POST /api/search/fields
Content-Type: application/json

{
  "fields": {
    "title": "Python",
    "company": "字节",
    "tech_stack": "React"
  },
  "mode": "keyword",
  "limit": 100
}

响应:与 GET /api/search 相同格式

重建索引

POST /api/rebuild-index

响应

{
  "success": true
}

📦 依赖清单

核心依赖

包名 版本要求 用途
typer >=0.9.0 CLI 框架
rich >=13.0.0 终端美化输出
tantivy >=0.22.0 全文检索引擎(Rust 底层)
jieba >=0.42.1 中文分词
openpyxl >=3.1.0 Excel 文件处理
flask >=2.3.0 Web 框架
filelock >=3.12.0 文件锁(并发安全)
llmdog >=0.1.0 LLM 服务客户端
larkfunc >=0.1.0 LLM 函数调用工具
pyyaml >=6.0 YAML 配置文件处理

可选依赖

依赖组 包名 用途
semantic sentence-transformers>=2.2.0, numpy>=1.24.0 语义向量搜索
dev pytest>=7.0, black>=23.0, ruff>=0.1.0 开发工具

前端依赖(CDN 引入)

  • TailwindCSS(v3.x):CSS 框架
  • Alpine.js(v3.x):前端交互框架

⚙️ LLM API 配置指南

JobDeer 的 LLM 辅助录入功能依赖于 llmdog 库,需要配置 API URL、API Key 和 Model 等参数。支持以下三种配置方式(按优先级从高到低):

方式 1:环境变量(推荐用于生产环境)

在终端中设置环境变量:

# macOS / Linux
export LLM_API_KEY="sk-your-api-key-here"
export LLM_API_URL="https://api.openai.com/v1/chat/completions"
export LLM_MODEL="gpt-3.5-turbo"

# Windows (CMD)
set LLM_API_KEY=sk-your-api-key-here
set LLM_API_URL=https://api.openai.com/v1/chat/completions
set LLM_MODEL=gpt-3.5-turbo

# Windows (PowerShell)
$env:LLM_API_KEY="sk-your-api-key-here"
$env:LLM_API_URL="https://api.openai.com/v1/chat/completions"
$env:LLM_MODEL="gpt-3.5-turbo"

支持的环境变量列表

环境变量 对应配置 必填 默认值 说明
LLM_API_KEY api_key ✅ 是 - API 鉴权密钥
LLM_API_URL api_url ✅ 是 - API 端点地址
LLM_MODEL model qwen2.5-coder-32b-instruct 模型名称
LLM_TIMEOUT timeout 120 请求超时(秒)
LLM_MAX_RETRIES max_retries 3 最大重试次数
LLM_VERIFY_SSL verify_ssl false 是否验证 SSL 证书
LLM_BACKEND backend llmapi 后端标识符

持久化配置(添加到 shell 配置文件):

# 添加到 ~/.bashrc 或 ~/.zshrc
echo 'export LLM_API_KEY="sk-your-api-key-here"' >> ~/.bashrc
echo 'export LLM_API_URL="https://api.openai.com/v1/chat/completions"' >> ~/.bashrc
source ~/.bashrc

方式 2:本地配置文件(推荐用于开发环境)

创建 YAML 或 JSON 格式的配置文件,llmdog 会自动按以下顺序查找:

  1. 当前目录:./.llmdog.yaml./.llmdog.json
  2. 用户目录:~/.llmdog.yaml~/.llmdog.json

YAML 配置示例.llmdog.yaml):

# API 配置(必填)
api_key: "sk-your-api-key-here"
api_url: "https://api.openai.com/v1/chat/completions"
model: "gpt-3.5-turbo"

# 可选配置
timeout: 120
max_retries: 3
verify_ssl: false

JSON 配置示例.llmdog.json):

{
  "api_key": "sk-your-api-key-here",
  "api_url": "https://api.openai.com/v1/chat/completions",
  "model": "gpt-3.5-turbo",
  "timeout": 120,
  "max_retries": 3,
  "verify_ssl": false
}

快速创建配置文件

# 复制示例配置文件
cp .llmdog.yaml.example .llmdog.yaml

# 编辑配置文件
vim .llmdog.yaml

方式 3:Web 界面动态配置(仅影响当前会话)

在 Web 界面中使用 LLM 功能时,会在浏览器中临时配置 API 参数:

  1. 打开 Web 界面:jobdeer web
  2. 点击"LLM 辅助录入"按钮
  3. 填写 API URL 和 API Key
  4. 点击"测试连接"验证配置
  5. 配置会保存到 localStorage(仅在当前浏览器有效)

注意:Web 界面配置仅用于前端临时调用,不会写入本地配置文件或环境变量。

配置优先级说明

llmdog 的配置加载遵循以下优先级(从高到低):

1. 函数调用时显式传入的参数(代码内部使用)
   ↓
2. 环境变量(LLM_API_KEY、LLM_API_URL 等)
   ↓
3. 配置文件(~/.llmdog.yaml 或 ./.llmdog.yaml)
   ↓
4. 内置默认值

最佳实践建议

  1. 开发环境:使用 .llmdog.yaml 配置文件,方便版本控制(记得添加到 .gitignore
  2. 生产环境:使用环境变量,避免敏感信息泄露
  3. 团队协作:提供 .llmdog.yaml.example 模板,每个人复制后填写自己的配置
  4. 安全注意永远不要将包含真实 API Key 的配置文件提交到 Git 仓库

验证配置

配置完成后,可以通过以下方式验证:

方法 1:使用 CLI 测试

# 尝试使用 LLM 辅助录入功能
jobdeer llm-add

方法 2:使用 Python 代码测试

from jobdeer.llm_helper import test_llm_api

# 如果已配置环境变量或配置文件,可以直接调用
from llmdog.config import load_config
config = load_config()
print(f"API URL: {config.api_url}")
print(f"Model: {config.model}")

# 测试 API 连接
success = test_llm_api(config.api_url, config.api_key)
print(f"API 连接: {'成功' if success else '失败'}")

方法 3:使用 Web 界面测试

  1. 启动 Web 服务:jobdeer web
  2. 访问 http://127.0.0.1:5000
  3. 点击"LLM 辅助录入"
  4. 填写 API URL 和 API Key
  5. 点击"测试连接"按钮

常见问题

Q1: 提示 "api_key 未配置" 错误?

A: 检查是否正确设置了 LLM_API_KEY 环境变量或 .llmdog.yaml 配置文件中的 api_key 字段。

Q2: 如何切换不同的 LLM 提供商?

A: 修改 api_urlmodel 即可。例如:

# OpenAI
api_url: "https://api.openai.com/v1/chat/completions"
model: "gpt-3.5-turbo"

# Azure OpenAI
api_url: "https://your-resource.openai.azure.com/openai/deployments/your-deployment/chat/completions?api-version=2023-05-15"
model: "gpt-35-turbo"

# 本地部署(如 Ollama)
api_url: "http://localhost:11434/v1/chat/completions"
model: "qwen2.5:32b"

Q3: CLI 的 llm-add 命令是否支持自定义 API 配置?

A: 当前版本的 jobdeer llm-add 命令依赖于环境变量或配置文件。如果需要临时使用不同的 API 配置,可以先设置环境变量:

# 场景 1:开发环境(使用配置文件)
cp .llmdog.yaml.example .llmdog.yaml
vim .llmdog.yaml  # 填写真实 API Key
jobdeer llm-add   # 直接使用

# 场景 2:生产环境(使用环境变量)
export LLM_API_KEY="sk-prod-key"
export LLM_API_URL="https://api.openai.com/v1/chat/completions"
jobdeer llm-add

# 场景 3:临时测试不同 API
jobdeer llm-add --api-url "http://localhost:11434/v1" --api-key "ollama" --model "qwen2.5:32b"

# 场景 4:验证配置
python3 -c "from llmdog.config import load_config; c = load_config(); print(f'URL: {c.api_url}, Model: {c.model}')"

Q4: 配置文件和环境变量同时存在时,哪个生效?

A: 环境变量优先级高于配置文件。如果同时设置了 LLM_API_KEY 环境变量和 .llmdog.yaml 中的 api_key,环境变量的值会覆盖配置文件。


🔍 搜索功能技术原理

1. 关键词搜索(Tantivy BM25)

实现流程

  1. 写入索引:职位数据写入时,使用 jieba 对中文文本进行预分词,以空格连接后存入 Tantivy
  2. 搜索查询:用户输入查询词同样经过 jieba 分词,构建 Tantivy 查询语句
  3. BM25 排序:Tantivy 使用 BM25 算法计算每个文档的相关性得分,按得分降序返回

中文分词策略

# 写入索引前
text = "Python后端开发工程师"
tokens = jieba.cut(text)  # ["Python", "后端", "开发", "工程师"]
indexed_text = " ".join(tokens)  # "Python 后端 开发 工程师"

# 搜索时
query = "后端开发"
query_tokens = jieba.cut(query)  # ["后端", "开发"]
indexed_query = " ".join(query_tokens)  # "后端 开发"

Tantivy 查询语法

# 单字段搜索
query = ix.parse_query("后端", ["title"])

# 多字段搜索
query = ix.parse_query("后端 开发", ["title", "description", "requirements"])

# 高级搜索(AND 逻辑)
query_str = "+title:后端 +title:开发 +company:字节"
query = ix.parse_query(query_str, all_fields)

2. 正则搜索(Python re)

实现流程

  1. 使用 re.compile() 编译正则表达式
  2. 遍历所有职位数据,将每个职位的所有字段拼接为文本
  3. 使用 prog.search() 匹配,返回所有匹配的职位

支持选项

  • ignore_case=True:忽略大小写(默认)
  • field="title":仅在指定字段搜索

示例

# 匹配包含 Python 或 Java 的职位
search_regex("Python|Java", ignore_case=True)

# 仅搜索 title 字段,忽略大小写
search_regex("^Python", ignore_case=True, field="title")

3. 语义搜索(向量相似度)

实现流程

  1. 向量化:使用 sentence-transformersshibing624/text2vec-base-chinese 模型,将所有职位的可搜索字段拼接后生成 768 维向量
  2. 存储:向量矩阵保存为 vectors.npy,对应的 job_id 列表保存为 ids.json
  3. 搜索:用户查询文本同样生成向量,与所有职位向量计算余弦相似度
  4. 排序:按相似度降序返回 top-N 结果

余弦相似度计算

# 向量已归一化,直接点积即为余弦相似度
scores = vectors @ query_vec  # (N,) 数组
top_indices = np.argsort(-scores)[:limit]

为什么用 text2vec-base-chinese?

  • 轻量模型(约 400MB),适合本地部署
  • 支持中英双语,适合技术职位搜索
  • 基于 SentenceTransformers,API 简洁

注意事项

  • 语义搜索为可选功能,不安装 sentence-transformers 不影响其他搜索
  • 首次使用会自动下载模型文件(约 400MB),后续缓存到本地
  • 每次添加/删除/更新职位后,需同步更新向量索引

🧩 扩展与维护

如何添加新的可搜索字段?

  1. jobdeer/models.pyCORE_FIELDS 集合中添加字段名
  2. jobdeer/search.pySEARCHABLE_FIELDS 列表中添加字段名
  3. jobdeer/templates/index.html 的高级搜索面板中添加对应的输入框
  4. jobdeer/static/app.jsadvancedFields 对象中添加初始值
  5. 执行 jobdeer rebuild-index 重建索引

如何更换语义搜索模型?

修改 jobdeer/search.py 中的 _get_embedding_model() 函数:

def _get_embedding_model():
    global _embedding_model
    if _embedding_model is None:
        from sentence_transformers import SentenceTransformer
        # 更换为你想使用的模型
        _embedding_model = SentenceTransformer("your-model-name")
    return _embedding_model

注意:更换模型后需执行 jobdeer rebuild-index 重新构建向量索引。

如何添加新的搜索模式?

  1. jobdeer/search.py 中实现新的搜索函数:
def search_custom(query_str: str, limit: int = 100) -> List[Dict[str, Any]]:
    """自定义搜索逻辑"""
    # 你的实现
    return results
  1. jobdeer/web.pyapi_search() 路由中添加新模式处理:
elif mode == "custom":
    results = search_custom(q, limit=limit)
  1. jobdeer/cli.pycmd_search() 中添加新模式处理
  2. jobdeer/templates/index.html 的下拉选择器中添加新选项
  3. jobdeer/static/app.jssearchMode 逻辑中处理新模式

如何迁移到其他数据库?

当前使用 JSON 文件存储,适合小规模数据(<10,000 条)。如需迁移到数据库:

  1. 修改 jobdeer/models.py 中的 JobStore 类,替换为 SQLAlchemy 或 ORM
  2. 替换 store.add()store.get() 等方法为数据库操作
  3. Tantivy 索引和向量索引无需修改,它们独立于数据存储

性能优化建议

场景 优化方案
数据量 > 10,000 条 考虑迁移到 PostgreSQL/SQLite
搜索速度慢 检查索引是否最新,执行 rebuild-index
语义搜索加载慢 预加载模型到内存,或使用更轻量的模型
并发写入冲突 filelock 已处理,无需额外配置
Web 响应慢 使用 gunicorn 替代 Flask 内置服务器

代码结构规范

jobdeer/
├── __init__.py          # 包入口,导出公共 API
├── models.py            # 数据模型和存储
├── search.py            # 搜索引擎实现
├── excel_io.py          # Excel 导入导出
├── llm_helper.py        # LLM 辅助功能
├── output.py            # CLI 输出工具函数
├── cli.py               # CLI 入口
├── web.py               # Web 服务端
├── templates/
│   └── index.html       # Web 页面模板
└── static/
    ├── app.js           # 前端逻辑
    └── style.css        # 自定义样式

开发建议

  • 新增功能优先在对应模块中实现
  • CLI 和 Web 共用业务逻辑(models/search/excel_io)
  • 前端修改只需刷新浏览器(Alpine.js 响应式)
  • 每次修改搜索相关代码后,务必重建索引测试

🤝 贡献指南

欢迎提交 Issue 和 Pull Request!

开发环境设置

# 1. 克隆仓库
git clone https://github.com/jobdeer/jobdeer.git
cd jobdeer

# 2. 安装开发依赖
pip install -e ".[dev,semantic]"

# 3. 运行测试
pytest

# 4. 代码格式化
black jobdeer/
ruff check jobdeer/

提交 PR 流程

  1. Fork 本仓库
  2. 创建特性分支:git checkout -b feature/amazing-feature
  3. 提交修改:git commit -m 'Add amazing feature'
  4. 推送分支:git push origin feature/amazing-feature
  5. 提交 Pull Request

📄 许可证

本项目采用 MIT 许可证。详见 LICENSE 文件。


🙏 致谢


⚠️ 免责声明

重要提示

  1. 使用风险:本软件按“现状”提供,不提供任何形式的明示或暗示保证,包括但不限于适销性、特定用途适用性和非侵权性的保证。使用本软件所产生的任何风险由用户自行承担。

  2. 数据安全

    • 本工具处理的数据(包括职位信息、API Key 等)由用户自行管理
    • 建议定期备份 joblist.json 数据文件
    • 切勿将包含 API Key 的配置文件(.llmdog.yaml)提交到版本控制系统
    • 使用强密码和安全的 API Key,并定期更换
  3. 第三方服务

    • 本工具集成的 LLM 服务(通过 llmdog 库)由第三方提供商提供
    • LLM 服务的质量、可用性和准确性不由本工具保证
    • 使用 LLM 功能时,请遵守相关服务提供商的条款和条件
    • LLM 生成的内容可能存在错误,请人工审核后使用
  4. 隐私保护

    • 本工具在本地运行,数据默认存储在本地文件系统
    • 使用 LLM API 时,职位描述等数据会发送到第三方 API 服务器
    • 请确保您有权限将相关数据发送到外部服务
    • 对于敏感职位信息,建议使用本地部署的 LLM 服务
  5. 合规性

    • 用户在使用本工具时应遵守适用的法律法规
    • 在收集、存储和处理个人信息时,请遵守相关数据保护法规(如 GDPR、个人信息保护法等)
    • 本工具不提供法律建议,如有合规性问题请咨询专业法律顾问
  6. 技术支持

    • 本工具为开源软件,社区提供支持
    • 不保证及时的技术响应和问题修复
    • 鼓励用户通过 Issue 和 Pull Request 参与贡献
  7. 版本兼容性

    • 不同版本之间可能存在不兼容的变更
    • 升级前请仔细阅读更新日志
    • 建议在测试环境验证后再升级到生产环境

通过使用本软件,您同意接受上述所有条款。如果您不同意这些条款,请不要使用本软件。

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

jobdeer-0.1.0.tar.gz (68.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

jobdeer-0.1.0-py3-none-any.whl (48.2 kB view details)

Uploaded Python 3

File details

Details for the file jobdeer-0.1.0.tar.gz.

File metadata

  • Download URL: jobdeer-0.1.0.tar.gz
  • Upload date:
  • Size: 68.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.3

File hashes

Hashes for jobdeer-0.1.0.tar.gz
Algorithm Hash digest
SHA256 54cb619c215712cc628057735e6e2b819870a9777c4478c7727095958800cde1
MD5 998d2e9582589202fed3a9d7f3628b5a
BLAKE2b-256 020b01ac818bc93a09e01921bfdf101b21a3347e738639070ff58e5a17e60c4d

See more details on using hashes here.

File details

Details for the file jobdeer-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: jobdeer-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 48.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.3

File hashes

Hashes for jobdeer-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 387a9e7168c1768056f859ccf91ee4256e449379ef756b037b217dc48875d3e0
MD5 30cb6835f9d6cb47d471029ddca3e01f
BLAKE2b-256 043abaac8f21e27e7a7135a359c47c9aac5783a09b97422f2779d8f1d191dcce

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page