https://github.com/niradler/streamlit-fastapi-proxy
https://github.com/niradler/streamlit-fastapi-proxy
Last synced: about 1 month ago
JSON representation
- Host: GitHub
- URL: https://github.com/niradler/streamlit-fastapi-proxy
- Owner: niradler
- License: mit
- Created: 2025-07-30T09:30:19.000Z (11 months ago)
- Default Branch: main
- Last Pushed: 2025-07-30T10:26:52.000Z (11 months ago)
- Last Synced: 2025-07-30T11:57:13.452Z (11 months ago)
- Language: Python
- Size: 386 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Streamlit FastAPI Proxy
A FastAPI-based proxy server for managing and serving multiple Streamlit applications with full WebSocket support. Can be used as a standalone proxy server or integrated into existing FastAPI applications.
## Features
- 🚀 **Multiple Streamlit Apps**: Run and manage multiple Streamlit applications simultaneously
- 🔌 **WebSocket Support**: Full WebSocket proxying for real-time Streamlit features
- 📡 **HTTP Proxy**: Complete HTTP request/response proxying
- 🎛️ **App Management**: RESTful API for starting, stopping, and managing apps
- 📊 **App Registry**: Persistent storage of registered applications
- 🔄 **Auto Port Management**: Automatic port allocation and management
- 📝 **Access Tracking**: Track last access times for apps
- 🧩 **Easy Integration**: Simple integration into existing FastAPI applications
- 🏁 **Default Apps**: Auto-start apps marked with `run_by_default=True`

## Installation
### From PyPI (Recommended)
```bash
pip install streamlit-fastapi-proxy
# Run the standalone server
streamlit-proxy
```
### From Source
```bash
# Clone the repository
git clone https://github.com/niradler/streamlit-fastapi-proxy.git
cd streamlit-fastapi-proxy
# Install dependencies with uv
uv sync
# Or install manually
pip install -e .
# Run the standalone server
streamlit-proxy
# Or run directly without installing
python -m streamlit_proxy.cli
```
### Using Docker
```bash
# Clone the repository
git clone https://github.com/niradler/streamlit-fastapi-proxy.git
cd streamlit-fastapi-proxy
# Build and run with Docker Compose
docker-compose up -d
# Or build and run manually
docker build -t streamlit-fastapi-proxy .
docker run -d -p 8000:8000 \
-v $(pwd)/app_registry.json:/app/app_registry.json \
-v $(pwd)/apps:/app/apps \
streamlit-fastapi-proxy
```
## Quick Start
### Option 1: Standalone Server
1. **Install the package:**
```bash
pip install streamlit-fastapi-proxy
```
2. **Start the proxy server:**
```bash
streamlit-proxy
# Or run directly from source
python -m streamlit_proxy.cli
```
3. **Register a Streamlit app:**
```bash
curl -X POST "http://localhost:8000/_apps/register" \
-H "Content-Type: application/json" \
-d '{
"name": "Test App",
"slug": "test-app",
"path": "/path/to/your/app.py",
"run_by_default": false
}'
```
4. **Start the app:**
```bash
curl -X POST "http://localhost:8000/_apps/test-app/start"
```
5. **Access your app:**
Open `http://localhost:8000/apps/test-app/` in your browser
### Option 2: Integration with Existing FastAPI App
```python
from fastapi import FastAPI
from streamlit_proxy import integrate_streamlit_proxy
# Create your FastAPI app
app = FastAPI(title="My Dashboard")
# Add your existing routes
@app.get("/")
def read_root():
return {"message": "Hello World"}
# Integrate Streamlit proxy
integrate_streamlit_proxy(app)
# Run with: uvicorn main:app --reload
```
This will add:
- Management endpoints at `/_apps/*`
- Proxy endpoints at `/apps/*`
- CORS middleware (if not already present)
### Option 3: Manual Integration
For more control over the integration:
```python
from fastapi import FastAPI
from streamlit_proxy.main import (
setup_streamlit_proxy_routes,
add_streamlit_proxy_middleware,
)
app = FastAPI()
# Add routes with custom prefix
setup_streamlit_proxy_routes(app)
# Optionally add CORS middleware
add_streamlit_proxy_middleware(app)
```
## API Endpoints
### App Management
- **GET** `/_apps/` - List all registered apps with status
- **POST** `/_apps/register` - Register a new Streamlit app
- **POST** `/_apps/{slug}/start` - Start a specific app
- **POST** `/_apps/{slug}/stop` - Stop a specific app
- **GET** `/_apps/{slug}/status` - Get detailed status of an app
- **POST** `/_apps/cleanup` - Stop and cleanup all running apps
### Proxy Endpoints
- **GET** `/apps/` - Redirect to first default app (if configured)
- **ALL** `/apps/{slug}/` - Proxy to app root
- **ALL** `/apps/{slug}/{path:path}` - Proxy HTTP requests to the app
- **WebSocket** `/apps/{slug}/stream` - Proxy WebSocket connections
- **WebSocket** `/apps/{slug}/_stcore/stream` - Proxy Streamlit core WebSocket
- **WebSocket** `/apps/{slug}/{ws_path:path}` - Generic WebSocket proxy
## Configuration
Environment variables:
- `ROOT_PATH` - Root directory for resolving relative paths (default: current working directory)
- `APP_REGISTRY_PATH` - Path to app registry JSON file (default: `app_registry.json`, relative to ROOT_PATH)
- `STARTING_PORT` - Starting port for Streamlit apps (default: `8503`)
- `MAX_PORT` - Maximum port for Streamlit apps (default: `8550`)
### Path Resolution
The proxy supports both absolute and relative paths:
- **Absolute paths**: Used as-is (e.g., `/home/user/apps/my_app.py`)
- **Relative paths**: Resolved relative to `ROOT_PATH` (e.g., `apps/my_app.py` → `{ROOT_PATH}/apps/my_app.py`)
This makes it easy to deploy in different environments (local, Docker, production) without changing app configurations.
## App Registration Format
```json
{
"name": "My Streamlit App",
"slug": "my-app",
"path": "/absolute/path/to/app.py",
"desired_port": 8503,
"run_by_default": false
}
```
### Fields
- **name** (required): Display name of the application
- **slug** (required): Unique identifier used in URLs (e.g., `/apps/{slug}/`)
- **path** (required): Path to the Streamlit app file (absolute or relative to ROOT_PATH)
- **desired_port** (optional): Preferred port for the app (auto-assigned if not specified)
- **run_by_default** (optional): If `true`, app will auto-start when proxy starts (default: `false`)
### Default Apps
Apps with `run_by_default: true` will:
1. Auto-start when the proxy server starts
2. Be accessible at the root `/apps/` path (first default app gets priority)
Example:
```json
{
"name": "Main Dashboard",
"slug": "dashboard",
"path": "apps/dashboard.py",
"run_by_default": true
}
```
Access at: `http://localhost:8000/apps/` → redirects to `http://localhost:8000/apps/dashboard/`
## WebSocket Support
This proxy provides full WebSocket support for Streamlit's real-time features:
- ✅ Real-time widget updates
- ✅ Interactive plots and charts
- ✅ Live data streaming
- ✅ Session state synchronization
- ✅ Auto-rerun functionality
## Example Usage
See the `apps/test_app.py` for a sample Streamlit application that demonstrates WebSocket functionality.
## Development
```bash
# Install development dependencies
uv sync
# Run in development mode with auto-reload
uvicorn main:app --reload --host 0.0.0.0 --port 8000
# Or with uv
uv run uvicorn main:app --reload
# Format code
uv run black .
uv run isort .
# Type checking
uv run mypy streamlit_proxy
# Linting
uv run ruff check .
# Build package
uv build
```
## Architecture
```
┌─────────────────┐ HTTP/WS ┌─────────────────┐
│ Client │ ◄─────────────► │ FastAPI Proxy │
│ Browser │ │ (Port 8000) │
└─────────────────┘ └─────────────────┘
│
│ HTTP/WS Proxy
▼
┌─────────────────┐
│ Streamlit Apps │
│ (Ports 8503+) │
│ │
│ ┌──────────┐ │
│ │ App 1 │ │
│ │ App 2 │ │
│ │ App N... │ │
│ └──────────┘ │
└─────────────────┘
```
## Advanced Usage
### Programmatic App Management
```python
from streamlit_proxy.manager_service import AppControllerService
from streamlit_proxy.models import AppConfig
# Create service instance
controller = AppControllerService()
# Register an app programmatically
app_config = AppConfig(
name="Analytics Dashboard",
slug="analytics",
path="apps/analytics.py",
run_by_default=True
)
controller.register_app(app_config)
# Start the app
await controller.start_app("analytics")
# Check status
status = controller.get_app_status("analytics")
print(status)
# Stop the app
await controller.stop_app("analytics")
```
### Custom Streamlit Command
By default, the proxy uses `python -m streamlit` to run apps. You can customize this by subclassing `AppService`:
```python
from streamlit_proxy.services import AppService
class CustomAppService(AppService):
def _get_streamlit_command(self) -> list[str]:
# Use a specific Python version or virtual environment
return ["/path/to/venv/bin/python", "-m", "streamlit"]
```
### Cleanup Handlers
If integrating into an existing FastAPI app, you may want to handle cleanup:
```python
from contextlib import asynccontextmanager
from fastapi import FastAPI
from streamlit_proxy import integrate_streamlit_proxy
from streamlit_proxy.main import cleanup_running_apps
@asynccontextmanager
async def lifespan(app: FastAPI):
# Startup
yield
# Shutdown - cleanup Streamlit apps
await cleanup_running_apps()
app = FastAPI(lifespan=lifespan)
integrate_streamlit_proxy(app)
```
## Troubleshooting
### Apps not starting
1. Check that the path to your Streamlit app is correct
2. Verify the port range is available (STARTING_PORT to MAX_PORT)
3. Ensure Streamlit is installed: `pip install streamlit`
4. Check logs for specific error messages
### WebSocket connection issues
1. Ensure your reverse proxy (if any) supports WebSocket connections
2. Check that CORS middleware is properly configured
3. Verify firewall rules allow WebSocket connections
### Port conflicts
If you get port conflicts, adjust the port range:
```bash
export STARTING_PORT=9000
export MAX_PORT=9100
streamlit-proxy
```
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request.