1.2.1
parent
1a15cdff88
commit
9a4686bedf
|
|
@ -50,6 +50,88 @@ def _process_tags(cursor, tag_string: Optional[str], creator_id: Optional[int] =
|
|||
tags_data = cursor.fetchall()
|
||||
return [Tag(**tag) for tag in tags_data]
|
||||
|
||||
def _get_meeting_overall_status(meeting_id: int) -> dict:
|
||||
"""
|
||||
获取会议的整体进度状态(包含转译和LLM两个阶段)
|
||||
|
||||
Returns:
|
||||
dict: {
|
||||
"overall_status": "pending" | "transcribing" | "summarizing" | "completed" | "failed",
|
||||
"overall_progress": 0-100,
|
||||
"current_stage": "transcription" | "llm" | "completed",
|
||||
"transcription": {status, progress, task_id, error_message, created_at},
|
||||
"llm": {status, progress, task_id, error_message, created_at}
|
||||
}
|
||||
"""
|
||||
# 获取转译状态
|
||||
transcription_status = transcription_service.get_meeting_transcription_status(meeting_id)
|
||||
trans_data = {
|
||||
"status": transcription_status.get('status', 'pending') if transcription_status else 'pending',
|
||||
"progress": transcription_status.get('progress', 0) if transcription_status else 0,
|
||||
"task_id": transcription_status.get('task_id') if transcription_status else None,
|
||||
"error_message": transcription_status.get('error_message') if transcription_status else None,
|
||||
"created_at": transcription_status.get('created_at') if transcription_status else None
|
||||
}
|
||||
|
||||
# 获取LLM状态
|
||||
llm_status = async_meeting_service.get_meeting_llm_status(meeting_id)
|
||||
llm_data = {
|
||||
"status": llm_status.get('status', 'pending') if llm_status else 'pending',
|
||||
"progress": llm_status.get('progress', 0) if llm_status else 0,
|
||||
"task_id": llm_status.get('task_id') if llm_status else None,
|
||||
"error_message": llm_status.get('error_message') if llm_status else None,
|
||||
"created_at": llm_status.get('created_at') if llm_status else None
|
||||
}
|
||||
|
||||
# 计算整体状态和进度
|
||||
trans_status_val = trans_data["status"]
|
||||
llm_status_val = llm_data["status"]
|
||||
|
||||
# 判断是否有失败
|
||||
if trans_status_val == 'failed':
|
||||
overall_status = "failed"
|
||||
current_stage = "transcription"
|
||||
overall_progress = 0
|
||||
elif llm_status_val == 'failed':
|
||||
overall_status = "failed"
|
||||
current_stage = "llm"
|
||||
overall_progress = 50 # 转译已完成
|
||||
# 判断当前阶段
|
||||
elif trans_status_val == 'completed' and llm_status_val == 'completed':
|
||||
overall_status = "completed"
|
||||
current_stage = "completed"
|
||||
overall_progress = 100
|
||||
elif trans_status_val == 'completed':
|
||||
# 转译完成,进入LLM阶段
|
||||
if llm_status_val in ['pending', 'processing']:
|
||||
overall_status = "summarizing"
|
||||
current_stage = "llm"
|
||||
overall_progress = 50 + int(llm_data["progress"] * 0.5)
|
||||
else:
|
||||
# llm还未开始
|
||||
overall_status = "summarizing"
|
||||
current_stage = "llm"
|
||||
overall_progress = 50
|
||||
else:
|
||||
# 还在转译阶段
|
||||
if trans_status_val in ['pending', 'processing']:
|
||||
overall_status = "transcribing"
|
||||
current_stage = "transcription"
|
||||
overall_progress = int(trans_data["progress"] * 0.5)
|
||||
else:
|
||||
# 转译还未开始
|
||||
overall_status = "pending"
|
||||
current_stage = "transcription"
|
||||
overall_progress = 0
|
||||
|
||||
return {
|
||||
"overall_status": overall_status,
|
||||
"overall_progress": overall_progress,
|
||||
"current_stage": current_stage,
|
||||
"transcription": trans_data,
|
||||
"llm": llm_data
|
||||
}
|
||||
|
||||
@router.get("/meetings")
|
||||
def get_meetings(
|
||||
current_user: dict = Depends(get_current_user),
|
||||
|
|
@ -164,7 +246,8 @@ def get_meetings(
|
|||
meeting_list.append(Meeting(
|
||||
meeting_id=meeting['meeting_id'], title=meeting['title'], meeting_time=meeting['meeting_time'],
|
||||
summary=meeting['summary'], created_at=meeting['created_at'], audio_file_path=meeting['audio_file_path'],
|
||||
attendees=attendees, creator_id=meeting['creator_id'], creator_username=meeting['creator_username'], tags=tags_list
|
||||
attendees=attendees, creator_id=meeting['creator_id'], creator_username=meeting['creator_username'], tags=tags_list,
|
||||
access_password=meeting.get('access_password')
|
||||
))
|
||||
|
||||
return create_api_response(code="200", message="获取会议列表成功", data={
|
||||
|
|
@ -882,12 +965,18 @@ def get_meeting_preview_data(meeting_id: int):
|
|||
"""
|
||||
获取会议预览数据(无需登录认证)
|
||||
用于二维码扫描后的预览页面
|
||||
|
||||
返回状态码说明:
|
||||
- 200: 会议已完成(summary已生成)
|
||||
- 400: 会议处理中(转译或总结阶段)
|
||||
- 503: 处理失败(转译或总结失败)
|
||||
- 404: 会议不存在
|
||||
"""
|
||||
try:
|
||||
with get_db_connection() as connection:
|
||||
cursor = connection.cursor(dictionary=True)
|
||||
|
||||
# 检查会议是否存在,并获取模版信息
|
||||
# 检查会议是否存在,并获取基本信息
|
||||
query = '''
|
||||
SELECT m.meeting_id, m.title, m.meeting_time, m.summary, m.updated_at, m.prompt_id,
|
||||
m.user_id as creator_id, u.caption as creator_username,
|
||||
|
|
@ -903,15 +992,55 @@ def get_meeting_preview_data(meeting_id: int):
|
|||
if not meeting:
|
||||
return create_api_response(code="404", message="会议不存在")
|
||||
|
||||
# 检查是否已生成会议总结
|
||||
if not meeting['summary'] or not meeting['updated_at']:
|
||||
return create_api_response(code="400", message="该会议总结尚未生成")
|
||||
# 获取整体进度状态(两阶段)
|
||||
progress_info = _get_meeting_overall_status(meeting_id)
|
||||
overall_status = progress_info["overall_status"]
|
||||
|
||||
# 根据整体状态返回不同响应
|
||||
|
||||
# 情况1: 任一阶段失败 → 返回503
|
||||
if overall_status == "failed":
|
||||
failed_stage = progress_info["current_stage"]
|
||||
error_info = progress_info["transcription"] if failed_stage == "transcription" else progress_info["llm"]
|
||||
error_message = error_info["error_message"] or "处理失败"
|
||||
|
||||
stage_name = "转译" if failed_stage == "transcription" else "总结"
|
||||
return create_api_response(
|
||||
code="503",
|
||||
message=f"会议{stage_name}失败: {error_message}",
|
||||
data={
|
||||
"meeting_id": meeting_id,
|
||||
"title": meeting['title'],
|
||||
"processing_status": progress_info
|
||||
}
|
||||
)
|
||||
|
||||
# 情况2: 处理中(转译或总结阶段)→ 返回400
|
||||
if overall_status in ["pending", "transcribing", "summarizing"]:
|
||||
stage_descriptions = {
|
||||
"pending": "等待开始",
|
||||
"transcribing": "正在转译音频",
|
||||
"summarizing": "正在生成总结"
|
||||
}
|
||||
return create_api_response(
|
||||
code="400",
|
||||
message=f"会议正在处理中: {stage_descriptions[overall_status]}",
|
||||
data={
|
||||
"meeting_id": meeting_id,
|
||||
"title": meeting['title'],
|
||||
"processing_status": progress_info
|
||||
}
|
||||
)
|
||||
|
||||
# 情况3: 全部完成 → 返回200,提供完整预览数据
|
||||
if overall_status == "completed" and meeting['summary']:
|
||||
# 获取参会人员信息
|
||||
attendees_query = 'SELECT u.user_id, u.caption FROM attendees a JOIN users u ON a.user_id = u.user_id WHERE a.meeting_id = %s'
|
||||
cursor.execute(attendees_query, (meeting_id,))
|
||||
attendees_data = cursor.fetchall()
|
||||
attendees = [{'user_id': row['user_id'], 'caption': row['caption']} for row in attendees_data]
|
||||
with get_db_connection() as connection:
|
||||
cursor = connection.cursor(dictionary=True)
|
||||
attendees_query = 'SELECT u.user_id, u.caption FROM attendees a JOIN users u ON a.user_id = u.user_id WHERE a.meeting_id = %s'
|
||||
cursor.execute(attendees_query, (meeting_id,))
|
||||
attendees_data = cursor.fetchall()
|
||||
attendees = [{'user_id': row['user_id'], 'caption': row['caption']} for row in attendees_data]
|
||||
|
||||
# 组装返回数据
|
||||
preview_data = {
|
||||
|
|
@ -924,7 +1053,8 @@ def get_meeting_preview_data(meeting_id: int):
|
|||
"prompt_name": meeting['prompt_name'],
|
||||
"attendees": attendees,
|
||||
"attendees_count": len(attendees),
|
||||
"has_password": bool(meeting.get('access_password')) # 新增:是否设置了访问密码
|
||||
"has_password": bool(meeting.get('access_password')),
|
||||
"processing_status": progress_info # 附带进度信息供调试
|
||||
}
|
||||
|
||||
return create_api_response(code="200", message="获取会议预览数据成功", data=preview_data)
|
||||
|
|
|
|||
|
|
@ -321,6 +321,57 @@ class AsyncMeetingService:
|
|||
print(f"Error getting meeting LLM tasks: {e}")
|
||||
return []
|
||||
|
||||
def get_meeting_llm_status(self, meeting_id: int) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
获取会议的最新LLM任务状态(与transcription对齐)
|
||||
|
||||
Args:
|
||||
meeting_id: 会议ID
|
||||
|
||||
Returns:
|
||||
Optional[Dict]: 任务状态信息,如果没有任务返回None
|
||||
"""
|
||||
try:
|
||||
with get_db_connection() as connection:
|
||||
cursor = connection.cursor(dictionary=True)
|
||||
|
||||
# 查询最新的LLM任务
|
||||
query = """
|
||||
SELECT task_id, status, progress, created_at, completed_at, error_message
|
||||
FROM llm_tasks
|
||||
WHERE meeting_id = %s
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 1
|
||||
"""
|
||||
cursor.execute(query, (meeting_id,))
|
||||
task_record = cursor.fetchone()
|
||||
|
||||
cursor.close()
|
||||
|
||||
if not task_record:
|
||||
return None
|
||||
|
||||
# 如果任务还在进行中,获取最新状态
|
||||
if task_record['status'] in ['pending', 'processing']:
|
||||
try:
|
||||
return self.get_task_status(task_record['task_id'])
|
||||
except Exception as e:
|
||||
print(f"Failed to get latest LLM task status for meeting {meeting_id}, returning DB status. Error: {e}")
|
||||
|
||||
return {
|
||||
'task_id': task_record['task_id'],
|
||||
'status': task_record['status'],
|
||||
'progress': task_record['progress'] or 0,
|
||||
'meeting_id': meeting_id,
|
||||
'created_at': task_record['created_at'].isoformat() if task_record['created_at'] else None,
|
||||
'completed_at': task_record['completed_at'].isoformat() if task_record['completed_at'] else None,
|
||||
'error_message': task_record['error_message']
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error getting meeting LLM status: {e}")
|
||||
return None
|
||||
|
||||
def _update_task_status_in_redis(self, task_id: str, status: str, progress: int, message: str = None, result: str = None, error_message: str = None):
|
||||
"""更新Redis中的任务状态"""
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -1,24 +1,20 @@
|
|||
"""
|
||||
APK解析工具
|
||||
用于从APK文件中提取版本信息
|
||||
用于从APK文件中提取版本信息(使用 pyaxmlparser)
|
||||
"""
|
||||
import zipfile
|
||||
import xml.etree.ElementTree as ET
|
||||
import struct
|
||||
|
||||
|
||||
# 如果安装了 androguard,使用更可靠的解析方法
|
||||
def parse_apk_with_androguard(apk_path):
|
||||
"""
|
||||
使用 androguard 库解析 APK
|
||||
需要先安装: pip install androguard
|
||||
解析APK文件,提取版本信息
|
||||
使用 pyaxmlparser 库(轻量级,~1MB)
|
||||
"""
|
||||
try:
|
||||
from androguard.core.apk import APK
|
||||
from pyaxmlparser import APK
|
||||
|
||||
apk = APK(apk_path)
|
||||
version_code = apk.get_androidversion_code()
|
||||
version_name = apk.get_androidversion_name()
|
||||
version_code = apk.version_code
|
||||
version_name = apk.version_name
|
||||
|
||||
print(f"APK解析成功: version_code={version_code}, version_name={version_name}")
|
||||
|
||||
|
|
@ -26,11 +22,12 @@ def parse_apk_with_androguard(apk_path):
|
|||
'version_code': int(version_code) if version_code else None,
|
||||
'version_name': version_name
|
||||
}
|
||||
except ImportError as ie:
|
||||
print(f"androguard 导入失败: {str(ie)}")
|
||||
return parse_apk(apk_path)
|
||||
except ImportError:
|
||||
print("错误: pyaxmlparser 未安装")
|
||||
print("请运行: pip install pyaxmlparser")
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"使用androguard解析APK失败: {str(e)}")
|
||||
print(f"APK解析失败: {str(e)}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -20,4 +20,4 @@ python-multipart
|
|||
psutil
|
||||
|
||||
# APK Parsing
|
||||
androguard
|
||||
pyaxmlparser
|
||||
|
|
|
|||
|
|
@ -10,4 +10,4 @@ dashscope
|
|||
PyJWT>=2.8.0
|
||||
python-jose[cryptography]>=3.3.0
|
||||
psutil
|
||||
androguard
|
||||
pyaxmlparser
|
||||
|
|
|
|||
Loading…
Reference in New Issue