From 5a34df39442953e66964d4d13e48c0b7b6d28c41 Mon Sep 17 00:00:00 2001 From: "mula.liu" Date: Sat, 27 Dec 2025 16:57:56 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=BC=82=E6=AD=A5=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E7=9A=84=E4=BF=9D=E6=8A=A4=E6=9C=BA=E5=88=B6=EF=BC=8C?= =?UTF-8?q?=E9=98=B2=E6=AD=A2=E9=87=8D=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .DS_Store | Bin 10244 -> 10244 bytes app.zip | Bin 95776 -> 96296 bytes app/core/config.py | 2 +- app/services/async_meeting_service.py | 49 ++++++++++++++---- app/services/async_transcription_service.py | 52 +++++++++++++++----- 5 files changed, 81 insertions(+), 22 deletions(-) diff --git a/.DS_Store b/.DS_Store index 0145aae6850e420621b20ef2bfe2f92d106bb17a..350e4a869deb3bdd71619405cf3a245fafb26a96 100644 GIT binary patch delta 19 acmZn(XbIThCCJ9Ont_4AZ*zd)7BK)j!3B~4 delta 19 acmZn(XbIThCCJ9Gfq{WhWOIPv7BK)ilLcJ> diff --git a/app.zip b/app.zip index 6af80b6756a791acd4721312c41d192101a2f93e..a857980d4a4cb8b909fab2b5b02e8b02e2e186c1 100644 GIT binary patch delta 13373 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 delta 12960 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 diff --git a/app/core/config.py b/app/core/config.py index d8c4e3a..fd594a1 100644 --- a/app/core/config.py +++ b/app/core/config.py @@ -46,7 +46,7 @@ API_CONFIG = { # 七牛云配置 QINIU_ACCESS_KEY = os.getenv('QINIU_ACCESS_KEY', 'A0tp96HCtg-wZCughTgi5vc2pJnw3btClwxRE_e8') QINIU_SECRET_KEY = os.getenv('QINIU_SECRET_KEY', 'Lj-MSHpaVbmzpS86kMIjmwikvYOT9iPBjCk9hm6k') -QINIU_BUCKET = os.getenv('QINIU_BUCKET', 'imeeting') +QINIU_BUCKET = os.getenv('QINIU_BUCKET', 'imeeting_dev') QINIU_DOMAIN = os.getenv('QINIU_DOMAIN', 't0vogyxkz.hn-bkt.clouddn.com') # 应用配置 diff --git a/app/services/async_meeting_service.py b/app/services/async_meeting_service.py index 9ec1f9b..363bf7c 100644 --- a/app/services/async_meeting_service.py +++ b/app/services/async_meeting_service.py @@ -159,17 +159,22 @@ class AsyncMeetingService: if current_status == 'completed': print(f"[Monitor] Transcription completed successfully for meeting {meeting_id}") - # 启动总结任务 - try: - summary_task_id = self.start_summary_generation(meeting_id, user_prompt="", prompt_id=prompt_id) - print(f"[Monitor] Summary task {summary_task_id} started for meeting {meeting_id}") + # 防止并发:检查是否已经有总结任务存在 + existing_task = self._get_existing_summary_task(meeting_id) + if existing_task: + print(f"[Monitor] Summary task already exists for meeting {meeting_id}, task_id: {existing_task}, skipping duplicate task creation") + else: + # 启动总结任务 + try: + summary_task_id = self.start_summary_generation(meeting_id, user_prompt="", prompt_id=prompt_id) + print(f"[Monitor] Summary task {summary_task_id} started for meeting {meeting_id}") - # 在后台执行总结任务 - self._process_task(summary_task_id) + # 在后台执行总结任务 + self._process_task(summary_task_id) - except Exception as e: - error_msg = f"Failed to start summary generation: {e}" - print(f"[Monitor] {error_msg}") + except Exception as e: + error_msg = f"Failed to start summary generation: {e}" + print(f"[Monitor] {error_msg}") # 监控任务完成,退出循环 break @@ -457,5 +462,31 @@ class AsyncMeetingService: print(f"Error getting task from database: {e}") return None + def _get_existing_summary_task(self, meeting_id: int) -> Optional[str]: + """ + 检查会议是否已经有总结任务(用于并发控制) + 返回最新的pending或processing状态的任务ID,如果没有则返回None + """ + try: + with get_db_connection() as connection: + cursor = connection.cursor(dictionary=True) + query = """ + SELECT task_id FROM llm_tasks + WHERE meeting_id = %s AND status IN ('pending', 'processing') + ORDER BY created_at DESC + LIMIT 1 + """ + cursor.execute(query, (meeting_id,)) + result = cursor.fetchone() + cursor.close() + + if result: + return result['task_id'] + return None + + except Exception as e: + print(f"Error checking existing summary task: {e}") + return None + # 创建全局实例 async_meeting_service = AsyncMeetingService() diff --git a/app/services/async_transcription_service.py b/app/services/async_transcription_service.py index 5c54da7..4d3b85c 100644 --- a/app/services/async_transcription_service.py +++ b/app/services/async_transcription_service.py @@ -144,17 +144,26 @@ class AsyncTranscriptionService: # 3. 如果任务完成,处理结果 if current_status == 'completed' and paraformer_response.output.get('results'): - try: - self._process_transcription_result( - business_task_id, - int(task_data['meeting_id']), - paraformer_response.output - ) - except Exception as e: - current_status = 'failed' - progress = 100 # 进度为100,但状态是失败 - error_message = f"Error processing transcription result: {e}" - print(error_message) + # 防止并发处理:先检查数据库中的状态 + db_task_status = self._get_task_status_from_db(business_task_id) + if db_task_status != 'completed': + # 只有当数据库中状态不是completed时才处理 + # 先将状态更新为completed,作为分布式锁 + self._update_task_status_in_db(business_task_id, 'completed', 100, None) + + try: + self._process_transcription_result( + business_task_id, + int(task_data['meeting_id']), + paraformer_response.output + ) + except Exception as e: + current_status = 'failed' + progress = 100 # 进度为100,但状态是失败 + error_message = f"Error processing transcription result: {e}" + print(error_message) + else: + print(f"Task {business_task_id} already processed, skipping duplicate processing") except Exception as e: error_message = f"Error getting task status: {e}" @@ -332,7 +341,26 @@ class AsyncTranscriptionService: except Exception as e: print(f"Error updating task status in database: {e}") - + + def _get_task_status_from_db(self, business_task_id: str) -> Optional[str]: + """从数据库获取任务状态(用于并发控制)""" + try: + with get_db_connection() as connection: + cursor = connection.cursor(dictionary=True) + + query = "SELECT status FROM transcript_tasks WHERE task_id = %s" + cursor.execute(query, (business_task_id,)) + result = cursor.fetchone() + cursor.close() + + if result: + return result['status'] + return None + + except Exception as e: + print(f"Error getting task status from database: {e}") + return None + def _get_task_from_db(self, business_task_id: str) -> Optional[Dict[str, str]]: """从数据库获取任务信息""" try: