Spaces:
Running
Running
File size: 5,116 Bytes
8987e34 79cceb8 8987e34 65038dc 8987e34 61119fe 65038dc 61119fe 8987e34 abaf7bb 8987e34 d3eab6a 8987e34 d3eab6a 79cceb8 8987e34 79cceb8 d3eab6a 8987e34 d3eab6a 65038dc 8987e34 d3eab6a 8987e34 d3eab6a 8987e34 79cceb8 8987e34 79cceb8 8987e34 d3eab6a 8987e34 d3eab6a 8987e34 d3eab6a 8987e34 d3eab6a 8987e34 abaf7bb 8987e34 d3eab6a 8987e34 d3eab6a 8987e34 79cceb8 8987e34 79cceb8 8987e34 61119fe 8987e34 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
# app.py
import os
import io
import base64
from typing import List, Dict, Any, Optional
import httpx
import gradio as gr
from PIL import Image
# ====== 配置(可用环境变量覆写)======
STEPFUN_ENDPOINT = os.getenv("STEPFUN_ENDPOINT", "https://api.stepfun.com/v1")
MODEL_NAME = os.getenv("STEPFUN_MODEL", "step-3") # 也可填 step-r1-v-mini
REQUEST_TIMEOUT = float(os.getenv("REQUEST_TIMEOUT", "60"))
# ===================================
def _get_api_key() -> Optional[str]:
"""
优先读 OPENAI_API_KEY(与 OpenAI 兼容),否则读 STEPFUN_KEY。
在 HF Space: Settings → Variables and secrets 添加其中一个即可。
"""
return os.getenv("OPENAI_API_KEY") or os.getenv("STEPFUN_KEY")
def _pil_to_data_url(img: Image.Image, fmt: str = "PNG") -> str:
"""
PIL -> data:image/...;base64,... 字符串(适配 OpenAI 兼容的 image_url 输入)
"""
buf = io.BytesIO()
img.save(buf, format=fmt)
b64 = base64.b64encode(buf.getvalue()).decode("utf-8")
mime = "image/png" if fmt.upper() == "PNG" else "image/jpeg"
return f"data:{mime};base64,{b64}"
def _post_chat(messages: List[Dict[str, Any]], temperature: float = 0.7, max_tokens: Optional[int] = None) -> str:
"""
直接请求 StepFun 的 /v1/chat/completions(OpenAI 兼容)。
返回纯字符串,避免 Gradio schema 问题。
"""
api_key = _get_api_key()
if not api_key:
raise RuntimeError(
"未检测到 API Key。请到 Space 的 Settings → Variables and secrets 添加:\n"
" OPENAI_API_KEY=你的 StepFun API Key (或使用 STEPFUN_KEY)"
)
url = f"{STEPFUN_ENDPOINT.rstrip('/')}/chat/completions"
headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json",
}
payload: Dict[str, Any] = {
"model": MODEL_NAME,
"messages": messages,
"temperature": temperature,
# StepFun 多数情况下无需强制 max_tokens;需要时再放开
}
if max_tokens is not None:
payload["max_tokens"] = max_tokens
with httpx.Client(timeout=REQUEST_TIMEOUT) as client:
resp = client.post(url, headers=headers, json=payload)
# 让 httpx 抛出更清晰的错误
resp.raise_for_status()
data = resp.json()
# 标准 OpenAI 兼容返回
try:
return str(data["choices"][0]["message"]["content"])
except Exception:
# 返回原始数据便于诊断
return f"[WARN] 无法解析返回格式:{data}"
def chat_with_step3(image: Optional[Image.Image], question: str, temperature: float) -> str:
"""
Gradio 的回调函数:接收 PIL 图片与文本,返回字符串。
"""
if image is None and not question.strip():
return "请上传一张图片,或至少输入一个问题。"
# 构造 messages(支持纯文本、纯图像,或图文混合)
content: List[Dict[str, Any]] = []
if image is not None:
data_url = _pil_to_data_url(image, fmt="PNG")
content.append({"type": "image_url", "image_url": {"url": data_url}})
if question.strip():
content.append({"type": "text", "text": question.strip()})
else:
content.append({"type": "text", "text": "请描述这张图片。"}) # 默认问题
messages = [{"role": "user", "content": content}]
try:
return _post_chat(messages, temperature=temperature)
except httpx.HTTPStatusError as e:
# 返回服务端 HTTP 错误 + 文本体,便于排查
try:
detail = e.response.text
except Exception:
detail = repr(e)
return f"[HTTP {e.response.status_code}] 接口错误:{detail}"
except Exception as e:
return f"调用失败:{e!r}"
# ================ Gradio UI ================
with gr.Blocks(title="Step3 (StepFun API Demo)") as demo:
gr.Markdown(
"""
# Step3 · 图文对话演示(StepFun OpenAI 兼容接口)
- 在 **Settings → Variables and secrets** 添加 `OPENAI_API_KEY`(或 `STEPFUN_KEY`)后即可使用
- 后端直连 `https://api.stepfun.com/v1/chat/completions`,不依赖 `openai` SDK
"""
)
with gr.Row():
image = gr.Image(type="pil", label="上传图片(可选)")
question = gr.Textbox(label="问题", placeholder="例如:帮我看看这是什么菜,怎么做?")
temperature = gr.Slider(0.0, 1.5, value=0.7, step=0.1, label="Temperature")
submit = gr.Button("提交", variant="primary")
output = gr.Textbox(label="模型回答", lines=8)
submit.click(fn=chat_with_step3, inputs=[image, question, temperature], outputs=[output])
gr.Markdown(
"""
**提示:**
- 如果看到 `调用失败:RuntimeError('未检测到 API Key')`,请检查 Space 的 Secrets
- 如需改模型:设置环境变量 `STEPFUN_MODEL`,或在代码顶部修改默认值
"""
)
if __name__ == "__main__":
# HF Space 环境会自动执行;本地运行也 OK
demo.launch()
|