Metadata-Version: 2.4
Name: recruitment-judge
Version: 0.3.1
Summary: 招聘判官 (Hire Fortune) — 打工人的招聘玄学搭子
Author-email: Chandler <275737875@qq.com>
License: MIT
Keywords: cli,divination,fastapi,fortune,metaphysics,recruitment
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Web Environment
Classifier: Framework :: FastAPI
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
Requires-Python: >=3.10
Requires-Dist: fastapi>=0.110
Requires-Dist: pydantic>=2.6
Requires-Dist: rich>=13.7
Requires-Dist: typer>=0.12
Requires-Dist: uvicorn>=0.29
Provides-Extra: dev
Requires-Dist: httpx>=0.27; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Description-Content-Type: text/markdown

# 招聘判官 (Hire Fortune)

> 先看天命，再开工。打工人的招聘玄学搭子。

[![PyPI version](https://img.shields.io/pypi/v/recruitment-judge.svg)](https://pypi.org/project/recruitment-judge/)
[![Python](https://img.shields.io/pypi/pyversions/recruitment-judge.svg)](https://pypi.org/project/recruitment-judge/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

招聘判官是一个面向招聘 HR 的趣味玄学断案工具。选场景、点断案、看天命——经历 3 秒仪式动画后获得一份判词结果（天命指数、五维命盘、判官断语、建议、甩锅话术）。结果可分享、可复现。

## 功能特色

### 三大入口

| 入口 | 路由 | 说明 |
|------|------|------|
| 一键断案 | `/judge` | 选择招聘场景 → 3 秒召唤仪式 → 天命指数 + 五维命盘 + 判词 + 甩锅话术 |
| 今日天命 | `/today` | 每日招聘运势：星级 + 关键词 + 宜忌 + 贵人/业障 + 四维能量条 |
| 招聘测字 | `/divine` | 写一个字 → 拆字判语 + 四维星级 + 判官解字 + 宜忌 |

### 一键断案流程

1. **选场景**：6 个招聘场景（候选人/业务/Offer/面试官/HC/随机）
2. **召唤仪式**：Three.js 3D 罗盘旋转 + 粒子收敛 + GSAP 相机关键帧 + Bloom 后处理
3. **天命已定**：指针锁定随机方向，结果揭晓
4. **结果卡**：天命指数计数动画 + D3 雷达图 + 判词卷轴 + 甩锅话术 + 分享/反馈

### 天命等级

| 分数区间 | 等级 | 标签 |
|----------|------|------|
| 90–100 | GREAT | 上上签 |
| 75–89 | GOOD | 上签 |
| 55–74 | NEUTRAL | 中签 |
| 35–54 | BAD | 下签 |
| 0–34 | WORST | 下下签 |

### 连续开工称号

| 连续天数 | 称号 |
|----------|------|
| 1 | 刚入法门 |
| 3 | 初窥天机 |
| 7 | 招聘通灵E师 |
| 14 | 判官记名弟子 |
| 30 | 天命猎手 |
| 60 | 业障克星 |
| 100 | 招聘飞升者 |

### 其他特色

- **结果可复现**：相同 seed + scene 产出完全相同结果，分享链接可扫码复现
- **分享卡**：Canvas 2D 生成 1080×1920 品牌字体分享图 + QR 码 + 稀缺感文案
- **3D 罗盘**：三环差速旋转（八卦/天干/地支）+ 阻尼指针 + RoomEnvironment 环境贴图
- **粒子能量场**：三色三层（白热核心 + 金光中层 + 暗金余烬）
- **彩蛋**：特定条件下触发特殊判语
- **降级策略**：WebGL 不可用 → CSS 罗盘；数据加载失败 → 硬编码兜底；判词池空 → 相邻等级降级
- **可访问性**：`prefers-reduced-motion` 支持、键盘 focus-visible、WCAG AA 对比度

## 技术栈

| 层 | 技术 |
|----|------|
| 前端 | 原生 HTML + CSS + vanilla JS（ES Modules） |
| 3D | Three.js 0.160.0（importmap CDN） |
| 图表 | D3.js（雷达图） |
| 动画 | GSAP 3.12.5（相机关键帧 + 时间线） |
| 后端 | Python 3.10+ / FastAPI / Uvicorn |
| 校验 | Pydantic v2 |
| CLI | Typer + Rich |
| 构建 | hatchling |
| 测试 | pytest + pytest-asyncio + httpx |

## 安装

### 从 PyPI 安装

```bash
pip install recruitment-judge
```

### 从源码安装

```bash
git clone https://github.com/recruitment-judge/recruitment-judge.git
cd recruitment-judge
pip install -e .
```

## 使用

### 启动 Web 服务

```bash
recruitment-judge web
```

启动后访问 http://localhost:8000

### CLI 选项

```bash
recruitment-judge web --host 0.0.0.0 --port 8000 --reload
```

| 选项 | 说明 | 默认值 |
|------|------|--------|
| `--host` / `-h` | 监听地址 | `0.0.0.0` |
| `--port` / `-p` | 监听端口 | `8000` |
| `--reload` | 热重载（开发模式） | 关闭 |

### 环境变量

| 变量 | 说明 | 默认值 |
|------|------|--------|
| `SERVER_HOST` | 监听地址 | `0.0.0.0` |
| `SERVER_PORT` | 监听端口 | `8000` |
| `MAX_EVENT_PAYLOAD_SIZE` | 埋点 payload 最大字节 | `10240` |

### 开发模式

```bash
pip install -e ".[dev]"
pytest tests/ -v
```

## API 端点

### `GET /api/v1/health`

健康检查，返回服务状态、版本、运行时间。

```json
{
  "code": 0,
  "message": "ok",
  "data": { "status": "healthy", "version": "1.1.0", "uptime": 42 }
}
```

### `POST /api/v1/events`

埋点收集，Rich 控制台打印 JSON 日志。

```json
{
  "event": "page_view",
  "payload": { "path": "/" },
  "timestamp": 1700000000000,
  "client_id": "abc123"
}
```

**支持的 event 类型**：

`page_view` · `scenario_select` · `fortune_start` · `fortune_complete` · `fortune_result` · `fortune_retry` · `fortune_share` · `fortune_feedback_positive` · `fortune_feedback_negative` · `special_judgement_trigger`

### 统一响应格式

```json
{ "code": 0, "message": "ok", "data": {} }
```

| code | 含义 |
|------|------|
| 0 | 成功 |
| 1001 | 请求格式错误 |
| 1002 | 校验错误 |
| 5000 | 内部错误 |

## 前端路由

| 路径 | 页面 | 说明 |
|------|------|------|
| `/` | 首页 | Logo + 标题 + 三入口卡片 |
| `/judge` | 一键断案 | 场景选择器 + 断案按钮 |
| `/today` | 今日天命 | 每日招聘运势完整卡 |
| `/divine` | 招聘测字 | 单字输入 + 拆字结果 |
| `/result?scene=&seed=` | 结果复现 | 通过 URL 参数复现断案结果 |
| `/share?char=&date=&seed=` | 分享卡 | 测字结果分享页 |

## 招聘场景

| ID | 图标 | 名称 | 副标题 |
|----|------|------|--------|
| `candidate` | 👤 | 候选人 | 这人简历能信吗？ |
| `business` | 📊 | 业务 | 业务方到底要啥？ |
| `offer` | 📜 | Offer | 发了Offer会接吗？ |
| `interviewer` | 🎯 | 面试官 | 反馈靠谱不靠谱？ |
| `hc` | 💰 | HC | 编制能批下来吗？ |
| `random` | 🎲 | 随便算算 | 今天适合招人吗？ |

## 目录结构

```
recruitment_judge/
├── pyproject.toml                # 构建配置 + 依赖 + 入口点
├── scripts/publish.ps1           # PyPI 一键发布脚本
├── docs/                         # 设计文档与评审报告
│   ├── visual_design_spec.md     # 视觉设计规格（16 Task）
│   ├── judge_page_spec.md        # 断案独立页面设计
│   ├── terms_review.md           # 品牌文案评审
│   └── ...
├── src/recruitment_judge/
│   ├── __init__.py               # 版本号
│   ├── __main__.py               # python -m 入口
│   ├── cli.py                    # Typer CLI
│   ├── app.py                    # FastAPI 应用
│   ├── api/v1/
│   │   ├── health.py             # GET /api/v1/health
│   │   └── events.py             # POST /api/v1/events
│   ├── core/
│   │   ├── config.py             # 环境变量配置
│   │   └── response.py           # 统一响应模型
│   ├── models/
│   │   └── event.py              # 埋点 Pydantic 模型
│   └── static/                   # 前端静态文件
│       ├── index.html            # SPA 主入口
│       ├── css/
│       │   ├── main.css          # 设计令牌 + 基础组件
│       │   ├── home.css          # 首页 + 场景卡
│       │   ├── judge.css         # 断案页
│       │   ├── result.css        # 结果卡
│       │   ├── daily_fortune.css # 今日天命
│       │   ├── character_divination.css  # 测字
│       │   ├── share_card.css    # 分享卡
│       │   └── animation.css     # 动画 keyframes
│       └── js/
│           ├── main.js           # 入口：Store + Router + 页面分发
│           ├── core/
│           │   ├── store.js      # 状态机（Flux）
│           │   ├── router.js     # 客户端路由（History API）
│           │   └── event_bus.js  # 事件总线
│           ├── engine/           # 纯逻辑层（零视觉依赖）
│           │   ├── fortune_engine.js    # 断案主编排
│           │   ├── daily_fortune_engine.js  # 今日天命
│           │   ├── character_engine.js     # 测字
│           │   ├── share_engine.js         # 分享卡生成
│           │   ├── seed.js / random.js    # 种子 + PRNG
│           │   ├── dimensions.js          # 五维计算
│           │   ├── score.js               # 天命指数
│           │   ├── level.js               # 等级映射
│           │   ├── result_selector.js     # 判词选择
│           │   ├── easter_egg.js          # 彩蛋触发
│           │   └── duplicate_guard.js     # 去重
│           ├── visual/           # 视觉表现层
│           │   ├── three_scene.js     # Three.js 场景 + Bloom
│           │   ├── compass.js          # 3D 罗盘
│           │   ├── particles.js        # 粒子能量场
│           │   ├── radar.js            # D3 雷达图
│           │   ├── share_image.js      # Canvas 分享图
│           │   └── easter_egg_fx.js    # 彩蛋特效
│           ├── animation/        # GSAP 时间线
│           │   ├── summon_timeline.js  # 召唤仪式
│           │   ├── reveal_timeline.js  # 结果揭示
│           │   ├── radar_timeline.js   # 雷达图动画
│           │   └── opening_ritual.js   # 开场仪式
│           ├── ui/               # UI 组件
│           │   ├── home_view.js        # 首页
│           │   ├── judge_view.js       # 断案页
│           │   ├── judge_flow.js       # 断案流程
│           │   ├── result_card.js      # 结果卡
│           │   ├── result_view.js      # 结果页
│           │   ├── scene_selector.js   # 场景选择器
│           │   ├── judge_button.js     # 断案按钮
│           │   ├── daily_fortune_page.js   # 今日天命页
│           │   ├── character_page_view.js  # 测字页
│           │   ├── share_page_view.js      # 分享页
│           │   └── feedback.js         # 反馈组件
│           ├── data/             # 静态数据 + 兜底
│           │   ├── judgements.json       # 判词库
│           │   ├── scenarios.json        # 场景配置
│           │   ├── character_library.js  # 100 字库
│           │   ├── title_table.js        # 称号表
│           │   └── *_fallback.js         # 硬编码兜底
│           ├── analytics/
│           │   └── analytics.js         # 埋点上报
│           ├── state/
│           │   └── streak_store.js      # 连续开工存储
│           └── utils/
│               ├── device.js            # 设备检测
│               └── qrcode.js            # QR 码生成
└── tests/
    └── server/test_api.py               # 6 个 API 测试
```

## 核心架构原则

1. **算法与视觉彻底解耦**：`engine/` 纯 JS 逻辑层零视觉依赖，可独立运行
2. **判词必达**：任意降级场景下（数据加载失败、判词池空），用户必定看到完整判词
3. **结果可复现**：相同 seed + scene 产出完全相同结果，URL 参数可复现
4. **渐进增强**：WebGL 不可用 → CSS 降级；Three.js 加载失败 → 跳过 3D

## 断案流程编排

```
用户点击"一键断案"
  → store.dispatch(JUDGE_START)
  → initThreeScene(canvas)           // Three.js 场景初始化
  → createCompass() + createParticles()  // 罗盘 + 粒子
  → animateCamera(gsap, camera)      // GSAP 相机关键帧
  → renderLoop()                     // rAF: spinCompass + convergeParticles + composer.render
  → calculateFortune(input)          // 纯逻辑：Seed → PRNG → 五维 → 天命指数 → 等级 → 判词
  → store.dispatch(JUDGE_CALCULATING)
  → playSummonTimeline()             // GSAP 召唤动画
  → store.dispatch(JUDGE_REVEAL)
  → renderResultCard()               // 结果卡渲染 + 雷达图 + 计数动画
  → store.dispatch(JUDGE_RESULT)
```

## 发布

### 一键发布脚本

```bash
./scripts/publish.ps1                  # patch bump + 发布到 PyPI
./scripts/publish.ps1 -bump minor      # minor bump + 发布
./scripts/publish.ps1 -bump none       # 不改版本，直接发布
./scripts/publish.ps1 -test            # 发布到 TestPyPI
./scripts/publish.ps1 -skipUpload      # 仅构建不上传
```

脚本流程：版本 bump → 测试预检 → 清理 → 构建 sdist + wheel → twine check → 上传 PyPI → git tag

## 开发约定

- Python 变量：`UPPER_SNAKE_CASE`
- JS 文件名：`lower_snake_case.js`
- CSS 类名：`kebab-case`
- 判词 ID：`UPPER_TAG_DIGITS`（如 `BUSINESS_003`）
- 设计令牌：`--color-*` / `--font-*` / `--space-*` / `--radius-*`（定义于 `main.css`）

## 生产部署

FastAPI 静态托管可无缝切换至 Nginx + CDN，前端无差异。伴生服务仅承担静态托管与埋点收集，不参与命运计算核心逻辑。

```bash
# Gunicorn + Uvicorn worker
gunicorn recruitment_judge.app:app -w 4 -k uvicorn.workers.UvicornWorker -b 0.0.0.0:8000
```

## License

MIT
