A zero-boilerplate framework for building interactive ChatGPT widgets
Project description
Floydr Framework
A zero-boilerplate framework for building interactive ChatGPT widgets
๐ Quick Start
1. Create Virtual Environment (Recommended)
python -m venv venv
source venv/bin/activate # macOS/Linux
venv\Scripts\activate # Windows
2. Install Floydr & Create Project
pip install floydr
floydr init my-widgets
This generates the complete project structure:
my-widgets/
โโโ server/
โ โโโ __init__.py
โ โโโ main.py # Auto-discovery server
โ โโโ tools/ # Widget backends
โ โ โโโ __init__.py
โ โโโ api/ # (optional) Shared APIs
โ โโโ __init__.py
โโโ widgets/ # Widget frontends (empty initially)
โโโ requirements.txt # Python dependencies
โโโ package.json # JavaScript dependencies
โโโ .gitignore
โโโ README.md
3. Install Dependencies
cd my-widgets
pip install -r requirements.txt
npm install
4. Create Your First Widget
floydr create greeting
This adds to your project:
my-widgets/
โโโ server/
โ โโโ tools/
โ โโโ greeting_tool.py # โ Generated: Widget backend
โโโ widgets/
โโโ greeting/
โโโ index.jsx # โ Generated: Widget frontend
5. Edit Your Widget Code
You only need to edit these 2 files:
server/tools/greeting_tool.py - Backend Logic
from floydr import BaseWidget, Field, ConfigDict
from pydantic import BaseModel
from typing import Dict, Any
class GreetingInput(BaseModel):
model_config = ConfigDict(populate_by_name=True)
name: str = Field(default="World")
class GreetingTool(BaseWidget):
identifier = "greeting"
title = "Greeting Widget"
input_schema = GreetingInput
invoking = "Preparing greeting..."
invoked = "Greeting ready!"
widget_csp = {
"connect_domains": [], # APIs you'll call
"resource_domains": [] # Images/fonts you'll use
}
async def execute(self, input_data: GreetingInput) -> Dict[str, Any]:
# Your logic here
return {
"name": input_data.name,
"message": f"Hello, {input_data.name}!"
}
widgets/greeting/index.jsx - Frontend UI
import React from 'react';
import { useWidgetProps } from 'chatjs-hooks';
export default function Greeting() {
const props = useWidgetProps();
return (
<div style={{
padding: '40px',
textAlign: 'center',
background: '#4A90E2',
color: 'white',
borderRadius: '12px'
}}>
<h1>๐ {props.message}</h1>
<p>Welcome, {props.name}!</p>
</div>
);
}
That's it! These are the only files you need to write.
6. Build and Run
# Build
npm run build
# Start server
python server/main.py
Your widget is now live at http://localhost:8001 ๐
๐ฆ What You Need to Know
Widget Structure
Every widget has exactly 2 files you write:
-
Python Tool (
server/tools/*_tool.py)- Define inputs with Pydantic
- Write your logic in
execute() - Return data as a dictionary
-
React Component (
widgets/*/index.jsx)- Get data with
useWidgetProps() - Render your UI
- Use inline styles
- Get data with
Everything else is automatic:
- โ Widget discovery
- โ Registration
- โ Build process
- โ Server setup
- โ Mounting logic
Input Schema
from floydr import Field, ConfigDict
from pydantic import BaseModel
class MyInput(BaseModel):
model_config = ConfigDict(populate_by_name=True)
name: str = Field(default="", description="User's name")
age: int = Field(default=0, ge=0, le=150)
email: str = Field(default="", pattern=r'^[\w\.-]+@[\w\.-]+\.\w+$')
CSP (Content Security Policy)
Allow external resources:
widget_csp = {
"connect_domains": ["https://api.example.com"], # For API calls
"resource_domains": ["https://cdn.example.com"] # For images/fonts
}
React Hooks
import { useWidgetProps, useWidgetState, useOpenAiGlobal } from 'chatjs-hooks';
function MyWidget() {
const props = useWidgetProps(); // Data from Python
const [state, setState] = useWidgetState({}); // Persistent state
const theme = useOpenAiGlobal('theme'); // ChatGPT theme
return <div>{props.message}</div>;
}
๐ Documentation
- Quick Start Guide - Detailed setup instructions
- Tutorial - Step-by-step widget examples
- API Reference - Complete API documentation
- Examples - Real-world widget examples
๐ง CLI Commands
# Create new widget (auto-generates both files)
python -m floydr.cli.main create mywidget
# Or if installed globally:
floydr create mywidget
๐ Project Structure After floydr create
When you run python -m floydr.cli.main create greeting, you get:
my-widgets/
โโโ server/
โ โโโ __init__.py
โ โโโ main.py # โ
Already setup (no edits needed)
โ โโโ tools/
โ โ โโโ __init__.py
โ โ โโโ greeting_tool.py # โ Edit this: Your widget logic
โ โโโ api/ # (optional: for shared APIs)
โ
โโโ widgets/
โ โโโ greeting/
โ โโโ index.jsx # โ Edit this: Your UI
โ
โโโ assets/ # โ๏ธ Auto-generated during build
โ โโโ greeting-HASH.html
โ โโโ greeting-HASH.js
โ
โโโ requirements.txt # Python dependencies
โโโ package.json # JavaScript dependencies
โโโ build-all.mts # โ๏ธ Auto-copied from chatjs-hooks
You only edit the 2 files marked with โ
๐ฏ Key Features
- โ Zero Boilerplate - Just write your widget code
- โ Auto-Discovery - Widgets automatically registered
- โ Type-Safe - Pydantic for Python, TypeScript for React
- โ CLI Tools - Scaffold widgets instantly
- โ
React Hooks - Modern React patterns via
chatjs-hooks - โ MCP Protocol - Native ChatGPT integration
๐ก Examples
Simple Widget
# server/tools/hello_tool.py
class HelloTool(BaseWidget):
identifier = "hello"
title = "Hello"
input_schema = HelloInput
async def execute(self, input_data):
return {"message": "Hello World!"}
// widgets/hello/index.jsx
export default function Hello() {
const props = useWidgetProps();
return <h1>{props.message}</h1>;
}
With API Call
async def execute(self, input_data):
async with httpx.AsyncClient() as client:
response = await client.get("https://api.example.com/data")
data = response.json()
return {"data": data}
With State
function Counter() {
const [state, setState] = useWidgetState({ count: 0 });
return (
<button onClick={() => setState({ count: state.count + 1 })}>
Count: {state.count}
</button>
);
}
๐ Troubleshooting
Widget not loading?
- Check
identifiermatches folder name - Rebuild:
npm run build - Restart:
python server/main.py
Import errors?
pip install --upgrade floydr
npm install chatjs-hooks@latest
Need help? Check our docs or open an issue
๐ค Contributing
See CONTRIBUTING.md
๐ License
MIT ยฉ Floydr Team
๐ Links
- PyPI: https://pypi.org/project/floydr/
- ChatJS Hooks: https://www.npmjs.com/package/chatjs-hooks
- GitHub: https://github.com/floydr-framework/floydr
- MCP Spec: https://modelcontextprotocol.io/
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file floydr-1.0.5.tar.gz.
File metadata
- Download URL: floydr-1.0.5.tar.gz
- Upload date:
- Size: 34.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
851fa03847687e5c4bc9e7c50d7b3517ff7a88483a7f290aac57a66f3fffd3bb
|
|
| MD5 |
934fb702fbb995d734e785949eec06e2
|
|
| BLAKE2b-256 |
00241a58aeb32dbdb19ee493d8c1309a14b66ada280e7f4b9711d362b93330b5
|
File details
Details for the file floydr-1.0.5-py3-none-any.whl.
File metadata
- Download URL: floydr-1.0.5-py3-none-any.whl
- Upload date:
- Size: 16.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4483ff206dfe7c3e858e8240a12e664e49a3f2cbbe22aebd95ad29cd5a6b788e
|
|
| MD5 |
5f7120054ca9c6bdd4c7013ca2152367
|
|
| BLAKE2b-256 |
fedc074373dcbf1a6cff99191ea258bb099b7e308fcd3df4f0540c7ab379b260
|