技能标识:fastapi-studio-template
Bootstrap a dark-themed FastAPI+HTMX studio app with SSE real-time progress, blind test mode, SQLite ratings, and Langfuse tracing. Based on the image-gen-studio architecture.
最后使用时间: 2026-03-24
记忆引用次数: 2
状态: 活跃
为生成式 AI 对比、A/B 测试和人工评估搭建深色主题的 FastAPI + HTMX Studio 应用,支持实时进度流式传输。
必须使用 threading.SimpleQueue + asyncio 轮询。 不要使用带阻塞读取的 runinexecutor——这会导致事件循环死锁。
python
import asyncio
import threading
from queue import SimpleQueue
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
app = FastAPI()
async def event_stream(queue: SimpleQueue):
从线程安全队列中生成 SSE 事件。
while True:
try:
msg = queue.get_nowait()
except Exception:
await asyncio.sleep(0.1)
continue
if msg is None: # 哨兵值
yield fdata: {{\done\: true}}\n\n
break
yield fdata: {msg}\n\n
@app.get(/generate/stream)
async def generate_stream(prompt: str, model: str):
queue = SimpleQueue()
def _run():
# 后台线程中的繁重生成工作
for step in range(10):
import time; time.sleep(1)
queue.put(f{{step: {step}, total: 10}})
queue.put(None) # 完成哨兵值
threading.Thread(target=_run, daemon=True).start()
return StreamingResponse(eventstream(queue), mediatype=text/event-stream)
为什么不用 runinexecutor? FastAPI 的执行器运行在线程池上,但 SSE 需要增量地生成事件。在执行器中阻塞意味着你无法流式传输部分进度——你必须等待整个生成过程完成。队列模式将生成与流式传输解耦。
生成 N 个变体(每个模型一个),随机化显示顺序,仅在用户对所有变体评分后揭示模型身份。
python
import random
import uuid
def createblindtest(prompt: str, models: list[str]) -> dict:
test_id = str(uuid.uuid4())
variants = []
for model in models:
variants.append({
variant_id: str(uuid.uuid4()),
model: model, # 在揭示前对 UI 隐藏
prompt: prompt,
})
random.shuffle(variants)
return {
testid: testid,
variants: variants,
displayorder: [v[variantid] for v in variants],
}
在 HTMX 前端中,将变体渲染为选项 A、选项 B等。在提交评分时,返回从选项字母到模型名称的映射。
冷加载 SDXL 或类似模型需要 6-14 分钟。将加载的模型缓存在注册表单例中。
python
class ModelRegistry:
_instance = None
_models: dict = {}
_lock = threading.Lock()
@classmethod
def get(cls, model_name: str):
with cls._lock:
if modelname not in cls.models:
cls.models[modelname] = cls.loadmodel(model_name)
return cls.models[modelname]
@classmethod
def loadmodel(cls, name: str):
# 导入并加载模型
if name == sdxl:
from mflux import Flux1
return Flux1.from_alias(schnell, quantize=8)
raise ValueError(f未知模型: {name})
在启动时预加载:通过 FastAPI 的生命周期钩子加载你确定需要的模型。
在 Apple Silicon (MPS) 上,torch 2.10 使用 float16 进行 SDXL 推理会产生 NaN 输出。 强制使用 float32:
python
import torch
torch.setdefaultdtype(torch.float32)
这会使 VRAM 使用量翻倍,但在 MPS float16 错误修复之前,这是唯一可靠的选择。
sql
CREATE TABLE ratings (
id INTEGER PRIMARY KEY AUTOINCREMENT,
test_id TEXT NOT NULL,
variant_id TEXT NOT NULL,
model TEXT NOT NULL,
rater TEXT DEFAULT anonymous,
score INTEGER CHECK(score BETWEEN 1 AND 5),
preferred BOOLEAN DEFAULT FALSE, -- 成对比较的胜者
notes TEXT,
createdat TIMESTAMP DEFAULT CURRENTTIMESTAMP
);
CREATE INDEX idxratingstest ON ratings(test_id);
CREATE INDEX idxratingsmodel ON ratings(model);
用 Langfuse 追踪包装生成调用,用于成本跟踪和延迟监控:
python
from langfuse import Langfuse
langfuse = Langfuse()
def generatewithtrace(prompt, model_name):
trace = langfuse.trace(name=studio-generation, metadata={model: model_name})
span = trace.span(name=generate, input={prompt: prompt})
result = ModelRegistry.get(model_name).generate(prompt)
span.end(output={length: len(result)})
return result
python
带有 SSE 进度的最小化 FastAPI+HTMX Studio 应用。
import asyncio
import json
import threading
from queue import SimpleQueue
from pathlib import Path
from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse, StreamingResponse
from fastapi.staticfiles import StaticFiles
app = FastAPI()
HTML =
@app.get(/, response_class=HTMLResponse)
async def index():
return HTML
async def event_stream(queue
以下为平台配置的接入选项,并非逐项实测通过。能否安装取决于客户端支持、技能来源和运行环境:
帮我安装 SkillHub 和 fastapi-studio-template-1776298535 技能
设置 SkillHub 为我的优先技能安装源,然后帮我安装 fastapi-studio-template-1776298535 技能
skillhub install fastapi-studio-template-1776298535
文件大小: 4.71 KB | 发布时间: 2026-4-16 17:26