Skip to content
cccskills
FreePublished on GitHub

openui-forge-python

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

The English summary is being prepared. Showing the original description.

Works withOpenAI
See how to install

Files included (1)

  • SKILL.md6.1 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

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:
npm install @openuidev/react-ui @openuidev/react-headless @openuidev/react-lang lucide-react zod
  1. Generate the system prompt from your component library:
npx @openuidev/cli generate ./src/lib/library.ts --out backend/system-prompt.txt
  1. Set up the Python backend (see Full Code below)
  2. 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

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

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)

"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:

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

ErrorCauseFix
CORS blockedFrontend origin not allowedAdd origin to allow_origins list
Connection refusedBackend not runningStart with uvicorn main:app --port 8000
FileNotFoundErrorsystem-prompt.txt missingRun the CLI generate command
Stream not renderingBackend not sending SSE formatEnsure data: prefix and \n\n after each chunk
422 Unprocessable EntityRequest body missing messagesCheck frontend sends { messages: [...] }

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

Build generative UI with OpenUI — any LLM provider, any backend language. Scaffold, integrate, validate.

The English summary is being prepared. Showing the original description.

OthmanAdi/openui-forge22Updated Aug 3, 2026

OpenUI generative UI with Anthropic Claude SDK backend. Stream conversion to OpenAI NDJSON format.

The English summary is being prepared. Showing the original description.

OthmanAdi/openui-forge22Updated Aug 3, 2026

OpenUI generative UI with C# ASP.NET Core Minimal API backend. Direct OpenAI API SSE streaming via HttpClient on .NET 10.

The English summary is being prepared. Showing the original description.

OthmanAdi/openui-forge22Updated Aug 3, 2026

OpenUI generative UI with Elixir Phoenix backend. Chunked SSE streaming via Plug.Conn and Req.

The English summary is being prepared. Showing the original description.

OthmanAdi/openui-forge22Updated Aug 3, 2026

OpenUI generative UI with Go (net/http) backend. Direct OpenAI API streaming via HTTP.

The English summary is being prepared. Showing the original description.

OthmanAdi/openui-forge22Updated Aug 3, 2026

OpenUI generative UI with a Java Spring Boot (WebFlux) backend. Streams the OpenAI API directly via WebClient as SSE.

The English summary is being prepared. Showing the original description.

OthmanAdi/openui-forge22Updated Aug 3, 2026

See all skills by OthmanAdi

Report a problem with this skill