From f616cb3fc3171d8ef7de812c7eba2e172e49146a Mon Sep 17 00:00:00 2001 From: "mula.liu" Date: Fri, 9 Jan 2026 16:06:24 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E4=BA=86=E8=BF=9B=E5=BA=A6?= =?UTF-8?q?=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .DS_Store | Bin 10244 -> 10244 bytes DEPLOYMENT_AUDIO_FEATURES.md | 106 --------- IMPLEMENTATION_SUMMARY.md | 167 -------------- KB_PROMPT_ID_IMPLEMENTATION_SUMMARY.md | 139 ------------ app.zip | Bin 96296 -> 100769 bytes app/api/endpoints/admin.py | 114 ---------- app/api/endpoints/audio.py | 2 +- app/api/endpoints/dict_data.py | 28 ++- app/api/endpoints/hot_words.py | 173 ++++++++++++++ app/api/endpoints/meetings.py | 32 ++- app/api/endpoints/users.py | 9 +- app/api/endpoints/voiceprint.py | 12 +- app/core/config.py | 10 +- app/main.py | 7 +- app/services/async_meeting_service.py | 17 -- app/services/async_transcription_service.py | 26 ++- app/services/llm_service.py | 14 +- app/services/system_config_service.py | 237 ++++++++++++++++++++ app/services/voiceprint_service.py | 1 - check_db_structure.py | 56 ----- config/system_config.json | 7 - sql/add_hot_words_table.sql | 16 ++ test_apk_parser.py | 24 -- 23 files changed, 525 insertions(+), 672 deletions(-) delete mode 100644 DEPLOYMENT_AUDIO_FEATURES.md delete mode 100644 IMPLEMENTATION_SUMMARY.md delete mode 100644 KB_PROMPT_ID_IMPLEMENTATION_SUMMARY.md create mode 100644 app/api/endpoints/hot_words.py create mode 100644 app/services/system_config_service.py delete mode 100644 check_db_structure.py delete mode 100644 config/system_config.json create mode 100644 sql/add_hot_words_table.sql delete mode 100644 test_apk_parser.py diff --git a/.DS_Store b/.DS_Store index 350e4a869deb3bdd71619405cf3a245fafb26a96..7ba88596e12e4de63543fb128740758ae77c4368 100644 GIT binary patch delta 267 zcmZn(XbG6$gHU^hRb@?;(XNmdC428J1vwFJJ@7nCIVlopp10R?Osf*C3qiWy26 zQWd%N`dTDpr}5B3qvAME)mEI1@coFiol{-44FVxnLu^=u}}SDfU*TZ znS6#Upo(OmdXUacuogGd8AJppvDVX9*@VP7W1bwRx||Ge*v|l;Y&1{QMlo$uq^mHXDmy;h5O)bThlc PFP6z$Mc-jaZ({@i5^F_& delta 537 zcmZn(XbG6$aFU^hRb>SP`PN!D%#1_r&!S^{4tpAyswU|bF4`uzt3Ad7)Plp&cR zgCP}2W;4Vyq%b4_$zp~Qh9ZVipjZizECR~vF%&RVdgkOOC*|ZP0d)xgu_F-cZT=&e z%;+n_;KJa_5WwKW;Li}r;0t8?F@yjOa%2bv%6I}r;~Ct5qK-h(P=+8ND;Q{GE<*~c zk&LoHBj-&H5#Cxa3Do5aHqjMs9!NLHEI*)W!9a6-fzT0XS|m2Jn9@OJA$e4d!JEMe zs51bl!yjxm$c3Ij_kl<>yG+1NCEl{DAj>xY6aL6JnMusYQV1Auso-FYXGjDF9VloE qfUF{*SSpaj5uA*ClMBV9Hphw`<=D)w@QY=$ugD@Q7&tjr><|F>xOK_^ diff --git a/DEPLOYMENT_AUDIO_FEATURES.md b/DEPLOYMENT_AUDIO_FEATURES.md deleted file mode 100644 index d7c8c9c..0000000 --- a/DEPLOYMENT_AUDIO_FEATURES.md +++ /dev/null @@ -1,106 +0,0 @@ -# 音频处理功能部署说明 - -## 1. 安装Python依赖 - -```bash -cd /Users/jiliu/工作/projects/imeeting/backend -source venv/bin/activate -pip install tinytag -``` - -## 2. 执行数据库迁移 - -### 2.1 创建用户日志表 -```bash -mysql -u root -p imeeting < sql/migrations/create_user_logs_table.sql -``` - -### 2.2 为audio_files表添加duration字段 -```bash -mysql -u root -p imeeting < sql/migrations/add_duration_to_audio_files.sql -``` - -## 3. 功能说明 - -### 3.1 用户日志表 (user_logs) -- 记录用户登录活动 -- 字段:log_id, user_id, action_type, ip_address, user_agent, metadata, created_at -- 管理后台可查询用户最后登录时间 - -### 3.2 音频处理优化 -**音频时长计算:** -- 使用TinyTag库读取音频文件时长 -- 纯Python实现,无需外部依赖 -- 支持mp3, m4a, mp4, wav, ogg, flac等常见格式 -- 能处理特殊/损坏元数据的文件 -- 时长保存到audio_files.duration字段(单位:秒) -- 时长读取功能位于`app/utils/audio_parser.py` - -### 3.3 管理后台用户统计 -- 排除没有会议的用户 -- 显示字段: - - ID - - 用户名 - - 姓名 - - 注册时间 - - 最新登录时间(从user_logs表查询) - - 会议数量 - - 会议时长(从audio_files.duration汇总,格式:Xh Ym) - -## 4. 代码变更清单 - -### 后端变更: -- `/backend/app/utils/audio_parser.py` - 新增音频时长解析工具(使用TinyTag) -- `/backend/app/api/endpoints/meetings.py` - 完整文件上传时调用audio_parser获取时长,修复Safari播放问题 -- `/backend/app/api/endpoints/audio.py` - Stream上传完成时调用audio_parser获取时长 -- `/backend/app/services/audio_service.py` - 增加duration参数 -- `/backend/app/api/endpoints/auth.py` - 登录时记录日志 -- `/backend/app/api/endpoints/admin_dashboard.py` - 更新用户统计查询 -- `/backend/app/models/models.py` - 新增UserLog模型 - -### 前端变更: -- `/frontend/src/pages/HomePage.jsx` - 密码显示/隐藏切换 -- `/frontend/src/pages/HomePage.css` - 密码切换按钮样式 -- `/frontend/src/pages/AdminDashboard.jsx` - 用户列表增加会议时长列 -- `/frontend/src/pages/MeetingPreview.jsx` - 新增转录标签页,修复Safari音频播放 -- `/frontend/src/pages/MeetingDetails.jsx` - 修复Safari音频播放问题 - -### 数据库变更: -- `sql/migrations/create_user_logs_table.sql` - 创建用户日志表 -- `sql/migrations/add_duration_to_audio_files.sql` - 添加音频时长字段 - -## 5. 测试检查清单 - -- [ ] 安装Python依赖成功 -- [ ] 数据库迁移执行成功 -- [ ] 用户登录后,user_logs表有记录 -- [ ] 上传音频文件,Safari可以正常播放 -- [ ] 上传音频后,audio_files.duration有正确的时长值 -- [ ] 管理后台用户列表显示正确(排除无会议用户) -- [ ] 用户列表中会议时长统计正确 -- [ ] 登录页面密码显示/隐藏按钮正常工作 -- [ ] 会议预览页面音频播放正常(Safari/Chrome) -- [ ] 会议详情页面音频播放正常(Safari/Chrome) - -## 6. 注意事项 - -1. **音频时长计算**: - - 使用TinyTag纯Python库 - - 无需系统依赖,跨平台兼容 - - 计算失败时duration为0,不影响其他功能 - - 支持所有TinyTag支持的格式 - -2. **Safari音频播放兼容性**: - - 使用直接src属性而非source子元素 - - preload="metadata"模式 - - 后端支持HTTP Range请求 - - 正确的MIME类型由后端自动设置 - -3. **用户日志**: - - 登录日志记录失败不影响登录流程 - - IP地址优先从X-Forwarded-For获取(考虑代理场景) - -4. **管理后台统计**: - - 使用INNER JOIN过滤无会议用户 - - 时长汇总从audio_files.duration计算 - - 最后登录时间从user_logs子查询获取 diff --git a/IMPLEMENTATION_SUMMARY.md b/IMPLEMENTATION_SUMMARY.md deleted file mode 100644 index 2ef37c1..0000000 --- a/IMPLEMENTATION_SUMMARY.md +++ /dev/null @@ -1,167 +0,0 @@ -# 提示词模版选择功能实现总结 - -## 功能概述 -实现了用户在创建会议时可以选择使用的总结模版功能。支持两种场景: -1. 手动生成会议总结时选择模版 -2. 上传音频文件时选择模版,自动总结时使用该模版 - -## 实现的功能点 - -### 1. 新增API接口 ✅ -**文件**: `app/api/endpoints/prompts.py` -- 新增 `GET /prompts/active/{task_type}` 接口 -- 功能:获取指定任务类型的所有启用状态的提示词模版 -- 返回字段:id, name, is_default -- 按默认模版优先、创建时间倒序排列 - -### 2. 修改LLM服务 ✅ -**文件**: `app/services/llm_service.py` -- 修改 `get_task_prompt()` 方法,增加 `prompt_id` 可选参数 -- 逻辑: - - 如果指定 prompt_id,查询该ID对应的提示词(需验证task_type和is_active) - - 如果不指定,使用默认提示词(is_default=TRUE) - - 如果都查不到,返回代码中的默认值 - -### 3. 修改会议总结服务 ✅ -**文件**: `app/services/async_meeting_service.py` - -#### 3.1 修改任务创建 -- `start_summary_generation()`: 增加 `prompt_id` 参数 -- 将 prompt_id 存储到 Redis 和数据库 - -#### 3.2 修改任务处理 -- `_process_task()`: 从 Redis 读取 prompt_id,传递给 `_build_prompt()` -- `_build_prompt()`: 增加 `prompt_id` 参数,传递给 `llm_service.get_task_prompt()` -- `_save_task_to_db()`: 增加 `prompt_id` 参数,存储到数据库 - -#### 3.3 修改自动总结监控 -- `monitor_and_auto_summarize()`: 增加 `prompt_id` 参数 -- 在转录完成后启动总结任务时,传递 prompt_id - -### 4. 修改音频服务 ✅ -**文件**: `app/services/audio_service.py` -- `handle_audio_upload()`: 增加 `prompt_id` 参数 -- 将 prompt_id 传递给 `monitor_and_auto_summarize()` - -### 5. 修改会议API接口 ✅ -**文件**: `app/api/endpoints/meetings.py` - -#### 5.1 手动生成总结 -- `GenerateSummaryRequest` 模型:增加 `prompt_id` 字段 -- `POST /meetings/{meeting_id}/generate-summary-async`: 传递 prompt_id 给服务层 - -#### 5.2 音频上传 -- `POST /meetings/upload-audio`: 增加 `prompt_id` 表单参数 -- 将 prompt_id 传递给 `handle_audio_upload()` - -### 6. 数据库迁移 ✅ -**文件**: `sql/add_prompt_id_to_llm_tasks.sql` -- 为 `llm_tasks` 表添加 `prompt_id` 列 -- 类型:int(11) -- 可空:YES -- 默认值:NULL -- 索引:idx_prompt_id - -## 数据流向 - -### 手动生成总结 -``` -前端 → POST /meetings/{id}/generate-summary-async (prompt_id) - → async_meeting_service.start_summary_generation(prompt_id) - → 存储到 Redis 和 DB (llm_tasks.prompt_id) - → _process_task() 读取 prompt_id - → _build_prompt(prompt_id) - → llm_service.get_task_prompt('MEETING_TASK', prompt_id) - → 获取指定模版或默认模版 -``` - -### 音频上传自动总结 -``` -前端 → POST /meetings/upload-audio (prompt_id, auto_summarize=true) - → handle_audio_upload(prompt_id) - → transcription_service.start_transcription() - → monitor_and_auto_summarize(prompt_id) - → 等待转录完成 - → start_summary_generation(prompt_id) - → (后续流程同手动生成总结) -``` - -## 向后兼容性 - -所有新增的 `prompt_id` 参数都是可选的(Optional[int] = None),确保: -1. 不传递 prompt_id 时,自动使用默认模版 -2. 现有代码无需修改即可正常工作 -3. 数据库中 prompt_id 允许为 NULL - -## 测试结果 - -执行 `test_prompt_id_feature.py` 测试脚本,所有测试通过: -- ✅ 获取启用的提示词列表 (6个模版) -- ✅ 通过prompt_id获取提示词内容 -- ✅ 获取默认提示词(不指定prompt_id) -- ✅ 验证方法签名支持prompt_id参数 -- ✅ 验证数据库schema包含prompt_id列 -- ✅ 验证API端点定义正确 - -## 使用示例 - -### 1. 获取启用的会议任务模版列表 -```bash -GET /api/prompts/active/MEETING_TASK -Authorization: Bearer -``` - -返回: -```json -{ - "code": "200", - "message": "获取启用模版列表成功", - "data": { - "prompts": [ - {"id": 1, "name": "默认会议总结", "is_default": true}, - {"id": 5, "name": "产品会议总结", "is_default": false} - ] - } -} -``` - -### 2. 手动生成总结时指定模版 -```bash -POST /api/meetings/123/generate-summary-async -Authorization: Bearer -Content-Type: application/json - -{ - "user_prompt": "重点关注技术讨论", - "prompt_id": 5 -} -``` - -### 3. 上传音频时指定模版 -```bash -POST /api/meetings/upload-audio -Authorization: Bearer -Content-Type: multipart/form-data - -- audio_file: -- meeting_id: 123 -- auto_summarize: true -- prompt_id: 5 -``` - -## 文件变更列表 - -1. `app/api/endpoints/prompts.py` - 新增API接口 -2. `app/api/endpoints/meetings.py` - 修改两个端点 -3. `app/services/llm_service.py` - 修改get_task_prompt方法 -4. `app/services/async_meeting_service.py` - 修改4个方法 -5. `app/services/audio_service.py` - 修改handle_audio_upload方法 -6. `sql/add_prompt_id_to_llm_tasks.sql` - 数据库迁移脚本 -7. `test_prompt_id_feature.py` - 测试脚本 - -## 注意事项 - -1. prompt_id 会与 task_type 一起验证,防止使用错误类型的模版 -2. 如果指定的 prompt_id 不存在或未启用,会自动使用默认模版 -3. 历史任务记录保留 prompt_id,即使对应的提示词被删除 -4. Redis 中 prompt_id 存储为字符串,使用时需转换为 int diff --git a/KB_PROMPT_ID_IMPLEMENTATION_SUMMARY.md b/KB_PROMPT_ID_IMPLEMENTATION_SUMMARY.md deleted file mode 100644 index cbc9505..0000000 --- a/KB_PROMPT_ID_IMPLEMENTATION_SUMMARY.md +++ /dev/null @@ -1,139 +0,0 @@ -# 知识库提示词模版选择功能实现总结 - -## 功能概述 -为知识库生成功能添加了提示词模版选择支持,用户在创建知识库时可以选择使用的生成模版。 - -## 实现的功能点 - -### 1. 修改请求模型 ✅ -**文件**: `app/models/models.py` -- `CreateKnowledgeBaseRequest` 模型增加 `prompt_id` 字段 -- 类型:Optional[int] = None -- 不指定时使用默认模版 - -### 2. 修改知识库异步服务 ✅ -**文件**: `app/services/async_knowledge_base_service.py` - -#### 2.1 修改任务创建 -- `start_generation()`: 增加 `prompt_id` 参数 -- 将 prompt_id 存储到 Redis 和数据库 -- 支持通过 cursor 参数直接插入(事务场景) - -#### 2.2 修改任务处理 -- `_process_task()`: 从 Redis 读取 prompt_id,传递给 `_build_prompt()` -- 处理空字符串情况,转换为 None - -#### 2.3 修改提示词构建 -- `_build_prompt()`: 增加 `prompt_id` 参数 -- 调用 `llm_service.get_task_prompt('KNOWLEDGE_TASK', prompt_id=prompt_id)` -- 支持获取指定模版或默认模版 - -#### 2.4 修改数据库保存 -- `_save_task_to_db()`: 增加 `prompt_id` 参数 -- 插入时包含 prompt_id 字段 - -### 3. 修改API接口 ✅ -**文件**: `app/api/endpoints/knowledge_base.py` -- `create_knowledge_base`: 从请求中获取 `prompt_id` -- 调用 `async_kb_service.start_generation()` 时传递 `prompt_id` - -### 4. 数据库字段 ✅ -- `knowledge_base_tasks` 表已包含 `prompt_id` 列(用户已添加) -- 类型:int -- 可空:NO(默认值:0) - -## 数据流向 - -``` -前端 → POST /api/knowledge-bases (prompt_id) - → CreateKnowledgeBaseRequest (prompt_id) - → async_kb_service.start_generation(prompt_id) - → 存储到 Redis 和 DB (knowledge_base_tasks.prompt_id) - → _process_task() 读取 prompt_id - → _build_prompt(prompt_id) - → llm_service.get_task_prompt('KNOWLEDGE_TASK', prompt_id) - → 获取指定模版或默认模版 -``` - -## 向后兼容性 - -所有新增的 `prompt_id` 参数都是可选的(Optional[int] = None),确保: -1. 不传递 prompt_id 时,自动使用默认模版 -2. 现有代码无需修改即可正常工作 -3. 数据库中 prompt_id 有默认值 0 - -## 测试结果 - -执行 `test_kb_prompt_id_feature.py` 测试脚本,所有测试通过: -- ✅ 获取启用的知识库提示词列表 (3个模版) -- ✅ 通过prompt_id获取提示词内容 -- ✅ 获取默认提示词(不指定prompt_id) -- ✅ 验证方法签名支持prompt_id参数 -- ✅ 验证数据库schema包含prompt_id列 -- ✅ 验证API模型定义正确 - -## 使用示例 - -### 1. 获取启用的知识库任务模版列表 -```bash -GET /api/prompts/active/KNOWLEDGE_TASK -Authorization: Bearer -``` - -返回: -```json -{ - "code": "200", - "message": "获取启用模版列表成功", - "data": { - "prompts": [ - {"id": 2, "name": "默认知识库生成", "is_default": true}, - {"id": 13, "name": "分析总结模版", "is_default": false} - ] - } -} -``` - -### 2. 创建知识库时指定模版 -```bash -POST /api/knowledge-bases -Authorization: Bearer -Content-Type: application/json - -{ - "title": "产品会议知识库", - "is_shared": false, - "user_prompt": "重点提取产品功能相关信息", - "source_meeting_ids": "1,2,3", - "tags": "产品,功能", - "prompt_id": 13 -} -``` - -## 文件变更列表 - -1. `app/models/models.py` - 修改CreateKnowledgeBaseRequest模型 -2. `app/services/async_knowledge_base_service.py` - 修改5个方法 -3. `app/api/endpoints/knowledge_base.py` - 修改create_knowledge_base端点 -4. `test_kb_prompt_id_feature.py` - 测试脚本 - -## 与会议总结功能的一致性 - -知识库的实现与会议总结功能保持一致: -- 相同的prompt_id传递机制 -- 相同的Redis存储格式(字符串) -- 相同的数据库字段类型 -- 相同的向后兼容策略 -- 相同的验证逻辑(task_type + is_active) - -## 注意事项 - -1. prompt_id 会与 task_type='KNOWLEDGE_TASK' 一起验证 -2. 如果指定的 prompt_id 不存在或未启用,会自动使用默认模版 -3. 历史任务记录保留 prompt_id,即使对应的提示词被删除 -4. Redis 中 prompt_id 存储为字符串,使用时需转换为 int -5. 数据库 prompt_id 默认值为 0(表示未指定) - -## 总结 - -知识库提示词模版选择功能已完全实现并通过测试,与会议总结功能保持一致的设计和实现方式。用户现在可以在创建知识库时选择不同的生成模版,以满足不同场景的需求。 diff --git a/app.zip b/app.zip index a857980d4a4cb8b909fab2b5b02e8b02e2e186c1..ee3f4b970f70fc4a83e38a484d7cb459d26ff85e 100644 GIT binary patch delta 50796 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 delta 46688 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 max_file_size: return create_api_response( code="400", @@ -987,6 +992,7 @@ def get_meeting_preview_data(meeting_id: int): - 200: 会议已完成(summary已生成) - 400: 会议处理中(转译或总结阶段) - 503: 处理失败(转译或总结失败) + - 504: 数据异常(流程完成但summary未生成) - 404: 会议不存在 """ try: @@ -1049,7 +1055,19 @@ def get_meeting_preview_data(meeting_id: int): } ) - # 情况3: 全部完成 → 返回200,提供完整预览数据 + # 情况3: 全部完成但Summary缺失 → 返回504 + if overall_status == "completed" and not meeting['summary']: + return create_api_response( + code="504", + message="处理已完成,AI总结尚未同步,请稍后重试", + data={ + "meeting_id": meeting_id, + "title": meeting['title'], + "processing_status": progress_info + } + ) + + # 情况4: 全部完成 → 返回200,提供完整预览数据 if overall_status == "completed" and meeting['summary']: # 获取参会人员信息 with get_db_connection() as connection: diff --git a/app/api/endpoints/users.py b/app/api/endpoints/users.py index ff89524..324a173 100644 --- a/app/api/endpoints/users.py +++ b/app/api/endpoints/users.py @@ -4,6 +4,7 @@ from app.models.models import UserInfo, PasswordChangeRequest, UserListResponse, from app.core.database import get_db_connection from app.core.auth import get_current_user from app.core.response import create_api_response +from app.services.system_config_service import SystemConfigService import app.core.config as config_module import hashlib import datetime @@ -46,7 +47,7 @@ def create_user(request: CreateUserRequest, current_user: dict = Depends(get_cur if cursor.fetchone(): return create_api_response(code="400", message="用户名已存在") - password = request.password if request.password else config_module.DEFAULT_RESET_PASSWORD + password = request.password if request.password else SystemConfigService.get_default_reset_password() hashed_password = hash_password(password) query = "INSERT INTO users (username, password_hash, caption, email, role_id, created_at) VALUES (%s, %s, %s, %s, %s, %s)" @@ -138,7 +139,7 @@ def reset_password(user_id: int, current_user: dict = Depends(get_current_user)) if not cursor.fetchone(): return create_api_response(code="404", message="用户不存在") - hashed_password = hash_password(config_module.DEFAULT_RESET_PASSWORD) + hashed_password = hash_password(SystemConfigService.get_default_reset_password()) query = "UPDATE users SET password_hash = %s WHERE user_id = %s" cursor.execute(query, (hashed_password, user_id)) @@ -162,7 +163,7 @@ def get_all_users( count_params = [] if role_id is not None: - where_conditions.append("role_id = %s") + where_conditions.append("u.role_id = %s") count_params.append(role_id) if search: @@ -171,7 +172,7 @@ def get_all_users( count_params.extend([search_pattern, search_pattern]) # 统计查询 - count_query = "SELECT COUNT(*) as total FROM users" + count_query = "SELECT COUNT(*) as total FROM users u" if where_conditions: count_query += " WHERE " + " AND ".join(where_conditions) diff --git a/app/api/endpoints/voiceprint.py b/app/api/endpoints/voiceprint.py index b7e333b..eca2d48 100644 --- a/app/api/endpoints/voiceprint.py +++ b/app/api/endpoints/voiceprint.py @@ -10,6 +10,7 @@ from app.models.models import VoiceprintStatus, VoiceprintTemplate from app.core.auth import get_current_user from app.core.response import create_api_response from app.services.voiceprint_service import voiceprint_service +from app.services.system_config_service import SystemConfigService import app.core.config as config_module router = APIRouter() @@ -23,7 +24,16 @@ def get_voiceprint_template(current_user: dict = Depends(get_current_user)): 权限:需要登录 """ try: - template_data = VoiceprintTemplate(**config_module.VOICEPRINT_CONFIG) + # 动态从数据库获取声纹模版 + template_text = SystemConfigService.get_voiceprint_template( + default="我正在进行声纹采集,这段语音将用于身份识别和验证。\n\n声纹技术能够准确识别每个人独特的声音特征。" + ) + template_data = VoiceprintTemplate( + template_text=template_text, + duration_seconds=config_module.VOICEPRINT_CONFIG.get('duration_seconds', 12), + sample_rate=config_module.VOICEPRINT_CONFIG.get('sample_rate', 16000), + channels=config_module.VOICEPRINT_CONFIG.get('channels', 1) + ) return create_api_response(code="200", message="获取朗读模板成功", data=template_data.dict()) except Exception as e: return create_api_response(code="500", message=f"获取朗读模板失败: {str(e)}") diff --git a/app/core/config.py b/app/core/config.py index fd594a1..3ae835c 100644 --- a/app/core/config.py +++ b/app/core/config.py @@ -29,10 +29,10 @@ CLIENT_DIR.mkdir(exist_ok=True) # 数据库配置 DATABASE_CONFIG = { - 'host': os.getenv('DB_HOST', '10.100.51.161'), + 'host': os.getenv('DB_HOST', '10.100.51.51'), 'user': os.getenv('DB_USER', 'root'), - 'password': os.getenv('DB_PASSWORD', 'sagacity'), - 'database': os.getenv('DB_NAME', 'imeeting'), + 'password': os.getenv('DB_PASSWORD', 'Unis@123'), + 'database': os.getenv('DB_NAME', 'imeeting_dev'), 'port': int(os.getenv('DB_PORT', '3306')), 'charset': 'utf8mb4' } @@ -56,10 +56,10 @@ APP_CONFIG = { # Redis配置 REDIS_CONFIG = { - 'host': os.getenv('REDIS_HOST', '10.100.51.161'), + 'host': os.getenv('REDIS_HOST', '10.100.51.51'), 'port': int(os.getenv('REDIS_PORT', '6379')), 'db': int(os.getenv('REDIS_DB', '0')), - 'password': os.getenv('REDIS_PASSWORD', ''), + 'password': os.getenv('REDIS_PASSWORD', 'Unis@123'), 'decode_responses': True } diff --git a/app/main.py b/app/main.py index 4e9e3b8..7635c80 100644 --- a/app/main.py +++ b/app/main.py @@ -13,9 +13,8 @@ import uvicorn from fastapi import FastAPI, Request, HTTPException from fastapi.middleware.cors import CORSMiddleware from fastapi.staticfiles import StaticFiles -from app.api.endpoints import auth, users, meetings, tags, admin, admin_dashboard, tasks, prompts, knowledge_base, client_downloads, voiceprint, audio, dict_data +from app.api.endpoints import auth, users, meetings, tags, admin, admin_dashboard, tasks, prompts, knowledge_base, client_downloads, voiceprint, audio, dict_data, hot_words from app.core.config import UPLOAD_DIR, API_CONFIG -from app.api.endpoints.admin import load_system_config app = FastAPI( title="iMeeting API", @@ -23,9 +22,6 @@ app = FastAPI( version="1.0.2" ) -# 加载系统配置 -load_system_config() - # 添加CORS中间件 app.add_middleware( CORSMiddleware, @@ -53,6 +49,7 @@ app.include_router(client_downloads.router, prefix="/api", tags=["ClientDownload app.include_router(dict_data.router, prefix="/api", tags=["DictData"]) app.include_router(voiceprint.router, prefix="/api", tags=["Voiceprint"]) app.include_router(audio.router, prefix="/api", tags=["Audio"]) +app.include_router(hot_words.router, prefix="/api", tags=["HotWords"]) @app.get("/") def read_root(): diff --git a/app/services/async_meeting_service.py b/app/services/async_meeting_service.py index 363bf7c..41dfbb2 100644 --- a/app/services/async_meeting_service.py +++ b/app/services/async_meeting_service.py @@ -404,23 +404,6 @@ class AsyncMeetingService: try: with get_db_connection() as connection: cursor = connection.cursor() - - # 如果没有指定 prompt_id,获取默认的会议总结模版ID - if prompt_id is None: - print(f"[Meeting Service] prompt_id is None, fetching default template for MEETING_TASK") - cursor.execute( - "SELECT id FROM prompts WHERE task_type = 'MEETING_TASK' AND is_default = TRUE AND is_active = TRUE LIMIT 1" - ) - default_prompt = cursor.fetchone() - if default_prompt: - prompt_id = default_prompt[0] - print(f"[Meeting Service] Found default template ID: {prompt_id}") - else: - print(f"[Meeting Service] WARNING: No default template found for MEETING_TASK!") - else: - print(f"[Meeting Service] Using provided prompt_id: {prompt_id}") - - print(f"[Meeting Service] Inserting task into llm_tasks - task_id: {task_id}, meeting_id: {meeting_id}, prompt_id: {prompt_id}") insert_query = "INSERT INTO llm_tasks (task_id, meeting_id, user_prompt, prompt_id, status, progress, created_at) VALUES (%s, %s, %s, %s, 'pending', 0, NOW())" cursor.execute(insert_query, (task_id, meeting_id, user_prompt, prompt_id)) connection.commit() diff --git a/app/services/async_transcription_service.py b/app/services/async_transcription_service.py index 4d3b85c..4d14e8c 100644 --- a/app/services/async_transcription_service.py +++ b/app/services/async_transcription_service.py @@ -11,6 +11,7 @@ from dashscope.audio.asr import Transcription from app.core.config import QWEN_API_KEY, REDIS_CONFIG, APP_CONFIG from app.core.database import get_db_connection +from app.services.system_config_service import SystemConfigService class AsyncTranscriptionService: @@ -58,17 +59,24 @@ class AsyncTranscriptionService: # 2. 构造完整的文件URL file_url = f"{self.base_url}{audio_file_path}" - print(f"Starting transcription for meeting_id: {meeting_id}, file_url: {file_url}") + # 获取热词表ID (asr_vocabulary_id) + vocabulary_id = SystemConfigService.get_asr_vocabulary_id() + + print(f"Starting transcription for meeting_id: {meeting_id}, file_url: {file_url}, vocabulary_id: {vocabulary_id}") # 3. 调用Paraformer异步API - task_response = Transcription.async_call( - model='paraformer-v2', - file_urls=[file_url], - language_hints=['zh', 'en'], - disfluency_removal_enabled=True, - diarization_enabled=True, - speaker_count=10 - ) + call_params = { + 'model': 'paraformer-v2', + 'file_urls': [file_url], + 'language_hints': ['zh', 'en'], + 'disfluency_removal_enabled': True, + 'diarization_enabled': True, + 'speaker_count': 10 + } + if vocabulary_id: + call_params['vocabulary_id'] = vocabulary_id + + task_response = Transcription.async_call(**call_params) if task_response.status_code != HTTPStatus.OK: print(f"Failed to start transcription: {task_response.status_code}, {task_response.message}") diff --git a/app/services/llm_service.py b/app/services/llm_service.py index a08ee0d..1f8429f 100644 --- a/app/services/llm_service.py +++ b/app/services/llm_service.py @@ -4,6 +4,7 @@ from http import HTTPStatus from typing import Optional, Dict, List, Generator import app.core.config as config_module from app.core.database import get_db_connection +from app.services.system_config_service import SystemConfigService class LLMService: @@ -16,27 +17,28 @@ class LLMService: @property def model_name(self): """动态获取模型名称""" - return config_module.LLM_CONFIG["model_name"] + return SystemConfigService.get_llm_model_name(default="qwen-plus") @property def system_prompt(self): - """动态获取系统提示词""" - return config_module.LLM_CONFIG["system_prompt"] + """动态获取系统提示词(fallback,优先使用prompts表)""" + # 保留config中的system_prompt作为后备 + return config_module.LLM_CONFIG.get("system_prompt", "请根据提供的内容进行总结和分析。") @property def time_out(self): """动态获取超时时间""" - return config_module.LLM_CONFIG["time_out"] + return SystemConfigService.get_llm_timeout(default=120) @property def temperature(self): """动态获取temperature""" - return config_module.LLM_CONFIG["temperature"] + return SystemConfigService.get_llm_temperature(default=0.7) @property def top_p(self): """动态获取top_p""" - return config_module.LLM_CONFIG["top_p"] + return SystemConfigService.get_llm_top_p(default=0.9) def get_task_prompt(self, task_type: str, cursor=None, prompt_id: Optional[int] = None) -> str: """ diff --git a/app/services/system_config_service.py b/app/services/system_config_service.py new file mode 100644 index 0000000..619f18c --- /dev/null +++ b/app/services/system_config_service.py @@ -0,0 +1,237 @@ +import json +from typing import Optional, Dict, Any +from app.core.database import get_db_connection + + +class SystemConfigService: + """系统配置服务 - 从 dict_data 表中读取和保存 system_config 类型的配置""" + + DICT_TYPE = 'system_config' + + # 配置键常量 + ASR_VOCABULARY_ID = 'asr_vocabulary_id' + VOICEPRINT_TEMPLATE = 'voiceprint_template' + TIMELINE_PAGESIZE = 'timeline_pagesize' + DEFAULT_RESET_PASSWORD = 'default_reset_password' + MAX_AUDIO_SIZE = 'max_audio_size' + + # LLM模型配置 + LLM_MODEL_NAME = 'llm_model_name' + LLM_TIMEOUT = 'llm_timeout' + LLM_TEMPERATURE = 'llm_temperature' + LLM_TOP_P = 'llm_top_p' + + @classmethod + def get_config(cls, dict_code: str, default_value: Any = None) -> Any: + """ + 获取指定配置项的值 + + Args: + dict_code: 配置项编码 + default_value: 默认值,如果配置不存在则返回此值 + + Returns: + 配置项的值 + """ + try: + with get_db_connection() as conn: + cursor = conn.cursor(dictionary=True) + query = """ + SELECT extension_attr + FROM dict_data + WHERE dict_type = %s AND dict_code = %s AND status = 1 + LIMIT 1 + """ + cursor.execute(query, (cls.DICT_TYPE, dict_code)) + result = cursor.fetchone() + cursor.close() + + if result and result['extension_attr']: + try: + ext_attr = json.loads(result['extension_attr']) if isinstance(result['extension_attr'], str) else result['extension_attr'] + return ext_attr.get('value', default_value) + except (json.JSONDecodeError, AttributeError): + pass + + return default_value + + except Exception as e: + print(f"Error getting config {dict_code}: {e}") + return default_value + + @classmethod + def set_config(cls, dict_code: str, value: Any, label_cn: str = None) -> bool: + """ + 设置指定配置项的值 + + Args: + dict_code: 配置项编码 + value: 配置值 + label_cn: 配置项中文名称(仅在配置不存在时需要) + + Returns: + 是否设置成功 + """ + try: + with get_db_connection() as conn: + cursor = conn.cursor(dictionary=True) + + # 检查配置是否存在 + cursor.execute( + "SELECT id FROM dict_data WHERE dict_type = %s AND dict_code = %s", + (cls.DICT_TYPE, dict_code) + ) + existing = cursor.fetchone() + + extension_attr = json.dumps({"value": value}, ensure_ascii=False) + + if existing: + # 更新现有配置 + update_query = """ + UPDATE dict_data + SET extension_attr = %s, update_time = NOW() + WHERE dict_type = %s AND dict_code = %s + """ + cursor.execute(update_query, (extension_attr, cls.DICT_TYPE, dict_code)) + else: + # 插入新配置 + if not label_cn: + label_cn = dict_code + + insert_query = """ + INSERT INTO dict_data ( + dict_type, dict_code, parent_code, label_cn, + extension_attr, status, sort_order + ) VALUES (%s, %s, 'ROOT', %s, %s, 1, 0) + """ + cursor.execute(insert_query, (cls.DICT_TYPE, dict_code, label_cn, extension_attr)) + + conn.commit() + cursor.close() + return True + + except Exception as e: + print(f"Error setting config {dict_code}: {e}") + return False + + @classmethod + def get_all_configs(cls) -> Dict[str, Any]: + """ + 获取所有系统配置 + + Returns: + 配置字典 {dict_code: value} + """ + try: + with get_db_connection() as conn: + cursor = conn.cursor(dictionary=True) + query = """ + SELECT dict_code, label_cn, extension_attr + FROM dict_data + WHERE dict_type = %s AND status = 1 + ORDER BY sort_order + """ + cursor.execute(query, (cls.DICT_TYPE,)) + results = cursor.fetchall() + cursor.close() + + configs = {} + for row in results: + if row['extension_attr']: + try: + ext_attr = json.loads(row['extension_attr']) if isinstance(row['extension_attr'], str) else row['extension_attr'] + configs[row['dict_code']] = ext_attr.get('value') + except (json.JSONDecodeError, AttributeError): + configs[row['dict_code']] = None + else: + configs[row['dict_code']] = None + + return configs + + except Exception as e: + print(f"Error getting all configs: {e}") + return {} + + @classmethod + def batch_set_configs(cls, configs: Dict[str, Any]) -> bool: + """ + 批量设置配置项 + + Args: + configs: 配置字典 {dict_code: value} + + Returns: + 是否全部设置成功 + """ + success = True + for dict_code, value in configs.items(): + if not cls.set_config(dict_code, value): + success = False + return success + + # 便捷方法:获取特定配置 + @classmethod + def get_asr_vocabulary_id(cls) -> Optional[str]: + """获取ASR热词字典ID""" + return cls.get_config(cls.ASR_VOCABULARY_ID) + + @classmethod + def get_voiceprint_template(cls, default: str = "") -> str: + """获取声纹采集模版""" + return cls.get_config(cls.VOICEPRINT_TEMPLATE, default) + + @classmethod + def get_timeline_pagesize(cls, default: int = 10) -> int: + """获取会议时间轴每页数量""" + value = cls.get_config(cls.TIMELINE_PAGESIZE, str(default)) + try: + return int(value) + except (ValueError, TypeError): + return default + + @classmethod + def get_default_reset_password(cls, default: str = "111111") -> str: + """获取默认重置密码""" + return cls.get_config(cls.DEFAULT_RESET_PASSWORD, default) + + @classmethod + def get_max_audio_size(cls, default: int = 100) -> int: + """获取上传音频文件大小限制(MB)""" + value = cls.get_config(cls.MAX_AUDIO_SIZE, str(default)) + try: + return int(value) + except (ValueError, TypeError): + return default + + # LLM模型配置获取方法 + @classmethod + def get_llm_model_name(cls, default: str = "qwen-plus") -> str: + """获取LLM模型名称""" + return cls.get_config(cls.LLM_MODEL_NAME, default) + + @classmethod + def get_llm_timeout(cls, default: int = 120) -> int: + """获取LLM超时时间(秒)""" + value = cls.get_config(cls.LLM_TIMEOUT, str(default)) + try: + return int(value) + except (ValueError, TypeError): + return default + + @classmethod + def get_llm_temperature(cls, default: float = 0.7) -> float: + """获取LLM temperature参数""" + value = cls.get_config(cls.LLM_TEMPERATURE, str(default)) + try: + return float(value) + except (ValueError, TypeError): + return default + + @classmethod + def get_llm_top_p(cls, default: float = 0.9) -> float: + """获取LLM top_p参数""" + value = cls.get_config(cls.LLM_TOP_P, str(default)) + try: + return float(value) + except (ValueError, TypeError): + return default diff --git a/app/services/voiceprint_service.py b/app/services/voiceprint_service.py index 13b04f7..e394244 100644 --- a/app/services/voiceprint_service.py +++ b/app/services/voiceprint_service.py @@ -17,7 +17,6 @@ class VoiceprintService: def __init__(self): self.voiceprint_dir = config_module.VOICEPRINT_DIR - self.voiceprint_config = config_module.VOICEPRINT_CONFIG def get_user_voiceprint_status(self, user_id: int) -> Dict: """ diff --git a/check_db_structure.py b/check_db_structure.py deleted file mode 100644 index 745f056..0000000 --- a/check_db_structure.py +++ /dev/null @@ -1,56 +0,0 @@ -import mysql.connector - -# 连接数据库 -conn = mysql.connector.connect( - host="10.100.51.51", - port=3306, - user="root", - password="Unis@123", - database="imeeting_dev" -) - -cursor = conn.cursor() - -print("=" * 80) -print("dict_data 表结构:") -print("=" * 80) -cursor.execute("SHOW CREATE TABLE dict_data") -result = cursor.fetchone() -print(result[1]) -print("\n") - -print("=" * 80) -print("dict_data 表数据:") -print("=" * 80) -cursor.execute("SELECT * FROM dict_data ORDER BY dict_code, sort_order") -rows = cursor.fetchall() -cursor.execute("SHOW COLUMNS FROM dict_data") -columns = [col[0] for col in cursor.fetchall()] -print(" | ".join(columns)) -print("-" * 80) -for row in rows: - print(" | ".join(str(val) for val in row)) -print("\n") - -print("=" * 80) -print("client_download 表结构:") -print("=" * 80) -cursor.execute("SHOW CREATE TABLE client_download") -result = cursor.fetchone() -print(result[1]) -print("\n") - -print("=" * 80) -print("client_download 表数据:") -print("=" * 80) -cursor.execute("SELECT * FROM client_download") -rows = cursor.fetchall() -cursor.execute("SHOW COLUMNS FROM client_download") -columns = [col[0] for col in cursor.fetchall()] -print(" | ".join(columns)) -print("-" * 80) -for row in rows: - print(" | ".join(str(val) for val in row)) - -cursor.close() -conn.close() diff --git a/config/system_config.json b/config/system_config.json deleted file mode 100644 index fed50d7..0000000 --- a/config/system_config.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "model_name": "qwen-plus", - "template_text": "我正在进行声纹采集,这段语音将用于身份识别和验证。\n声纹技术能够识别每个人独特的声音特征,用于人声识别应用。", - "DEFAULT_RESET_PASSWORD": "123456", - "MAX_FILE_SIZE": 209715200, - "TIMELINE_PAGESIZE": 10 -} \ No newline at end of file diff --git a/sql/add_hot_words_table.sql b/sql/add_hot_words_table.sql new file mode 100644 index 0000000..ee6351e --- /dev/null +++ b/sql/add_hot_words_table.sql @@ -0,0 +1,16 @@ +CREATE TABLE IF NOT EXISTS `hot_words` ( + `id` INT NOT NULL AUTO_INCREMENT, + `text` VARCHAR(255) NOT NULL COMMENT '热词内容', + `weight` INT NOT NULL DEFAULT 4 COMMENT '词汇权重 (1-10)', + `lang` VARCHAR(20) NOT NULL DEFAULT 'zh' COMMENT '语言 (zh/en)', + `status` TINYINT NOT NULL DEFAULT 1 COMMENT '状态 (1:启用, 0:禁用)', + `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `idx_text_lang` (`text`, `lang`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='系统语音识别热词表'; + +-- 预留存储 Vocabulary ID 的配置项(如果不想用字典表存储配置,也可以在系统配置表中增加) +INSERT INTO `dict_data` (dict_type, dict_code, parent_code, label_cn, status) +VALUES ('system_config', 'asr_vocabulary_id', 'ROOT', '阿里云ASR热词表ID', 1) +ON DUPLICATE KEY UPDATE label_cn='阿里云ASR热词表ID'; diff --git a/test_apk_parser.py b/test_apk_parser.py deleted file mode 100644 index 10c03f9..0000000 --- a/test_apk_parser.py +++ /dev/null @@ -1,24 +0,0 @@ -""" -测试APK解析功能 -""" -from app.utils.apk_parser import parse_apk_with_androguard - -# 测试导入是否正常 -try: - from androguard.core.apk import APK - print("✅ androguard 导入成功") - print(f" androguard 模块路径: {APK.__module__}") -except ImportError as e: - print(f"❌ androguard 导入失败: {e}") - exit(1) - -# 如果有测试APK文件,可以在这里测试解析 -# apk_path = "path/to/your/test.apk" -# result = parse_apk_with_androguard(apk_path) -# print(f"解析结果: {result}") - -print("\n📋 测试结果:") -print(" 1. androguard 库已成功安装") -print(" 2. 导入路径正确: androguard.core.apk.APK") -print(" 3. 可以正常使用 APK 解析功能") -print("\n💡 提示: 请重启后台服务以使更改生效")