Skip to main content

openui-forge-python

OpenUI generative UI with Python FastAPI backend. OpenAI and Anthropic SDK variants.

Informations de source

Dépôt
OthmanAdi/openui-forge
Dernière activité de la source
20 juin 2026 à 02:24
Langue détectée de SKILL.md
anglais
Étoiles
24
Forks
1

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
openui-forge-python
description
OpenUI generative UI with Python FastAPI backend. OpenAI and Anthropic SDK variants.
version
1.2.0
author
OthmanAdi
# OpenUI Forge — Python Build generative UI apps with a React frontend + Python FastAPI backend. Streams OpenAI-compatible NDJSON. ## Activation Triggers - "openui python", "openui fastapi", "openui flask" - "generative ui python", "python streaming ui backend" ## Prerequisites - Node.js >= 22 (24 LTS recommended) + React >= 18.3.1 (19+ recommended) (frontend) - Python >= 3.10 (backend) - `OPENAI_API_KEY` or `ANTHROPIC_API_KEY` set ## Quick Start 1. Create the React frontend and install OpenUI deps: ```bash npm install @openuidev/react-ui @openuidev/react-headless @openuidev/react-lang lucide-react zod ``` 2. Generate the system prompt from your component library: ```bash npx @openuidev/cli generate ./src/lib/library.ts --out backend/system-prompt.txt ``` 3. Set up the Python backend (see Full Code below) 4. Run both: frontend on `:3000`, backend on `:8000` ## Full Code ### Backend: `backend/requirements.txt` ``` fastapi>=0.115.0 uvicorn>=0.24.0 openai>=2.0 anthropic>=0.111.0 python-dotenv>=1.0.0 ``` > The Python >= 3.10 floor comes from fastapi/uvicorn/python-dotenv; openai and anthropic themselves need only Python 3.9. ### Backend (OpenAI): `backend/main.py` ```python import 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 (Anthropic variant): `backend/main_anthropic.py` ```python import 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") ``` ### Frontend: `app/chat/page.tsx` (or `src/Chat.tsx` for Vite) ```tsx "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 with `openAIAdapter()` on the frontend. `openAIReadableStreamAdapter()` is for NDJSON (no `data:` prefix) and will silently produce no output here. ## System Prompt Generation Generate once, copy to backend directory: ```bash npx @openuidev/cli generate ./src/lib/library.ts --out backend/system-prompt.txt ``` Regenerate after every component change. ## Validation Checklist - [ ] `system-prompt.txt` exists in the backend directory - [ ] CORS allows the frontend origin - [ ] Backend streams `data: {json}\n\n` lines with OpenAI chunk format - [ ] Final chunk has `finish_reason: "stop"` followed by `data: [DONE]` - [ ] Frontend `apiUrl` points to the correct backend URL - [ ] Frontend uses `streamProtocol={openAIAdapter()}` and `openAIMessageFormat` - [ ] `componentLibrary={openuiChatLibrary}` prop passed to `FullScreen` - [ ] CSS import in root layout (`@openuidev/react-ui/components.css`) - [ ] Run backend: `uvicorn main:app --reload --port 8000` ## Error Patterns | 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: [...] }` |
Voir sur GitHub