dan92 commited on
Commit
d405779
·
verified ·
1 Parent(s): f1bc5af

Upload 2 files

Browse files
Files changed (2) hide show
  1. Dockerfile +9 -1
  2. retry_middleware.py +117 -46
Dockerfile CHANGED
@@ -3,9 +3,17 @@ FROM hpyp/bbapi:latest
3
  # 复制重试中间件文件到容器中
4
  COPY retry_middleware.py /app/retry_middleware.py
5
 
 
 
 
 
 
 
 
6
  # ENV APP_SECRET=
7
 
8
  EXPOSE 8001
9
 
10
- CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8001"]
 
11
 
 
3
  # 复制重试中间件文件到容器中
4
  COPY retry_middleware.py /app/retry_middleware.py
5
 
6
+ # 创建一个新的入口点脚本
7
+ RUN echo 'from fastapi import FastAPI\n\
8
+ from retry_middleware import RetryMiddleware\n\
9
+ from main import app\n\
10
+ \n\
11
+ app.add_middleware(RetryMiddleware, max_retries=3, delay=1.0)' > /app/wrapper.py
12
+
13
  # ENV APP_SECRET=
14
 
15
  EXPOSE 8001
16
 
17
+ # 使用新的入口点脚本
18
+ CMD ["uvicorn", "wrapper:app", "--host", "0.0.0.0", "--port", "8001"]
19
 
retry_middleware.py CHANGED
@@ -1,48 +1,119 @@
1
- import time
2
- from functools import wraps
3
-
4
- def retry_on_unsafe_content(max_retries=3, delay=1):
5
- """
6
- 装饰器函数,用于在收到 'content is not safe' 响应时自动重试
7
-
8
- Args:
9
- max_retries (int): 最大重试次数
10
- delay (int): 重试之间的延迟时间(秒)
11
- """
12
- def decorator(func):
13
- @wraps(func)
14
- async def wrapper(*args, **kwargs):
15
- retries = 0
16
- while retries < max_retries:
17
- try:
18
- response = await func(*args, **kwargs)
19
-
20
- # 检查响应中是否包含 "content is not safe" 错误
21
- if isinstance(response, dict) and response.get('error') and 'content is not safe' in response['error'].lower():
22
- retries += 1
23
- if retries < max_retries:
24
- print(f"检测到内容安全问题,正在进行第 {retries} 次重试...")
25
- time.sleep(delay)
26
- continue
27
- return response
28
- except Exception as e:
29
- if 'content is not safe' in str(e).lower():
30
- retries += 1
31
- if retries < max_retries:
32
- print(f"检测到内容安全问题,正在进行第 {retries} 次重试...")
33
- time.sleep(delay)
34
- continue
35
- raise e
36
-
37
- # 如果所有重试都失败,返回最后一次的响应
38
- return response
39
- return wrapper
40
- return decorator
41
-
42
- # 使用示例:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  """
44
- @retry_on_unsafe_content(max_retries=3, delay=1)
45
- async def your_ai_chat_function(message):
46
- # 原有的AI聊天处理逻辑
47
- pass
 
 
48
  """
 
1
+ from fastapi import Request, Response
2
+ from fastapi.responses import JSONResponse
3
+ import asyncio
4
+ import json
5
+ from typing import Callable
6
+ import logging
7
+
8
+ logging.basicConfig(level=logging.INFO)
9
+ logger = logging.getLogger(__name__)
10
+
11
+ class RetryMiddleware:
12
+ def __init__(
13
+ self,
14
+ app,
15
+ max_retries: int = 3,
16
+ delay: float = 1.0
17
+ ):
18
+ self.app = app
19
+ self.max_retries = max_retries
20
+ self.delay = delay
21
+
22
+ async def __call__(self, scope, receive, send):
23
+ if scope["type"] != "http":
24
+ return await self.app(scope, receive, send)
25
+
26
+ async def wrapped_send(message):
27
+ if message["type"] == "http.response.body":
28
+ body = message.get("body", b"")
29
+ if body:
30
+ try:
31
+ response_data = json.loads(body.decode())
32
+ if isinstance(response_data, dict) and response_data.get("error"):
33
+ error_msg = response_data["error"].lower()
34
+ if "content is not safe" in error_msg:
35
+ # 需要���试
36
+ return await self.handle_retry(scope, receive, send)
37
+ except json.JSONDecodeError:
38
+ pass
39
+ await send(message)
40
+
41
+ await self.app(scope, receive, wrapped_send)
42
+
43
+ async def handle_retry(self, scope, receive, send):
44
+ original_receive = receive
45
+ for attempt in range(self.max_retries):
46
+ try:
47
+ logger.info(f"正在进行第 {attempt + 1} 次尝试...")
48
+
49
+ # 重新构造请求体
50
+ request_body = b""
51
+ more_body = True
52
+ while more_body:
53
+ message = await original_receive()
54
+ if message["type"] == "http.request":
55
+ request_body += message.get("body", b"")
56
+ more_body = message.get("more_body", False)
57
+
58
+ async def modified_receive():
59
+ if not hasattr(modified_receive, 'called'):
60
+ modified_receive.called = True
61
+ return {
62
+ "type": "http.request",
63
+ "body": request_body,
64
+ "more_body": False
65
+ }
66
+ return {"type": "http.disconnect"}
67
+
68
+ response_sent = False
69
+ async def modified_send(message):
70
+ nonlocal response_sent
71
+ if message["type"] == "http.response.start":
72
+ await send(message)
73
+ elif message["type"] == "http.response.body":
74
+ body = message.get("body", b"")
75
+ if body:
76
+ try:
77
+ response_data = json.loads(body.decode())
78
+ if isinstance(response_data, dict) and response_data.get("error"):
79
+ error_msg = response_data["error"].lower()
80
+ if "content is not safe" in error_msg:
81
+ if attempt < self.max_retries - 1:
82
+ logger.info(f"检测到内容安全问题,等待 {self.delay} 秒后重试...")
83
+ await asyncio.sleep(self.delay)
84
+ return
85
+ except json.JSONDecodeError:
86
+ pass
87
+ response_sent = True
88
+ await send(message)
89
+
90
+ await self.app(scope, modified_receive, modified_send)
91
+ if response_sent:
92
+ break
93
+
94
+ except Exception as e:
95
+ logger.error(f"重试过程中发生错误: {str(e)}")
96
+ if attempt == self.max_retries - 1:
97
+ # 如果是最后一次尝试,发送错误响应
98
+ error_response = {
99
+ "error": f"在 {self.max_retries} 次尝试后仍然失败: {str(e)}"
100
+ }
101
+ await send({
102
+ "type": "http.response.start",
103
+ "status": 500,
104
+ "headers": [(b"content-type", b"application/json")]
105
+ })
106
+ await send({
107
+ "type": "http.response.body",
108
+ "body": json.dumps(error_response).encode()
109
+ })
110
+
111
+ # 使用方法:
112
  """
113
+ main.py 中添加:
114
+ from fastapi import FastAPI
115
+ from retry_middleware import RetryMiddleware
116
+
117
+ app = FastAPI()
118
+ app.add_middleware(RetryMiddleware, max_retries=3, delay=1.0)
119
  """