Spaces:
Build error
Build error
Upload app.py
Browse files
app.py
CHANGED
@@ -3,7 +3,7 @@ import os
|
|
3 |
import base64
|
4 |
import gradio as gr
|
5 |
from PIL import Image
|
6 |
-
|
7 |
|
8 |
# ------- 配置区 -------
|
9 |
# 推荐在 HF Space 的 Settings - Variables and secrets 里设置:
|
@@ -11,46 +11,67 @@ from openai import OpenAI
|
|
11 |
# 如果前台定义变量 (比如 STEPFUN_KEY),下面会依然被读取。
|
12 |
STEPFUN_ENDPOINT = "https://api.stepfun.com/v1"
|
13 |
MODEL_NAME = "step-3"
|
14 |
-
|
15 |
# --------------------
|
16 |
|
17 |
def _get_api_key() -> str:
|
18 |
-
"""
|
19 |
-
|
|
|
|
|
|
|
20 |
return os.getenv("OPENAI_API_KEY") or os.getenv("STEPFUN_KEY")
|
21 |
|
22 |
-
|
23 |
def _pil_to_data_url(img: Image.Image, fmt: str = "PNG") -> str:
|
24 |
-
"""
|
|
|
|
|
|
|
|
|
25 |
buf = io.BytesIO()
|
26 |
img.save(buf, format=fmt)
|
27 |
b64 = base64.b64encode(buf.getvalue()).decode("utf-8")
|
28 |
mime = "image/png" if fmt.upper() == "PNG" else "image/jpeg"
|
29 |
return f"data:{mime};base64,{b64}"
|
30 |
|
31 |
-
|
32 |
-
|
|
|
|
|
|
|
|
|
|
|
33 |
key = _get_api_key()
|
34 |
if not key:
|
35 |
raise RuntimeError(
|
36 |
"API Key 未设置\n请到 Space 的 Settings - Variables and secrets 添加:\n"
|
37 |
"Name=OPENAI_API_KEY, Value=你的 StepFun API Key(或用 STEPFUN_KEY 也可)。"
|
38 |
)
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
45 |
|
46 |
def chat_with_step3(image: Image.Image, question: str) -> str:
|
47 |
-
"""
|
|
|
|
|
|
|
|
|
|
|
48 |
if image is None:
|
49 |
return "请先上传图片。"
|
50 |
if not question:
|
51 |
question = "请描述这张图片。"
|
52 |
-
|
53 |
-
# 将 PIL 图片转成 Data URL,传到 StepFun
|
54 |
data_url = _pil_to_data_url(image, fmt="PNG")
|
55 |
messages = [
|
56 |
{
|
@@ -62,17 +83,10 @@ def chat_with_step3(image: Image.Image, question: str) -> str:
|
|
62 |
},
|
63 |
]
|
64 |
try:
|
65 |
-
|
66 |
-
resp = client.chat.completions.create(
|
67 |
-
model=MODEL_NAME,
|
68 |
-
messages=messages,
|
69 |
-
)
|
70 |
-
return resp.choices[0].message.content
|
71 |
except Exception as e:
|
72 |
-
# 返回异常信息,方便调试
|
73 |
return f"调用失败: {e!r}"
|
74 |
|
75 |
-
|
76 |
# 构建 Gradio 界面
|
77 |
iface = gr.Interface(
|
78 |
fn=chat_with_step3,
|
|
|
3 |
import base64
|
4 |
import gradio as gr
|
5 |
from PIL import Image
|
6 |
+
import httpx # Use httpx for direct API calls instead of openai SDK
|
7 |
|
8 |
# ------- 配置区 -------
|
9 |
# 推荐在 HF Space 的 Settings - Variables and secrets 里设置:
|
|
|
11 |
# 如果前台定义变量 (比如 STEPFUN_KEY),下面会依然被读取。
|
12 |
STEPFUN_ENDPOINT = "https://api.stepfun.com/v1"
|
13 |
MODEL_NAME = "step-3"
|
|
|
14 |
# --------------------
|
15 |
|
16 |
def _get_api_key() -> str:
|
17 |
+
"""
|
18 |
+
获取 API KEY,如果没有设置则返回 None。
|
19 |
+
首先尝试读取环境变量 OPENAI_API_KEY(OpenAI SDK 的默认约定),
|
20 |
+
如果不存在再尝试读取 STEPFUN_KEY。
|
21 |
+
"""
|
22 |
return os.getenv("OPENAI_API_KEY") or os.getenv("STEPFUN_KEY")
|
23 |
|
|
|
24 |
def _pil_to_data_url(img: Image.Image, fmt: str = "PNG") -> str:
|
25 |
+
"""
|
26 |
+
将 PIL 图片转换成 base64 Data URL。
|
27 |
+
接收一个 PIL.Image 对象和输出格式(默认为 PNG),
|
28 |
+
返回可用于 StepFun OpenAI 兼容接口的 data:image/...;base64,... 字符串。
|
29 |
+
"""
|
30 |
buf = io.BytesIO()
|
31 |
img.save(buf, format=fmt)
|
32 |
b64 = base64.b64encode(buf.getvalue()).decode("utf-8")
|
33 |
mime = "image/png" if fmt.upper() == "PNG" else "image/jpeg"
|
34 |
return f"data:{mime};base64,{b64}"
|
35 |
|
36 |
+
def _post_chat(messages: list, temperature: float = 0.7) -> str:
|
37 |
+
"""
|
38 |
+
调用 StepFun 的 chat/completions 接口并返回模型回复。
|
39 |
+
使用 httpx 库向 StepFun 的 OpenAI 兼容接口发送请求,
|
40 |
+
避免使用 openai SDK 导致的 "No API found" 错误。
|
41 |
+
messages 参数应符合 OpenAI 接口规范。
|
42 |
+
"""
|
43 |
key = _get_api_key()
|
44 |
if not key:
|
45 |
raise RuntimeError(
|
46 |
"API Key 未设置\n请到 Space 的 Settings - Variables and secrets 添加:\n"
|
47 |
"Name=OPENAI_API_KEY, Value=你的 StepFun API Key(或用 STEPFUN_KEY 也可)。"
|
48 |
)
|
49 |
+
url = f"{STEPFUN_ENDPOINT}/chat/completions"
|
50 |
+
headers = {
|
51 |
+
"Authorization": f"Bearer {key}",
|
52 |
+
"Content-Type": "application/json",
|
53 |
+
}
|
54 |
+
payload = {
|
55 |
+
"model": MODEL_NAME,
|
56 |
+
"messages": messages,
|
57 |
+
"temperature": temperature,
|
58 |
+
}
|
59 |
+
resp = httpx.post(url, headers=headers, json=payload, timeout=60)
|
60 |
+
resp.raise_for_status()
|
61 |
+
data = resp.json()
|
62 |
+
return data["choices"][0]["message"]["content"]
|
63 |
|
64 |
def chat_with_step3(image: Image.Image, question: str) -> str:
|
65 |
+
"""
|
66 |
+
调用 StepFun 的 step-3 模型进行推理。
|
67 |
+
首先检查上传的图像和问题文本是否有效,将图像编码为 data URL,
|
68 |
+
构造符合 OpenAI 接口规范的 messages 数组,然后通过 `_post_chat` 发送请求。
|
69 |
+
如遇异常则返回错误信息。
|
70 |
+
"""
|
71 |
if image is None:
|
72 |
return "请先上传图片。"
|
73 |
if not question:
|
74 |
question = "请描述这张图片。"
|
|
|
|
|
75 |
data_url = _pil_to_data_url(image, fmt="PNG")
|
76 |
messages = [
|
77 |
{
|
|
|
83 |
},
|
84 |
]
|
85 |
try:
|
86 |
+
return _post_chat(messages)
|
|
|
|
|
|
|
|
|
|
|
87 |
except Exception as e:
|
|
|
88 |
return f"调用失败: {e!r}"
|
89 |
|
|
|
90 |
# 构建 Gradio 界面
|
91 |
iface = gr.Interface(
|
92 |
fn=chat_with_step3,
|