lazyc commited on
Commit
1008a71
·
verified ·
1 Parent(s): 4234311

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +175 -31
app.py CHANGED
@@ -1,36 +1,185 @@
1
  import os
2
  import uuid
3
-
4
  import gradio as gr
5
  import modelscope_studio.components.antd as antd
6
  import modelscope_studio.components.antdx as antdx
7
  import modelscope_studio.components.base as ms
8
- # from langfuse import Langfuse
9
- # from langfuse.openai import OpenAI
10
  from openai import OpenAI
 
 
 
 
11
 
12
  # =========== Configuration
13
- # API KEY and API BASE
14
- client = OpenAI(
15
- base_url=os.getenv("API_BASE"),
16
- api_key=os.getenv("API_KEY"),
17
- )
18
  # MODEL NAME
19
  model = os.getenv("MODEL_NAME")
20
-
 
 
 
 
21
  save_history = True
22
 
23
  # =========== Configuration
24
 
25
- is_modelscope_studio = os.getenv('MODELSCOPE_ENVIRONMENT') == 'studio'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
 
 
 
27
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  def get_text(text: str, cn_text: str):
29
  if is_modelscope_studio:
30
  return cn_text
31
  return text
32
 
33
-
34
  logo_img = os.path.join(os.path.dirname(__file__), "rednote_hilab.png")
35
 
36
  DEFAULT_PROMPTS = [{
@@ -97,7 +246,7 @@ DEFAULT_THEME = {
97
  def format_history(history):
98
  messages = [{
99
  "role": "system",
100
- "content": "You are a helpful and harmless assistant.",
101
  }]
102
  for item in history:
103
  if item["role"] == "user":
@@ -131,39 +280,34 @@ class Gradio_Events:
131
  state: gr.update(value=state_value),
132
  }
133
  try:
134
- response = client.chat.completions.create(
135
- model=model, # Model-Id
136
- messages=history_messages,
137
- stream=True)
138
  thought_done = False
139
  for chunk in response:
140
- # reasoning_content = chunk.choices[0].delta.reasoning_content
141
- content = chunk.choices[0].delta.content
 
 
 
 
 
142
  history[-1]["loading"] = False
143
 
144
  if content and not thought_done:
145
- thought_done = True
146
- #history[-1]["meta"]["reason_content"] = history[-1]["content"]
147
-
148
- # print("Reason: ",history[-1]["meta"]["reason_content"])
149
-
150
  history[-1]["content"] = ""
151
- # history[-1]["meta"]["thought_end_message"] = get_text("End of Thought", "已深度思考")
152
 
153
- history[-1]["content"] += content or ""
 
154
 
155
  yield {
156
  chatbot: gr.update(items=history),
157
  state: gr.update(value=state_value)
158
  }
 
159
  history[-1]["meta"]["end"] = True
 
160
 
161
- print("Answer: ",history[-1]["content"])
162
-
163
- yield {
164
- chatbot: gr.update(items=history),
165
- state: gr.update(value=state_value),
166
- }
167
  except Exception as e:
168
  history[-1]["loading"] = False
169
  history[-1]["meta"]["end"] = True
 
1
  import os
2
  import uuid
3
+ import json
4
  import gradio as gr
5
  import modelscope_studio.components.antd as antd
6
  import modelscope_studio.components.antdx as antdx
7
  import modelscope_studio.components.base as ms
 
 
8
  from openai import OpenAI
9
+ import requests
10
+ from typing import Generator, Dict, Any
11
+ import logging
12
+ import time
13
 
14
  # =========== Configuration
 
 
 
 
 
15
  # MODEL NAME
16
  model = os.getenv("MODEL_NAME")
17
+ # 代理服务器配置
18
+ PROXY_BASE_URL = os.getenv("PROXY_API_BASE", "http://localhost:8000")
19
+ PROXY_TIMEOUT = int(os.getenv("PROXY_TIMEOUT", 30))
20
+ MAX_RETRIES = int(os.getenv("MAX_RETRIES", 3))
21
+ # 保存历史
22
  save_history = True
23
 
24
  # =========== Configuration
25
 
26
+ # 配置日志
27
+ logging.basicConfig(level=logging.INFO)
28
+ logger = logging.getLogger(__name__)
29
+
30
+ class DeltaObject:
31
+ """模拟OpenAI Delta对象"""
32
+ def __init__(self, data: dict):
33
+ self.content = data.get('content')
34
+ self.role = data.get('role')
35
+
36
+ class ChoiceObject:
37
+ """模拟OpenAI Choice对象"""
38
+ def __init__(self, choice_data: dict):
39
+ delta_data = choice_data.get('delta', {})
40
+ self.delta = DeltaObject(delta_data)
41
+ self.finish_reason = choice_data.get('finish_reason')
42
+ self.index = choice_data.get('index', 0)
43
+
44
+ class ChunkObject:
45
+ """模拟OpenAI Chunk对象"""
46
+ def __init__(self, chunk_data: dict):
47
+ choices_data = chunk_data.get('choices', [])
48
+ self.choices = [ChoiceObject(choice) for choice in choices_data]
49
+ self.id = chunk_data.get('id', '')
50
+ self.object = chunk_data.get('object', 'chat.completion.chunk')
51
+ self.created = chunk_data.get('created', 0)
52
+ self.model = chunk_data.get('model', '')
53
+
54
+ class ProxyClient:
55
+ """代理客户端,用于与中间服务通信"""
56
+
57
+ def __init__(self, base_url: str, timeout: int = 30):
58
+ self.base_url = base_url.rstrip('/')
59
+ self.timeout = timeout
60
+ self.session = requests.Session()
61
+
62
+ def chat_completions_create(self, model: str, messages: list, stream: bool = True, **kwargs):
63
+ """创建聊天完成请求"""
64
+ url = f"{self.base_url}/chat/completions"
65
+
66
+ payload = {
67
+ "model": model,
68
+ "messages": messages,
69
+ "stream": stream,
70
+ **kwargs
71
+ }
72
+
73
+ try:
74
+ response = self.session.post(
75
+ url,
76
+ json=payload,
77
+ stream=stream,
78
+ timeout=self.timeout,
79
+ headers={"Content-Type": "application/json"}
80
+ )
81
+ response.raise_for_status()
82
+
83
+ if stream:
84
+ return self._parse_stream_response(response)
85
+ else:
86
+ return response.json()
87
+
88
+ except requests.exceptions.RequestException as e:
89
+ logger.error(f"Request failed: {str(e)}")
90
+ raise Exception(f"Failed to connect to proxy server: {str(e)}")
91
+
92
+ def _parse_stream_response(self, response) -> Generator[ChunkObject, None, None]:
93
+ """解析流式响应"""
94
+ try:
95
+ # 确保响应编码正确
96
+ response.encoding = 'utf-8'
97
+
98
+ for line in response.iter_lines(decode_unicode=True):
99
+ if not line:
100
+ continue
101
+
102
+ line = line.strip()
103
+ if line.startswith('data: '):
104
+ data = line[6:] # 移除 'data: ' 前缀
105
+
106
+ if data == '[DONE]':
107
+ break
108
+
109
+ try:
110
+ chunk_data = json.loads(data)
111
+
112
+ # 检查是否是错误响应
113
+ if 'error' in chunk_data:
114
+ raise Exception(f"Stream error: {chunk_data.get('detail', chunk_data['error'])}")
115
+
116
+ # 创建与OpenAI客户端兼容的响应对象
117
+ yield ChunkObject(chunk_data)
118
+
119
+ except json.JSONDecodeError as e:
120
+ logger.warning(f"Failed to parse JSON: {data}, error: {str(e)}")
121
+ continue
122
+
123
+ except Exception as e:
124
+ logger.error(f"Error parsing stream response: {str(e)}")
125
+ raise
126
+
127
+ def health_check(self) -> dict:
128
+ """健康检查"""
129
+ try:
130
+ url = f"{self.base_url}/health"
131
+ response = self.session.get(url, timeout=5)
132
+ response.raise_for_status()
133
+ return response.json()
134
+ except Exception as e:
135
+ logger.error(f"Health check failed: {str(e)}")
136
+ return {"status": "unhealthy", "error": str(e)}
137
 
138
+ # 初始化代理客户端
139
+ client = ProxyClient(PROXY_BASE_URL, PROXY_TIMEOUT)
140
 
141
+ def chat_with_retry(history_messages, max_retries=MAX_RETRIES):
142
+ """带重试机制的聊天函数"""
143
+ last_exception = None
144
+
145
+ for attempt in range(max_retries):
146
+ try:
147
+ logger.info(f"Chat attempt {attempt + 1}/{max_retries}")
148
+
149
+ # 检查代理服务健康状态
150
+ health = client.health_check()
151
+ if health.get("status") != "healthy":
152
+ raise Exception(f"Proxy service unhealthy: {health}")
153
+
154
+ response = client.chat_completions_create(
155
+ model=model,
156
+ messages=history_messages,
157
+ stream=True
158
+ )
159
+
160
+ return response
161
+
162
+ except Exception as e:
163
+ last_exception = e
164
+ logger.warning(f"Attempt {attempt + 1} failed: {str(e)}")
165
+
166
+ if attempt < max_retries - 1:
167
+ # 指数退避
168
+ wait_time = 2 ** attempt
169
+ logger.info(f"Retrying in {wait_time} seconds...")
170
+ time.sleep(wait_time)
171
+ else:
172
+ logger.error(f"All {max_retries} attempts failed")
173
+
174
+ raise last_exception
175
+
176
+
177
+ is_modelscope_studio = os.getenv('MODELSCOPE_ENVIRONMENT') == 'studio'
178
  def get_text(text: str, cn_text: str):
179
  if is_modelscope_studio:
180
  return cn_text
181
  return text
182
 
 
183
  logo_img = os.path.join(os.path.dirname(__file__), "rednote_hilab.png")
184
 
185
  DEFAULT_PROMPTS = [{
 
246
  def format_history(history):
247
  messages = [{
248
  "role": "system",
249
+ "content": "You are a helpful assistant",
250
  }]
251
  for item in history:
252
  if item["role"] == "user":
 
280
  state: gr.update(value=state_value),
281
  }
282
  try:
283
+ response = chat_with_retry(history_messages)
284
+
 
 
285
  thought_done = False
286
  for chunk in response:
287
+ # 安全地访问chunk属性
288
+ if chunk.choices and len(chunk.choices) > 0:
289
+ content = chunk.choices[0].delta.content
290
+ else:
291
+ content = None
292
+ raise ValueError('Content is None')
293
+
294
  history[-1]["loading"] = False
295
 
296
  if content and not thought_done:
297
+ thought_done = True
 
 
 
 
298
  history[-1]["content"] = ""
 
299
 
300
+ if content:
301
+ history[-1]["content"] += content
302
 
303
  yield {
304
  chatbot: gr.update(items=history),
305
  state: gr.update(value=state_value)
306
  }
307
+
308
  history[-1]["meta"]["end"] = True
309
+ print("Answer: ", history[-1]["content"])
310
 
 
 
 
 
 
 
311
  except Exception as e:
312
  history[-1]["loading"] = False
313
  history[-1]["meta"]["end"] = True