From 14ff607b52ec9045e4e10ea601e435c019a7b4e5 Mon Sep 17 00:00:00 2001 From: python Date: Tue, 9 Dec 2025 11:41:45 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=BA=E5=8D=8E=E4=B8=BA=E5=A4=A7=E6=A8=A1?= =?UTF-8?q?=E5=9E=8BAPI=E8=B0=83=E7=94=A8=E6=B7=BB=E5=8A=A0=E9=87=8D?= =?UTF-8?q?=E8=AF=95=E6=9C=BA=E5=88=B6=EF=BC=8C=E5=A2=9E=E5=BC=BA=E4=BA=86?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E5=A4=84=E7=90=86=E9=80=BB=E8=BE=91=EF=BC=8C?= =?UTF-8?q?=E7=A1=AE=E4=BF=9D=E5=9C=A8=E8=AF=B7=E6=B1=82=E5=A4=B1=E8=B4=A5?= =?UTF-8?q?=E6=97=B6=E8=83=BD=E5=A4=9F=E8=87=AA=E5=8A=A8=E9=87=8D=E8=AF=95?= =?UTF-8?q?=E5=B9=B6=E6=8F=90=E4=BE=9B=E8=AF=A6=E7=BB=86=E7=9A=84=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E4=BF=A1=E6=81=AF=E3=80=82=E5=90=8C=E6=97=B6=EF=BC=8C?= =?UTF-8?q?=E5=B0=86API=E8=B0=83=E7=94=A8=E9=80=BB=E8=BE=91=E5=88=86?= =?UTF-8?q?=E7=A6=BB=E5=88=B0=E5=8D=95=E7=8B=AC=E7=9A=84=E6=96=B9=E6=B3=95?= =?UTF-8?q?=E4=B8=AD=EF=BC=8C=E4=BB=A5=E6=8F=90=E9=AB=98=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E5=8F=AF=E8=AF=BB=E6=80=A7=E5=92=8C=E5=8F=AF=E7=BB=B4=E6=8A=A4?= =?UTF-8?q?=E6=80=A7=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- services/ai_service.py | 198 +++++++++++++++++++++++++++-------------- 1 file changed, 132 insertions(+), 66 deletions(-) diff --git a/services/ai_service.py b/services/ai_service.py index 8bf6df0..95b2f44 100644 --- a/services/ai_service.py +++ b/services/ai_service.py @@ -4,6 +4,7 @@ AI服务 - 封装大模型调用 """ import os import re +import time import requests import json from typing import Dict, List, Optional @@ -116,74 +117,139 @@ class AIService: raise Exception(f"AI服务调用失败: {str(e)}") def _extract_with_huawei(self, prompt: str, output_fields: List[Dict]) -> Optional[Dict]: - """使用华为大模型API提取字段""" - try: - payload = { - "model": self.huawei_model, - "messages": [ - { - "role": "system", - "content": "你是一个专业的数据提取助手,擅长从非结构化文本中准确提取结构化信息。你需要仔细分析输入文本,识别所有相关信息,并按照指定的JSON格式返回结果。请确保提取的信息准确、完整,对于能够从文本中推断出的信息也要尽量提取。" - }, - { - "role": "user", - "content": prompt - } - ], - "stream": False, - "presence_penalty": 1.03, - "frequency_penalty": 1.0, - "repetition_penalty": 1.0, - "temperature": 0.3, - "top_p": 0.95, - "top_k": 1, - "seed": 1, - "max_tokens": 8192, - "n": 1, - "enable_thinking": True - } - - headers = { - "Authorization": f"Bearer {self.huawei_api_key}", - "Content-Type": "application/json" - } - - response = requests.post( - self.huawei_api_endpoint, - json=payload, - headers=headers, - timeout=60 - ) - - if response.status_code != 200: - raise Exception(f"API调用失败: {response.status_code} - {response.text}") - - result = response.json() - - # 提取AI返回的内容 - if 'choices' in result and len(result['choices']) > 0: - content = result['choices'][0]['message']['content'] + """ + 使用华为大模型API提取字段(带重试机制) + 至少重试3次,总共最多尝试4次 + """ + max_retries = 3 # 最多重试3次,总共4次尝试 + retry_delay = 1 # 重试延迟(秒),每次重试延迟递增 + + last_exception = None + + for attempt in range(max_retries + 1): # 0, 1, 2, 3 (总共4次) + try: + if attempt > 0: + # 重试前等待,延迟时间递增(1秒、2秒、3秒) + wait_time = retry_delay * attempt + print(f"[AI服务] 第 {attempt} 次重试,等待 {wait_time} 秒后重试...") + time.sleep(wait_time) - # 处理思考过程标签(华为大模型可能返回思考过程) - # 移除思考过程标签之前的内容,只保留实际回答 - # 根据用户提供的示例,华为大模型使用 标签 - if '' in content: - content = content.split('')[-1].strip() + print(f"[AI服务] 正在调用华为大模型API (尝试 {attempt + 1}/{max_retries + 1})...") + result = self._call_huawei_api_once(prompt, output_fields) - # 尝试解析JSON - extracted_data = self._extract_json_from_text(content) - if extracted_data: - return extracted_data - - # 如果无法提取JSON,尝试从文本中提取 - return self._parse_text_response(content, output_fields) - else: - raise Exception("API返回格式异常") - - except requests.exceptions.Timeout: - raise Exception("AI服务调用超时") - except Exception as e: - raise Exception(f"AI服务调用失败: {str(e)}") + if result is not None: + if attempt > 0: + print(f"[AI服务] 重试成功!") + return result + + except requests.exceptions.Timeout as e: + last_exception = e + error_msg = f"AI服务调用超时 (尝试 {attempt + 1}/{max_retries + 1})" + print(f"[AI服务] {error_msg}") + if attempt < max_retries: + continue + else: + raise Exception(f"{error_msg}: {str(e)}") + + except requests.exceptions.ConnectionError as e: + last_exception = e + error_msg = f"连接错误 (尝试 {attempt + 1}/{max_retries + 1})" + print(f"[AI服务] {error_msg}: {str(e)}") + if attempt < max_retries: + continue + else: + raise Exception(f"{error_msg}: {str(e)}") + + except requests.exceptions.RequestException as e: + last_exception = e + error_msg = f"请求异常 (尝试 {attempt + 1}/{max_retries + 1})" + print(f"[AI服务] {error_msg}: {str(e)}") + if attempt < max_retries: + continue + else: + raise Exception(f"{error_msg}: {str(e)}") + + except Exception as e: + last_exception = e + error_msg = f"AI服务调用失败 (尝试 {attempt + 1}/{max_retries + 1})" + print(f"[AI服务] {error_msg}: {str(e)}") + # 对于其他类型的错误,也进行重试 + if attempt < max_retries: + continue + else: + raise Exception(f"{error_msg}: {str(e)}") + + # 如果所有重试都失败了 + if last_exception: + raise Exception(f"AI服务调用失败,已重试 {max_retries} 次: {str(last_exception)}") + else: + raise Exception(f"AI服务调用失败,已重试 {max_retries} 次") + + def _call_huawei_api_once(self, prompt: str, output_fields: List[Dict]) -> Optional[Dict]: + """ + 单次调用华为大模型API(不包含重试逻辑) + """ + payload = { + "model": self.huawei_model, + "messages": [ + { + "role": "system", + "content": "你是一个专业的数据提取助手,擅长从非结构化文本中准确提取结构化信息。你需要仔细分析输入文本,识别所有相关信息,并按照指定的JSON格式返回结果。请确保提取的信息准确、完整,对于能够从文本中推断出的信息也要尽量提取。" + }, + { + "role": "user", + "content": prompt + } + ], + "stream": False, + "presence_penalty": 1.03, + "frequency_penalty": 1.0, + "repetition_penalty": 1.0, + "temperature": 0.3, + "top_p": 0.95, + "top_k": 1, + "seed": 1, + "max_tokens": 8192, + "n": 1, + "enable_thinking": True + } + + headers = { + "Authorization": f"Bearer {self.huawei_api_key}", + "Content-Type": "application/json" + } + + response = requests.post( + self.huawei_api_endpoint, + json=payload, + headers=headers, + timeout=60 + ) + + if response.status_code != 200: + raise Exception(f"API调用失败: {response.status_code} - {response.text}") + + result = response.json() + + # 提取AI返回的内容 + if 'choices' in result and len(result['choices']) > 0: + content = result['choices'][0]['message']['content'] + + # 处理思考过程标签(华为大模型可能返回思考过程) + # 移除思考过程标签之前的内容,只保留实际回答 + # 根据用户提供的示例,华为大模型使用 标签 + if '' in content: + content = content.split('')[-1].strip() + + # 尝试解析JSON + extracted_data = self._extract_json_from_text(content) + if extracted_data: + return extracted_data + + # 如果无法提取JSON,尝试从文本中提取 + return self._parse_text_response(content, output_fields) + else: + raise Exception("API返回格式异常:未找到choices字段或choices为空") def _extract_json_from_text(self, text: str) -> Optional[Dict]: """