imetting_backend/app/services/audio_service.py

173 lines
6.5 KiB
Python
Raw Normal View History

2025-12-11 08:48:12 +00:00
"""
音频处理服务
处理已保存的完整音频文件数据库更新转录自动总结
"""
from fastapi import BackgroundTasks
from app.core.database import get_db_connection
from app.core.response import create_api_response
from app.core.config import BASE_DIR
from app.services.async_transcription_service import AsyncTranscriptionService
from app.services.async_meeting_service import async_meeting_service
from pathlib import Path
import os
transcription_service = AsyncTranscriptionService()
def handle_audio_upload(
file_path: str,
file_name: str,
file_size: int,
meeting_id: int,
current_user: dict,
auto_summarize: bool = True,
background_tasks: BackgroundTasks = None,
prompt_id: int = None
) -> dict:
"""
处理已保存的完整音频文件
职责
1. 权限检查
2. 检查已有文件和转录记录
3. 更新数据库audio_files
4. 启动转录任务
5. 可选启动自动总结监控
Args:
file_path: 已保存的文件路径相对于 BASE_DIR 的路径 /uploads/audio/123/xxx.webm
file_name: 原始文件名
file_size: 文件大小字节
meeting_id: 会议ID
current_user: 当前用户信息
auto_summarize: 是否自动生成总结默认True
background_tasks: FastAPI 后台任务对象
prompt_id: 提示词模版ID可选如果不指定则使用默认模版
Returns:
dict: {
"success": bool, # 是否成功
"response": dict, # 如果需要返回,这里是响应数据
"file_info": dict, # 文件信息 (成功时)
"transcription_task_id": str, # 转录任务ID (成功时)
"replaced_existing": bool, # 是否替换了现有文件 (成功时)
"has_transcription": bool # 原来是否有转录记录 (成功时)
}
"""
print(f"[Audio Service] handle_audio_upload called - Meeting ID: {meeting_id}, Auto-summarize: {auto_summarize}, Received prompt_id: {prompt_id}, Type: {type(prompt_id)}")
# 1. 权限和已有文件检查
try:
with get_db_connection() as connection:
cursor = connection.cursor(dictionary=True)
# 检查会议是否存在及权限
cursor.execute("SELECT user_id FROM meetings WHERE meeting_id = %s", (meeting_id,))
meeting = cursor.fetchone()
if not meeting:
return {
"success": False,
"response": create_api_response(code="404", message="会议不存在")
}
if meeting['user_id'] != current_user['user_id']:
return {
"success": False,
"response": create_api_response(code="403", message="无权限操作此会议")
}
# 检查已有音频文件
cursor.execute(
"SELECT file_name, file_path, upload_time FROM audio_files WHERE meeting_id = %s",
(meeting_id,)
)
existing_info = cursor.fetchone()
# 检查是否有转录记录
has_transcription = False
if existing_info:
cursor.execute(
"SELECT COUNT(*) as segment_count FROM transcript_segments WHERE meeting_id = %s",
(meeting_id,)
)
has_transcription = cursor.fetchone()['segment_count'] > 0
cursor.close()
except Exception as e:
return {
"success": False,
"response": create_api_response(code="500", message=f"检查已有文件失败: {str(e)}")
}
# 2. 删除旧的音频文件(如果存在)
replaced_existing = existing_info is not None
if replaced_existing and existing_info['file_path']:
old_file_path = BASE_DIR / existing_info['file_path'].lstrip('/')
if old_file_path.exists():
try:
os.remove(old_file_path)
print(f"Deleted old audio file: {old_file_path}")
except Exception as e:
print(f"Warning: Failed to delete old file {old_file_path}: {e}")
transcription_task_id = None
try:
# 3. 更新数据库记录
with get_db_connection() as connection:
cursor = connection.cursor(dictionary=True)
if replaced_existing:
cursor.execute(
'UPDATE audio_files SET file_name = %s, file_path = %s, file_size = %s, upload_time = NOW(), task_id = NULL WHERE meeting_id = %s',
(file_name, file_path, file_size, meeting_id)
)
else:
cursor.execute(
'INSERT INTO audio_files (meeting_id, file_name, file_path, file_size, upload_time) VALUES (%s, %s, %s, %s, NOW())',
(meeting_id, file_name, file_path, file_size)
)
connection.commit()
cursor.close()
# 4. 启动转录任务
try:
transcription_task_id = transcription_service.start_transcription(meeting_id, file_path)
print(f"Transcription task {transcription_task_id} started for meeting {meeting_id}")
# 5. 如果启用自动总结且提供了 background_tasks添加监控任务
if auto_summarize and transcription_task_id and background_tasks:
background_tasks.add_task(
async_meeting_service.monitor_and_auto_summarize,
meeting_id,
transcription_task_id,
prompt_id # 传递 prompt_id 给自动总结监控任务
)
print(f"[audio_service] Auto-summarize enabled, monitor task added for meeting {meeting_id}, prompt_id: {prompt_id}")
except Exception as e:
print(f"Failed to start transcription: {e}")
raise
except Exception as e:
# 出错时的处理(文件已保存,不删除)
return {
"success": False,
"response": create_api_response(code="500", message=f"处理失败: {str(e)}")
}
# 6. 返回成功结果
return {
"success": True,
"file_info": {
"file_name": file_name,
"file_path": file_path,
"file_size": file_size
},
"transcription_task_id": transcription_task_id,
"replaced_existing": replaced_existing,
"has_transcription": has_transcription
}