Zenith Wang commited on
Commit
b34c488
·
1 Parent(s): 578098f

使用官方示例代码结构,简化实现,固定依赖版本

Browse files
Files changed (2) hide show
  1. app.py +59 -171
  2. requirements.txt +2 -4
app.py CHANGED
@@ -1,18 +1,11 @@
1
  import gradio as gr
2
  import time
3
  import base64
 
4
  import os
5
  from io import BytesIO
6
  from PIL import Image
7
 
8
- # 清理环境变量中的代理设置,避免与 OpenAI 客户端冲突
9
- for key in list(os.environ.keys()):
10
- if 'proxy' in key.lower() or 'PROXY' in key:
11
- del os.environ[key]
12
-
13
- # 导入 OpenAI(在清理环境变量后)
14
- from openai import OpenAI
15
-
16
  # 配置
17
  BASE_URL = "https://api.stepfun.com/v1"
18
  # 从环境变量获取API密钥
@@ -29,53 +22,11 @@ def image_to_base64(image):
29
  if isinstance(image, Image.Image):
30
  buffered = BytesIO()
31
  image.save(buffered, format="PNG")
32
- img_str = base64.b64encode(buffered.getvalue()).decode()
33
  return img_str
34
 
35
  return None
36
 
37
- def create_client():
38
- """创建 OpenAI 客户端,处理各种环境问题"""
39
- import importlib
40
- import sys
41
-
42
- # 重新加载 openai 模块以确保干净的状态
43
- if 'openai' in sys.modules:
44
- importlib.reload(sys.modules['openai'])
45
-
46
- # 尝试不同的初始化方式
47
- try:
48
- # 方式1:只传递必需参数
49
- return OpenAI(
50
- api_key=STEP_API_KEY,
51
- base_url=BASE_URL
52
- )
53
- except:
54
- pass
55
-
56
- try:
57
- # 方式2:通过环境变量
58
- os.environ['OPENAI_API_KEY'] = STEP_API_KEY
59
- os.environ['OPENAI_BASE_URL'] = BASE_URL
60
- return OpenAI()
61
- except:
62
- pass
63
-
64
- # 方式3:使用 httpx 客户端自定义
65
- try:
66
- import httpx
67
- http_client = httpx.Client()
68
- return OpenAI(
69
- api_key=STEP_API_KEY,
70
- base_url=BASE_URL,
71
- http_client=http_client
72
- )
73
- except:
74
- pass
75
-
76
- # 如果都失败,返回 None
77
- return None
78
-
79
  def call_step_api(image, prompt, model, temperature=0.7, max_tokens=2000):
80
  """调用Step API进行分析,支持纯文本和图像+文本"""
81
 
@@ -87,7 +38,7 @@ def call_step_api(image, prompt, model, temperature=0.7, max_tokens=2000):
87
  yield "", "❌ API密钥未配置。请在 Hugging Face Space 的 Settings 中添加 STEP_API_KEY 环境变量。"
88
  return
89
 
90
- # 构造消息内容
91
  if image is not None:
92
  # 有图片的情况
93
  try:
@@ -95,109 +46,55 @@ def call_step_api(image, prompt, model, temperature=0.7, max_tokens=2000):
95
  if base64_image is None:
96
  yield "", "❌ 图片处理失败"
97
  return
98
-
99
- message_content = [
100
- {
101
- "type": "image_url",
102
- "image_url": {
103
- "url": f"data:image/png;base64,{base64_image}",
104
- "detail": "high"
105
- }
106
- },
107
- {
108
- "type": "text",
109
- "text": prompt
110
- }
111
  ]
112
  except Exception as e:
113
  yield "", f"❌ 图片处理错误: {str(e)}"
114
  return
115
  else:
116
  # 纯文本的情况
117
- message_content = prompt
 
 
118
 
119
- # 构造消息
120
- messages = [
121
- {
122
- "role": "user",
123
- "content": message_content
124
- }
125
- ]
126
-
127
- # 创建OpenAI客户端
128
- client = create_client()
129
- if client is None:
130
- # 如果客户端创建失败,尝试直接使用 requests
131
- try:
132
- import requests
133
-
134
- headers = {
135
- "Authorization": f"Bearer {STEP_API_KEY}",
136
- "Content-Type": "application/json"
137
- }
138
-
139
- data = {
140
- "model": model,
141
- "messages": messages,
142
- "temperature": temperature,
143
- "max_tokens": max_tokens,
144
- "stream": False
145
- }
146
-
147
- response = requests.post(
148
- f"{BASE_URL}/chat/completions",
149
- headers=headers,
150
- json=data,
151
- timeout=60
152
- )
153
-
154
- if response.status_code == 200:
155
- result = response.json()
156
- if result.get("choices") and result["choices"][0].get("message"):
157
- content = result["choices"][0]["message"]["content"]
158
-
159
- # 解析 reasoning 标记
160
- reasoning_content = ""
161
- final_answer = content
162
-
163
- if "<reasoning>" in content and "</reasoning>" in content:
164
- parts = content.split("<reasoning>")
165
- before = parts[0]
166
- after_reasoning = parts[1].split("</reasoning>")
167
- reasoning_content = after_reasoning[0]
168
- final_answer = before + after_reasoning[1] if len(after_reasoning) > 1 else before
169
-
170
- yield reasoning_content, final_answer
171
- else:
172
- yield "", "❌ API 返回格式错误"
173
- else:
174
- yield "", f"❌ API 请求失败: {response.status_code}"
175
-
176
- except Exception as e:
177
- yield "", f"❌ 请求失败: {str(e)}"
178
  return
179
 
 
 
 
180
  try:
181
- # 记录开始时间
182
- start_time = time.time()
183
-
184
- # 流式输出
185
  response = client.chat.completions.create(
186
  model=model,
187
  messages=messages,
188
- temperature=temperature,
189
- max_tokens=max_tokens,
190
  stream=True
191
  )
192
-
193
- full_response = ""
194
- reasoning_content = ""
195
- final_answer = ""
196
- is_reasoning = False
197
- reasoning_started = False
198
-
 
 
 
 
 
199
  for chunk in response:
200
- if chunk.choices and chunk.choices[0].delta:
 
201
  delta = chunk.choices[0].delta
202
 
203
  if hasattr(delta, 'content') and delta.content:
@@ -208,47 +105,38 @@ def call_step_api(image, prompt, model, temperature=0.7, max_tokens=2000):
208
  if "<reasoning>" in content:
209
  is_reasoning = True
210
  reasoning_started = True
211
- # 提取<reasoning>之前的内容添加到final_answer
212
- before_reasoning = content.split("<reasoning>")[0]
213
- if before_reasoning:
214
- final_answer += before_reasoning
215
- # 提取<reasoning>之后的内容开始reasoning
216
- after_tag = content.split("<reasoning>")[1] if len(content.split("<reasoning>")) > 1 else ""
217
- reasoning_content += after_tag
218
  elif "</reasoning>" in content:
219
- # 提取</reasoning>之前的内容添加到reasoning
220
- before_tag = content.split("</reasoning>")[0]
221
- reasoning_content += before_tag
 
222
  is_reasoning = False
223
- # 提取</reasoning>之后的内容添加到final_answer
224
- after_reasoning = content.split("</reasoning>")[1] if len(content.split("</reasoning>")) > 1 else ""
225
- final_answer += after_reasoning
226
  elif is_reasoning:
227
  reasoning_content += content
228
  else:
229
  final_answer += content
230
 
231
  # 实时输出
232
- if reasoning_started:
233
- yield reasoning_content, final_answer
234
- else:
235
- yield "", final_answer
236
-
237
- # 添加生成时间
238
- elapsed_time = time.time() - start_time
239
- time_info = f"\n\n⏱️ 生成用时: {elapsed_time:.2f}秒"
240
- final_answer += time_info
241
-
242
- yield reasoning_content, final_answer
243
-
244
  except Exception as e:
245
- error_msg = str(e)
246
- if "api_key" in error_msg.lower():
247
- yield "", "❌ API密钥错误:请检查密钥是否有效"
248
- elif "network" in error_msg.lower() or "connection" in error_msg.lower():
249
- yield "", "❌ 网络连接错误:请检查网络连接"
250
- else:
251
- yield "", f"❌ API调用错误: {error_msg[:200]}"
 
 
252
 
253
  # 创建Gradio界面
254
  with gr.Blocks(title="Step-3", theme=gr.themes.Soft()) as demo:
 
1
  import gradio as gr
2
  import time
3
  import base64
4
+ from openai import OpenAI
5
  import os
6
  from io import BytesIO
7
  from PIL import Image
8
 
 
 
 
 
 
 
 
 
9
  # 配置
10
  BASE_URL = "https://api.stepfun.com/v1"
11
  # 从环境变量获取API密钥
 
22
  if isinstance(image, Image.Image):
23
  buffered = BytesIO()
24
  image.save(buffered, format="PNG")
25
+ img_str = base64.b64encode(buffered.getvalue()).decode('utf-8')
26
  return img_str
27
 
28
  return None
29
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  def call_step_api(image, prompt, model, temperature=0.7, max_tokens=2000):
31
  """调用Step API进行分析,支持纯文本和图像+文本"""
32
 
 
38
  yield "", "❌ API密钥未配置。请在 Hugging Face Space 的 Settings 中添加 STEP_API_KEY 环境变量。"
39
  return
40
 
41
+ # 构造消息内容 - 参考官方示例
42
  if image is not None:
43
  # 有图片的情况
44
  try:
 
46
  if base64_image is None:
47
  yield "", "❌ 图片处理失败"
48
  return
49
+
50
+ # 按照官方示例的格式构造消息
51
+ messages = [
52
+ {"role": "user", "content": [
53
+ {"type": "image_url", "image_url": {"url": f"data:image/jpg;base64,{base64_image}", "detail": "high"}},
54
+ {"type": "text", "text": prompt}
55
+ ]}
 
 
 
 
 
 
56
  ]
57
  except Exception as e:
58
  yield "", f"❌ 图片处理错误: {str(e)}"
59
  return
60
  else:
61
  # 纯文本的情况
62
+ messages = [
63
+ {"role": "user", "content": prompt}
64
+ ]
65
 
66
+ # 创建OpenAI客户端 - 完全按照官方示例
67
+ try:
68
+ client = OpenAI(api_key=STEP_API_KEY, base_url=BASE_URL)
69
+ except Exception as e:
70
+ yield "", f"❌ 客户端初始化失败: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  return
72
 
73
+ # 记录开始时间
74
+ start_time = time.time()
75
+
76
  try:
77
+ # 调用API - 按照官方示例
 
 
 
78
  response = client.chat.completions.create(
79
  model=model,
80
  messages=messages,
 
 
81
  stream=True
82
  )
83
+ except Exception as e:
84
+ yield "", f"❌ API请求失败: {str(e)}"
85
+ return
86
+
87
+ # 处理流式响应
88
+ full_response = ""
89
+ reasoning_content = ""
90
+ final_answer = ""
91
+ is_reasoning = False
92
+ reasoning_started = False
93
+
94
+ try:
95
  for chunk in response:
96
+ # 按照官方示例处理chunk
97
+ if chunk.choices and len(chunk.choices) > 0:
98
  delta = chunk.choices[0].delta
99
 
100
  if hasattr(delta, 'content') and delta.content:
 
105
  if "<reasoning>" in content:
106
  is_reasoning = True
107
  reasoning_started = True
108
+ # 处理标记前后的内容
109
+ parts = content.split("<reasoning>")
110
+ if parts[0]:
111
+ final_answer += parts[0]
112
+ if len(parts) > 1:
113
+ reasoning_content += parts[1]
 
114
  elif "</reasoning>" in content:
115
+ # 处理结束标记
116
+ parts = content.split("</reasoning>")
117
+ if parts[0]:
118
+ reasoning_content += parts[0]
119
  is_reasoning = False
120
+ if len(parts) > 1:
121
+ final_answer += parts[1]
 
122
  elif is_reasoning:
123
  reasoning_content += content
124
  else:
125
  final_answer += content
126
 
127
  # 实时输出
128
+ yield reasoning_content, final_answer
129
+
 
 
 
 
 
 
 
 
 
 
130
  except Exception as e:
131
+ yield reasoning_content, final_answer + f"\n\n❌ 流处理错误: {str(e)}"
132
+ return
133
+
134
+ # 添加生成时间
135
+ elapsed_time = time.time() - start_time
136
+ time_info = f"\n\n⏱️ 生成用时: {elapsed_time:.2f}秒"
137
+ final_answer += time_info
138
+
139
+ yield reasoning_content, final_answer
140
 
141
  # 创建Gradio界面
142
  with gr.Blocks(title="Step-3", theme=gr.themes.Soft()) as demo:
requirements.txt CHANGED
@@ -1,5 +1,3 @@
1
  gradio==4.19.2
2
- openai>=1.0.0,<2.0.0
3
- Pillow>=10.0.0
4
- httpx>=0.24.0
5
- requests>=2.25.0
 
1
  gradio==4.19.2
2
+ openai==1.12.0
3
+ Pillow==10.2.0