with one click
openui-forge-python
// OpenUI generative UI with Python FastAPI backend. OpenAI and Anthropic SDK variants.
// OpenUI generative UI with Python FastAPI backend. OpenAI and Anthropic SDK variants.
| name | openui-forge-python |
| description | OpenUI generative UI with Python FastAPI backend. OpenAI and Anthropic SDK variants. |
| version | 1.0.0 |
| author | OthmanAdi |
Build generative UI apps with a React frontend + Python FastAPI backend. Streams OpenAI-compatible NDJSON.
OPENAI_API_KEY or ANTHROPIC_API_KEY setnpm install @openuidev/react-ui @openuidev/react-headless @openuidev/react-lang lucide-react zod
npx @openuidev/cli generate ./src/lib/library.ts --out backend/system-prompt.txt
:3000, backend on :8000backend/requirements.txtfastapi>=0.104.0
uvicorn>=0.24.0
openai>=1.6.0
anthropic>=0.40.0
python-dotenv>=1.0.0
backend/main.pyimport os
from pathlib import Path
from dotenv import load_dotenv
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import StreamingResponse
from openai import AsyncOpenAI
load_dotenv()
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:3000"],
allow_methods=["POST"],
allow_headers=["*"],
)
# AsyncOpenAI keeps the request from blocking the event loop during streaming.
client = AsyncOpenAI()
SYSTEM_PROMPT = Path("system-prompt.txt").read_text()
@app.post("/api/chat")
async def chat(request: Request):
body = await request.json()
messages = [{"role": "system", "content": SYSTEM_PROMPT}] + body["messages"]
async def generate():
response = await client.chat.completions.create(
model=os.getenv("OPENAI_MODEL", "gpt-5.5"),
stream=True,
messages=messages,
)
async for chunk in response:
data = chunk.model_dump_json()
yield f"data: {data}\n\n"
yield "data: [DONE]\n\n"
return StreamingResponse(generate(), media_type="text/event-stream")
backend/main_anthropic.pyimport os, json, time
from pathlib import Path
from dotenv import load_dotenv
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import StreamingResponse
from anthropic import AsyncAnthropic
load_dotenv()
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:3000"],
allow_methods=["POST"],
allow_headers=["*"],
)
# AsyncAnthropic mirrors AsyncOpenAI so the stream does not block the loop.
client = AsyncAnthropic()
SYSTEM_PROMPT = Path("system-prompt.txt").read_text()
@app.post("/api/chat")
async def chat(request: Request):
body = await request.json()
stream_id = f"chatcmpl-{int(time.time())}"
async def generate():
async with client.messages.stream(
model=os.getenv("ANTHROPIC_MODEL", "claude-sonnet-4-6"),
max_tokens=4096,
system=SYSTEM_PROMPT,
messages=body["messages"],
) as stream:
async for text in stream.text_stream:
chunk = {"id": stream_id, "object": "chat.completion.chunk",
"choices": [{"index": 0, "delta": {"content": text}, "finish_reason": None}]}
yield f"data: {json.dumps(chunk)}\n\n"
done = {"id": stream_id, "object": "chat.completion.chunk",
"choices": [{"index": 0, "delta": {}, "finish_reason": "stop"}]}
yield f"data: {json.dumps(done)}\n\n"
yield "data: [DONE]\n\n"
return StreamingResponse(generate(), media_type="text/event-stream")
app/chat/page.tsx (or src/Chat.tsx for Vite)"use client";
import { FullScreen } from "@openuidev/react-ui";
import { openuiChatLibrary } from "@openuidev/react-ui/genui-lib";
import {
openAIAdapter,
openAIMessageFormat,
} from "@openuidev/react-headless";
export default function ChatPage() {
return (
<FullScreen
componentLibrary={openuiChatLibrary}
streamProtocol={openAIAdapter()}
messageFormat={openAIMessageFormat}
apiUrl="http://localhost:8000/api/chat"
/>
);
}
The Python backend emits SSE (
data: {json}\n\n). Pair it withopenAIAdapter()on the frontend.openAIReadableStreamAdapter()is for NDJSON (nodata:prefix) and will silently produce no output here.
Generate once, copy to backend directory:
npx @openuidev/cli generate ./src/lib/library.ts --out backend/system-prompt.txt
Regenerate after every component change.
system-prompt.txt exists in the backend directorydata: {json}\n\n lines with OpenAI chunk formatfinish_reason: "stop" followed by data: [DONE]apiUrl points to the correct backend URLstreamProtocol={openAIAdapter()} and openAIMessageFormatcomponentLibrary={openuiChatLibrary} prop passed to FullScreen@openuidev/react-ui/components.css)uvicorn main:app --reload --port 8000| Error | Cause | Fix |
|---|---|---|
| CORS blocked | Frontend origin not allowed | Add origin to allow_origins list |
| Connection refused | Backend not running | Start with uvicorn main:app --port 8000 |
| FileNotFoundError | system-prompt.txt missing | Run the CLI generate command |
| Stream not rendering | Backend not sending SSE format | Ensure data: prefix and \n\n after each chunk |
| 422 Unprocessable Entity | Request body missing messages | Check frontend sends { messages: [...] } |
OpenUI generative UI with Anthropic Claude SDK backend. Stream conversion to OpenAI NDJSON format.
OpenUI generative UI with Go (net/http) backend. Direct OpenAI API streaming via HTTP.
OpenUI generative UI with LangChain/LangGraph backend. Supports ChatOpenAI and ChatAnthropic.
OpenUI generative UI with OpenAI SDK backend. Streaming chat completions with gpt-5.5 (or any current OpenAI-compatible model).
OpenUI generative UI with Rust Axum backend. Async SSE streaming with reqwest and async-stream.
Build generative UI with OpenUI — any LLM provider, any backend language. Scaffold, integrate, validate.