diff --git a/.dockerignore b/.dockerignore
deleted file mode 100644
index 28928c33f309c4ef4a8c5c1fc4ac4ea2e38fdeb5..0000000000000000000000000000000000000000
--- a/.dockerignore
+++ /dev/null
@@ -1,67 +0,0 @@
-# Python
-__pycache__/
-*.py[cod]
-*$py.class
-*.so
-.Python
-venv/
-.venv/
-ENV/
-env/
-*.egg-info/
-dist/
-build/
-
-# Node
-node_modules/
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-.pnpm-debug.log*
-
-# Next.js
-frontend/.next/
-frontend/out/
-frontend/build/
-
-# Git
-.git/
-.gitignore
-
-# IDE
-.vscode/
-.idea/
-*.swp
-*.swo
-*~
-
-# OS
-.DS_Store
-Thumbs.db
-
-# Documentation
-*.md
-!README.md
-
-# Docker
-Dockerfile*
-docker-compose*.yml
-.dockerignore
-
-# Logs
-*.log
-logs/
-log/
-
-# Generated
-generated_projects/
-
-# Tests
-test/
-tests/
-__tests__/
-
-# Lock files (will be regenerated)
-uv.lock
-poetry.lock
-
diff --git a/.gitattributes b/.gitattributes
index 1abc6d15eb80582bc2bc48e8b790dd790b00d25b..a6344aac8c09253b3b630fb776ae94478aa0275b 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1 +1,35 @@
-Animated_Logo_Video_Ready.gif filter=lfs diff=lfs merge=lfs -text
+*.7z filter=lfs diff=lfs merge=lfs -text
+*.arrow filter=lfs diff=lfs merge=lfs -text
+*.bin filter=lfs diff=lfs merge=lfs -text
+*.bz2 filter=lfs diff=lfs merge=lfs -text
+*.ckpt filter=lfs diff=lfs merge=lfs -text
+*.ftz filter=lfs diff=lfs merge=lfs -text
+*.gz filter=lfs diff=lfs merge=lfs -text
+*.h5 filter=lfs diff=lfs merge=lfs -text
+*.joblib filter=lfs diff=lfs merge=lfs -text
+*.lfs.* filter=lfs diff=lfs merge=lfs -text
+*.mlmodel filter=lfs diff=lfs merge=lfs -text
+*.model filter=lfs diff=lfs merge=lfs -text
+*.msgpack filter=lfs diff=lfs merge=lfs -text
+*.npy filter=lfs diff=lfs merge=lfs -text
+*.npz filter=lfs diff=lfs merge=lfs -text
+*.onnx filter=lfs diff=lfs merge=lfs -text
+*.ot filter=lfs diff=lfs merge=lfs -text
+*.parquet filter=lfs diff=lfs merge=lfs -text
+*.pb filter=lfs diff=lfs merge=lfs -text
+*.pickle filter=lfs diff=lfs merge=lfs -text
+*.pkl filter=lfs diff=lfs merge=lfs -text
+*.pt filter=lfs diff=lfs merge=lfs -text
+*.pth filter=lfs diff=lfs merge=lfs -text
+*.rar filter=lfs diff=lfs merge=lfs -text
+*.safetensors filter=lfs diff=lfs merge=lfs -text
+saved_model/**/* filter=lfs diff=lfs merge=lfs -text
+*.tar.* filter=lfs diff=lfs merge=lfs -text
+*.tar filter=lfs diff=lfs merge=lfs -text
+*.tflite filter=lfs diff=lfs merge=lfs -text
+*.tgz filter=lfs diff=lfs merge=lfs -text
+*.wasm filter=lfs diff=lfs merge=lfs -text
+*.xz filter=lfs diff=lfs merge=lfs -text
+*.zip filter=lfs diff=lfs merge=lfs -text
+*.zst filter=lfs diff=lfs merge=lfs -text
+*tfevents* filter=lfs diff=lfs merge=lfs -text
diff --git a/.gitignore b/.gitignore
index d417b3f614c560cff6191af108ba3d3da38ad8e4..524bb8b69e3fbaaea9b88bfe283fbb38470e45aa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,12 +1,8 @@
-# Byte-compiled / optimized / DLL files
+# Python
__pycache__/
*.py[cod]
*$py.class
-
-# C extensions
*.so
-
-# Distribution / packaging
.Python
build/
develop-eggs/
@@ -14,37 +10,54 @@ dist/
downloads/
eggs/
.eggs/
-# Ignore Python lib directories but NOT frontend/src/lib
-/lib/
-/lib64/
-venv/lib/
-venv/lib64/
+lib/
+lib64/
parts/
sdist/
var/
+wheels/
*.egg-info/
.installed.cfg
*.egg
-MANIFEST
-# Virtual environments
+# Virtual Environment
venv/
env/
ENV/
-.venv/
+.env
+.venv
+env.bak/
+venv.bak/
+
+# IDE specific files
+.idea/
+.vscode/
+*.swp
+*.swo
+.DS_Store
+.vs/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# Gradio
+flagged/
+gradio_cached_examples/
-# PyInstaller
-*.manifest
-*.spec
+# Logs
+*.log
+logs/
+*.out
-# Installer logs
-pip-log.txt
-pip-delete-this-directory.txt
+# Local development settings
+.env.local
+.env.development.local
+.env.test.local
+.env.production.local
-# Unit test / coverage reports
+# Coverage reports
htmlcov/
.tox/
-.nox/
.coverage
.coverage.*
.cache
@@ -52,43 +65,21 @@ nosetests.xml
coverage.xml
*.cover
.hypothesis/
-.pytest_cache/
-
-# Jupyter Notebook
-.ipynb_checkpoints
-
-# pyenv
-.python-version
-
-# mypy
-.mypy_cache/
-.dmypy.json
-
-# Pyre type checker
-.pyre/
-
-# Gradio cache
-log/
-logs/
-# Documentation cache files (backend)
-.backend_gradio_docs_cache.txt
-.backend_gradio_docs_last_update.txt
-.gradio_docs_cache.txt
-.gradio_docs_last_update.txt
-.comfyui_docs_cache.txt
-.comfyui_docs_last_update.txt
-.fastrtc_docs_cache.txt
-.fastrtc_docs_last_update.txt
-
-# System files
-.DS_Store
-Thumbs.db
-
-# Lock files
-uv.lock
-poetry.lock
-Pipfile.lock
-
-# VSCode
-.vscode/
\ No newline at end of file
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+*.egg-info/
+.installed.cfg
+*.egg
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..2e9d3fd4ca3e8ea19d530ca7c2485c9f7da6ac3c
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,64 @@
+repos:
+ - repo: https://github.com/pre-commit/pre-commit-hooks
+ rev: v5.0.0
+ hooks:
+ - id: check-executables-have-shebangs
+ - id: check-json
+ - id: check-merge-conflict
+ - id: check-shebang-scripts-are-executable
+ - id: check-toml
+ - id: check-yaml
+ - id: end-of-file-fixer
+ - id: mixed-line-ending
+ args: ["--fix=lf"]
+ - id: requirements-txt-fixer
+ - id: trailing-whitespace
+ - repo: https://github.com/myint/docformatter
+ rev: v1.7.5
+ hooks:
+ - id: docformatter
+ args: ["--in-place"]
+ - repo: https://github.com/pycqa/isort
+ rev: 5.13.2
+ hooks:
+ - id: isort
+ args: ["--profile", "black"]
+ - repo: https://github.com/pre-commit/mirrors-mypy
+ rev: v1.13.0
+ hooks:
+ - id: mypy
+ args: ["--ignore-missing-imports"]
+ additional_dependencies:
+ [
+ "types-python-slugify",
+ "types-requests",
+ "types-PyYAML",
+ "types-pytz",
+ ]
+ - repo: https://github.com/psf/black
+ rev: 24.10.0
+ hooks:
+ - id: black
+ language_version: python3.10
+ args: ["--line-length", "119"]
+ - repo: https://github.com/charliermarsh/ruff-pre-commit
+ rev: v0.7.4
+ hooks:
+ - id: ruff
+ - repo: https://github.com/kynan/nbstripout
+ rev: 0.8.1
+ hooks:
+ - id: nbstripout
+ args:
+ [
+ "--extra-keys",
+ "metadata.interpreter metadata.kernelspec cell.metadata.pycharm",
+ ]
+ - repo: https://github.com/nbQA-dev/nbQA
+ rev: 1.9.1
+ hooks:
+ - id: nbqa-black
+ - id: nbqa-pyupgrade
+ args: ["--py37-plus"]
+ - id: nbqa-isort
+ args: ["--float-to-top"]
diff --git a/.python-version b/.python-version
new file mode 100644
index 0000000000000000000000000000000000000000..c8cfe3959183f8e9a50f83f54cd723f2dc9c252d
--- /dev/null
+++ b/.python-version
@@ -0,0 +1 @@
+3.10
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000000000000000000000000000000000000..4c7e97e23c3c5f93cf8865c196978835f5dd35f3
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,30 @@
+{
+ "editor.formatOnSave": true,
+ "files.insertFinalNewline": false,
+ "[python]": {
+ "editor.defaultFormatter": "ms-python.black-formatter",
+ "editor.formatOnType": true,
+ "editor.codeActionsOnSave": {
+ "source.organizeImports": "explicit"
+ }
+ },
+ "[jupyter]": {
+ "files.insertFinalNewline": false
+ },
+ "black-formatter.args": [
+ "--line-length=119"
+ ],
+ "isort.args": ["--profile", "black"],
+ "flake8.args": [
+ "--max-line-length=119"
+ ],
+ "ruff.lint.args": [
+ "--line-length=119"
+ ],
+ "notebook.output.scrolling": true,
+ "notebook.formatOnCellExecution": true,
+ "notebook.formatOnSave.enabled": true,
+ "notebook.codeActionsOnSave": {
+ "source.organizeImports": "explicit"
+ }
+}
diff --git a/Dockerfile b/Dockerfile
deleted file mode 100644
index 5a770c486ff435366b475dc6743ade5056af3d67..0000000000000000000000000000000000000000
--- a/Dockerfile
+++ /dev/null
@@ -1,105 +0,0 @@
-# Multi-stage build for AnyCoder Docker Space
-
-# Stage 1: Build frontend
-FROM node:22-slim AS frontend-builder
-
-WORKDIR /build
-
-# Copy frontend package files
-COPY frontend/package*.json ./
-RUN npm ci
-
-# Copy all frontend source files and configs
-COPY frontend/src ./src
-COPY frontend/public ./public
-COPY frontend/next.config.js ./
-COPY frontend/tsconfig.json ./
-COPY frontend/tailwind.config.js ./
-COPY frontend/postcss.config.js ./
-# Note: next-env.d.ts is auto-generated by Next.js, not needed for build
-
-# Build frontend
-RUN npm run build
-
-# Stage 2: Production image
-FROM python:3.11-slim
-
-# Install system dependencies as root (git for pip, nodejs for frontend)
-# Install Node.js 22 from NodeSource (Debian repo only has v18)
-RUN apt-get update && \
- apt-get install -y --no-install-recommends curl ca-certificates gnupg git && \
- curl -fsSL https://deb.nodesource.com/setup_22.x | bash - && \
- apt-get install -y --no-install-recommends nodejs && \
- rm -rf /var/lib/apt/lists/*
-
-# Set up a new user named "user" with user ID 1000
-RUN useradd -m -u 1000 user
-
-# Switch to the "user" user
-USER user
-
-# Set home to the user's home directory
-ENV HOME=/home/user \
- PATH=/home/user/.local/bin:$PATH \
- PYTHONUNBUFFERED=1
-
-# Set the working directory to the user's home directory
-WORKDIR $HOME/app
-
-# Copy Python requirements and install dependencies
-COPY --chown=user:user requirements.txt .
-RUN pip install --no-cache-dir --upgrade pip && \
- pip install --no-cache-dir -r requirements.txt
-
-# Copy application code
-COPY --chown=user:user backend_api.py .
-COPY --chown=user:user backend_models.py .
-COPY --chown=user:user backend_docs_manager.py .
-COPY --chown=user:user backend_prompts.py .
-COPY --chown=user:user backend_parsers.py .
-COPY --chown=user:user backend_deploy.py .
-COPY --chown=user:user backend_search_replace.py .
-COPY --chown=user:user project_importer.py .
-
-# Copy built frontend from builder stage
-COPY --chown=user:user --from=frontend-builder /build/.next ./frontend/.next
-COPY --chown=user:user --from=frontend-builder /build/public ./frontend/public
-COPY --chown=user:user --from=frontend-builder /build/package*.json ./frontend/
-COPY --chown=user:user --from=frontend-builder /build/next.config.js ./frontend/
-COPY --chown=user:user --from=frontend-builder /build/node_modules ./frontend/node_modules
-
-# Set environment variables for the application
-# BACKEND_HOST is used by Next.js server for proxying
-# Do NOT set NEXT_PUBLIC_API_URL - let frontend use relative URLs
-ENV BACKEND_HOST=http://localhost:8000 \
- PORT=7860
-
-# Create startup script that runs both services
-# Backend on 8000, Frontend on 7860 (exposed port)
-RUN echo '#!/bin/bash\n\
-set -e\n\
-\n\
-echo "🚀 Starting AnyCoder Docker Space..."\n\
-\n\
-# Start backend on port 8000 in background\n\
-echo "📡 Starting FastAPI backend on port 8000..."\n\
-cd $HOME/app\n\
-uvicorn backend_api:app --host 0.0.0.0 --port 8000 &\n\
-BACKEND_PID=$!\n\
-\n\
-# Wait for backend to be ready\n\
-echo "⏳ Waiting for backend to start..."\n\
-sleep 5\n\
-\n\
-# Start frontend on port 7860 (HF Spaces exposed port)\n\
-echo "🎨 Starting Next.js frontend on port 7860..."\n\
-cd $HOME/app/frontend\n\
-PORT=7860 BACKEND_HOST=http://localhost:8000 npm start\n\
-' > $HOME/app/start.sh && chmod +x $HOME/app/start.sh
-
-# Expose port 7860 (HF Spaces default)
-EXPOSE 7860
-
-# Run the startup script
-CMD ["./start.sh"]
-
diff --git a/README.md b/README.md
index 164ba376aae99d0edc28776a3c4f5592bf04cfc6..6807efa26a415f9885e9481bc3aff7e124cd2e9c 100644
--- a/README.md
+++ b/README.md
@@ -1,162 +1,13 @@
---
-title: AnyCoder
-emoji: 🏆
-colorFrom: blue
-colorTo: purple
-sdk: docker
-app_port: 7860
+title: Anychat
+emoji: 🏢
+colorFrom: indigo
+colorTo: indigo
+sdk: gradio
+sdk_version: 5.7.1
+app_file: app.py
pinned: false
-disable_embedding: false
-hf_oauth: true
-hf_oauth_expiration_minutes: 43200
-hf_oauth_scopes:
-- manage-repos
-- write-discussions
-models:
- - MiniMaxAI/MiniMax-M2.5
- - zai-org/GLM-5
- - Qwen/Qwen3-Coder-Next
- - moonshotai/Kimi-K2.5
- - zai-org/GLM-4.7-Flash
- - zai-org/GLM-4.7
- - MiniMaxAI/MiniMax-M2.1
- - zai-org/GLM-4.6
- - zai-org/GLM-4.6V
- - deepseek-ai/DeepSeek-V3
- - deepseek-ai/DeepSeek-R1
- - MiniMaxAI/MiniMax-M2
- - moonshotai/Kimi-K2-Thinking
+disable_embedding: true
---
-
-# AnyCoder - AI Code Generator with React Frontend
-
-AnyCoder is a full-stack AI-powered code generator with a modern React/TypeScript frontend and FastAPI backend. Generate applications by describing them in plain English, with support for multiple AI models and one-click deployment to Hugging Face Spaces.
-
-## 🎨 Features
-
-- **Modern React UI**: Apple-inspired design with VS Code layout
-- **Real-time Streaming**: Server-Sent Events for live code generation
-- **Multi-Model Support**: MiniMax M2, DeepSeek V3, and more via HuggingFace InferenceClient
-- **Multiple Languages**: HTML, Gradio, Streamlit, React, Transformers.js, ComfyUI
-- **Authentication**: HuggingFace OAuth + Dev mode for local testing
-- **One-Click Deployment**: Deploy generated apps directly to HF Spaces
-
-## 🏗️ Architecture
-
-```
-anycoder/
-├── backend_api.py # FastAPI backend with streaming
-├── frontend/ # Next.js React frontend
-│ ├── src/
-│ │ ├── app/ # Pages (page.tsx, layout.tsx, globals.css)
-│ │ ├── components/ # React components
-│ │ ├── lib/ # API client, auth utilities
-│ │ └── types/ # TypeScript types
-│ └── package.json
-├── requirements.txt # Python dependencies
-├── Dockerfile # Docker Space configuration
-└── start_fullstack.sh # Local development script
-```
-
-## 🚀 Quick Start
-
-### Local Development
-
-1. **Backend**:
-```bash
-export HF_TOKEN="your_huggingface_token"
-export GEMINI_API_KEY="your_gemini_api_key"
-python backend_api.py
-```
-
-2. **Frontend** (new terminal):
-```bash
-cd frontend
-npm install
-npm run dev
-```
-
-3. Open `http://localhost:3000`
-
-### Using start script:
-```bash
-export HF_TOKEN="your_token"
-export GEMINI_API_KEY="your_gemini_api_key"
-./start_fullstack.sh
-```
-
-## 🐳 Docker Space Deployment
-
-This app runs as a Docker Space on HuggingFace. The Dockerfile:
-- Builds the Next.js frontend
-- Runs FastAPI backend on port 7860
-- Uses proper user permissions (UID 1000)
-- Handles environment variables securely
-
-## 🔑 Authentication
-
-- **Dev Mode** (localhost): Mock login for testing
-- **Production**: HuggingFace OAuth with manage-repos scope
-
-## 📝 Supported Languages
-
-- `html` - Static HTML pages
-- `gradio` - Python Gradio apps
-- `streamlit` - Python Streamlit apps
-- `react` - React/Next.js apps
-- `transformers.js` - Browser ML apps
-- `comfyui` - ComfyUI workflows
-
-## 🤖 Available Models
-
-The following models are currently supported and used by AnyCoder:
-
-models:
- - MiniMaxAI/MiniMax-M2.5
- - zai-org/GLM-5
- - Qwen/Qwen3-Coder-Next
- - moonshotai/Kimi-K2.5
- - zai-org/GLM-4.7-Flash
- - zai-org/GLM-4.7
- - MiniMaxAI/MiniMax-M2.1
- - zai-org/GLM-4.6
- - zai-org/GLM-4.6V
- - deepseek-ai/DeepSeek-V3
- - deepseek-ai/DeepSeek-R1
- - MiniMaxAI/MiniMax-M2
- - moonshotai/Kimi-K2-Thinking
-
-## 🎯 Usage
-
-1. Sign in with HuggingFace (or use Dev Login locally)
-2. Select a language and AI model
-3. Describe your app in the chat
-4. Watch code generate in real-time
-5. Click **🚀 Deploy** to publish to HF Spaces
-
-## 🛠️ Environment Variables
-
-- `HF_TOKEN` - HuggingFace API token (required)
-- `GEMINI_API_KEY` - Google Gemini API key (required for Gemini 3 Pro Preview)
-- `POE_API_KEY` - Poe API key (optional, for GPT-5 and Claude models)
-- `DASHSCOPE_API_KEY` - DashScope API key (optional, for Qwen models)
-- `OPENROUTER_API_KEY` - OpenRouter API key (optional, for Sherlock models)
-- `MISTRAL_API_KEY` - Mistral API key (optional, for Mistral models)
-
-## 📦 Tech Stack
-
-**Frontend:**
-- Next.js 14
-- TypeScript
-- Tailwind CSS
-- Monaco Editor
-
-**Backend:**
-- FastAPI
-- HuggingFace Hub
-- Server-Sent Events (SSE)
-
-## 📄 License
-
-MIT
\ No newline at end of file
+Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
diff --git a/app.py b/app.py
new file mode 100644
index 0000000000000000000000000000000000000000..53844b6741baa22160ca291acc2d0435dd69f8f4
--- /dev/null
+++ b/app.py
@@ -0,0 +1,107 @@
+import gradio as gr
+
+from app_huggingface import demo as demo_huggingface
+from app_playai import demo as demo_playai
+from app_allenai import demo as demo_allenai
+from app_claude import demo as demo_claude
+from app_experimental import demo as demo_experimental
+from app_fireworks import demo as demo_fireworks
+from app_flux import demo as demo_flux
+from app_gemini import demo as demo_gemini
+from app_groq import demo as demo_groq
+from app_hyperbolic import demo as demo_hyperbolic
+from app_fal import demo as demo_fal
+from app_marco_o1 import demo as demo_marco_o1
+from app_mistral import demo as demo_mistral
+from app_nvidia import demo as demo_nvidia
+from app_openai import demo as demo_openai
+from app_perplexity import demo as demo_perplexity
+from app_qwen import demo as demo_qwen
+from app_sambanova import demo as demo_sambanova
+from app_together import demo as demo_together
+from app_xai import demo as demo_grok
+from app_showui import demo as demo_showui
+
+with gr.Blocks(fill_height=True) as demo:
+ with gr.Tab("Huggingface"):
+ demo_huggingface.render()
+ with gr.Tab("Fal"):
+ demo_fal.render()
+ gr.Markdown("This app is built with gradio, check out gradio github and star: Gradio
.")
+ with gr.Tab("Hyperbolic"):
+ demo_hyperbolic.render()
+ gr.Markdown(
+ """
+
+

+
+
+ **Note:** This model is supported by Hyperbolic. Build your AI apps at [Hyperbolic](https://app.hyperbolic.xyz/).
+
+ This app is built with gradio, check out gradio github and star: Gradio
.
+ """
+ )
+ with gr.Tab("ShowUI"):
+ demo_showui.render()
+ gr.Markdown("This app is built with gradio, check out gradio github and star: Gradio
.")
+ with gr.Tab("PlayAI"):
+ demo_playai.render()
+ gr.Markdown("This app is built with gradio, check out gradio github and star: Gradio
.")
+ with gr.Tab("Grok"):
+ demo_grok.render()
+ gr.Markdown("This app is built with gradio, check out gradio github and star: Gradio
.")
+ with gr.Tab("Gemini"):
+ demo_gemini.render()
+ gr.Markdown("This app is built with gradio, check out gradio github and star: Gradio
.")
+ with gr.Tab("ChatGPT"):
+ demo_openai.render()
+ gr.Markdown("This app is built with gradio, check out gradio github and star: Gradio
.")
+ with gr.Tab("Claude"):
+ demo_claude.render()
+ gr.Markdown("This app is built with gradio, check out gradio github and star: Gradio
.")
+ with gr.Tab("Qwen"):
+ demo_qwen.render()
+ gr.Markdown("This app is built with gradio, check out gradio github and star: Gradio
.")
+ with gr.Tab("Allen AI"):
+ demo_allenai.render()
+ gr.Markdown("This app is built with gradio, check out gradio github and star: Gradio
.")
+ with gr.Tab("Perplexity"):
+ demo_perplexity.render()
+ gr.Markdown("This app is built with gradio, check out gradio github and star: Gradio
.")
+ with gr.Tab("Experimental"):
+ demo_experimental.render()
+ gr.Markdown("This app is built with gradio, check out gradio github and star: Gradio
.")
+ with gr.Tab("Meta Llama"):
+ demo_sambanova.render()
+ gr.Markdown(
+ """
+ **Note:** You need to use a SambaNova API key from [SambaNova Cloud](https://cloud.sambanova.ai/).
+
+ This app is built with gradio, check out gradio github and star: Gradio
.
+ """
+ )
+ with gr.Tab("Marco-o1"):
+ demo_marco_o1.render()
+ gr.Markdown("This app is built with gradio, check out gradio github and star: Gradio
.")
+ with gr.Tab("Groq"):
+ demo_groq.render()
+ gr.Markdown("This app is built with gradio, check out gradio github and star: Gradio
.")
+ with gr.Tab("Mistral"):
+ demo_mistral.render()
+ gr.Markdown("This app is built with gradio, check out gradio github and star: Gradio
.")
+ with gr.Tab("Fireworks"):
+ demo_fireworks.render()
+ gr.Markdown("This app is built with gradio, check out gradio github and star: Gradio
.")
+ with gr.Tab("Together"):
+ demo_together.render()
+ gr.Markdown("This app is built with gradio, check out gradio github and star: Gradio
.")
+ with gr.Tab("NVIDIA"):
+ demo_nvidia.render()
+ gr.Markdown("This app is built with gradio, check out gradio github and star: Gradio
.")
+ with gr.Tab("Flux"):
+ demo_flux.render()
+ gr.Markdown("This app is built with gradio, check out gradio github and star: Gradio
.")
+
+
+if __name__ == "__main__":
+ demo.queue(api_open=False).launch(show_api=False)
diff --git a/app_allenai.py b/app_allenai.py
new file mode 100644
index 0000000000000000000000000000000000000000..43302b4bb922be87e3126b645c24c75a52e462ef
--- /dev/null
+++ b/app_allenai.py
@@ -0,0 +1,73 @@
+from gradio_client import Client
+import gradio as gr
+
+MODELS = {
+ "OLMo-2-1124-13B-Instruct": "akhaliq/olmo-anychat",
+ "Llama-3.1-Tulu-3-8B": "akhaliq/allen-test"
+}
+
+def create_chat_fn(client):
+ def chat(message, history):
+ response = client.predict(
+ message=message,
+ system_prompt="You are a helpful AI assistant.",
+ temperature=0.7,
+ max_new_tokens=1024,
+ top_k=40,
+ repetition_penalty=1.1,
+ top_p=0.95,
+ api_name="/chat"
+ )
+ return response
+ return chat
+
+def set_client_for_session(model_name, request: gr.Request):
+ headers = {}
+ if request and hasattr(request, 'request') and hasattr(request.request, 'headers'):
+ x_ip_token = request.request.headers.get('x-ip-token')
+ if x_ip_token:
+ headers["X-IP-Token"] = x_ip_token
+
+ return Client(MODELS[model_name], headers=headers)
+
+def safe_chat_fn(message, history, client):
+ if client is None:
+ return "Error: Client not initialized. Please refresh the page."
+ return create_chat_fn(client)(message, history)
+
+with gr.Blocks() as demo:
+
+ client = gr.State()
+
+ model_dropdown = gr.Dropdown(
+ choices=list(MODELS.keys()),
+ value="OLMo-2-1124-13B-Instruct",
+ label="Select Model",
+ interactive=True
+ )
+
+ chat_interface = gr.ChatInterface(
+ fn=safe_chat_fn,
+ additional_inputs=[client]
+ )
+
+ # Update client when model changes
+ def update_model(model_name, request):
+ return set_client_for_session(model_name, request)
+
+ model_dropdown.change(
+ fn=update_model,
+ inputs=[model_dropdown],
+ outputs=[client],
+ )
+
+ # Initialize client on page load
+ demo.load(
+ fn=set_client_for_session,
+ inputs=gr.State("OLMo-2-1124-13B-Instruct"),
+ outputs=client,
+ )
+
+demo = demo
+
+
diff --git a/app_cerebras.py b/app_cerebras.py
new file mode 100644
index 0000000000000000000000000000000000000000..8765b1b25553d8c3b6ac941a9b5aee837700620d
--- /dev/null
+++ b/app_cerebras.py
@@ -0,0 +1,19 @@
+import os
+
+import cerebras_gradio
+
+from utils import get_app
+
+demo = get_app(
+ models=[
+ "llama3.1-8b",
+ "llama3.1-70b",
+ "llama3.1-405b",
+ ],
+ default_model="llama3.1-70b",
+ src=cerebras_gradio.registry,
+ accept_token=not os.getenv("CEREBRAS_API_KEY"),
+)
+
+if __name__ == "__main__":
+ demo.launch()
diff --git a/app_claude.py b/app_claude.py
new file mode 100644
index 0000000000000000000000000000000000000000..92d31efe49a69bdbd2aec422326dbd5e83fe8314
--- /dev/null
+++ b/app_claude.py
@@ -0,0 +1,21 @@
+import os
+
+import anthropic_gradio
+
+from utils import get_app
+
+demo = get_app(
+ models=[
+ "claude-3-5-sonnet-20241022",
+ "claude-3-5-haiku-20241022",
+ "claude-3-opus-20240229",
+ "claude-3-sonnet-20240229",
+ "claude-3-haiku-20240307",
+ ],
+ default_model="claude-3-5-sonnet-20241022",
+ src=anthropic_gradio.registry,
+ accept_token=not os.getenv("ANTHROPIC_API_KEY"),
+)
+
+if __name__ == "__main__":
+ demo.launch()
diff --git a/app_experimental.py b/app_experimental.py
new file mode 100644
index 0000000000000000000000000000000000000000..4455d2918672f9d6db948d8ea95cad5fc8651102
--- /dev/null
+++ b/app_experimental.py
@@ -0,0 +1,297 @@
+import os
+import random
+from typing import Dict, List
+
+import google.generativeai as genai
+import gradio as gr
+import openai
+from anthropic import Anthropic
+from openai import OpenAI # Add explicit OpenAI import
+
+
+def get_all_models():
+ """Get all available models from the registries."""
+ return [
+ "SambaNova: Meta-Llama-3.2-1B-Instruct",
+ "SambaNova: Meta-Llama-3.2-3B-Instruct",
+ "SambaNova: Llama-3.2-11B-Vision-Instruct",
+ "SambaNova: Llama-3.2-90B-Vision-Instruct",
+ "SambaNova: Meta-Llama-3.1-8B-Instruct",
+ "SambaNova: Meta-Llama-3.1-70B-Instruct",
+ "SambaNova: Meta-Llama-3.1-405B-Instruct",
+ "Hyperbolic: Qwen/Qwen2.5-Coder-32B-Instruct",
+ "Hyperbolic: meta-llama/Llama-3.2-3B-Instruct",
+ "Hyperbolic: meta-llama/Meta-Llama-3.1-8B-Instruct",
+ "Hyperbolic: meta-llama/Meta-Llama-3.1-70B-Instruct",
+ "Hyperbolic: meta-llama/Meta-Llama-3-70B-Instruct",
+ "Hyperbolic: NousResearch/Hermes-3-Llama-3.1-70B",
+ "Hyperbolic: Qwen/Qwen2.5-72B-Instruct",
+ "Hyperbolic: deepseek-ai/DeepSeek-V2.5",
+ "Hyperbolic: meta-llama/Meta-Llama-3.1-405B-Instruct",
+ ]
+
+
+def generate_discussion_prompt(original_question: str, previous_responses: List[str]) -> str:
+ """Generate a prompt for models to discuss and build upon previous
+ responses."""
+ prompt = f"""You are participating in a multi-AI discussion about this question: "{original_question}"
+
+Previous responses from other AI models:
+{chr(10).join(f"- {response}" for response in previous_responses)}
+
+Please provide your perspective while:
+1. Acknowledging key insights from previous responses
+2. Adding any missing important points
+3. Respectfully noting if you disagree with anything and explaining why
+4. Building towards a complete answer
+
+Keep your response focused and concise (max 3-4 paragraphs)."""
+ return prompt
+
+
+def generate_consensus_prompt(original_question: str, discussion_history: List[str]) -> str:
+ """Generate a prompt for final consensus building."""
+ return f"""Review this multi-AI discussion about: "{original_question}"
+
+Discussion history:
+{chr(10).join(discussion_history)}
+
+As a final synthesizer, please:
+1. Identify the key points where all models agreed
+2. Explain how any disagreements were resolved
+3. Present a clear, unified answer that represents our collective best understanding
+4. Note any remaining uncertainties or caveats
+
+Keep the final consensus concise but complete."""
+
+
+def chat_with_openai(model: str, messages: List[Dict], api_key: str | None) -> str:
+ import openai
+
+ client = openai.OpenAI(api_key=api_key)
+ response = client.chat.completions.create(model=model, messages=messages)
+ return response.choices[0].message.content
+
+
+def chat_with_anthropic(messages: List[Dict], api_key: str | None) -> str:
+ """Chat with Anthropic's Claude model."""
+ client = Anthropic(api_key=api_key)
+ response = client.messages.create(model="claude-3-sonnet-20240229", messages=messages, max_tokens=1024)
+ return response.content[0].text
+
+
+def chat_with_gemini(messages: List[Dict], api_key: str | None) -> str:
+ """Chat with Gemini Pro model."""
+ genai.configure(api_key=api_key)
+ model = genai.GenerativeModel("gemini-pro")
+
+ # Convert messages to Gemini format
+ gemini_messages = []
+ for msg in messages:
+ role = "user" if msg["role"] == "user" else "model"
+ gemini_messages.append({"role": role, "parts": [msg["content"]]})
+
+ response = model.generate_content([m["parts"][0] for m in gemini_messages])
+ return response.text
+
+
+def chat_with_sambanova(
+ messages: List[Dict], api_key: str | None, model_name: str = "Llama-3.2-90B-Vision-Instruct"
+) -> str:
+ """Chat with SambaNova's models using their OpenAI-compatible API."""
+ client = openai.OpenAI(
+ api_key=api_key,
+ base_url="https://api.sambanova.ai/v1",
+ )
+
+ response = client.chat.completions.create(
+ model=model_name, messages=messages, temperature=0.1, top_p=0.1 # Use the specific model name passed in
+ )
+ return response.choices[0].message.content
+
+
+def chat_with_hyperbolic(
+ messages: List[Dict], api_key: str | None, model_name: str = "Qwen/Qwen2.5-Coder-32B-Instruct"
+) -> str:
+ """Chat with Hyperbolic's models using their OpenAI-compatible API."""
+ client = OpenAI(api_key=api_key, base_url="https://api.hyperbolic.xyz/v1")
+
+ # Add system message to the start of the messages list
+ full_messages = [
+ {"role": "system", "content": "You are a helpful assistant. Be descriptive and clear."},
+ *messages,
+ ]
+
+ response = client.chat.completions.create(
+ model=model_name, # Use the specific model name passed in
+ messages=full_messages,
+ temperature=0.7,
+ max_tokens=1024,
+ )
+ return response.choices[0].message.content
+
+
+def multi_model_consensus(
+ question: str, selected_models: List[str], rounds: int = 3, progress: gr.Progress = gr.Progress()
+) -> list[tuple[str, str]]:
+ if not selected_models:
+ raise gr.Error("Please select at least one model to chat with.")
+
+ chat_history = []
+ discussion_history = []
+
+ # Initial responses
+ progress(0, desc="Getting initial responses...")
+ initial_responses = []
+ for i, model in enumerate(selected_models):
+ provider, model_name = model.split(": ", 1)
+
+ try:
+ if provider == "Anthropic":
+ api_key = os.getenv("ANTHROPIC_API_KEY")
+ response = chat_with_anthropic(messages=[{"role": "user", "content": question}], api_key=api_key)
+ elif provider == "SambaNova":
+ api_key = os.getenv("SAMBANOVA_API_KEY")
+ response = chat_with_sambanova(
+ messages=[
+ {"role": "system", "content": "You are a helpful assistant"},
+ {"role": "user", "content": question},
+ ],
+ api_key=api_key,
+ )
+ elif provider == "Hyperbolic": # Add Hyperbolic case
+ api_key = os.getenv("HYPERBOLIC_API_KEY")
+ response = chat_with_hyperbolic(messages=[{"role": "user", "content": question}], api_key=api_key)
+ else: # Gemini
+ api_key = os.getenv("GEMINI_API_KEY")
+ response = chat_with_gemini(messages=[{"role": "user", "content": question}], api_key=api_key)
+
+ initial_responses.append(f"{model}: {response}")
+ discussion_history.append(f"Initial response from {model}:\n{response}")
+ chat_history.append((f"Initial response from {model}", response))
+ except Exception as e:
+ chat_history.append((f"Error from {model}", str(e)))
+
+ # Discussion rounds
+ for round_num in range(rounds):
+ progress((round_num + 1) / (rounds + 2), desc=f"Discussion round {round_num + 1}...")
+ round_responses = []
+
+ random.shuffle(selected_models) # Randomize order each round
+ for model in selected_models:
+ provider, model_name = model.split(": ", 1)
+
+ try:
+ discussion_prompt = generate_discussion_prompt(question, discussion_history)
+ if provider == "Anthropic":
+ api_key = os.getenv("ANTHROPIC_API_KEY")
+ response = chat_with_anthropic(
+ messages=[{"role": "user", "content": discussion_prompt}], api_key=api_key
+ )
+ elif provider == "SambaNova":
+ api_key = os.getenv("SAMBANOVA_API_KEY")
+ response = chat_with_sambanova(
+ messages=[
+ {"role": "system", "content": "You are a helpful assistant"},
+ {"role": "user", "content": discussion_prompt},
+ ],
+ api_key=api_key,
+ )
+ elif provider == "Hyperbolic": # Add Hyperbolic case
+ api_key = os.getenv("HYPERBOLIC_API_KEY")
+ response = chat_with_hyperbolic(
+ messages=[{"role": "user", "content": discussion_prompt}], api_key=api_key
+ )
+ else: # Gemini
+ api_key = os.getenv("GEMINI_API_KEY")
+ response = chat_with_gemini(
+ messages=[{"role": "user", "content": discussion_prompt}], api_key=api_key
+ )
+
+ round_responses.append(f"{model}: {response}")
+ discussion_history.append(f"Round {round_num + 1} - {model}:\n{response}")
+ chat_history.append((f"Round {round_num + 1} - {model}", response))
+ except Exception as e:
+ chat_history.append((f"Error from {model} in round {round_num + 1}", str(e)))
+
+ # Final consensus
+ progress(0.9, desc="Building final consensus...")
+ model = selected_models[0]
+ provider, model_name = model.split(": ", 1)
+
+ try:
+ consensus_prompt = generate_consensus_prompt(question, discussion_history)
+ if provider == "Anthropic":
+ api_key = os.getenv("ANTHROPIC_API_KEY")
+ final_consensus = chat_with_anthropic(
+ messages=[{"role": "user", "content": consensus_prompt}], api_key=api_key
+ )
+ elif provider == "SambaNova":
+ api_key = os.getenv("SAMBANOVA_API_KEY")
+ final_consensus = chat_with_sambanova(
+ messages=[
+ {"role": "system", "content": "You are a helpful assistant"},
+ {"role": "user", "content": consensus_prompt},
+ ],
+ api_key=api_key,
+ )
+ elif provider == "Hyperbolic": # Add Hyperbolic case
+ api_key = os.getenv("HYPERBOLIC_API_KEY")
+ final_consensus = chat_with_hyperbolic(
+ messages=[{"role": "user", "content": consensus_prompt}], api_key=api_key
+ )
+ else: # Gemini
+ api_key = os.getenv("GEMINI_API_KEY")
+ final_consensus = chat_with_gemini(
+ messages=[{"role": "user", "content": consensus_prompt}], api_key=api_key
+ )
+ except Exception as e:
+ final_consensus = f"Error getting consensus from {model}: {str(e)}"
+
+ chat_history.append(("Final Consensus", final_consensus))
+
+ progress(1.0, desc="Done!")
+ return chat_history
+
+
+with gr.Blocks() as demo:
+ gr.Markdown("# Experimental Multi-Model Consensus Chat")
+ gr.Markdown(
+ """Select multiple models to collaborate on answering your question.
+ The models will discuss with each other and attempt to reach a consensus.
+ Maximum 3 models can be selected at once."""
+ )
+
+ with gr.Row():
+ with gr.Column():
+ model_selector = gr.Dropdown(
+ choices=get_all_models(),
+ multiselect=True,
+ label="Select Models (max 3)",
+ info="Choose up to 3 models to participate in the discussion",
+ value=["SambaNova: Llama-3.2-90B-Vision-Instruct", "Hyperbolic: Qwen/Qwen2.5-Coder-32B-Instruct"],
+ max_choices=3,
+ )
+ rounds_slider = gr.Slider(
+ minimum=1,
+ maximum=2,
+ value=1,
+ step=1,
+ label="Discussion Rounds",
+ info="Number of rounds of discussion between models",
+ )
+
+ chatbot = gr.Chatbot(height=600, label="Multi-Model Discussion")
+ msg = gr.Textbox(label="Your Question", placeholder="Ask a question for the models to discuss...")
+
+ def respond(message, selected_models, rounds):
+ chat_history = multi_model_consensus(message, selected_models, rounds)
+ return chat_history
+
+ msg.submit(respond, [msg, model_selector, rounds_slider], [chatbot], api_name="consensus_chat")
+
+for fn in demo.fns.values():
+ fn.api_name = False
+
+if __name__ == "__main__":
+ demo.launch()
diff --git a/app_fal.py b/app_fal.py
new file mode 100644
index 0000000000000000000000000000000000000000..67a7b012e28db957a6abd67cf0d577abe17ba971
--- /dev/null
+++ b/app_fal.py
@@ -0,0 +1,16 @@
+import fal_gradio
+
+from utils import get_app
+
+demo = get_app(
+ models=[
+ "fal-ai/ltx-video",
+ "fal-ai/ltx-video/image-to-video",
+ "fal-ai/luma-photon",
+ ],
+ default_model="fal-ai/luma-photon",
+ src=fal_gradio.registry,
+)
+
+if __name__ == "__main__":
+ demo.launch()
diff --git a/app_fireworks.py b/app_fireworks.py
new file mode 100644
index 0000000000000000000000000000000000000000..8811108ca33c2ae0cde987e6d062dbbf40d297f2
--- /dev/null
+++ b/app_fireworks.py
@@ -0,0 +1,18 @@
+import os
+
+import fireworks_gradio
+
+from utils import get_app
+
+demo = get_app(
+ models=[
+ "f1-preview",
+ "f1-mini-preview",
+ ],
+ default_model="f1-preview",
+ src=fireworks_gradio.registry,
+ accept_token=not os.getenv("FIREWORKS_API_KEY"),
+)
+
+if __name__ == "__main__":
+ demo.launch()
diff --git a/app_flux.py b/app_flux.py
new file mode 100644
index 0000000000000000000000000000000000000000..be7f51e5c1a408e5566c3fa0e2e5cc08ff49b45c
--- /dev/null
+++ b/app_flux.py
@@ -0,0 +1,17 @@
+import replicate_gradio
+
+from utils import get_app
+
+demo = get_app(
+ models=[
+ "black-forest-labs/flux-depth-pro",
+ "black-forest-labs/flux-canny-pro",
+ "black-forest-labs/flux-fill-pro",
+ "black-forest-labs/flux-depth-dev",
+ ],
+ default_model="black-forest-labs/flux-depth-pro",
+ src=replicate_gradio.registry,
+)
+
+if __name__ == "__main__":
+ demo.launch()
diff --git a/app_gemini.py b/app_gemini.py
new file mode 100644
index 0000000000000000000000000000000000000000..d3d0e67ebad578a18da1f67c510e07ea7cc0a6e1
--- /dev/null
+++ b/app_gemini.py
@@ -0,0 +1,21 @@
+import os
+
+import gemini_gradio
+
+from utils import get_app
+
+demo = get_app(
+ models=[
+ "gemini-1.5-flash",
+ "gemini-1.5-flash-8b",
+ "gemini-1.5-pro",
+ "gemini-exp-1114",
+ "gemini-exp-1121",
+ ],
+ default_model="gemini-1.5-flash",
+ src=gemini_gradio.registry,
+ accept_token=not os.getenv("GEMINI_API_KEY"),
+)
+
+if __name__ == "__main__":
+ demo.launch()
diff --git a/app_groq.py b/app_groq.py
new file mode 100644
index 0000000000000000000000000000000000000000..cb81172749566c9d1ead352f06df7496910c543d
--- /dev/null
+++ b/app_groq.py
@@ -0,0 +1,25 @@
+import os
+
+import groq_gradio
+
+from utils import get_app
+
+demo = get_app(
+ models=[
+ "llama3-groq-8b-8192-tool-use-preview",
+ "llama3-groq-70b-8192-tool-use-preview",
+ "llama-3.2-1b-preview",
+ "llama-3.2-3b-preview",
+ "llama-3.2-11b-vision-preview",
+ "llama-3.2-90b-vision-preview",
+ "mixtral-8x7b-32768",
+ "gemma2-9b-it",
+ "gemma-7b-it",
+ ],
+ default_model="llama3-groq-70b-8192-tool-use-preview",
+ src=groq_gradio.registry,
+ accept_token=not os.getenv("GROQ_API_KEY"),
+)
+
+if __name__ == "__main__":
+ demo.launch()
diff --git a/app_hf.py b/app_hf.py
new file mode 100644
index 0000000000000000000000000000000000000000..bb2a82e24c198a225e1ef553eb4fa28fdaab90d0
--- /dev/null
+++ b/app_hf.py
@@ -0,0 +1,17 @@
+from utils import get_app
+
+demo = get_app(
+ models=[
+ "microsoft/Phi-3.5-mini-instruct",
+ "HuggingFaceTB/SmolLM2-1.7B-Instruct",
+ "google/gemma-2-2b-it",
+ "openai-community/gpt2",
+ "microsoft/phi-2",
+ "TinyLlama/TinyLlama-1.1B-Chat-v1.0",
+ ],
+ default_model="HuggingFaceTB/SmolLM2-1.7B-Instruct",
+ src="models",
+)
+
+if __name__ == "__main__":
+ demo.launch()
diff --git a/app_huggingface.py b/app_huggingface.py
new file mode 100644
index 0000000000000000000000000000000000000000..49827d9cca1c1945ac0ef770f986ce45d6240df0
--- /dev/null
+++ b/app_huggingface.py
@@ -0,0 +1,82 @@
+from gradio_client import Client, handle_file
+import gradio as gr
+import os
+
+
+MODELS = {
+ "SmolVLM-Instruct": "akhaliq/SmolVLM-Instruct"
+}
+
+def create_chat_fn(client):
+ def chat(message, history):
+ # Extract text and files from the message
+ text = message.get("text", "")
+ files = message.get("files", [])
+
+ # Handle file uploads if present
+ processed_files = [handle_file(f) for f in files]
+
+ response = client.predict(
+ message={"text": text, "files": processed_files},
+ system_prompt="You are a helpful AI assistant.",
+ temperature=0.7,
+ max_new_tokens=1024,
+ top_k=40,
+ repetition_penalty=1.1,
+ top_p=0.95,
+ api_name="/chat"
+ )
+ return response
+ return chat
+
+def set_client_for_session(model_name, request: gr.Request):
+ headers = {}
+ if request and hasattr(request, 'headers'):
+ x_ip_token = request.headers.get('x-ip-token')
+ if x_ip_token:
+ headers["X-IP-Token"] = x_ip_token
+
+ return Client(MODELS[model_name], headers=headers)
+
+def safe_chat_fn(message, history, client):
+ if client is None:
+ return "Error: Client not initialized. Please refresh the page."
+ try:
+ return create_chat_fn(client)(message, history)
+ except Exception as e:
+ print(f"Error during chat: {str(e)}")
+ return f"Error during chat: {str(e)}"
+
+with gr.Blocks() as demo:
+
+ client = gr.State()
+
+ model_dropdown = gr.Dropdown(
+ choices=list(MODELS.keys()),
+ value="SmolVLM-Instruct",
+ label="Select Model",
+ interactive=True
+ )
+
+ chat_interface = gr.ChatInterface(
+ fn=safe_chat_fn,
+ additional_inputs=[client],
+ multimodal=True
+ )
+
+ # Update client when model changes
+ model_dropdown.change(
+ fn=set_client_for_session,
+ inputs=[model_dropdown],
+ outputs=[client]
+ )
+
+ # Initialize client on page load
+ demo.load(
+ fn=set_client_for_session,
+ inputs=[gr.State("SmolVLM-Instruct")],
+ outputs=[client]
+ )
+
+demo = demo
+
diff --git a/app_hyperbolic.py b/app_hyperbolic.py
new file mode 100644
index 0000000000000000000000000000000000000000..e6f3a134cc11c647e4f261537351fa40d7e2ef73
--- /dev/null
+++ b/app_hyperbolic.py
@@ -0,0 +1,26 @@
+import os
+
+import hyperbolic_gradio
+
+from utils import get_app
+
+demo = get_app(
+ models=[
+ "Qwen/Qwen2.5-Coder-32B-Instruct",
+ "meta-llama/Llama-3.2-3B-Instruct",
+ "meta-llama/Meta-Llama-3.1-8B-Instruct",
+ "meta-llama/Meta-Llama-3.1-70B-Instruct",
+ "meta-llama/Meta-Llama-3-70B-Instruct",
+ "NousResearch/Hermes-3-Llama-3.1-70B",
+ "Qwen/Qwen2.5-72B-Instruct",
+ "deepseek-ai/DeepSeek-V2.5",
+ "meta-llama/Meta-Llama-3.1-405B-Instruct",
+ "Qwen/QwQ-32B-Preview",
+ ],
+ default_model="Qwen/QwQ-32B-Preview",
+ src=hyperbolic_gradio.registry,
+ accept_token=not os.getenv("HYPERBOLIC_API_KEY"),
+)
+
+if __name__ == "__main__":
+ demo.launch()
diff --git a/app_marco_o1.py b/app_marco_o1.py
new file mode 100644
index 0000000000000000000000000000000000000000..b2b2a2ca1afa977a91b5785b8e98bf55883a90ab
--- /dev/null
+++ b/app_marco_o1.py
@@ -0,0 +1,12 @@
+import gradio as gr
+import spaces
+import transformers_gradio
+
+demo = gr.load(name="AIDC-AI/Marco-o1", src=transformers_gradio.registry)
+demo.fn = spaces.GPU()(demo.fn)
+
+for fn in demo.fns.values():
+ fn.api_name = False
+
+if __name__ == "__main__":
+ demo.launch()
diff --git a/app_mistral.py b/app_mistral.py
new file mode 100644
index 0000000000000000000000000000000000000000..994cf6c652d723791897f7b0523c4f06c1eaf741
--- /dev/null
+++ b/app_mistral.py
@@ -0,0 +1,27 @@
+import os
+
+import mistral_gradio
+
+from utils import get_app
+
+demo = get_app(
+ models=[
+ "mistral-large-latest",
+ "pixtral-large-latest",
+ "ministral-3b-latest",
+ "ministral-8b-latest",
+ "mistral-small-latest",
+ "codestral-latest",
+ "mistral-embed",
+ "mistral-moderation-latest",
+ "pixtral-12b-2409",
+ "open-mistral-nemo",
+ "open-codestral-mamba",
+ ],
+ default_model="pixtral-large-latest",
+ src=mistral_gradio.registry,
+ accept_token=not os.getenv("MISTRAL_API_KEY"),
+)
+
+if __name__ == "__main__":
+ demo.launch()
diff --git a/app_nvidia.py b/app_nvidia.py
new file mode 100644
index 0000000000000000000000000000000000000000..a23bf59cf7df444ddbc835316e4e30d9cb7ca4bb
--- /dev/null
+++ b/app_nvidia.py
@@ -0,0 +1,52 @@
+import os
+
+import nvidia_gradio
+
+from utils import get_app
+
+demo = get_app(
+ models=[
+ "nvidia/llama3-chatqa-1.5-70b",
+ "nvidia/llama3-chatqa-1.5-8b",
+ "nvidia-nemotron-4-340b-instruct",
+ "meta/llama-3.1-70b-instruct",
+ "meta/codellama-70b",
+ "meta/llama2-70b",
+ "meta/llama3-8b",
+ "meta/llama3-70b",
+ "mistralai/codestral-22b-instruct-v0.1",
+ "mistralai/mathstral-7b-v0.1",
+ "mistralai/mistral-large-2-instruct",
+ "mistralai/mistral-7b-instruct",
+ "mistralai/mistral-7b-instruct-v0.3",
+ "mistralai/mixtral-8x7b-instruct",
+ "mistralai/mixtral-8x22b-instruct",
+ "mistralai/mistral-large",
+ "google/gemma-2b",
+ "google/gemma-7b",
+ "google/gemma-2-2b-it",
+ "google/gemma-2-9b-it",
+ "google/gemma-2-27b-it",
+ "google/codegemma-1.1-7b",
+ "google/codegemma-7b",
+ "google/recurrentgemma-2b",
+ "google/shieldgemma-9b",
+ "microsoft/phi-3-medium-128k-instruct",
+ "microsoft/phi-3-medium-4k-instruct",
+ "microsoft/phi-3-mini-128k-instruct",
+ "microsoft/phi-3-mini-4k-instruct",
+ "microsoft/phi-3-small-128k-instruct",
+ "microsoft/phi-3-small-8k-instruct",
+ "qwen/qwen2-7b-instruct",
+ "databricks/dbrx-instruct",
+ "deepseek-ai/deepseek-coder-6.7b-instruct",
+ "upstage/solar-10.7b-instruct",
+ "snowflake/arctic",
+ ],
+ default_model="meta/llama-3.1-70b-instruct",
+ src=nvidia_gradio.registry,
+ accept_token=not os.getenv("NVIDIA_API_KEY"),
+)
+
+if __name__ == "__main__":
+ demo.launch()
diff --git a/app_openai.py b/app_openai.py
new file mode 100644
index 0000000000000000000000000000000000000000..c18fb88599a1b995211d58075e648f0a4dc6684b
--- /dev/null
+++ b/app_openai.py
@@ -0,0 +1,34 @@
+import os
+
+import openai_gradio
+
+from utils import get_app
+
+demo = get_app(
+ models=[
+ "gpt-4o-2024-11-20",
+ "gpt-4o",
+ "gpt-4o-2024-08-06",
+ "gpt-4o-2024-05-13",
+ "chatgpt-4o-latest",
+ "gpt-4o-mini",
+ "gpt-4o-mini-2024-07-18",
+ "o1-preview",
+ "o1-preview-2024-09-12",
+ "o1-mini",
+ "o1-mini-2024-09-12",
+ "gpt-4-turbo",
+ "gpt-4-turbo-2024-04-09",
+ "gpt-4-turbo-preview",
+ "gpt-4-0125-preview",
+ "gpt-4-1106-preview",
+ "gpt-4",
+ "gpt-4-0613",
+ ],
+ default_model="gpt-4o-2024-11-20",
+ src=openai_gradio.registry,
+ accept_token=not os.getenv("OPENAI_API_KEY"),
+)
+
+if __name__ == "__main__":
+ demo.launch()
diff --git a/app_perplexity.py b/app_perplexity.py
new file mode 100644
index 0000000000000000000000000000000000000000..62c6d320792696577a14e707ae34e52f457b4476
--- /dev/null
+++ b/app_perplexity.py
@@ -0,0 +1,23 @@
+import os
+
+import perplexity_gradio
+
+from utils import get_app
+
+demo = get_app(
+ models=[
+ "llama-3.1-sonar-large-128k-online",
+ "llama-3.1-sonar-small-128k-online",
+ "llama-3.1-sonar-huge-128k-online",
+ "llama-3.1-sonar-small-128k-chat",
+ "llama-3.1-sonar-large-128k-chat",
+ "llama-3.1-8b-instruct",
+ "llama-3.1-70b-instruct",
+ ],
+ default_model="llama-3.1-sonar-huge-128k-online",
+ src=perplexity_gradio.registry,
+ accept_token=not os.getenv("PERPLEXITY_API_KEY"),
+)
+
+if __name__ == "__main__":
+ demo.launch()
diff --git a/app_playai.py b/app_playai.py
new file mode 100644
index 0000000000000000000000000000000000000000..b7b1deb388b578ca103e7207cc0f041a80a80bee
--- /dev/null
+++ b/app_playai.py
@@ -0,0 +1,10 @@
+import gradio as gr
+import playai_gradio
+
+demo =gr.load(
+ name='PlayDialog',
+ src=playai_gradio.registry,
+)
+
+for fn in demo.fns.values():
+ fn.api_name = False
\ No newline at end of file
diff --git a/app_qwen.py b/app_qwen.py
new file mode 100644
index 0000000000000000000000000000000000000000..30773270f515c83346cfe451b8b2adfddde6323c
--- /dev/null
+++ b/app_qwen.py
@@ -0,0 +1,26 @@
+import os
+
+import dashscope_gradio
+
+from utils import get_app
+
+demo = get_app(
+ models=[
+ "qwen-turbo-latest",
+ "qwen-turbo",
+ "qwen-plus",
+ "qwen-max",
+ "qwen1.5-110b-chat",
+ "qwen1.5-72b-chat",
+ "qwen1.5-32b-chat",
+ "qwen1.5-14b-chat",
+ "qwen1.5-7b-chat",
+ "qwq-32b-preview",
+ ],
+ default_model="qwq-32b-preview",
+ src=dashscope_gradio.registry,
+ accept_token=not os.getenv("DASHSCOPE_API_KEY"),
+)
+
+if __name__ == "__main__":
+ demo.launch()
diff --git a/app_sambanova.py b/app_sambanova.py
new file mode 100644
index 0000000000000000000000000000000000000000..582500a1e9cdc15b240016641b4abd0da6d240a5
--- /dev/null
+++ b/app_sambanova.py
@@ -0,0 +1,24 @@
+import os
+
+import sambanova_gradio
+
+from utils import get_app
+
+demo = get_app(
+ models=[
+ "Meta-Llama-3.2-1B-Instruct",
+ "Meta-Llama-3.2-3B-Instruct",
+ "Llama-3.2-11B-Vision-Instruct",
+ "Llama-3.2-90B-Vision-Instruct",
+ "Meta-Llama-3.1-8B-Instruct",
+ "Meta-Llama-3.1-70B-Instruct",
+ "Meta-Llama-3.1-405B-Instruct",
+ ],
+ default_model="Llama-3.2-90B-Vision-Instruct",
+ src=sambanova_gradio.registry,
+ accept_token=not os.getenv("SAMBANOVA_API_KEY"),
+ multimodal=True,
+)
+
+if __name__ == "__main__":
+ demo.launch()
diff --git a/app_sambanova_qwen.py b/app_sambanova_qwen.py
new file mode 100644
index 0000000000000000000000000000000000000000..3d5c6e8af611ef1c0dc995bf0ea4fa88a1860c8f
--- /dev/null
+++ b/app_sambanova_qwen.py
@@ -0,0 +1,21 @@
+import os
+
+import sambanova_gradio
+
+from utils import get_app
+
+demo = get_app(
+ models=[
+ "Qwen2.5-Coder-0.5B-Instruct",
+ "Qwen2.5-0.5B-Instruct",
+ "Qwen2.5-Coder-32B-Instruct",
+ "Qwen2.5-72B-Instruct",
+ ],
+ default_model="Qwen2.5-Coder-32B-Instruct",
+ src=sambanova_gradio.registry,
+ accept_token=not os.getenv("SAMBANOVA_API_KEY"),
+ multimodal=True,
+)
+
+if __name__ == "__main__":
+ demo.launch()
diff --git a/app_showui.py b/app_showui.py
new file mode 100644
index 0000000000000000000000000000000000000000..beda5ee3608963330e49c56b627578b76da21c93
--- /dev/null
+++ b/app_showui.py
@@ -0,0 +1,17 @@
+import gradio as gr
+import spaces
+
+# Load the Gradio space
+demo = gr.load(name="showlab/ShowUI", src="spaces")
+
+# Ensure the main function runs on a GPU
+if hasattr(demo, 'fn'):
+ demo.fn = spaces.GPU()(demo.fn)
+
+# Disable API access for all functions
+if hasattr(demo, 'fns'):
+ for fn in demo.fns.values():
+ fn.api_name = False
+
+if __name__ == "__main__":
+ demo.launch()
\ No newline at end of file
diff --git a/app_together.py b/app_together.py
new file mode 100644
index 0000000000000000000000000000000000000000..a8ce094f55a0adf7273b17f7411b638014c41cf3
--- /dev/null
+++ b/app_together.py
@@ -0,0 +1,51 @@
+import os
+
+import together_gradio
+
+from utils import get_app
+
+demo = get_app(
+ models=[
+ "meta-llama/Llama-Vision-Free",
+ "meta-llama/Llama-3.2-11B-Vision-Instruct-Turbo",
+ "meta-llama/Llama-3.2-90B-Vision-Instruct-Turbo",
+ "meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo",
+ "meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo",
+ "meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo",
+ "meta-llama/Meta-Llama-3-8B-Instruct-Turbo",
+ "meta-llama/Meta-Llama-3-70B-Instruct-Turbo",
+ "meta-llama/Llama-3.2-3B-Instruct-Turbo",
+ "meta-llama/Meta-Llama-3-8B-Instruct-Lite",
+ "meta-llama/Meta-Llama-3-70B-Instruct-Lite",
+ "meta-llama/Llama-3-8b-chat-hf",
+ "meta-llama/Llama-3-70b-chat-hf",
+ "nvidia/Llama-3.1-Nemotron-70B-Instruct-HF",
+ "Qwen/Qwen2.5-Coder-32B-Instruct",
+ "microsoft/WizardLM-2-8x22B",
+ "google/gemma-2-27b-it",
+ "google/gemma-2-9b-it",
+ "databricks/dbrx-instruct",
+ "mistralai/Mixtral-8x7B-Instruct-v0.1",
+ "mistralai/Mixtral-8x22B-Instruct-v0.1",
+ "Qwen/Qwen2.5-7B-Instruct-Turbo",
+ "Qwen/Qwen2.5-72B-Instruct-Turbo",
+ "Qwen/Qwen2-72B-Instruct",
+ "deepseek-ai/deepseek-llm-67b-chat",
+ "google/gemma-2b-it",
+ "Gryphe/MythoMax-L2-13b",
+ "meta-llama/Llama-2-13b-chat-hf",
+ "mistralai/Mistral-7B-Instruct-v0.1",
+ "mistralai/Mistral-7B-Instruct-v0.2",
+ "mistralai/Mistral-7B-Instruct-v0.3",
+ "NousResearch/Nous-Hermes-2-Mixtral-8x7B-DPO",
+ "togethercomputer/StripedHyena-Nous-7B",
+ "upstage/SOLAR-10.7B-Instruct-v1.0",
+ ],
+ default_model="meta-llama/Llama-3.2-11B-Vision-Instruct-Turbo",
+ src=together_gradio.registry,
+ accept_token=not os.getenv("TOGETHER_API_KEY"),
+ multimodal=True,
+)
+
+if __name__ == "__main__":
+ demo.launch()
diff --git a/app_xai.py b/app_xai.py
new file mode 100644
index 0000000000000000000000000000000000000000..a64fa3886931b113117851c4e7467ef6499748f2
--- /dev/null
+++ b/app_xai.py
@@ -0,0 +1,18 @@
+import os
+
+import xai_gradio
+
+from utils import get_app
+
+demo = get_app(
+ models=[
+ "grok-beta",
+ "grok-vision-beta",
+ ],
+ default_model="grok-vision-beta",
+ src=xai_gradio.registry,
+ accept_token=not os.getenv("XAI_API_KEY"),
+)
+
+if __name__ == "__main__":
+ demo.launch()
diff --git a/backend_api.py b/backend_api.py
deleted file mode 100644
index 95267e900031ae7f672cbc11cc46d20885f2cf39..0000000000000000000000000000000000000000
--- a/backend_api.py
+++ /dev/null
@@ -1,1738 +0,0 @@
-"""
-FastAPI backend for AnyCoder - provides REST API endpoints
-"""
-from fastapi import FastAPI, HTTPException, Header, WebSocket, WebSocketDisconnect, Request, Response
-from fastapi.middleware.cors import CORSMiddleware
-from fastapi.responses import StreamingResponse, RedirectResponse, JSONResponse
-from pydantic import BaseModel
-from typing import Optional, List, Dict, AsyncGenerator
-import json
-import asyncio
-from datetime import datetime, timedelta
-import secrets
-import base64
-import urllib.parse
-import re
-
-# Import only what we need, avoiding Gradio UI imports
-import sys
-import os
-from huggingface_hub import InferenceClient
-import httpx
-
-# Import model handling from backend_models
-from backend_models import (
- get_inference_client,
- get_real_model_id,
- is_native_sdk_model,
- is_mistral_model
-)
-
-# Import project importer for importing from HF/GitHub
-from project_importer import ProjectImporter
-
-# Import system prompts from standalone backend_prompts.py
-# No dependencies on Gradio or heavy libraries
-print("[Startup] Loading system prompts from backend_prompts...")
-
-try:
- from backend_prompts import (
- HTML_SYSTEM_PROMPT,
- TRANSFORMERS_JS_SYSTEM_PROMPT,
- STREAMLIT_SYSTEM_PROMPT,
- REACT_SYSTEM_PROMPT,
- REACT_FOLLOW_UP_SYSTEM_PROMPT, # Import React followup prompt
- get_gradio_system_prompt, # Import the function to get dynamic prompt
- get_comfyui_system_prompt, # Import the function to get dynamic ComfyUI prompt
- JSON_SYSTEM_PROMPT,
- DAGGR_SYSTEM_PROMPT,
- GENERIC_SYSTEM_PROMPT
- )
- # Get the Gradio system prompt (includes full Gradio 6 documentation)
- GRADIO_SYSTEM_PROMPT = get_gradio_system_prompt()
- # Get the ComfyUI system prompt (includes full ComfyUI documentation)
- COMFYUI_SYSTEM_PROMPT = get_comfyui_system_prompt()
- print("[Startup] ✅ All system prompts loaded successfully from backend_prompts.py")
- print(f"[Startup] 📚 Gradio system prompt loaded with full documentation ({len(GRADIO_SYSTEM_PROMPT)} chars)")
- print(f"[Startup] 📚 ComfyUI system prompt loaded with full documentation ({len(COMFYUI_SYSTEM_PROMPT)} chars)")
-except Exception as e:
- import traceback
- print(f"[Startup] ❌ ERROR: Could not import from backend_prompts: {e}")
- print(f"[Startup] Traceback: {traceback.format_exc()}")
- print("[Startup] Using minimal fallback prompts")
-
- # Define minimal fallback prompts
- HTML_SYSTEM_PROMPT = "You are an expert web developer. Create complete HTML applications with CSS and JavaScript."
- TRANSFORMERS_JS_SYSTEM_PROMPT = "You are an expert at creating transformers.js applications. Generate complete working code."
- STREAMLIT_SYSTEM_PROMPT = "You are an expert Streamlit developer. Create complete Streamlit applications."
- REACT_SYSTEM_PROMPT = "You are an expert React developer. Create complete React applications with Next.js."
- GRADIO_SYSTEM_PROMPT = "You are an expert Gradio developer. Create complete, working Gradio applications."
- COMFYUI_SYSTEM_PROMPT = "You are an expert ComfyUI developer. Generate clean, valid JSON workflows for ComfyUI based on the user's request. READ THE USER'S REQUEST CAREFULLY and create a workflow that matches their specific needs."
- JSON_SYSTEM_PROMPT = "You are an expert at generating JSON configurations. Create valid, well-structured JSON."
- GENERIC_SYSTEM_PROMPT = "You are an expert {language} developer. Create complete, working {language} applications."
-
-print("[Startup] System prompts initialization complete")
-
-# Cache system prompts map for fast lookup (created once at startup)
-SYSTEM_PROMPT_CACHE = {
- "html": HTML_SYSTEM_PROMPT,
- "gradio": GRADIO_SYSTEM_PROMPT,
- "streamlit": STREAMLIT_SYSTEM_PROMPT,
- "transformers.js": TRANSFORMERS_JS_SYSTEM_PROMPT,
- "react": REACT_SYSTEM_PROMPT,
- "comfyui": COMFYUI_SYSTEM_PROMPT, # Use ComfyUI-specific prompt with documentation
- "daggr": DAGGR_SYSTEM_PROMPT,
-}
-
-# Client connection pool for reuse (thread-safe)
-import threading
-_client_pool = {}
-_client_pool_lock = threading.Lock()
-
-def get_cached_client(model_id: str, provider: str = "auto"):
- """Get or create a cached API client for reuse"""
- cache_key = f"{model_id}:{provider}"
-
- with _client_pool_lock:
- if cache_key not in _client_pool:
- _client_pool[cache_key] = get_inference_client(model_id, provider)
- return _client_pool[cache_key]
-
-# Define models and languages here to avoid importing Gradio UI
-AVAILABLE_MODELS = [
- {"name": "Kimi-K2.6 ✨", "id": "moonshotai/Kimi-K2.6", "description": "Kimi-K2.6 - Latest powerful model via HuggingFace Router with Novita provider (Default)", "supports_images": True},
- {"name": "Gemma-4-31B 🤖", "id": "google/gemma-4-31B-it", "description": "Gemma-4-31B-it - Powerful model via HuggingFace Router with fastest provider", "supports_images": True},
- {"name": "GLM-5.1 🚀", "id": "zai-org/GLM-5.1", "description": "GLM-5.1 - Powerful model via HuggingFace Router with Novita provider", "supports_images": False},
- {"name": "Qwen3.5-397B 🤖", "id": "Qwen/Qwen3.5-397B-A17B", "description": "Qwen3.5-397B-A17B - Latest powerful model via HuggingFace Router", "supports_images": True},
- {"name": "MiniMax-M2.5 🤖", "id": "MiniMaxAI/MiniMax-M2.5", "description": "MiniMax-M2.5 - Latest powerful coder model via HuggingFace Router with fastest provider", "supports_images": False},
- {"name": "GLM-5 🧠", "id": "zai-org/GLM-5", "description": "GLM-5 - New powerful reasoning model via HuggingFace Router", "supports_images": False},
- {"name": "Qwen3-Coder-Next 🤖", "id": "Qwen/Qwen3-Coder-Next", "description": "Qwen3-Coder-Next - Latest powerful coder model via HuggingFace Router with Novita provider", "supports_images": False},
- {"name": "Kimi-K2.5 🧠", "id": "moonshotai/Kimi-K2.5", "description": "Kimi-K2.5 - New powerful reasoning model via HuggingFace Router with Novita provider", "supports_images": True},
- {"name": "GLM-4.7-Flash ⚡", "id": "zai-org/GLM-4.7-Flash", "description": "GLM-4.7-Flash - Ultra-fast GLM model via HuggingFace Router with Novita provider", "supports_images": False},
- {"name": "GLM-4.7", "id": "zai-org/GLM-4.7", "description": "GLM-4.7 - Latest GLM model via HuggingFace Router with Cerebras provider", "supports_images": False},
- {"name": "MiniMax M2.1", "id": "MiniMaxAI/MiniMax-M2.1", "description": "MiniMax M2.1 - Enhanced model via HuggingFace Router", "supports_images": False},
- {"name": "GLM-4.6", "id": "zai-org/GLM-4.6", "description": "GLM-4.6 model via HuggingFace with Cerebras provider", "supports_images": False},
- {"name": "GLM-4.6V 👁️", "id": "zai-org/GLM-4.6V:zai-org", "description": "GLM-4.6V vision model - supports image uploads for visual understanding", "supports_images": True},
- {"name": "DeepSeek V3", "id": "deepseek-ai/DeepSeek-V3", "description": "DeepSeek V3 - Fast model for code generation via HuggingFace Router with Novita provider", "supports_images": False},
- {"name": "DeepSeek R1", "id": "deepseek-ai/DeepSeek-R1", "description": "DeepSeek R1 model for code generation via HuggingFace", "supports_images": False},
- {"name": "MiniMax M2", "id": "MiniMaxAI/MiniMax-M2", "description": "MiniMax M2 model via HuggingFace InferenceClient with Novita provider", "supports_images": False},
- {"name": "Kimi K2 Thinking", "id": "moonshotai/Kimi-K2-Thinking", "description": "Moonshot Kimi K2 Thinking model via HuggingFace with Together AI provider", "supports_images": False},
-]
-
-# Cache model lookup for faster access (built after AVAILABLE_MODELS is defined)
-MODEL_CACHE = {model["id"]: model for model in AVAILABLE_MODELS}
-print(f"[Startup] ✅ Performance optimizations loaded: {len(SYSTEM_PROMPT_CACHE)} cached prompts, {len(MODEL_CACHE)} cached models, client pooling enabled")
-
-LANGUAGE_CHOICES = ["html", "gradio", "transformers.js", "streamlit", "comfyui", "react", "daggr"]
-
-app = FastAPI(title="AnyCoder API", version="1.0.0")
-
-# OAuth and environment configuration (must be before CORS)
-OAUTH_CLIENT_ID = os.getenv("OAUTH_CLIENT_ID", "")
-OAUTH_CLIENT_SECRET = os.getenv("OAUTH_CLIENT_SECRET", "")
-OAUTH_SCOPES = os.getenv("OAUTH_SCOPES", "openid profile manage-repos write-discussions")
-OPENID_PROVIDER_URL = os.getenv("OPENID_PROVIDER_URL", "https://huggingface.co")
-SPACE_HOST = os.getenv("SPACE_HOST", "localhost:7860")
-
-# Configure CORS - allow all origins in production, specific in dev
-# In Docker Space, requests come from the same domain via Next.js proxy
-ALLOWED_ORIGINS = os.getenv("ALLOWED_ORIGINS", "*").split(",") if os.getenv("ALLOWED_ORIGINS") else [
- "http://localhost:3000",
- "http://localhost:3001",
- "http://localhost:7860",
- f"https://{SPACE_HOST}" if SPACE_HOST and not SPACE_HOST.startswith("localhost") else "http://localhost:7860"
-]
-
-app.add_middleware(
- CORSMiddleware,
- allow_origins=ALLOWED_ORIGINS if ALLOWED_ORIGINS != ["*"] else ["*"],
- allow_credentials=True,
- allow_methods=["*"],
- allow_headers=["*"],
- allow_origin_regex=r"https://.*\.hf\.space" if SPACE_HOST and not SPACE_HOST.startswith("localhost") else None,
-)
-
-# In-memory store for OAuth states (in production, use Redis or similar)
-oauth_states = {}
-
-# In-memory store for user sessions
-user_sessions = {}
-
-
-def is_session_expired(session_data: dict) -> bool:
- """Check if session has expired"""
- expires_at = session_data.get("expires_at")
- if not expires_at:
- # If no expiration info, check if session is older than 8 hours
- timestamp = session_data.get("timestamp", datetime.now())
- return (datetime.now() - timestamp) > timedelta(hours=8)
-
- return datetime.now() >= expires_at
-
-
-# Background task for cleaning up expired sessions
-async def cleanup_expired_sessions():
- """Periodically clean up expired sessions"""
- while True:
- try:
- await asyncio.sleep(3600) # Run every hour
-
- expired_sessions = []
- for session_token, session_data in user_sessions.items():
- if is_session_expired(session_data):
- expired_sessions.append(session_token)
-
- for session_token in expired_sessions:
- user_sessions.pop(session_token, None)
- print(f"[Auth] Cleaned up expired session: {session_token[:10]}...")
-
- if expired_sessions:
- print(f"[Auth] Cleaned up {len(expired_sessions)} expired session(s)")
- except Exception as e:
- print(f"[Auth] Cleanup error: {e}")
-
-# Start cleanup task on app startup
-@app.on_event("startup")
-async def startup_event():
- """Run startup tasks"""
- asyncio.create_task(cleanup_expired_sessions())
- print("[Startup] ✅ Session cleanup task started")
-
-
-# Pydantic models for request/response
-class CodeGenerationRequest(BaseModel):
- query: str
- language: str = "html"
- model_id: str = "moonshotai/Kimi-K2.6"
- provider: str = "auto"
- history: List[List[str]] = []
- agent_mode: bool = False
- existing_repo_id: Optional[str] = None # For auto-deploy to update existing space
- skip_auto_deploy: bool = False # Skip auto-deploy (for PR creation)
- image_url: Optional[str] = None # For vision models like GLM-4.6V
-
-
-class DeploymentRequest(BaseModel):
- code: str
- space_name: Optional[str] = None
- language: str
- requirements: Optional[str] = None
- existing_repo_id: Optional[str] = None # For updating existing spaces
- commit_message: Optional[str] = None
- history: List[Dict] = [] # Chat history for tracking deployed spaces
-
-
-class AuthStatus(BaseModel):
- authenticated: bool
- username: Optional[str] = None
- message: str
-
-
-class ModelInfo(BaseModel):
- name: str
- id: str
- description: str
-
-
-class CodeGenerationResponse(BaseModel):
- code: str
- history: List[List[str]]
- status: str
-
-
-class ImportRequest(BaseModel):
- url: str
- prefer_local: bool = False
- username: Optional[str] = None # Username of authenticated user for ownership check
-
-
-class ImportResponse(BaseModel):
- status: str
- message: str
- code: str
- language: str
- url: str
- metadata: Dict
- owned_by_user: bool = False # True if user owns the imported repo
- repo_id: Optional[str] = None # The repo ID (username/repo-name) if applicable
-
-
-class PullRequestRequest(BaseModel):
- repo_id: str # username/space-name
- code: str
- language: str
- pr_title: Optional[str] = None
- pr_description: Optional[str] = None
-
-
-class PullRequestResponse(BaseModel):
- success: bool
- message: str
- pr_url: Optional[str] = None
-
-
-class DuplicateSpaceRequest(BaseModel):
- from_space_id: str # username/space-name
- to_space_name: Optional[str] = None # Just the name, not full ID
- private: bool = False
-
-
-class DuplicateSpaceResponse(BaseModel):
- success: bool
- message: str
- space_url: Optional[str] = None
- space_id: Optional[str] = None
-
-
-# Mock authentication for development
-# In production, integrate with HuggingFace OAuth
-class MockAuth:
- def __init__(self, token: Optional[str] = None, username: Optional[str] = None):
- self.token = token
- self.username = username
-
- def is_authenticated(self):
- return bool(self.token)
-
-
-def get_auth_from_header(authorization: Optional[str] = None):
- """Extract authentication from header or session token"""
- if not authorization:
- return MockAuth(None, None)
-
- # Handle "Bearer " prefix
- if authorization.startswith("Bearer "):
- token = authorization.replace("Bearer ", "")
- else:
- token = authorization
-
- # Check if this is a session token (UUID format)
- if token and "-" in token and len(token) > 20:
- # Look up the session to get user info
- if token in user_sessions:
- session = user_sessions[token]
- username = session.get("username")
-
- # If username is missing from session (e.g., old session), try to fetch it
- if not username and session.get("user_info"):
- user_info = session["user_info"]
- # Use same order as OAuth callback for consistency
- username = (
- user_info.get("preferred_username") or
- user_info.get("name") or
- user_info.get("sub") or
- user_info.get("username") or
- "user"
- )
- # Update the session with the username for future requests
- session["username"] = username
- print(f"[Auth] Extracted and cached username from user_info: {username}")
-
- return MockAuth(session["access_token"], username)
-
- # Dev token format: dev_token__
- if token and token.startswith("dev_token_"):
- parts = token.split("_")
- username = parts[2] if len(parts) > 2 else "user"
- return MockAuth(token, username)
-
- # Regular OAuth access token passed directly - try to fetch username from HF
- # This happens when frontend sends OAuth token after OAuth callback
- if token and len(token) > 20:
- try:
- from huggingface_hub import HfApi
- hf_api = HfApi(token=token)
- user_info = hf_api.whoami()
- username = (
- user_info.get("preferred_username") or
- user_info.get("name") or
- user_info.get("sub") or
- "user"
- )
- print(f"[Auth] Fetched username from OAuth token: {username}")
- return MockAuth(token, username)
- except Exception as e:
- print(f"[Auth] Could not fetch username from OAuth token: {e}")
- # Return with token but no username - deployment will try to fetch it
- return MockAuth(token, None)
-
- # Fallback: token with no username
- return MockAuth(token, None)
-
-
-@app.get("/")
-async def root():
- """Health check endpoint"""
- return {"status": "ok", "message": "AnyCoder API is running"}
-
-
-@app.get("/api/models", response_model=List[ModelInfo])
-async def get_models():
- """Get available AI models"""
- return [
- ModelInfo(
- name=model["name"],
- id=model["id"],
- description=model["description"]
- )
- for model in AVAILABLE_MODELS
- ]
-
-
-@app.get("/api/languages")
-async def get_languages():
- """Get available programming languages/frameworks"""
- return {"languages": LANGUAGE_CHOICES}
-
-
-@app.get("/api/auth/login")
-async def oauth_login(request: Request):
- """Initiate OAuth login flow"""
- # Generate a random state to prevent CSRF
- state = secrets.token_urlsafe(32)
- oauth_states[state] = {"timestamp": datetime.now()}
-
- # Build redirect URI
- protocol = "https" if SPACE_HOST and not SPACE_HOST.startswith("localhost") else "http"
- redirect_uri = f"{protocol}://{SPACE_HOST}/api/auth/callback"
-
- # Build authorization URL
- auth_url = (
- f"{OPENID_PROVIDER_URL}/oauth/authorize"
- f"?client_id={OAUTH_CLIENT_ID}"
- f"&redirect_uri={urllib.parse.quote(redirect_uri)}"
- f"&scope={urllib.parse.quote(OAUTH_SCOPES)}"
- f"&state={state}"
- f"&response_type=code"
- )
-
- return JSONResponse({"login_url": auth_url, "state": state})
-
-
-@app.get("/api/auth/callback")
-async def oauth_callback(code: str, state: str, request: Request):
- """Handle OAuth callback"""
- # Verify state to prevent CSRF
- if state not in oauth_states:
- raise HTTPException(status_code=400, detail="Invalid state parameter")
-
- # Clean up old states
- oauth_states.pop(state, None)
-
- # Exchange code for tokens
- protocol = "https" if SPACE_HOST and not SPACE_HOST.startswith("localhost") else "http"
- redirect_uri = f"{protocol}://{SPACE_HOST}/api/auth/callback"
-
- # Prepare authorization header
- auth_string = f"{OAUTH_CLIENT_ID}:{OAUTH_CLIENT_SECRET}"
- auth_bytes = auth_string.encode('utf-8')
- auth_b64 = base64.b64encode(auth_bytes).decode('utf-8')
-
- async with httpx.AsyncClient() as client:
- try:
- token_response = await client.post(
- f"{OPENID_PROVIDER_URL}/oauth/token",
- data={
- "client_id": OAUTH_CLIENT_ID,
- "code": code,
- "grant_type": "authorization_code",
- "redirect_uri": redirect_uri,
- },
- headers={
- "Authorization": f"Basic {auth_b64}",
- "Content-Type": "application/x-www-form-urlencoded",
- },
- )
- token_response.raise_for_status()
- token_data = token_response.json()
-
- # Get user info
- access_token = token_data.get("access_token")
- userinfo_response = await client.get(
- f"{OPENID_PROVIDER_URL}/oauth/userinfo",
- headers={"Authorization": f"Bearer {access_token}"},
- )
- userinfo_response.raise_for_status()
- user_info = userinfo_response.json()
-
- # Extract username - try multiple possible fields
- username = (
- user_info.get("preferred_username") or # Primary HF field
- user_info.get("name") or # Alternative field
- user_info.get("sub") or # OpenID subject
- user_info.get("username") or # Generic username
- "user" # Fallback
- )
-
- print(f"[OAuth] User info received: {user_info}")
- print(f"[OAuth] Extracted username: {username}")
-
- # Calculate token expiration
- # OAuth tokens typically have expires_in in seconds
- expires_in = token_data.get("expires_in", 28800) # Default 8 hours
- expires_at = datetime.now() + timedelta(seconds=expires_in)
-
- # Create session
- session_token = secrets.token_urlsafe(32)
- user_sessions[session_token] = {
- "access_token": access_token,
- "user_info": user_info,
- "timestamp": datetime.now(),
- "expires_at": expires_at,
- "username": username,
- "deployed_spaces": [] # Track deployed spaces for follow-up updates
- }
-
- print(f"[OAuth] Session created: {session_token[:10]}... for user: {username}")
-
- # Redirect to frontend with session token
- frontend_url = f"{protocol}://{SPACE_HOST}/?session={session_token}"
- return RedirectResponse(url=frontend_url)
-
- except httpx.HTTPError as e:
- print(f"OAuth error: {e}")
- raise HTTPException(status_code=500, detail=f"OAuth failed: {str(e)}")
-
-
-async def validate_token_with_hf(access_token: str) -> bool:
- """Validate token with HuggingFace API"""
- try:
- async with httpx.AsyncClient() as client:
- response = await client.get(
- f"{OPENID_PROVIDER_URL}/oauth/userinfo",
- headers={"Authorization": f"Bearer {access_token}"},
- timeout=5.0
- )
- return response.status_code == 200
- except Exception as e:
- print(f"[Auth] Token validation error: {e}")
- return False
-
-
-@app.get("/api/auth/session")
-async def get_session(session: str):
- """Get user info from session token"""
- if session not in user_sessions:
- raise HTTPException(status_code=401, detail="Invalid session")
-
- session_data = user_sessions[session]
-
- # Check if session has expired
- if is_session_expired(session_data):
- # Clean up expired session
- user_sessions.pop(session, None)
- raise HTTPException(status_code=401, detail="Session expired. Please sign in again.")
-
- # Validate token with HuggingFace
- if not await validate_token_with_hf(session_data["access_token"]):
- # Token is invalid, clean up session
- user_sessions.pop(session, None)
- raise HTTPException(status_code=401, detail="Authentication expired. Please sign in again.")
-
- return {
- "access_token": session_data["access_token"],
- "user_info": session_data["user_info"],
- }
-
-
-@app.get("/api/auth/status")
-async def auth_status(authorization: Optional[str] = Header(None)):
- """Check authentication status and validate token"""
- auth = get_auth_from_header(authorization)
-
- if not auth.is_authenticated():
- return AuthStatus(
- authenticated=False,
- username=None,
- message="Not authenticated"
- )
-
- # For dev tokens, skip validation
- if auth.token and auth.token.startswith("dev_token_"):
- return AuthStatus(
- authenticated=True,
- username=auth.username,
- message=f"Authenticated as {auth.username} (dev mode)"
- )
-
- # For session tokens, check expiration and validate
- token = authorization.replace("Bearer ", "") if authorization else None
- if token and "-" in token and len(token) > 20 and token in user_sessions:
- session_data = user_sessions[token]
-
- # Check if session has expired
- if is_session_expired(session_data):
- # Clean up expired session
- user_sessions.pop(token, None)
- return AuthStatus(
- authenticated=False,
- username=None,
- message="Session expired"
- )
-
- # Validate token with HuggingFace
- if not await validate_token_with_hf(session_data["access_token"]):
- # Token is invalid, clean up session
- user_sessions.pop(token, None)
- return AuthStatus(
- authenticated=False,
- username=None,
- message="Authentication expired"
- )
-
- return AuthStatus(
- authenticated=True,
- username=auth.username,
- message=f"Authenticated as {auth.username}"
- )
-
- # For direct OAuth tokens, validate with HF
- if auth.token:
- is_valid = await validate_token_with_hf(auth.token)
- if is_valid:
- return AuthStatus(
- authenticated=True,
- username=auth.username,
- message=f"Authenticated as {auth.username}"
- )
- else:
- return AuthStatus(
- authenticated=False,
- username=None,
- message="Token expired or invalid"
- )
-
- return AuthStatus(
- authenticated=False,
- username=None,
- message="Not authenticated"
- )
-
-
-def cleanup_generated_code(code: str, language: str) -> str:
- """Remove LLM explanatory text and extract only the actual code"""
- try:
- original_code = code
-
- # Special handling for transformers.js - don't clean, pass through as-is
- # The parser will handle extracting the files from === markers
- if language == "transformers.js":
- return code
-
- # Special handling for ComfyUI JSON
- if language == "comfyui":
- # Try to parse as JSON first
- try:
- json.loads(code)
- return code # If it parses, return as-is
- except json.JSONDecodeError:
- pass
-
- # Find the last } in the code
- last_brace = code.rfind('}')
- if last_brace != -1:
- # Extract everything up to and including the last }
- potential_json = code[:last_brace + 1]
-
- # Try to find where the JSON actually starts
- json_start = 0
- if '```json' in potential_json:
- match = re.search(r'```json\s*\n', potential_json)
- if match:
- json_start = match.end()
- elif '```' in potential_json:
- match = re.search(r'```\s*\n', potential_json)
- if match:
- json_start = match.end()
-
- # Extract the JSON
- cleaned_json = potential_json[json_start:].strip()
- cleaned_json = re.sub(r'```\s*$', '', cleaned_json).strip()
-
- # Validate
- try:
- json.loads(cleaned_json)
- return cleaned_json
- except json.JSONDecodeError:
- pass
-
- # General cleanup for code languages
- # Remove markdown code blocks and extract code
- if '```' in code:
- # Pattern to match code blocks with language specifiers
- patterns = [
- r'```(?:html|HTML)\s*\n([\s\S]+?)(?:\n```|$)',
- r'```(?:python|py|Python)\s*\n([\s\S]+?)(?:\n```|$)',
- r'```(?:javascript|js|jsx|JavaScript)\s*\n([\s\S]+?)(?:\n```|$)',
- r'```(?:typescript|ts|tsx|TypeScript)\s*\n([\s\S]+?)(?:\n```|$)',
- r'```\s*\n([\s\S]+?)(?:\n```|$)', # Generic code block
- ]
-
- for pattern in patterns:
- match = re.search(pattern, code, re.IGNORECASE)
- if match:
- code = match.group(1).strip()
- break
-
- # Remove common LLM explanatory patterns
- # Remove lines that start with explanatory text
- lines = code.split('\n')
- cleaned_lines = []
- in_code = False
-
- for line in lines:
- stripped = line.strip()
-
- # Skip common explanatory patterns at the start
- if not in_code and (
- stripped.lower().startswith('here') or
- stripped.lower().startswith('this') or
- stripped.lower().startswith('the above') or
- stripped.lower().startswith('note:') or
- stripped.lower().startswith('explanation:') or
- stripped.lower().startswith('to use') or
- stripped.lower().startswith('usage:') or
- stripped.lower().startswith('instructions:') or
- stripped.startswith('===') and '===' in stripped # Section markers
- ):
- continue
-
- # Once we hit actual code, we're in
- if stripped and not stripped.startswith('#') and not stripped.startswith('//'):
- in_code = True
-
- cleaned_lines.append(line)
-
- code = '\n'.join(cleaned_lines).strip()
-
- # Remove trailing explanatory text after the code ends
- # For HTML: remove everything after final closing tag
- if language == "html":
- # Find last