Spaces:
Runtime error
Runtime 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,
|