# offer-byok **Repository Path**: notperfunctory/offer-byok ## Basic Information - **Project Name**: offer-byok - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-07-09 - **Last Updated**: 2026-07-09 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # OfferIn AI — AI 面试辅助与评估系统 基于 FastAPI + LangChain + Vue 3 的 AI 面试模拟平台。支持多 LLM 提供商切换、语音识别输入、结构化评估报告生成。 ## 技术栈 | 层 | 技术 | |---|---| | **后端框架** | Python 3.12 + FastAPI | | **LLM 编排** | LangChain (ChatPromptTemplate) | | **数据库** | PostgreSQL 16 + SQLAlchemy 2.0 (async) | | **前端** | Vue 3 (Composition API) + Vite | | **语音识别** | Web Speech API (浏览器端) | | **语音合成** | edge-tts / OpenAI TTS (后端) | | **部署** | Docker + Docker Compose | ## 快速开始 ### 前置条件 - Python 3.12+ - Node.js 18+ - PostgreSQL 16 (或使用 Docker) - (可选) Chrome 浏览器以使用语音识别 ### 1. 克隆项目 ```bash git clone cd offer-byok ``` ### 2. 配置环境变量 ```bash cp .env.example .env ``` 编辑 `.env`,至少填入 LLM Provider 的 API Key: ```ini OFFR_BYOK_LLM_PROVIDER=openai OFFR_BYOK_OPENAI_API_KEY=sk-your-key-here OFFR_BYOK_OPENAI_MODEL_NAME=gpt-4o ``` 可切换 Provider: | Provider | 变量前缀 | 需要 API Key | |---|---|---| | OpenAI | `OFFR_BYOK_OPENAI_*` | 是 | | DeepSeek | `OFFR_BYOK_DEEPSEEK_*` | 是 | | Ollama | `OFFR_BYOK_OLLAMA_*` | 否 (本地) | ### 3. 启动后端 ```bash # 方式 A:Docker Compose(推荐) docker-compose up -d # 方式 B:手动启动 pip install -r requirements.txt # 确保 PostgreSQL 已运行,然后: uvicorn app.main:app --reload ``` 后端运行在 `http://localhost:8000`。 ### 4. 启动前端 ```bash cd frontend npm install npm run dev ``` 前端运行在 `http://localhost:5173`,API 请求自动代理到 `:8000`。 ## 架构概览 ``` ┌─────────────────────────────────────────────────────────┐ │ Vue 3 Frontend │ │ ┌───────────┐ ┌──────────────┐ ┌─────────────────┐ │ │ │ Voice I/O │ │ Chat Interface│ │ Evaluation Card │ │ │ │ (Web API) │ │ (实时对话) │ │ (评估报告) │ │ │ └─────┬─────┘ └──────┬───────┘ └────────┬────────┘ │ │ │ │ │ │ └────────┼───────────────┼───────────────────┼───────────┘ │ │ │ HTTP │ │ POST /messages │ POST /evaluations │ ▼ ▼ ┌────────┴────────────────────────────────────────────────┐ │ FastAPI Backend │ │ ┌────────────┐ ┌────────────────┐ ┌───────────────┐ │ │ │ LLM Adapter│◄─│ InterviewEngine│ │EvaluationSvc │ │ │ │ (可插拔) │ │ (LangChain) │ │(结构化JSON) │ │ │ └─────┬──────┘ └───────┬────────┘ └───────┬───────┘ │ │ │ │ │ │ │ ┌─────┴─────┐ ┌──────┴───────┐ │ │ │ │OpenAI │ │ SQLAlchemy │◄───────────┘ │ │ │DeepSeek │ │ (asyncpg) │ │ │ │Ollama │ └──────┬───────┘ │ │ └───────────┘ │ │ └──────────────────────────┼───────────────────────────────┘ │ ┌──────▼──────┐ │ PostgreSQL │ └─────────────┘ ``` ## API 端点 ### 面试管理 | Method | Path | 说明 | |---|---|---| | `POST` | `/api/v1/interviews` | 创建面试并返回开场问题 | | `GET` | `/api/v1/interviews` | 列表(支持 `?status=active` 筛选) | | `GET` | `/api/v1/interviews/{id}` | 面试详情含完整对话历史 | | `POST` | `/api/v1/interviews/{id}/messages` | 发送候选回答,返回追问 | | `PATCH` | `/api/v1/interviews/{id}/status?status=completed` | 更新状态 | ### 评估报告 | Method | Path | 说明 | |---|---|---| | `POST` | `/api/v1/evaluations/interviews/{id}/evaluations` | 生成评估报告 | | `GET` | `/api/v1/evaluations/interviews/{id}/evaluations` | 查询某面试的所有评估 | | `GET` | `/api/v1/evaluations/evaluations/{id}` | 查询单个评估详情 | ### 示例 ```bash # 创建面试 curl -X POST http://localhost:8000/api/v1/interviews \ -H "Content-Type: application/json" \ -d '{"candidate_name": "张三", "position": "高级后端工程师", "difficulty": "senior"}' # 发送回答 curl -X POST http://localhost:8000/api/v1/interviews/{id}/messages \ -H "Content-Type: application/json" \ -d '{"message": "我熟悉 Python 和 Go,有 5 年后端开发经验..."}' # 生成评估 curl -X POST http://localhost:8000/api/v1/evaluations/interviews/{id}/evaluations ``` ## 语音功能 前端使用浏览器 Web Speech API 进行**语音识别**,无需额外安装。 后端提供可插拔的语音合成 (TTS) 和本地语音识别 (STT) 适配器: ```python from app.services.voice.tts import create_tts_adapter from app.services.voice.stt import create_stt_adapter, capture_mic_audio # TTS:文字转语音 tts = create_tts_adapter("edge") # 免费,无需 API Key await tts.synthesize("你好,欢迎参加面试", "output.mp3") # STT:本地 Whisper 转录 stt = create_stt_adapter("local") audio = await capture_mic_audio(duration_seconds=5) text = await stt.transcribe(audio) ``` | Provider | 类型 | 依赖 | 需要 Key | |---|---|---|---| | `local` | STT | `openai-whisper` | 否 | | `whisper_api` | STT | `openai` | 是 | | `edge` | TTS | `edge-tts` | 否 | | `openai` | TTS | `openai` | 是 | ## 项目结构 ``` offer-byok/ ├── app/ │ ├── main.py # FastAPI 入口 │ ├── core/ │ │ ├── config.py # Pydantic Settings (OFFR_BYOK_ 前缀) │ │ └── exceptions.py # 统一异常体系 │ ├── api/ │ │ ├── deps.py # 依赖注入 │ │ └── v1/ │ │ ├── router.py # 路由聚合 │ │ ├── interview.py # 面试端点 │ │ └── evaluation.py # 评估端点 │ ├── models/ │ │ ├── base.py # Declarative Base + Mixins │ │ ├── interview.py # 面试模型 (JSONB) │ │ └── evaluation.py # 评估模型 (JSONB) │ ├── schemas/ │ │ ├── interview.py # Pydantic 校验 │ │ └── evaluation.py │ ├── services/ │ │ ├── interview.py # 对话引擎 (LangChain) │ │ ├── evaluation.py # 评估生成 │ │ ├── llm/ │ │ │ ├── adapter.py # LLM 适配器抽象 │ │ │ └── providers/ # OpenAI / DeepSeek / Ollama │ │ └── voice/ │ │ ├── stt.py # 语音转文字 │ │ └── tts.py # 文字转语音 │ └── db/ │ └── session.py # 异步会话管理 ├── frontend/ │ ├── src/ │ │ ├── composables/ # useSpeechRecognition / useInterview / useEvaluation │ │ ├── components/ # InterviewChat / VoiceButton / EvaluationCard │ │ └── api/ # Axios 客户端 │ └── vite.config.js # 代理 /api → :8000 ├── docker-compose.yml ├── Dockerfile ├── requirements.txt └── .env.example ``` ## License MIT