Zenith Wang commited on
Commit
d2001c1
·
1 Parent(s): 96f986b

优化代码结构,改进错误处理,支持环境变量配置API密钥

Browse files
Files changed (3) hide show
  1. README.md +68 -8
  2. app.py +240 -207
  3. requirements.txt +4 -3
README.md CHANGED
@@ -1,14 +1,74 @@
1
  ---
2
- title: Step3
3
- emoji: 💬
4
- colorFrom: yellow
5
- colorTo: purple
6
  sdk: gradio
7
- sdk_version: 5.0.1
8
  app_file: app.py
9
  pinned: false
10
- license: apache-2.0
11
- short_description: ' Our latest multimodal reasoning model'
12
  ---
13
 
14
- An example chatbot using [Gradio](https://gradio.app), [`huggingface_hub`](https://huggingface.co/docs/huggingface_hub/v0.22.2/en/index), and the [Hugging Face Inference API](https://huggingface.co/docs/api-inference/index).
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: Step-3 图像理解助手
3
+ emoji: 🤖
4
+ colorFrom: purple
5
+ colorTo: blue
6
  sdk: gradio
7
+ sdk_version: 4.19.2
8
  app_file: app.py
9
  pinned: false
10
+ license: mit
 
11
  ---
12
 
13
+ # Step-3 图像理解助手 🤖
14
+
15
+ 基于阶跃星辰 Step-3 模型的智能图像理解和分析工具。
16
+
17
+ ## 功能特点
18
+
19
+ - 🖼️ **图像理解**:上传图片,AI 自动分析图像内容
20
+ - 💬 **自然语言交互**:使用中文自然语言描述你的需求
21
+ - 🔄 **实时流式输出**:支持流式响应,实时查看生成结果
22
+ - 🧠 **深度推理**:Step-3 模型具备强大的推理能力
23
+
24
+ ## 如何使用
25
+
26
+ ### 在 Hugging Face Spaces 中使用
27
+
28
+ 1. **配置 API 密钥**(重要!)
29
+ - 进入 Space 的 Settings 页面
30
+ - 在 "Repository secrets" 部分添加:
31
+ - Name: `STEP_API_KEY`
32
+ - Value: 你的阶跃星辰 API 密钥
33
+
34
+ 2. **使用应用**
35
+ - 上传一张图片
36
+ - 输入提示词(例如:"这是什么?请详细描述")
37
+ - 点击"开始分析"
38
+ - 等待 AI 返回结果
39
+
40
+ ### 获取 API 密钥
41
+
42
+ 1. 访问 [阶跃星辰官网](https://www.stepfun.com/)
43
+ 2. 注册/登录账号
44
+ 3. 在控制台创建 API 密钥
45
+
46
+ ## 示例提示词
47
+
48
+ - "这张图片中有什么内容?请详细描述。"
49
+ - "帮我看看这是什么菜,如何制作?"
50
+ - "分析这张图片的构图和色彩运用。"
51
+ - "这张图片可能是在什么地方拍摄的?"
52
+ - "图片中的人物在做什么?他们的表情如何?"
53
+
54
+ ## 技术栈
55
+
56
+ - **模型**: Step-3 / Step-r1-v-mini
57
+ - **框架**: Gradio 4.19.2
58
+ - **API**: OpenAI Python SDK (兼容 Step API)
59
+
60
+ ## 注意事项
61
+
62
+ - 请确保图片清晰度足够
63
+ - 提示词越具体,分析结果越准确
64
+ - API 密钥请妥善保管,不要公开分享
65
+
66
+ ## 许可证
67
+
68
+ MIT License
69
+
70
+ ## 致谢
71
+
72
+ - [阶跃星辰](https://www.stepfun.com/) - 提供强大的 AI 模型
73
+ - [Gradio](https://gradio.app/) - 提供优秀的 Web UI 框架
74
+ - [Hugging Face](https://huggingface.co/) - 提供免费的部署平台
app.py CHANGED
@@ -1,240 +1,273 @@
1
- import os
2
- import io
3
- import base64
4
  import gradio as gr
5
- from PIL import Image
 
6
  from openai import OpenAI
 
 
 
7
 
8
  # 配置
9
  BASE_URL = "https://api.stepfun.com/v1"
10
- DEFAULT_MODEL = "step-3" # 可选: step-3, step-r1-v-mini
 
11
 
12
- def get_api_key():
13
- """获取API密钥"""
14
- api_key = os.environ.get("STEPFUN_API_KEY")
15
- if not api_key:
16
- raise ValueError("请设置环境变量 STEPFUN_API_KEY")
17
- return api_key
18
 
19
  def image_to_base64(image):
20
- """将PIL图像转换为base64编码"""
21
  if image is None:
22
  return None
23
 
24
- # 转换为RGB格式
25
- if image.mode != 'RGB':
26
- image = image.convert('RGB')
 
 
 
27
 
28
- # 保存到字节流
29
- buffer = io.BytesIO()
30
- image.save(buffer, format='JPEG', quality=85)
31
-
32
- # 编码为base64
33
- img_str = base64.b64encode(buffer.getvalue()).decode('utf-8')
34
- return f"data:image/jpeg;base64,{img_str}"
35
 
36
- def chat_with_stepfun(message, image, history, model, system_prompt):
37
- """
38
- 处理聊天请求
39
-
40
- Args:
41
- message: 用户输入的文本
42
- image: 用户上传的图片 (PIL Image)
43
- history: 聊天历史
44
- model: 选择的模型
45
- system_prompt: 系统提示词
46
-
47
- Returns:
48
- 更新后的聊天历史
49
- """
50
  try:
51
- # 获取API密钥
52
- api_key = get_api_key()
53
- client = OpenAI(api_key=api_key, base_url=BASE_URL)
54
-
55
- # 构建消息列表
56
- messages = []
57
-
58
- # 添加系统提示
59
- if system_prompt and system_prompt.strip():
60
- messages.append({
61
- "role": "system",
62
- "content": system_prompt
63
- })
64
-
65
- # 添加历史对话
66
- for user_msg, assistant_msg in history:
67
- if user_msg:
68
- messages.append({
69
- "role": "user",
70
- "content": user_msg
71
- })
72
- if assistant_msg:
73
- messages.append({
74
- "role": "assistant",
75
- "content": assistant_msg
76
- })
77
-
78
- # 构建当前用户消息
79
- current_content = []
80
-
81
- # 添加图片
82
- if image is not None:
83
- img_base64 = image_to_base64(image)
84
- current_content.append({
85
- "type": "image_url",
86
- "image_url": {
87
- "url": img_base64,
88
- "detail": "high"
89
- }
90
- })
91
-
92
- # 添加文本
93
- if message and message.strip():
94
- current_content.append({
95
- "type": "text",
96
- "text": message
97
- })
98
-
99
- # 如果没有任何内容,返回
100
- if not current_content:
101
- return history
102
-
103
- # 添加当前消息
104
- messages.append({
105
  "role": "user",
106
- "content": current_content
107
- })
108
-
109
- # 调用API
110
- response = client.chat.completions.create(
111
- model=model,
112
- messages=messages,
113
- stream=True
114
- )
115
-
116
- # 处理流式响应
117
- full_response = ""
118
- for chunk in response:
119
- if chunk.choices[0].delta.content:
120
- full_response += chunk.choices[0].delta.content
121
- # 实时更新界面
122
- yield history + [(message, full_response)]
123
-
124
- # 返回最终结果
125
- yield history + [(message, full_response)]
 
 
 
 
 
126
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  except Exception as e:
128
- error_msg = f"错误: {str(e)}"
129
- yield history + [(message, error_msg)]
 
 
 
 
 
130
 
131
- def clear_chat():
132
- """清空聊天记录"""
133
- return None, None, []
 
 
 
134
 
135
  # 创建Gradio界面
136
- def create_interface():
137
- with gr.Blocks(title="StepFun 多模态对话") as demo:
 
 
 
 
 
 
 
 
 
 
 
 
 
138
  gr.Markdown("""
139
- # 🚀 StepFun Step-3 多模态对话
140
 
141
- 支持图片理解和文本对话,使用StepFun API。
142
-
143
- **使用说明:**
144
- 1. 在环境变量中设置 `STEPFUN_API_KEY`
145
- 2. 可选择上传图片进行视觉理解
146
- 3. 输入文本进行对话
147
  """)
148
-
149
- with gr.Row():
150
- with gr.Column(scale=3):
151
- # 聊天界面
152
- chatbot = gr.Chatbot(
153
- height=500,
154
- bubble_full_width=False,
155
- avatar_images=(None, None)
156
- )
157
-
158
- with gr.Row():
159
- with gr.Column(scale=3):
160
- msg = gr.Textbox(
161
- label="输入消息",
162
- placeholder="输入你的问题...",
163
- lines=2
164
- )
165
- with gr.Column(scale=1):
166
- img = gr.Image(
167
- label="上传图片(可选)",
168
- type="pil"
169
- )
170
-
171
- with gr.Row():
172
- submit = gr.Button("发送", variant="primary")
173
- clear = gr.Button("清空对话")
174
 
175
- with gr.Column(scale=1):
176
- # 设置面板
177
- model = gr.Dropdown(
178
- label="选择模型",
179
- choices=["step-3", "step-r1-v-mini"],
180
- value="step-3"
181
  )
182
 
183
- system_prompt = gr.Textbox(
184
- label="系统提示(可选)",
185
- placeholder="设置AI的角色或行为...",
186
- lines=3
 
 
187
  )
188
 
189
- gr.Markdown("""
190
- ### 说明
191
- - **step-3**: 标准多模态模型
192
- - **step-r1-v-mini**: 轻量级版本
 
 
 
193
 
194
- ### 提示
195
- - 支持中英文对话
196
- - 图片支持JPG/PNG格式
197
- - 可以询问图片内容
198
- """)
199
-
200
- # 事件绑定
201
- submit.click(
202
- fn=chat_with_stepfun,
203
- inputs=[msg, img, chatbot, model, system_prompt],
204
- outputs=[chatbot],
205
- queue=True
206
- ).then(
207
- lambda: (None, None),
208
- outputs=[msg, img]
209
- )
210
-
211
- msg.submit(
212
- fn=chat_with_stepfun,
213
- inputs=[msg, img, chatbot, model, system_prompt],
214
- outputs=[chatbot],
215
- queue=True
216
- ).then(
217
- lambda: (None, None),
218
- outputs=[msg, img]
219
- )
220
 
221
- clear.click(
222
- fn=clear_chat,
223
- outputs=[msg, img, chatbot]
224
- )
 
 
 
 
225
 
226
- return demo
227
-
228
- # 主程序
229
- if __name__ == "__main__":
230
- demo = create_interface()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
231
 
232
- # 获取端口
233
- port = int(os.environ.get("PORT", 7860))
 
 
 
 
 
 
234
 
235
- # 启动应用
236
- demo.launch(
237
- server_name="0.0.0.0",
238
- server_port=port,
239
- share=False
240
- )
 
 
 
 
 
 
 
 
 
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密钥(Hugging Face Spaces 推荐方式)
12
+ STEP_API_KEY = os.environ.get("STEP_API_KEY", "")
13
 
14
+ # 可选模型
15
+ MODELS = ["step-3", "step-r1-v-mini"]
 
 
 
 
16
 
17
  def image_to_base64(image):
18
+ """将PIL图像转换为base64字符串"""
19
  if image is None:
20
  return None
21
 
22
+ # 如果是PIL图像,直接处理
23
+ if isinstance(image, Image.Image):
24
+ buffered = BytesIO()
25
+ image.save(buffered, format="PNG")
26
+ img_str = base64.b64encode(buffered.getvalue()).decode()
27
+ return img_str
28
 
29
+ return None
 
 
 
 
 
 
30
 
31
+ def call_step_api(image, prompt, model, temperature=0.7, max_tokens=2000, stream_output=True):
32
+ """调用Step API进行图像分析和文本生成"""
33
+
34
+ if image is None:
35
+ return "❌ 请先上传一张图片"
36
+
37
+ if not prompt:
38
+ return "❌ 请输入提示词"
39
+
40
+ if not STEP_API_KEY:
41
+ return "❌ API密钥未配置。请在 Hugging Face Space 的 Settings 中添加 STEP_API_KEY 环境变量。"
42
+
43
+ # 转换图像为base64
 
44
  try:
45
+ base64_image = image_to_base64(image)
46
+ if base64_image is None:
47
+ return "❌ 图片处理失败"
48
+ except Exception as e:
49
+ return f"❌ 图片处理错误: {str(e)}"
50
+
51
+ # 构造消息
52
+ messages = [
53
+ {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  "role": "user",
55
+ "content": [
56
+ {
57
+ "type": "image_url",
58
+ "image_url": {
59
+ "url": f"data:image/png;base64,{base64_image}",
60
+ "detail": "high"
61
+ }
62
+ },
63
+ {
64
+ "type": "text",
65
+ "text": prompt
66
+ }
67
+ ]
68
+ }
69
+ ]
70
+
71
+ # 创建OpenAI客户端
72
+ try:
73
+ client = OpenAI(api_key=STEP_API_KEY, base_url=BASE_URL)
74
+ except Exception as e:
75
+ return f"❌ 客户端初始化失败: {str(e)}"
76
+
77
+ try:
78
+ # 记录开始时间
79
+ start_time = time.time()
80
 
81
+ if stream_output:
82
+ # 流式输出
83
+ response = client.chat.completions.create(
84
+ model=model,
85
+ messages=messages,
86
+ temperature=temperature,
87
+ max_tokens=max_tokens,
88
+ stream=True
89
+ )
90
+
91
+ full_response = ""
92
+ for chunk in response:
93
+ if chunk.choices and chunk.choices[0].delta:
94
+ delta = chunk.choices[0].delta
95
+
96
+ # 检查是否有内容
97
+ if hasattr(delta, 'content') and delta.content:
98
+ content = delta.content
99
+ full_response += content
100
+ yield content
101
+
102
+ # 显示生成时间
103
+ elapsed_time = time.time() - start_time
104
+ yield f"\n\n⏱️ 生成用时: {elapsed_time:.2f}秒"
105
+
106
+ else:
107
+ # 非流式输出
108
+ response = client.chat.completions.create(
109
+ model=model,
110
+ messages=messages,
111
+ temperature=temperature,
112
+ max_tokens=max_tokens,
113
+ stream=False
114
+ )
115
+
116
+ if response.choices and response.choices[0].message:
117
+ full_response = response.choices[0].message.content
118
+ elapsed_time = time.time() - start_time
119
+ yield f"{full_response}\n\n⏱️ 生成用时: {elapsed_time:.2f}秒"
120
+ else:
121
+ yield "❌ API返回空响应"
122
+
123
  except Exception as e:
124
+ error_msg = str(e)
125
+ if "api_key" in error_msg.lower():
126
+ yield "❌ API密钥错误:请检查密钥是否有效"
127
+ elif "network" in error_msg.lower() or "connection" in error_msg.lower():
128
+ yield "❌ 网络连接错误:请检查网络连接"
129
+ else:
130
+ yield f"❌ API调用错误: {error_msg[:200]}"
131
 
132
+ def process_image_and_prompt(image, prompt, model, temperature, max_tokens, stream_output):
133
+ """处理图像和提示词的主函数"""
134
+ output = ""
135
+ for chunk in call_step_api(image, prompt, model, temperature, max_tokens, stream_output):
136
+ output = chunk
137
+ yield output
138
 
139
  # 创建Gradio界面
140
+ with gr.Blocks(title="Step-3 图像理解助手", theme=gr.themes.Soft()) as demo:
141
+ gr.Markdown("""
142
+ # 🤖 Step-3 图像理解助手
143
+
144
+ 基于阶跃星辰 Step-3 模型的图像理解和分析工具。上传图片并输入提示词,让AI帮你分析图像内容。
145
+
146
+ ### 功能特点:
147
+ - 🖼️ 支持多种图片格式上传
148
+ - 💬 自然语言交互
149
+ - 🔄 实时流式输出
150
+ - 🧠 深度推理能力
151
+ """)
152
+
153
+ # API密钥状态提示
154
+ if not STEP_API_KEY:
155
  gr.Markdown("""
156
+ ⚠️ **注意:API密钥未配置**
157
 
158
+ 请在 Hugging Face Space 的 Settings 中添加 Secret:
159
+ - Name: `STEP_API_KEY`
160
+ - Value: 你的阶跃星辰 API 密钥
 
 
 
161
  """)
162
+
163
+ with gr.Row():
164
+ with gr.Column(scale=1):
165
+ # 输入区域
166
+ image_input = gr.Image(
167
+ label="上传图片",
168
+ type="pil",
169
+ height=300
170
+ )
171
+
172
+ prompt_input = gr.Textbox(
173
+ label="提示词",
174
+ placeholder="例如:帮我看看这是什么菜,如何制作?",
175
+ lines=3,
176
+ value="帮我详细描述这张图片的内容。"
177
+ )
 
 
 
 
 
 
 
 
 
 
178
 
179
+ with gr.Accordion("高级设置", open=False):
180
+ model_select = gr.Dropdown(
181
+ choices=MODELS,
182
+ value=MODELS[0],
183
+ label="选择模型"
 
184
  )
185
 
186
+ temperature_slider = gr.Slider(
187
+ minimum=0,
188
+ maximum=1,
189
+ value=0.7,
190
+ step=0.1,
191
+ label="Temperature (创造性)"
192
  )
193
 
194
+ max_tokens_slider = gr.Slider(
195
+ minimum=100,
196
+ maximum=4000,
197
+ value=2000,
198
+ step=100,
199
+ label="最大输出长度"
200
+ )
201
 
202
+ stream_checkbox = gr.Checkbox(
203
+ value=True,
204
+ label="流式输出"
205
+ )
206
+
207
+ submit_btn = gr.Button("🚀 开始分析", variant="primary")
208
+ clear_btn = gr.Button("🗑️ 清空", variant="secondary")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
209
 
210
+ with gr.Column(scale=1):
211
+ # 输出区域
212
+ output_text = gr.Textbox(
213
+ label="分析结果",
214
+ lines=20,
215
+ max_lines=30,
216
+ show_copy_button=True
217
+ )
218
 
219
+ # 示例(仅提供提示词示例)
220
+ gr.Examples(
221
+ examples=[
222
+ ["这张图片中有什么内容?请详细描述。", "step-3"],
223
+ ["帮我看看这是什么菜,如何制作?", "step-3"],
224
+ ["分析这张图片的构图和色彩运用。", "step-3"],
225
+ ["这张图片可能是在什么地方拍摄的?", "step-3"],
226
+ ["图片中的人物在做什么?他们的表情如何?", "step-3"],
227
+ ["这个产品的设计有什么特点?", "step-3"],
228
+ ],
229
+ inputs=[prompt_input, model_select],
230
+ label="提示词示例(请先上传图片)"
231
+ )
232
+
233
+ # 事件处理
234
+ submit_btn.click(
235
+ fn=process_image_and_prompt,
236
+ inputs=[
237
+ image_input,
238
+ prompt_input,
239
+ model_select,
240
+ temperature_slider,
241
+ max_tokens_slider,
242
+ stream_checkbox
243
+ ],
244
+ outputs=output_text,
245
+ show_progress=True
246
+ )
247
+
248
+ clear_btn.click(
249
+ fn=lambda: (None, "", ""),
250
+ inputs=[],
251
+ outputs=[image_input, prompt_input, output_text]
252
+ )
253
 
254
+ # 页脚
255
+ gr.Markdown("""
256
+ ---
257
+ ### 使用说明:
258
+ 1. 上传一张图片(支持 JPG、PNG 等格式)
259
+ 2. 输入你的问题或分析需求
260
+ 3. 点击"开始分析"按钮
261
+ 4. 等待AI返回分析结果
262
 
263
+ ### 注意事项:
264
+ - 请确保图片清晰度足够
265
+ - 提示词越具体,分析结果越准确
266
+ - 可以在高级设置中调整模型参数
267
+
268
+ Powered by [阶跃星辰 Step-3](https://www.stepfun.com/)
269
+ """)
270
+
271
+ # 启动应用 - Hugging Face Spaces 会自动调用
272
+ if __name__ == "__main__":
273
+ demo.launch()
requirements.txt CHANGED
@@ -1,3 +1,4 @@
1
- gradio==3.50.2
2
- openai>=1.0.0
3
- Pillow>=9.0.0
 
 
1
+ gradio==4.19.2
2
+ openai==1.12.0
3
+ Pillow==10.2.0
4
+ python-dotenv==1.0.1