Spaces:
Sleeping
Sleeping
Commit ·
df2b1f9
0
Parent(s):
Gradio UI updated
Browse files- .gradio/certificate.pem +31 -0
- .idea/.gitignore +8 -0
- DEPLOYMENT.md +366 -0
- PROJECT_SUMMARY.md +210 -0
- QUICKSTART.md +57 -0
- README.md +347 -0
- __pycache__/database.cpython-312.pyc +0 -0
- database.py +376 -0
- firebase-credentials.json +13 -0
- gitignore +31 -0
- gradio_app.py +584 -0
- pyproject.toml +13 -0
- uv.lock +0 -0
.gradio/certificate.pem
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
-----BEGIN CERTIFICATE-----
|
| 2 |
+
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
|
| 3 |
+
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
|
| 4 |
+
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
|
| 5 |
+
WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
|
| 6 |
+
ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
|
| 7 |
+
MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
|
| 8 |
+
h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
|
| 9 |
+
0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
|
| 10 |
+
A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
|
| 11 |
+
T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
|
| 12 |
+
B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
|
| 13 |
+
B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
|
| 14 |
+
KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
|
| 15 |
+
OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
|
| 16 |
+
jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
|
| 17 |
+
qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
|
| 18 |
+
rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
|
| 19 |
+
HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
|
| 20 |
+
hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
|
| 21 |
+
ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
|
| 22 |
+
3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
|
| 23 |
+
NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
|
| 24 |
+
ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
|
| 25 |
+
TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
|
| 26 |
+
jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
|
| 27 |
+
oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
|
| 28 |
+
4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
|
| 29 |
+
mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
|
| 30 |
+
emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
|
| 31 |
+
-----END CERTIFICATE-----
|
.idea/.gitignore
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Default ignored files
|
| 2 |
+
/shelf/
|
| 3 |
+
/workspace.xml
|
| 4 |
+
# Editor-based HTTP Client requests
|
| 5 |
+
/httpRequests/
|
| 6 |
+
# Datasource local storage ignored files
|
| 7 |
+
/dataSources/
|
| 8 |
+
/dataSources.local.xml
|
DEPLOYMENT.md
ADDED
|
@@ -0,0 +1,366 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Deployment Guide
|
| 2 |
+
|
| 3 |
+
Complete guide for deploying your React Agent Builder to various platforms.
|
| 4 |
+
|
| 5 |
+
---
|
| 6 |
+
|
| 7 |
+
## 🚀 Option 1: Hugging Face Spaces (Easiest)
|
| 8 |
+
|
| 9 |
+
**Best for:** Quick deployment, free hosting, automatic HTTPS
|
| 10 |
+
|
| 11 |
+
### Steps:
|
| 12 |
+
|
| 13 |
+
1. **Create requirements.txt for HF compatibility:**
|
| 14 |
+
```bash
|
| 15 |
+
uv pip compile pyproject.toml -o requirements.txt
|
| 16 |
+
```
|
| 17 |
+
|
| 18 |
+
2. **Create a `app.py` file:**
|
| 19 |
+
```bash
|
| 20 |
+
cp gradio_app.py app.py
|
| 21 |
+
```
|
| 22 |
+
|
| 23 |
+
3. **Create account on [Hugging Face](https://huggingface.co/join)**
|
| 24 |
+
|
| 25 |
+
4. **Create a new Space:**
|
| 26 |
+
- Go to https://huggingface.co/spaces
|
| 27 |
+
- Click "Create new Space"
|
| 28 |
+
- Choose "Gradio" as SDK
|
| 29 |
+
- Name your space
|
| 30 |
+
|
| 31 |
+
5. **Upload files:**
|
| 32 |
+
- `app.py`
|
| 33 |
+
- `requirements.txt`
|
| 34 |
+
- `firebase-credentials-template.json` (rename without "template")
|
| 35 |
+
|
| 36 |
+
6. **Add Firebase credentials as Secret:**
|
| 37 |
+
- Go to Settings → Repository Secrets
|
| 38 |
+
- Add secret named `FIREBASE_CREDENTIALS`
|
| 39 |
+
- Paste your Firebase JSON
|
| 40 |
+
|
| 41 |
+
7. **Deploy!** Space will auto-build and deploy
|
| 42 |
+
|
| 43 |
+
**URL:** `https://huggingface.co/spaces/YOUR_USERNAME/SPACE_NAME`
|
| 44 |
+
|
| 45 |
+
---
|
| 46 |
+
|
| 47 |
+
## 🚂 Option 2: Railway (Recommended for Production)
|
| 48 |
+
|
| 49 |
+
**Best for:** Production apps, custom domains, automatic deployments
|
| 50 |
+
|
| 51 |
+
### Steps:
|
| 52 |
+
|
| 53 |
+
1. **Install Railway CLI:**
|
| 54 |
+
```bash
|
| 55 |
+
npm i -g @railway/cli
|
| 56 |
+
# or
|
| 57 |
+
brew install railway
|
| 58 |
+
```
|
| 59 |
+
|
| 60 |
+
2. **Login:**
|
| 61 |
+
```bash
|
| 62 |
+
railway login
|
| 63 |
+
```
|
| 64 |
+
|
| 65 |
+
3. **Initialize project:**
|
| 66 |
+
```bash
|
| 67 |
+
railway init
|
| 68 |
+
```
|
| 69 |
+
|
| 70 |
+
4. **Add Firebase credentials:**
|
| 71 |
+
```bash
|
| 72 |
+
railway variables set FIREBASE_CREDENTIALS_JSON="$(cat firebase-credentials.json)"
|
| 73 |
+
```
|
| 74 |
+
|
| 75 |
+
5. **Deploy:**
|
| 76 |
+
```bash
|
| 77 |
+
railway up
|
| 78 |
+
```
|
| 79 |
+
|
| 80 |
+
6. **Get URL:**
|
| 81 |
+
```bash
|
| 82 |
+
railway domain
|
| 83 |
+
```
|
| 84 |
+
|
| 85 |
+
**Automatic deployments:** Railway auto-deploys on git push
|
| 86 |
+
|
| 87 |
+
**Config file** (`railway.json`):
|
| 88 |
+
```json
|
| 89 |
+
{
|
| 90 |
+
"build": {
|
| 91 |
+
"builder": "NIXPACKS"
|
| 92 |
+
},
|
| 93 |
+
"deploy": {
|
| 94 |
+
"startCommand": "uv run python gradio_app.py",
|
| 95 |
+
"restartPolicyType": "ON_FAILURE"
|
| 96 |
+
}
|
| 97 |
+
}
|
| 98 |
+
```
|
| 99 |
+
|
| 100 |
+
---
|
| 101 |
+
|
| 102 |
+
## 🎨 Option 3: Render
|
| 103 |
+
|
| 104 |
+
**Best for:** Free tier, simple deployment
|
| 105 |
+
|
| 106 |
+
### Steps:
|
| 107 |
+
|
| 108 |
+
1. **Push code to GitHub**
|
| 109 |
+
|
| 110 |
+
2. **Go to [Render Dashboard](https://dashboard.render.com/)**
|
| 111 |
+
|
| 112 |
+
3. **Create New Web Service**
|
| 113 |
+
|
| 114 |
+
4. **Connect your GitHub repo**
|
| 115 |
+
|
| 116 |
+
5. **Configure:**
|
| 117 |
+
- **Name:** your-agent-builder
|
| 118 |
+
- **Environment:** Python 3
|
| 119 |
+
- **Build Command:** `pip install uv && uv sync`
|
| 120 |
+
- **Start Command:** `uv run python gradio_app.py`
|
| 121 |
+
|
| 122 |
+
6. **Add Environment Variables:**
|
| 123 |
+
- `FIREBASE_CREDENTIALS_JSON`: Paste your Firebase JSON
|
| 124 |
+
|
| 125 |
+
7. **Deploy!**
|
| 126 |
+
|
| 127 |
+
**Free tier limits:** 750 hours/month, sleeps after 15 min inactivity
|
| 128 |
+
|
| 129 |
+
---
|
| 130 |
+
|
| 131 |
+
## 🐳 Option 4: Docker + Any Platform
|
| 132 |
+
|
| 133 |
+
**Best for:** Maximum control, can deploy anywhere
|
| 134 |
+
|
| 135 |
+
### Create `Dockerfile`:
|
| 136 |
+
|
| 137 |
+
```dockerfile
|
| 138 |
+
FROM python:3.12-slim
|
| 139 |
+
|
| 140 |
+
# Install uv
|
| 141 |
+
RUN pip install uv
|
| 142 |
+
|
| 143 |
+
# Set working directory
|
| 144 |
+
WORKDIR /app
|
| 145 |
+
|
| 146 |
+
# Copy project files
|
| 147 |
+
COPY pyproject.toml uv.lock ./
|
| 148 |
+
COPY gradio_app.py ./
|
| 149 |
+
COPY firebase-credentials.json ./
|
| 150 |
+
|
| 151 |
+
# Install dependencies
|
| 152 |
+
RUN uv sync
|
| 153 |
+
|
| 154 |
+
# Expose Gradio port
|
| 155 |
+
EXPOSE 7860
|
| 156 |
+
|
| 157 |
+
# Run the app
|
| 158 |
+
CMD ["uv", "run", "python", "gradio_app.py"]
|
| 159 |
+
```
|
| 160 |
+
|
| 161 |
+
### Create `.dockerignore`:
|
| 162 |
+
|
| 163 |
+
```
|
| 164 |
+
.venv/
|
| 165 |
+
__pycache__/
|
| 166 |
+
*.pyc
|
| 167 |
+
.git/
|
| 168 |
+
.gitignore
|
| 169 |
+
README.md
|
| 170 |
+
```
|
| 171 |
+
|
| 172 |
+
### Build and Run:
|
| 173 |
+
|
| 174 |
+
```bash
|
| 175 |
+
# Build image
|
| 176 |
+
docker build -t react-agent-builder .
|
| 177 |
+
|
| 178 |
+
# Run container
|
| 179 |
+
docker run -p 7860:7860 react-agent-builder
|
| 180 |
+
```
|
| 181 |
+
|
| 182 |
+
### Deploy to:
|
| 183 |
+
- **Google Cloud Run**
|
| 184 |
+
- **AWS ECS/Fargate**
|
| 185 |
+
- **Azure Container Instances**
|
| 186 |
+
- **DigitalOcean App Platform**
|
| 187 |
+
|
| 188 |
+
---
|
| 189 |
+
|
| 190 |
+
## ☁️ Option 5: Google Cloud Run
|
| 191 |
+
|
| 192 |
+
**Best for:** Serverless, scales to zero, pay per use
|
| 193 |
+
|
| 194 |
+
### Steps:
|
| 195 |
+
|
| 196 |
+
1. **Install Google Cloud CLI:**
|
| 197 |
+
```bash
|
| 198 |
+
curl https://sdk.cloud.google.com | bash
|
| 199 |
+
```
|
| 200 |
+
|
| 201 |
+
2. **Login:**
|
| 202 |
+
```bash
|
| 203 |
+
gcloud auth login
|
| 204 |
+
gcloud config set project YOUR_PROJECT_ID
|
| 205 |
+
```
|
| 206 |
+
|
| 207 |
+
3. **Build with Cloud Build:**
|
| 208 |
+
```bash
|
| 209 |
+
gcloud builds submit --tag gcr.io/YOUR_PROJECT_ID/agent-builder
|
| 210 |
+
```
|
| 211 |
+
|
| 212 |
+
4. **Deploy:**
|
| 213 |
+
```bash
|
| 214 |
+
gcloud run deploy agent-builder \
|
| 215 |
+
--image gcr.io/YOUR_PROJECT_ID/agent-builder \
|
| 216 |
+
--platform managed \
|
| 217 |
+
--region us-central1 \
|
| 218 |
+
--allow-unauthenticated
|
| 219 |
+
```
|
| 220 |
+
|
| 221 |
+
5. **Set Firebase credentials:**
|
| 222 |
+
```bash
|
| 223 |
+
gcloud run services update agent-builder \
|
| 224 |
+
--set-env-vars FIREBASE_CREDENTIALS_JSON="$(cat firebase-credentials.json)"
|
| 225 |
+
```
|
| 226 |
+
|
| 227 |
+
---
|
| 228 |
+
|
| 229 |
+
## 🌐 Option 6: Vercel (with Serverless Functions)
|
| 230 |
+
|
| 231 |
+
**Best for:** Static sites with API routes
|
| 232 |
+
|
| 233 |
+
Requires converting to serverless functions. Not recommended for this app (use Railway/Render instead).
|
| 234 |
+
|
| 235 |
+
---
|
| 236 |
+
|
| 237 |
+
## 🔧 Environment Variables
|
| 238 |
+
|
| 239 |
+
All platforms need these environment variables:
|
| 240 |
+
|
| 241 |
+
### Required (for Firebase):
|
| 242 |
+
```bash
|
| 243 |
+
FIREBASE_CREDENTIALS_JSON='{
|
| 244 |
+
"type": "service_account",
|
| 245 |
+
"project_id": "...",
|
| 246 |
+
...
|
| 247 |
+
}'
|
| 248 |
+
```
|
| 249 |
+
|
| 250 |
+
### Optional:
|
| 251 |
+
```bash
|
| 252 |
+
# Change default port
|
| 253 |
+
PORT=8080
|
| 254 |
+
|
| 255 |
+
# Set custom domain
|
| 256 |
+
GRADIO_SERVER_NAME=0.0.0.0
|
| 257 |
+
GRADIO_SERVER_PORT=7860
|
| 258 |
+
|
| 259 |
+
# Enable sharing
|
| 260 |
+
GRADIO_SHARE=false
|
| 261 |
+
```
|
| 262 |
+
|
| 263 |
+
---
|
| 264 |
+
|
| 265 |
+
## 📊 Performance Comparison
|
| 266 |
+
|
| 267 |
+
| Platform | Setup Time | Cost | Scaling | Custom Domain |
|
| 268 |
+
|----------|-----------|------|---------|---------------|
|
| 269 |
+
| HF Spaces | 5 min | Free | Limited | Yes ($9/mo) |
|
| 270 |
+
| Railway | 10 min | $5/mo | Auto | Free |
|
| 271 |
+
| Render | 10 min | Free/$7 | Auto | Free |
|
| 272 |
+
| Cloud Run | 15 min | Pay-per-use | Excellent | Free |
|
| 273 |
+
| Docker | 20 min | Varies | Manual | Varies |
|
| 274 |
+
|
| 275 |
+
---
|
| 276 |
+
|
| 277 |
+
## 🔐 Security Checklist
|
| 278 |
+
|
| 279 |
+
Before deploying to production:
|
| 280 |
+
|
| 281 |
+
- [ ] Move Firebase credentials to environment variables
|
| 282 |
+
- [ ] Enable HTTPS (automatic on most platforms)
|
| 283 |
+
- [ ] Set up Firebase Security Rules
|
| 284 |
+
- [ ] Enable CORS if needed
|
| 285 |
+
- [ ] Add rate limiting
|
| 286 |
+
- [ ] Set up monitoring/logging
|
| 287 |
+
- [ ] Add error tracking (Sentry)
|
| 288 |
+
- [ ] Configure backups
|
| 289 |
+
- [ ] Set up CI/CD pipeline
|
| 290 |
+
- [ ] Add health check endpoint
|
| 291 |
+
|
| 292 |
+
---
|
| 293 |
+
|
| 294 |
+
## 🐛 Troubleshooting
|
| 295 |
+
|
| 296 |
+
### "Module not found" error
|
| 297 |
+
```bash
|
| 298 |
+
# Regenerate lock file
|
| 299 |
+
uv lock --upgrade
|
| 300 |
+
```
|
| 301 |
+
|
| 302 |
+
### "Port already in use"
|
| 303 |
+
```bash
|
| 304 |
+
# Change port in gradio_app.py
|
| 305 |
+
server_port=8080
|
| 306 |
+
```
|
| 307 |
+
|
| 308 |
+
### Firebase connection fails
|
| 309 |
+
```bash
|
| 310 |
+
# Check credentials format
|
| 311 |
+
cat firebase-credentials.json | jq .
|
| 312 |
+
|
| 313 |
+
# Verify environment variable
|
| 314 |
+
echo $FIREBASE_CREDENTIALS_JSON
|
| 315 |
+
```
|
| 316 |
+
|
| 317 |
+
### App crashes on startup
|
| 318 |
+
```bash
|
| 319 |
+
# Check logs
|
| 320 |
+
railway logs # Railway
|
| 321 |
+
gcloud run logs read # Cloud Run
|
| 322 |
+
docker logs CONTAINER_ID # Docker
|
| 323 |
+
```
|
| 324 |
+
|
| 325 |
+
---
|
| 326 |
+
|
| 327 |
+
## 🎯 Recommended Setup
|
| 328 |
+
|
| 329 |
+
**For Development:**
|
| 330 |
+
- Local with `uv run python gradio_app.py`
|
| 331 |
+
- Use mock mode (no Firebase needed)
|
| 332 |
+
|
| 333 |
+
**For Staging:**
|
| 334 |
+
- Hugging Face Spaces (free, easy)
|
| 335 |
+
- Connect to Firebase
|
| 336 |
+
|
| 337 |
+
**For Production:**
|
| 338 |
+
- Railway or Cloud Run
|
| 339 |
+
- Custom domain
|
| 340 |
+
- Firebase with security rules
|
| 341 |
+
- Monitoring enabled
|
| 342 |
+
|
| 343 |
+
---
|
| 344 |
+
|
| 345 |
+
## 📚 Next Steps
|
| 346 |
+
|
| 347 |
+
After deployment:
|
| 348 |
+
|
| 349 |
+
1. **Test authentication** thoroughly
|
| 350 |
+
2. **Create your first agent**
|
| 351 |
+
3. **Set up monitoring** (use Railway/Cloud metrics)
|
| 352 |
+
4. **Configure custom domain**
|
| 353 |
+
5. **Add more models** to the dropdown
|
| 354 |
+
6. **Implement agent analytics**
|
| 355 |
+
7. **Add email notifications**
|
| 356 |
+
|
| 357 |
+
---
|
| 358 |
+
|
| 359 |
+
## 🆘 Need Help?
|
| 360 |
+
|
| 361 |
+
- Railway: https://railway.app/help
|
| 362 |
+
- Render: https://render.com/docs
|
| 363 |
+
- Cloud Run: https://cloud.google.com/run/docs
|
| 364 |
+
- HF Spaces: https://huggingface.co/docs/hub/spaces
|
| 365 |
+
|
| 366 |
+
Good luck with your deployment! 🚀
|
PROJECT_SUMMARY.md
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# React Agent Builder - Project Summary
|
| 2 |
+
|
| 3 |
+
## 📦 What You Have
|
| 4 |
+
|
| 5 |
+
A production-ready Gradio web application with:
|
| 6 |
+
- ✅ User authentication (login/registration)
|
| 7 |
+
- ✅ Dashboard with agent management
|
| 8 |
+
- ✅ React agent creation interface
|
| 9 |
+
- ✅ Firebase integration (with mock mode fallback)
|
| 10 |
+
- ✅ Modern dependency management with uv
|
| 11 |
+
|
| 12 |
+
## 🚀 Getting Started (3 Steps)
|
| 13 |
+
|
| 14 |
+
### 1. Install uv
|
| 15 |
+
```bash
|
| 16 |
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
| 17 |
+
```
|
| 18 |
+
|
| 19 |
+
### 2. Install Dependencies
|
| 20 |
+
```bash
|
| 21 |
+
uv sync
|
| 22 |
+
```
|
| 23 |
+
|
| 24 |
+
### 3. Run the App
|
| 25 |
+
```bash
|
| 26 |
+
uv run python gradio_app.py
|
| 27 |
+
```
|
| 28 |
+
|
| 29 |
+
**That's it!** Open http://localhost:7860 in your browser.
|
| 30 |
+
|
| 31 |
+
## 📁 Files Included
|
| 32 |
+
|
| 33 |
+
| File | Purpose |
|
| 34 |
+
|------|---------|
|
| 35 |
+
| `gradio_app.py` | Main application code |
|
| 36 |
+
| `pyproject.toml` | Project configuration & dependencies |
|
| 37 |
+
| `uv.lock` | Locked dependencies for reproducibility |
|
| 38 |
+
| `README.md` | Comprehensive documentation |
|
| 39 |
+
| `QUICKSTART.md` | Quick reference guide |
|
| 40 |
+
| `firebase-credentials-template.json` | Template for Firebase setup |
|
| 41 |
+
| `.gitignore` | Git ignore rules |
|
| 42 |
+
|
| 43 |
+
## 🎯 Key Features
|
| 44 |
+
|
| 45 |
+
### Authentication System
|
| 46 |
+
- Secure password hashing
|
| 47 |
+
- Session management
|
| 48 |
+
- Input validation
|
| 49 |
+
- Works with or without Firebase
|
| 50 |
+
|
| 51 |
+
### Dashboard
|
| 52 |
+
- Large, prominent "Create React Agent" button (with plus icon)
|
| 53 |
+
- List of all created agents
|
| 54 |
+
- Refresh functionality
|
| 55 |
+
- Clean, modern UI
|
| 56 |
+
|
| 57 |
+
### Agent Creation
|
| 58 |
+
1. **Agent Name** - Text input field
|
| 59 |
+
2. **Model Selection** - Dropdown with:
|
| 60 |
+
- GPT-4 Turbo
|
| 61 |
+
- GPT-4
|
| 62 |
+
- GPT-3.5 Turbo
|
| 63 |
+
3. **System Context Prompt** - Large text area
|
| 64 |
+
4. **Submit Button** - Creates and saves agent
|
| 65 |
+
5. **URL Generation** - Unique URL for each agent
|
| 66 |
+
|
| 67 |
+
### Data Storage
|
| 68 |
+
- Firebase Firestore integration
|
| 69 |
+
- Mock mode for development/testing
|
| 70 |
+
- Automatic user and agent data management
|
| 71 |
+
|
| 72 |
+
## 🔧 Configuration
|
| 73 |
+
|
| 74 |
+
### Add More Models
|
| 75 |
+
Edit `gradio_app.py`, find the model dropdown:
|
| 76 |
+
```python
|
| 77 |
+
model_dropdown = gr.Dropdown(
|
| 78 |
+
choices=[
|
| 79 |
+
"gpt-4-turbo",
|
| 80 |
+
"gpt-4",
|
| 81 |
+
"gpt-3.5-turbo",
|
| 82 |
+
"gpt-4o", # Add here
|
| 83 |
+
"gpt-3.5-turbo-16k", # Add here
|
| 84 |
+
],
|
| 85 |
+
...
|
| 86 |
+
)
|
| 87 |
+
```
|
| 88 |
+
|
| 89 |
+
### Firebase Setup (Optional)
|
| 90 |
+
1. Go to [Firebase Console](https://console.firebase.google.com/)
|
| 91 |
+
2. Create a project
|
| 92 |
+
3. Download service account credentials
|
| 93 |
+
4. Save as `firebase-credentials.json`
|
| 94 |
+
5. Enable Firestore and Authentication
|
| 95 |
+
|
| 96 |
+
**Note:** App works perfectly without Firebase in mock mode!
|
| 97 |
+
|
| 98 |
+
## 🎨 UI Design
|
| 99 |
+
|
| 100 |
+
The app features:
|
| 101 |
+
- Clean, modern interface
|
| 102 |
+
- Responsive design
|
| 103 |
+
- Custom CSS styling
|
| 104 |
+
- Tab-based navigation
|
| 105 |
+
- Professional color scheme (gradient buttons)
|
| 106 |
+
- Large, accessible buttons
|
| 107 |
+
- Clear form layouts
|
| 108 |
+
|
| 109 |
+
## 📊 Database Structure
|
| 110 |
+
|
| 111 |
+
### Users Collection
|
| 112 |
+
```
|
| 113 |
+
users/{uid}
|
| 114 |
+
- username: string
|
| 115 |
+
- email: string
|
| 116 |
+
- created_at: timestamp
|
| 117 |
+
```
|
| 118 |
+
|
| 119 |
+
### Agents Collection
|
| 120 |
+
```
|
| 121 |
+
agents/{agent_id}
|
| 122 |
+
- agent_id: string
|
| 123 |
+
- agent_name: string
|
| 124 |
+
- model_name: string
|
| 125 |
+
- system_prompt: string
|
| 126 |
+
- created_by: string (email)
|
| 127 |
+
- created_at: string
|
| 128 |
+
- agent_url: string
|
| 129 |
+
```
|
| 130 |
+
|
| 131 |
+
## 🛠️ Development Workflow
|
| 132 |
+
|
| 133 |
+
### Add Dependencies
|
| 134 |
+
```bash
|
| 135 |
+
uv add package-name
|
| 136 |
+
```
|
| 137 |
+
|
| 138 |
+
### Update Dependencies
|
| 139 |
+
```bash
|
| 140 |
+
uv lock --upgrade
|
| 141 |
+
```
|
| 142 |
+
|
| 143 |
+
### Run with Auto-reload
|
| 144 |
+
```bash
|
| 145 |
+
uv run gradio gradio_app.py
|
| 146 |
+
```
|
| 147 |
+
|
| 148 |
+
## 🌐 Deployment Options
|
| 149 |
+
|
| 150 |
+
### Hugging Face Spaces
|
| 151 |
+
```bash
|
| 152 |
+
uv pip compile pyproject.toml -o requirements.txt
|
| 153 |
+
# Upload to HF Spaces
|
| 154 |
+
```
|
| 155 |
+
|
| 156 |
+
### Railway / Render
|
| 157 |
+
- Push to Git
|
| 158 |
+
- Set start command: `uv run python gradio_app.py`
|
| 159 |
+
- Deploy!
|
| 160 |
+
|
| 161 |
+
### Docker
|
| 162 |
+
```dockerfile
|
| 163 |
+
FROM python:3.12
|
| 164 |
+
RUN pip install uv
|
| 165 |
+
COPY . /app
|
| 166 |
+
WORKDIR /app
|
| 167 |
+
RUN uv sync
|
| 168 |
+
CMD ["uv", "run", "python", "gradio_app.py"]
|
| 169 |
+
```
|
| 170 |
+
|
| 171 |
+
## 🔐 Security Features
|
| 172 |
+
|
| 173 |
+
- Password hashing (SHA-256)
|
| 174 |
+
- Session management
|
| 175 |
+
- Input validation
|
| 176 |
+
- Firebase security rules (when enabled)
|
| 177 |
+
- Protected routes
|
| 178 |
+
- CSRF protection (via Gradio)
|
| 179 |
+
|
| 180 |
+
## ⚡ Why uv?
|
| 181 |
+
|
| 182 |
+
- **10-100x faster** than pip
|
| 183 |
+
- **Single lock file** for reproducibility
|
| 184 |
+
- **Disk efficient** with global cache
|
| 185 |
+
- **Python version management** included
|
| 186 |
+
- **Modern tooling** for Python projects
|
| 187 |
+
|
| 188 |
+
## 📚 Learn More
|
| 189 |
+
|
| 190 |
+
- [uv Documentation](https://docs.astral.sh/uv/)
|
| 191 |
+
- [Gradio Documentation](https://www.gradio.app/docs/)
|
| 192 |
+
- [Firebase Documentation](https://firebase.google.com/docs)
|
| 193 |
+
|
| 194 |
+
## 🆘 Troubleshooting
|
| 195 |
+
|
| 196 |
+
**App won't start?**
|
| 197 |
+
```bash
|
| 198 |
+
uv sync --reinstall
|
| 199 |
+
```
|
| 200 |
+
|
| 201 |
+
**Firebase errors?**
|
| 202 |
+
- Check `firebase-credentials.json` path
|
| 203 |
+
- Or just use mock mode (no Firebase needed!)
|
| 204 |
+
|
| 205 |
+
**Port already in use?**
|
| 206 |
+
Edit `gradio_app.py` and change `server_port=7860` to another port.
|
| 207 |
+
|
| 208 |
+
## 🎉 You're All Set!
|
| 209 |
+
|
| 210 |
+
Your Gradio app with authentication and agent creation is ready to go. Happy building!
|
QUICKSTART.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Quick Start Guide
|
| 2 |
+
|
| 3 |
+
## Installation & Setup (30 seconds)
|
| 4 |
+
|
| 5 |
+
1. **Install uv** (if not already installed):
|
| 6 |
+
```bash
|
| 7 |
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
| 8 |
+
```
|
| 9 |
+
|
| 10 |
+
2. **Install dependencies**:
|
| 11 |
+
```bash
|
| 12 |
+
uv sync
|
| 13 |
+
```
|
| 14 |
+
|
| 15 |
+
3. **Run the app**:
|
| 16 |
+
```bash
|
| 17 |
+
uv run python gradio_app.py
|
| 18 |
+
```
|
| 19 |
+
|
| 20 |
+
That's it! The app will open at http://localhost:7860
|
| 21 |
+
|
| 22 |
+
## Common Commands
|
| 23 |
+
|
| 24 |
+
```bash
|
| 25 |
+
# Add a new package
|
| 26 |
+
uv add package-name
|
| 27 |
+
|
| 28 |
+
# Update dependencies
|
| 29 |
+
uv lock --upgrade
|
| 30 |
+
|
| 31 |
+
# Run Python scripts
|
| 32 |
+
uv run python script.py
|
| 33 |
+
|
| 34 |
+
# Activate virtual environment
|
| 35 |
+
source .venv/bin/activate # Unix
|
| 36 |
+
.venv\Scripts\activate # Windows
|
| 37 |
+
```
|
| 38 |
+
|
| 39 |
+
## Firebase Setup (Optional)
|
| 40 |
+
|
| 41 |
+
For production use with Firebase:
|
| 42 |
+
|
| 43 |
+
1. Get Firebase credentials from [Firebase Console](https://console.firebase.google.com/)
|
| 44 |
+
2. Save as `firebase-credentials.json`
|
| 45 |
+
3. Enable Firestore and Authentication
|
| 46 |
+
|
| 47 |
+
For development, the app works in mock mode without Firebase.
|
| 48 |
+
|
| 49 |
+
## Why uv?
|
| 50 |
+
|
| 51 |
+
- ⚡ **10-100x faster** than pip
|
| 52 |
+
- 🔒 **Reproducible builds** with lock file
|
| 53 |
+
- 🎯 **Single tool** for all Python project needs
|
| 54 |
+
- 💾 **Disk space efficient** with global cache
|
| 55 |
+
- 🐍 **Python version management** built-in
|
| 56 |
+
|
| 57 |
+
Learn more: https://docs.astral.sh/uv/
|
README.md
ADDED
|
@@ -0,0 +1,347 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# React Agent Builder - Gradio App
|
| 2 |
+
|
| 3 |
+
A complete Gradio web application with authentication and React agent creation functionality.
|
| 4 |
+
|
| 5 |
+
## Features
|
| 6 |
+
|
| 7 |
+
✅ **User Authentication**
|
| 8 |
+
- Registration page with validation
|
| 9 |
+
- Login page with session management
|
| 10 |
+
- Secure password hashing
|
| 11 |
+
|
| 12 |
+
✅ **Dashboard**
|
| 13 |
+
- Clean interface with large "Create React Agent" button
|
| 14 |
+
- View all created agents
|
| 15 |
+
- Refresh agent list
|
| 16 |
+
|
| 17 |
+
✅ **Agent Creation**
|
| 18 |
+
- Agent name input
|
| 19 |
+
- Model selection (GPT-4o, GPT-4o-mini)
|
| 20 |
+
- System context prompt editor
|
| 21 |
+
- Firebase integration for data storage
|
| 22 |
+
- Unique URL generation for each agent
|
| 23 |
+
|
| 24 |
+
## Setup Instructions
|
| 25 |
+
|
| 26 |
+
### Prerequisites
|
| 27 |
+
|
| 28 |
+
This project uses [uv](https://github.com/astral-sh/uv) for dependency management. Install it first:
|
| 29 |
+
|
| 30 |
+
```bash
|
| 31 |
+
# On macOS and Linux
|
| 32 |
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
| 33 |
+
|
| 34 |
+
# On Windows
|
| 35 |
+
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
|
| 36 |
+
|
| 37 |
+
# Or with pip
|
| 38 |
+
pip install uv
|
| 39 |
+
```
|
| 40 |
+
|
| 41 |
+
### 1. Install Dependencies
|
| 42 |
+
|
| 43 |
+
Using uv, dependencies are automatically managed:
|
| 44 |
+
|
| 45 |
+
```bash
|
| 46 |
+
# Clone or navigate to the project directory
|
| 47 |
+
cd gradio-react-agent
|
| 48 |
+
|
| 49 |
+
# Install dependencies (uv will handle everything)
|
| 50 |
+
uv sync
|
| 51 |
+
```
|
| 52 |
+
|
| 53 |
+
This will create a virtual environment and install all required packages from `pyproject.toml`.
|
| 54 |
+
|
| 55 |
+
### 2. Configure Firebase
|
| 56 |
+
|
| 57 |
+
#### Option A: Use Firebase (Production)
|
| 58 |
+
|
| 59 |
+
1. Go to [Firebase Console](https://console.firebase.google.com/)
|
| 60 |
+
2. Create a new project or select existing one
|
| 61 |
+
3. Go to Project Settings → Service Accounts
|
| 62 |
+
4. Click "Generate New Private Key"
|
| 63 |
+
5. Save the JSON file as `firebase-credentials.json` in the project directory
|
| 64 |
+
6. Enable Firestore Database and Authentication in Firebase Console
|
| 65 |
+
|
| 66 |
+
#### Option B: Use Mock Mode (Development)
|
| 67 |
+
|
| 68 |
+
The app works without Firebase in mock mode for testing. Just run it and it will use in-memory storage.
|
| 69 |
+
|
| 70 |
+
### 3. Run the Application
|
| 71 |
+
|
| 72 |
+
Using uv:
|
| 73 |
+
|
| 74 |
+
```bash
|
| 75 |
+
# Run with uv
|
| 76 |
+
uv run python gradio_app.py
|
| 77 |
+
|
| 78 |
+
# Or activate the virtual environment and run directly
|
| 79 |
+
source .venv/bin/activate # On Windows: .venv\Scripts\activate
|
| 80 |
+
python gradio_app.py
|
| 81 |
+
```
|
| 82 |
+
|
| 83 |
+
The app will launch at `http://localhost:7860`
|
| 84 |
+
|
| 85 |
+
## Usage Guide
|
| 86 |
+
|
| 87 |
+
### Registration
|
| 88 |
+
1. Navigate to the "Register" tab
|
| 89 |
+
2. Fill in username, email, and password
|
| 90 |
+
3. Click "Register"
|
| 91 |
+
4. Switch to "Login" tab
|
| 92 |
+
|
| 93 |
+
### Login
|
| 94 |
+
1. Enter your email and password
|
| 95 |
+
2. Click "Login"
|
| 96 |
+
3. You'll be redirected to the Dashboard
|
| 97 |
+
|
| 98 |
+
### Create React Agent
|
| 99 |
+
1. Click the big "➕ Create React Agent" button
|
| 100 |
+
2. Fill in:
|
| 101 |
+
- **Agent Name**: Give your agent a descriptive name
|
| 102 |
+
- **Model Name**: Choose from GPT-4 Turbo, GPT-4, or GPT-3.5 Turbo
|
| 103 |
+
- **System Context Prompt**: Define how your agent should behave
|
| 104 |
+
3. Click "✅ Submit & Create Agent"
|
| 105 |
+
4. Copy the generated Agent URL
|
| 106 |
+
|
| 107 |
+
### View Your Agents
|
| 108 |
+
- All created agents appear in the "Your Agents" section
|
| 109 |
+
- Click "🔄 Refresh List" to update the list
|
| 110 |
+
|
| 111 |
+
## Project Structure
|
| 112 |
+
|
| 113 |
+
```
|
| 114 |
+
react-agent-builder/
|
| 115 |
+
├── gradio_app.py # Main application
|
| 116 |
+
├── pyproject.toml # Project config & dependencies
|
| 117 |
+
├── uv.lock # Lock file for reproducible builds
|
| 118 |
+
├── firebase-credentials.json # Firebase config (you create this)
|
| 119 |
+
├── firebase-credentials-template.json # Template for Firebase config
|
| 120 |
+
└── README.md # Documentation
|
| 121 |
+
```
|
| 122 |
+
|
| 123 |
+
## Dependency Management with uv
|
| 124 |
+
|
| 125 |
+
### Add New Dependencies
|
| 126 |
+
|
| 127 |
+
```bash
|
| 128 |
+
# Add a new package
|
| 129 |
+
uv add package-name
|
| 130 |
+
|
| 131 |
+
# Add a development dependency
|
| 132 |
+
uv add --dev package-name
|
| 133 |
+
|
| 134 |
+
# Add a specific version
|
| 135 |
+
uv add package-name==1.2.3
|
| 136 |
+
```
|
| 137 |
+
|
| 138 |
+
### Update Dependencies
|
| 139 |
+
|
| 140 |
+
```bash
|
| 141 |
+
# Update all dependencies
|
| 142 |
+
uv lock --upgrade
|
| 143 |
+
|
| 144 |
+
# Update a specific package
|
| 145 |
+
uv lock --upgrade-package package-name
|
| 146 |
+
```
|
| 147 |
+
|
| 148 |
+
### Remove Dependencies
|
| 149 |
+
|
| 150 |
+
```bash
|
| 151 |
+
uv remove package-name
|
| 152 |
+
```
|
| 153 |
+
|
| 154 |
+
### View Installed Packages
|
| 155 |
+
|
| 156 |
+
```bash
|
| 157 |
+
uv pip list
|
| 158 |
+
```
|
| 159 |
+
|
| 160 |
+
#### Option A: Use Firebase (Production)
|
| 161 |
+
|
| 162 |
+
1. Go to [Firebase Console](https://console.firebase.google.com/)
|
| 163 |
+
2. Create a new project or select existing one
|
| 164 |
+
3. Go to Project Settings → Service Accounts
|
| 165 |
+
4. Click "Generate New Private Key"
|
| 166 |
+
5. Save the JSON file as `firebase-credentials.json` in the project directory
|
| 167 |
+
6. Enable Firestore Database and Authentication in Firebase Console
|
| 168 |
+
|
| 169 |
+
#### Option B: Use Mock Mode (Development)
|
| 170 |
+
|
| 171 |
+
The app works without Firebase in mock mode for testing. Just run it and it will use in-memory storage.
|
| 172 |
+
|
| 173 |
+
### 3. Run the Application
|
| 174 |
+
|
| 175 |
+
```bash
|
| 176 |
+
python gradio_app.py
|
| 177 |
+
```
|
| 178 |
+
|
| 179 |
+
The app will launch at `http://localhost:7860`
|
| 180 |
+
|
| 181 |
+
## Usage Guide
|
| 182 |
+
|
| 183 |
+
### Registration
|
| 184 |
+
1. Navigate to the "Register" tab
|
| 185 |
+
2. Fill in username, email, and password
|
| 186 |
+
3. Click "Register"
|
| 187 |
+
4. Switch to "Login" tab
|
| 188 |
+
|
| 189 |
+
### Login
|
| 190 |
+
1. Enter your email and password
|
| 191 |
+
2. Click "Login"
|
| 192 |
+
3. You'll be redirected to the Dashboard
|
| 193 |
+
|
| 194 |
+
### Create React Agent
|
| 195 |
+
1. Click the big "➕ Create React Agent" button
|
| 196 |
+
2. Fill in:
|
| 197 |
+
- **Agent Name**: Give your agent a descriptive name
|
| 198 |
+
- **Model Name**: Choose from GPT-4 Turbo, GPT-4, or GPT-3.5 Turbo
|
| 199 |
+
- **System Context Prompt**: Define how your agent should behave
|
| 200 |
+
3. Click "✅ Submit & Create Agent"
|
| 201 |
+
4. Copy the generated Agent URL
|
| 202 |
+
|
| 203 |
+
### View Your Agents
|
| 204 |
+
- All created agents appear in the "Your Agents" section
|
| 205 |
+
- Click "🔄 Refresh List" to update the list
|
| 206 |
+
|
| 207 |
+
## Firebase Database Structure
|
| 208 |
+
|
| 209 |
+
### Collections
|
| 210 |
+
|
| 211 |
+
**users**
|
| 212 |
+
```json
|
| 213 |
+
{
|
| 214 |
+
"uid": {
|
| 215 |
+
"username": "string",
|
| 216 |
+
"email": "string",
|
| 217 |
+
"created_at": "timestamp"
|
| 218 |
+
}
|
| 219 |
+
}
|
| 220 |
+
```
|
| 221 |
+
|
| 222 |
+
**agents**
|
| 223 |
+
```json
|
| 224 |
+
{
|
| 225 |
+
"agent_id": {
|
| 226 |
+
"agent_id": "string",
|
| 227 |
+
"agent_name": "string",
|
| 228 |
+
"model_name": "string",
|
| 229 |
+
"system_prompt": "string",
|
| 230 |
+
"created_by": "string (user email)",
|
| 231 |
+
"created_at": "timestamp",
|
| 232 |
+
"agent_url": "string"
|
| 233 |
+
}
|
| 234 |
+
}
|
| 235 |
+
```
|
| 236 |
+
|
| 237 |
+
## Configuration Options
|
| 238 |
+
|
| 239 |
+
### Customize Models
|
| 240 |
+
|
| 241 |
+
Edit the `model_dropdown` choices in the code:
|
| 242 |
+
|
| 243 |
+
```python
|
| 244 |
+
model_dropdown = gr.Dropdown(
|
| 245 |
+
choices=[
|
| 246 |
+
"gpt-4-turbo",
|
| 247 |
+
"gpt-4",
|
| 248 |
+
"gpt-3.5-turbo",
|
| 249 |
+
"gpt-4o", # Add new models here
|
| 250 |
+
],
|
| 251 |
+
...
|
| 252 |
+
)
|
| 253 |
+
```
|
| 254 |
+
|
| 255 |
+
### Customize Agent URL
|
| 256 |
+
|
| 257 |
+
Modify the `agent_url` generation in the `create_agent` function:
|
| 258 |
+
|
| 259 |
+
```python
|
| 260 |
+
'agent_url': f"https://your-domain.com/agent/{agent_id}"
|
| 261 |
+
```
|
| 262 |
+
|
| 263 |
+
## Security Notes
|
| 264 |
+
|
| 265 |
+
🔒 **Important Security Considerations:**
|
| 266 |
+
|
| 267 |
+
1. **Password Storage**: Passwords are hashed using SHA-256 in mock mode. In production with Firebase, use Firebase Auth's built-in security.
|
| 268 |
+
|
| 269 |
+
2. **Session Management**: Sessions are stored in-memory. For production, use a proper session store (Redis, database).
|
| 270 |
+
|
| 271 |
+
3. **HTTPS**: Always use HTTPS in production to encrypt data in transit.
|
| 272 |
+
|
| 273 |
+
4. **Firebase Rules**: Set up proper Firestore security rules:
|
| 274 |
+
|
| 275 |
+
```javascript
|
| 276 |
+
rules_version = '2';
|
| 277 |
+
service cloud.firestore {
|
| 278 |
+
match /databases/{database}/documents {
|
| 279 |
+
match /users/{userId} {
|
| 280 |
+
allow read, write: if request.auth != null && request.auth.uid == userId;
|
| 281 |
+
}
|
| 282 |
+
match /agents/{agentId} {
|
| 283 |
+
allow read: if request.auth != null;
|
| 284 |
+
allow write: if request.auth != null;
|
| 285 |
+
}
|
| 286 |
+
}
|
| 287 |
+
}
|
| 288 |
+
```
|
| 289 |
+
|
| 290 |
+
## Deployment
|
| 291 |
+
|
| 292 |
+
### Deploy to Hugging Face Spaces
|
| 293 |
+
|
| 294 |
+
1. Create a new Space on Hugging Face
|
| 295 |
+
2. Add a `requirements.txt` file for Hugging Face compatibility:
|
| 296 |
+
```bash
|
| 297 |
+
uv pip compile pyproject.toml -o requirements.txt
|
| 298 |
+
```
|
| 299 |
+
3. Upload all files including `requirements.txt`
|
| 300 |
+
4. Add Firebase credentials as a Secret
|
| 301 |
+
5. The app will automatically deploy
|
| 302 |
+
|
| 303 |
+
### Deploy with uv on Cloud Platforms
|
| 304 |
+
|
| 305 |
+
For platforms that support uv:
|
| 306 |
+
|
| 307 |
+
1. Ensure `pyproject.toml` and `uv.lock` are in your repository
|
| 308 |
+
2. Set the start command to: `uv run python gradio_app.py`
|
| 309 |
+
3. The platform will automatically install dependencies using uv
|
| 310 |
+
|
| 311 |
+
Compatible with:
|
| 312 |
+
- Railway (supports uv natively)
|
| 313 |
+
- Render
|
| 314 |
+
- Google Cloud Run
|
| 315 |
+
- AWS Lambda (with custom runtime)
|
| 316 |
+
- Azure Functions
|
| 317 |
+
|
| 318 |
+
## Troubleshooting
|
| 319 |
+
|
| 320 |
+
### Firebase Connection Issues
|
| 321 |
+
- Verify credentials file path
|
| 322 |
+
- Check Firebase project configuration
|
| 323 |
+
- Ensure Firestore and Auth are enabled
|
| 324 |
+
|
| 325 |
+
### Mock Mode
|
| 326 |
+
- If Firebase credentials are not found, the app runs in mock mode
|
| 327 |
+
- Data is stored in memory and will be lost on restart
|
| 328 |
+
- Perfect for testing and development
|
| 329 |
+
|
| 330 |
+
## Features to Add
|
| 331 |
+
|
| 332 |
+
Potential enhancements:
|
| 333 |
+
- [ ] Email verification
|
| 334 |
+
- [ ] Password reset functionality
|
| 335 |
+
- [ ] Agent editing/deletion
|
| 336 |
+
- [ ] Agent analytics dashboard
|
| 337 |
+
- [ ] Team collaboration features
|
| 338 |
+
- [ ] API key management
|
| 339 |
+
- [ ] Agent deployment options
|
| 340 |
+
|
| 341 |
+
## License
|
| 342 |
+
|
| 343 |
+
MIT License
|
| 344 |
+
|
| 345 |
+
## Support
|
| 346 |
+
|
| 347 |
+
For issues or questions, please create an issue in the repository.
|
__pycache__/database.cpython-312.pyc
ADDED
|
Binary file (14 kB). View file
|
|
|
database.py
ADDED
|
@@ -0,0 +1,376 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import email
|
| 2 |
+
import os
|
| 3 |
+
import hashlib
|
| 4 |
+
from datetime import datetime
|
| 5 |
+
import firebase_admin
|
| 6 |
+
from firebase_admin import credentials, firestore, auth as firebase_auth
|
| 7 |
+
|
| 8 |
+
# Initialize Firebase
|
| 9 |
+
FIREBASE_ENABLED = False
|
| 10 |
+
db = None
|
| 11 |
+
|
| 12 |
+
try:
|
| 13 |
+
cred = credentials.Certificate('firebase-credentials.json')
|
| 14 |
+
firebase_admin.initialize_app(cred)
|
| 15 |
+
db = firestore.client()
|
| 16 |
+
FIREBASE_ENABLED = True
|
| 17 |
+
print("Firebase initialized successfully!")
|
| 18 |
+
except Exception as e:
|
| 19 |
+
print(f"Firebase not configured. Using mock mode. Error: {e}")
|
| 20 |
+
db = None
|
| 21 |
+
|
| 22 |
+
# Mock databases for development/testing
|
| 23 |
+
mock_users = {}
|
| 24 |
+
mock_agents = {}
|
| 25 |
+
mock_workspaces = {}
|
| 26 |
+
|
| 27 |
+
# Default workspace ID (same for all users)
|
| 28 |
+
DEFAULT_WORKSPACE_ID = "q7KfX2rP9Wb83hNa64RmTpUiAZ0vL3dS"
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
def hash_password(password):
|
| 32 |
+
"""Hash password for storage"""
|
| 33 |
+
return hashlib.sha256(password.encode()).hexdigest()
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def generate_workspace_data(user_id, workspace_id):
|
| 37 |
+
"""
|
| 38 |
+
Generate workspace data with shareScript
|
| 39 |
+
"""
|
| 40 |
+
share_script = f'''<script> (function (w, d) {{ w.CLIENT_IDENTIFIER = "{user_id}"; w.WORKSPACE_IDENTIFIER = '{workspace_id}'; w.AVATAR_IMAGE_URL = 'https://firebasestorage.googleapis.com/v0/b/curious-learner-3845a.appspot.com/o/avatars%2Fchatbot.png?alt=media&token=7d937685-197b-4947-b9f9-3c05f0271d20'; w.CHATBOT_IDENTIFIER = ''; var h = d.head || d.getElementsByTagName("head")[0]; var s = d.createElement('script'); s.setAttribute('type', 'text/javascript'); s.async = true; s.setAttribute('src', 'https://curious-learner-chatbot.web.app/client.js'); h.appendChild(s); }})(window, document); </script>'''
|
| 41 |
+
|
| 42 |
+
return {
|
| 43 |
+
'chatbotType': 'widget',
|
| 44 |
+
'id': workspace_id,
|
| 45 |
+
'shareScript': share_script,
|
| 46 |
+
'workspaceName': 'Default Workspace'
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def register_user(username, email, password):
|
| 51 |
+
"""
|
| 52 |
+
Register a new user in Firebase
|
| 53 |
+
Returns: (success: bool, message: str, user_id: str or None)
|
| 54 |
+
"""
|
| 55 |
+
try:
|
| 56 |
+
if FIREBASE_ENABLED:
|
| 57 |
+
# Create user in Firebase Auth
|
| 58 |
+
user = firebase_auth.create_user(
|
| 59 |
+
email=email,
|
| 60 |
+
password=password,
|
| 61 |
+
display_name=username
|
| 62 |
+
)
|
| 63 |
+
|
| 64 |
+
# Store user data in g_users collection
|
| 65 |
+
user_data = {
|
| 66 |
+
'name': username,
|
| 67 |
+
'email': email,
|
| 68 |
+
'created_at': firestore.SERVER_TIMESTAMP
|
| 69 |
+
}
|
| 70 |
+
db.collection('g_users').document(user.uid).set(user_data)
|
| 71 |
+
|
| 72 |
+
# Create default workspace as subcollection inside user's document
|
| 73 |
+
# Path: g_users/{user_id}/workspaces/{DEFAULT_WORKSPACE_ID}
|
| 74 |
+
workspace_data = generate_workspace_data(user.uid, DEFAULT_WORKSPACE_ID)
|
| 75 |
+
workspace_data['timestamp'] = firestore.SERVER_TIMESTAMP
|
| 76 |
+
db.collection('g_users').document(user.uid).collection('workspaces').document(DEFAULT_WORKSPACE_ID).set(
|
| 77 |
+
workspace_data)
|
| 78 |
+
|
| 79 |
+
return True, "Registration successful!", user.uid
|
| 80 |
+
else:
|
| 81 |
+
# Mock registration
|
| 82 |
+
if email in mock_users:
|
| 83 |
+
return False, "User already exists!", None
|
| 84 |
+
|
| 85 |
+
user_id = hashlib.sha256(f"{email}{datetime.now()}".encode()).hexdigest()[:28]
|
| 86 |
+
|
| 87 |
+
workspace_data = generate_workspace_data(user_id, DEFAULT_WORKSPACE_ID)
|
| 88 |
+
workspace_data['timestamp'] = datetime.now()
|
| 89 |
+
|
| 90 |
+
mock_users[email] = {
|
| 91 |
+
'user_id': user_id,
|
| 92 |
+
'name': username,
|
| 93 |
+
'email': email,
|
| 94 |
+
'password': hash_password(password),
|
| 95 |
+
'created_at': datetime.now(),
|
| 96 |
+
'workspaces': {
|
| 97 |
+
DEFAULT_WORKSPACE_ID: workspace_data
|
| 98 |
+
}
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
return True, "Registration successful!", user_id
|
| 102 |
+
|
| 103 |
+
except Exception as e:
|
| 104 |
+
return False, f"Registration failed: {str(e)}", None
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
def login_user(email, password):
|
| 108 |
+
"""
|
| 109 |
+
Login user
|
| 110 |
+
Returns: (success: bool, message: str, user_id: str or None)
|
| 111 |
+
"""
|
| 112 |
+
try:
|
| 113 |
+
if FIREBASE_ENABLED:
|
| 114 |
+
# In production, you'd verify with Firebase Auth
|
| 115 |
+
# For Gradio, we'll use a simplified approach
|
| 116 |
+
users = db.collection('g_users').where('email', '==', email).limit(1).get()
|
| 117 |
+
if users:
|
| 118 |
+
user_doc = list(users)[0]
|
| 119 |
+
user_id = user_doc.id
|
| 120 |
+
return True, "Login successful!", user_id
|
| 121 |
+
else:
|
| 122 |
+
return False, "Invalid credentials!", None
|
| 123 |
+
else:
|
| 124 |
+
# Mock login
|
| 125 |
+
if email in mock_users:
|
| 126 |
+
user_data = mock_users[email]
|
| 127 |
+
if user_data['password'] == hash_password(password):
|
| 128 |
+
return True, "Login successful!", user_data['user_id']
|
| 129 |
+
return False, "Invalid credentials!", None
|
| 130 |
+
|
| 131 |
+
except Exception as e:
|
| 132 |
+
return False, f"Login failed: {str(e)}", None
|
| 133 |
+
|
| 134 |
+
|
| 135 |
+
def generate_chatbot_share_script(user_id, workspace_id, chatbot_id):
|
| 136 |
+
"""
|
| 137 |
+
Generate shareScript for chatbot
|
| 138 |
+
"""
|
| 139 |
+
return f'''<script> (function (w, d) {{ w.CLIENT_IDENTIFIER = "{user_id}"; w.WORKSPACE_IDENTIFIER = '{workspace_id}'; w.AVATAR_IMAGE_URL = 'https://firebasestorage.googleapis.com/v0/b/curious-learner-3845a.appspot.com/o/avatars%2Ffemale_profile.png?alt=media&token=58bf4a74-24c8-41b1-b8bd-e381b798bb8d'; w.CHATBOT_IDENTIFIER = '{chatbot_id}'; var h = d.head || d.getElementsByTagName("head")[0]; var s = d.createElement('script'); s.setAttribute('type', 'text/javascript'); s.async = true; s.setAttribute('src', 'https://curious-learner-chatbot.web.app/client.js'); h.appendChild(s); }})(window, document); </script>'''
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
def generate_chatbot_data(user_id, workspace_id, chatbot_id, chatbot_name, model_name, mcp_github_enabled, github_token,
|
| 143 |
+
system_prompt):
|
| 144 |
+
"""
|
| 145 |
+
Generate chatbot document data with agent configuration
|
| 146 |
+
"""
|
| 147 |
+
# Build MCP config for chatMessageModels
|
| 148 |
+
mcp_config = {}
|
| 149 |
+
if mcp_github_enabled and github_token:
|
| 150 |
+
mcp_config["github"] = {
|
| 151 |
+
"url": "https://api.githubcopilot.com/mcp/",
|
| 152 |
+
"transport": "streamable_http",
|
| 153 |
+
"headers": {
|
| 154 |
+
"Authorization": f"Bearer {github_token}"
|
| 155 |
+
}
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
# Agent chat message model
|
| 159 |
+
agent_message_model = {
|
| 160 |
+
'chatMessageType': 'agent',
|
| 161 |
+
'chatMessage': 'Hi I am a GitHub MCP server bot, how can I help you today?',
|
| 162 |
+
'llm': {
|
| 163 |
+
'provider': 'openai',
|
| 164 |
+
'model': model_name
|
| 165 |
+
},
|
| 166 |
+
'mcp': mcp_config,
|
| 167 |
+
'systemPrompt': system_prompt,
|
| 168 |
+
'label': '',
|
| 169 |
+
'iconPath': '',
|
| 170 |
+
'errorText': '',
|
| 171 |
+
'validationRegex': '',
|
| 172 |
+
'switchButtonEntities': [
|
| 173 |
+
{
|
| 174 |
+
'title': 'Back Button',
|
| 175 |
+
'value': True,
|
| 176 |
+
'isDisabled': False
|
| 177 |
+
},
|
| 178 |
+
{
|
| 179 |
+
'title': 'Skip Button',
|
| 180 |
+
'value': True,
|
| 181 |
+
'isDisabled': False
|
| 182 |
+
}
|
| 183 |
+
],
|
| 184 |
+
'optionEntities': []
|
| 185 |
+
}
|
| 186 |
+
|
| 187 |
+
return {
|
| 188 |
+
'chatMessageModels': [agent_message_model],
|
| 189 |
+
'chatbotName': chatbot_name,
|
| 190 |
+
'chatbotType': 'widget',
|
| 191 |
+
'designModel': {
|
| 192 |
+
'avatarModel': {
|
| 193 |
+
'avatarType': 'asset',
|
| 194 |
+
'value': 'asset/image/female_profile.png'
|
| 195 |
+
},
|
| 196 |
+
'branding': True,
|
| 197 |
+
'position': 'bottomRight',
|
| 198 |
+
'primaryColor': 4287203839,
|
| 199 |
+
'themeColor': 4294967295,
|
| 200 |
+
'welcomeMessage': True
|
| 201 |
+
},
|
| 202 |
+
'id': chatbot_id,
|
| 203 |
+
'shareScript': generate_chatbot_share_script(user_id, workspace_id, chatbot_id)
|
| 204 |
+
}
|
| 205 |
+
|
| 206 |
+
|
| 207 |
+
def create_agent(user_id, agent_name, model_name, mcp_github_enabled, github_token, system_prompt):
|
| 208 |
+
"""
|
| 209 |
+
Create a new React agent
|
| 210 |
+
Returns: (success: bool, message: str, agent_url: str or None)
|
| 211 |
+
"""
|
| 212 |
+
if not user_id:
|
| 213 |
+
return False, "Please login first!", None
|
| 214 |
+
|
| 215 |
+
if not agent_name or not model_name or not system_prompt:
|
| 216 |
+
return False, "Agent name, model, and system prompt are required!", None
|
| 217 |
+
|
| 218 |
+
# Validate GitHub token if GitHub MCP is enabled
|
| 219 |
+
if mcp_github_enabled and not github_token:
|
| 220 |
+
return False, "GitHub token is required when GitHub MCP is enabled!", None
|
| 221 |
+
|
| 222 |
+
try:
|
| 223 |
+
agent_id = hashlib.sha256(f"{agent_name}{user_id}{datetime.now()}".encode()).hexdigest()[:12]
|
| 224 |
+
|
| 225 |
+
# Generate unique chatbot ID (UUID format)
|
| 226 |
+
import uuid
|
| 227 |
+
chatbot_id = str(uuid.uuid1())
|
| 228 |
+
|
| 229 |
+
# Build MCP config
|
| 230 |
+
mcp_config = {}
|
| 231 |
+
if mcp_github_enabled:
|
| 232 |
+
mcp_config["github"] = {
|
| 233 |
+
"url": "https://api.githubcopilot.com/mcp/",
|
| 234 |
+
"transport": "streamable_http",
|
| 235 |
+
"headers": {
|
| 236 |
+
"Authorization": f"Bearer {github_token}"}
|
| 237 |
+
}
|
| 238 |
+
|
| 239 |
+
agent_data = {
|
| 240 |
+
'agent_id': agent_id,
|
| 241 |
+
'agent_name': agent_name,
|
| 242 |
+
'model_name': model_name,
|
| 243 |
+
'mcp_config': mcp_config,
|
| 244 |
+
'github_token': github_token if mcp_github_enabled else None,
|
| 245 |
+
'system_prompt': system_prompt,
|
| 246 |
+
'created_by': user_id,
|
| 247 |
+
'created_at': firestore.SERVER_TIMESTAMP if FIREBASE_ENABLED else datetime.now().isoformat(),
|
| 248 |
+
'agent_url': f"https://curious-learner-chatbot.web.app/#/chats?clientId={user_id}&workspaceId={DEFAULT_WORKSPACE_ID}&chatbotId={chatbot_id}",
|
| 249 |
+
'chatbot_id': chatbot_id
|
| 250 |
+
}
|
| 251 |
+
|
| 252 |
+
# Generate chatbot document data with agent configuration
|
| 253 |
+
chatbot_data = generate_chatbot_data(
|
| 254 |
+
user_id,
|
| 255 |
+
DEFAULT_WORKSPACE_ID,
|
| 256 |
+
chatbot_id,
|
| 257 |
+
agent_name,
|
| 258 |
+
model_name,
|
| 259 |
+
mcp_github_enabled,
|
| 260 |
+
github_token,
|
| 261 |
+
system_prompt
|
| 262 |
+
)
|
| 263 |
+
|
| 264 |
+
if FIREBASE_ENABLED:
|
| 265 |
+
# Save agent to agents collection
|
| 266 |
+
db.collection('agents').document(agent_id).set(agent_data)
|
| 267 |
+
|
| 268 |
+
# Create chatbot document inside workspace
|
| 269 |
+
# Path: g_users/{user_id}/workspaces/{DEFAULT_WORKSPACE_ID}/chatbots/{chatbot_id}
|
| 270 |
+
chatbot_data['timestamp'] = firestore.SERVER_TIMESTAMP
|
| 271 |
+
db.collection('g_users').document(user_id).collection('workspaces').document(
|
| 272 |
+
DEFAULT_WORKSPACE_ID).collection('chatbots').document(chatbot_id).set(chatbot_data)
|
| 273 |
+
else:
|
| 274 |
+
mock_agents[agent_id] = agent_data
|
| 275 |
+
|
| 276 |
+
# Store chatbot in mock workspace
|
| 277 |
+
for user_email, user_data in mock_users.items():
|
| 278 |
+
if user_data['user_id'] == user_id:
|
| 279 |
+
if 'chatbots' not in user_data['workspaces'][DEFAULT_WORKSPACE_ID]:
|
| 280 |
+
user_data['workspaces'][DEFAULT_WORKSPACE_ID]['chatbots'] = {}
|
| 281 |
+
chatbot_data['timestamp'] = datetime.now()
|
| 282 |
+
user_data['workspaces'][DEFAULT_WORKSPACE_ID]['chatbots'][chatbot_id] = chatbot_data
|
| 283 |
+
break
|
| 284 |
+
|
| 285 |
+
success_msg = f"✅ Agent '{agent_name}' created successfully!"
|
| 286 |
+
return True, success_msg, chatbot_id
|
| 287 |
+
|
| 288 |
+
except Exception as e:
|
| 289 |
+
return False, f"Failed to create agent: {str(e)}", None
|
| 290 |
+
|
| 291 |
+
|
| 292 |
+
def get_user_agents(user_id):
|
| 293 |
+
"""
|
| 294 |
+
Get all agents/chatbots created by a user
|
| 295 |
+
Returns: list of agent info strings
|
| 296 |
+
"""
|
| 297 |
+
if not user_id:
|
| 298 |
+
return []
|
| 299 |
+
|
| 300 |
+
try:
|
| 301 |
+
if FIREBASE_ENABLED:
|
| 302 |
+
# Fetch chatbots from the workspace subcollection
|
| 303 |
+
# Path: g_users/{user_id}/workspaces/{DEFAULT_WORKSPACE_ID}/chatbots
|
| 304 |
+
chatbots = db.collection('g_users').document(user_id).collection('workspaces').document(
|
| 305 |
+
DEFAULT_WORKSPACE_ID).collection('chatbots').get()
|
| 306 |
+
agent_list = []
|
| 307 |
+
for chatbot in chatbots:
|
| 308 |
+
data = chatbot.to_dict()
|
| 309 |
+
chatbot_id = data.get('id', chatbot.id)
|
| 310 |
+
chatbot_name = data.get('chatbotName', 'Unnamed Agent')
|
| 311 |
+
agent_url = f"https://curious-learner-chatbot.web.app/#/chats?clientId={user_id}&workspaceId={DEFAULT_WORKSPACE_ID}&chatbotId={chatbot_id}"
|
| 312 |
+
agent_list.append(f"• {chatbot_name}\n {agent_url}")
|
| 313 |
+
return agent_list
|
| 314 |
+
else:
|
| 315 |
+
agent_list = []
|
| 316 |
+
for user_email, user_data in mock_users.items():
|
| 317 |
+
if user_data['user_id'] == user_id:
|
| 318 |
+
workspaces = user_data.get('workspaces', {})
|
| 319 |
+
default_workspace = workspaces.get(DEFAULT_WORKSPACE_ID, {})
|
| 320 |
+
chatbots = default_workspace.get('chatbots', {})
|
| 321 |
+
for chatbot_id, data in chatbots.items():
|
| 322 |
+
chatbot_name = data.get('chatbotName', 'Unnamed Agent')
|
| 323 |
+
agent_url = f"https://curious-learner-chatbot.web.app/#/chats?clientId={user_id}&workspaceId={DEFAULT_WORKSPACE_ID}&chatbotId={chatbot_id}"
|
| 324 |
+
agent_list.append(f"• {chatbot_name}\n {agent_url}")
|
| 325 |
+
break
|
| 326 |
+
return agent_list
|
| 327 |
+
|
| 328 |
+
except Exception as e:
|
| 329 |
+
print(f"Error fetching agents: {e}")
|
| 330 |
+
return []
|
| 331 |
+
|
| 332 |
+
|
| 333 |
+
def get_user_by_id(user_id):
|
| 334 |
+
"""
|
| 335 |
+
Get user data by user ID
|
| 336 |
+
Returns: user data dict or None
|
| 337 |
+
"""
|
| 338 |
+
try:
|
| 339 |
+
if FIREBASE_ENABLED:
|
| 340 |
+
user_doc = db.collection('g_users').document(user_id).get()
|
| 341 |
+
if user_doc.exists:
|
| 342 |
+
return user_doc.to_dict()
|
| 343 |
+
return None
|
| 344 |
+
else:
|
| 345 |
+
for email, data in mock_users.items():
|
| 346 |
+
if data['user_id'] == user_id:
|
| 347 |
+
return data
|
| 348 |
+
return None
|
| 349 |
+
|
| 350 |
+
except Exception as e:
|
| 351 |
+
print(f"Error fetching user: {e}")
|
| 352 |
+
return None
|
| 353 |
+
|
| 354 |
+
|
| 355 |
+
def get_user_workspace(user_id):
|
| 356 |
+
"""
|
| 357 |
+
Get user's default workspace
|
| 358 |
+
Returns: workspace data dict or None
|
| 359 |
+
"""
|
| 360 |
+
try:
|
| 361 |
+
if FIREBASE_ENABLED:
|
| 362 |
+
# Path: g_users/{user_id}/workspaces/{DEFAULT_WORKSPACE_ID}
|
| 363 |
+
workspace_doc = db.collection('g_users').document(user_id).collection('workspaces').document(
|
| 364 |
+
DEFAULT_WORKSPACE_ID).get()
|
| 365 |
+
if workspace_doc.exists:
|
| 366 |
+
return workspace_doc.to_dict()
|
| 367 |
+
return None
|
| 368 |
+
else:
|
| 369 |
+
for user_email, user_data in mock_users.items():
|
| 370 |
+
if user_data['user_id'] == user_id and 'workspaces' in user_data:
|
| 371 |
+
return user_data['workspaces'].get(DEFAULT_WORKSPACE_ID)
|
| 372 |
+
return None
|
| 373 |
+
|
| 374 |
+
except Exception as e:
|
| 375 |
+
print(f"Error fetching workspace: {e}")
|
| 376 |
+
return None
|
firebase-credentials.json
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"type": "service_account",
|
| 3 |
+
"project_id": "curious-learner-3845a",
|
| 4 |
+
"private_key_id": "eb95158f55a274b71933c84128a9a608d079ec88",
|
| 5 |
+
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDLAPxtOdioHs7i\ndrac6/mfyjTX6qZ5NKVLWiJTfx+73U89YYA6oDboKwMLez1xYQilRckCcyMPdfXx\nH/UW5iKR+8U/2aCkbgy5J4Jzzprj5PEoVO+h/4pum3aDpaKeShTKbQcmnTDCHl1q\nRkUg4k5cFv3IExR/iZk5kG3Lt84dDXrH7KhJRpr1MsFjpYQ33+ngoL0G/RJ9Hyu2\nkn4KUPpegZ+QqOgpcO5YhIv0EHdV59bcCqeX6E4Dj32bPcOKBg3Z7C45Ooxhl+Ep\nvq06UgmgZ08ul0SDI5DRMgje6VPI3VrTWEEKKvWmI395Kybqbi9FZV1o40pAYiGF\n5rW84/L5AgMBAAECggEAAqoWe2fadZ5t5bVcK+QW/dISw9C4cvfOFuvtw73JO1cq\nGT/52wsg8rF50+vqqwh0gMLROBSDHcqqZIn1rAwaNmNLu/ejGaAOJQdP5C2OhTY1\n32skorIuwsk3PX7DiyNQHDYLytBzruCPe6ZvdYEy48Izfi2YmRyZDmiHCw5Js2zk\ntj5WZoMvoZunJSYiMOIT9AzqcaUmB/lPnYPCzWKa3cjN9U+3hlaagqBWUV/fLj9w\nvLTF6HwK4KxWHLQf9oSK60YoizSz7R7Dx0j8XAWTUJhPgMK75XGT4D2DRaXlk+8l\ngoiNKjGWcDO8oVeIzyozdXE7NaMWH0G4rVrofS6a7wKBgQDsLixH/aETc8ybPEdw\ns8Y4BTlXOfEXpwVMI6Xk6+4T+r8OmEdkFtWLj7QKWncege6m7T7VbmIRNiR4Gs8m\nPrRrczHwfS9P230qHty40DuJchfX/O7WyQ2D6Zmx4ixnDq1DTl9hZtmddxGPjaTD\n8VxdmPY44fkAI5/WLKGGE/8q7wKBgQDcChZLgcl/h/YSEvKJEdWwO0aDPzRz7g58\n3dx7aalPh+tRMjcazJRJxAxkt8ArZ+cJfyMjL6PkMn6US9ULUgN6rKT3Vsfi2Faq\nVFC5bzdi6gUIQsyw73dsvemJL+C4ZaXELss6yNduXomUVG95iFHFFNdQHhDnDXpw\nhy1S8zhglwKBgAxGQgrjxZFLPWD7+wKCdVTIALjly//csEvKtn51PIRRTcimZV9w\nSFzedQ7ssLAnNI38Wn2hJPucAr0zN3zXWW0UKY5EE0dlMtYTkIkSWWXFRjP1czw6\nardmVpSGGqSogJy04AQh4kFqxMDfLab5TkGXB4ThSZ2WPGJXI3XiaCqFAoGAHUD2\nD9nUeTERRPvh5NlLKJ/o0wAvMA6BPJaefoXgraMrZOMhMl3qhRgccbOASAULUVbm\nzAHEb01LSNoAG/4uWjvjvsJ51q3eb8y/4rdnjK4CN0PyRL/Bh+KDzupfnQRekoOK\nH2meQp0s+1xyaZz3ChWoPo2Qv7cqBRXjr7iIUUcCgYAVuS9+VWu49pedZ/qiUWhJ\nLRraOm5LHgkC08BdCl78XfvxrbfhhzmrDyhaiK9Qa/z705Wz9TufLmUfjk8MzdZW\nu2EqnNugcAPGPCTjuZq+cpKAN4IwxweWZyQddqnffIQTltfAhZ5gC0wCo/7moS1D\nG/rRBqYnj1gDyliDyZL25g==\n-----END PRIVATE KEY-----\n",
|
| 6 |
+
"client_email": "firebase-adminsdk-hg5x7@curious-learner-3845a.iam.gserviceaccount.com",
|
| 7 |
+
"client_id": "100249815186071791369",
|
| 8 |
+
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
| 9 |
+
"token_uri": "https://oauth2.googleapis.com/token",
|
| 10 |
+
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
|
| 11 |
+
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-hg5x7%40curious-learner-3845a.iam.gserviceaccount.com",
|
| 12 |
+
"universe_domain": "googleapis.com"
|
| 13 |
+
}
|
gitignore
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Python-generated files
|
| 2 |
+
__pycache__/
|
| 3 |
+
*.py[oc]
|
| 4 |
+
build/
|
| 5 |
+
dist/
|
| 6 |
+
wheels/
|
| 7 |
+
*.egg-info
|
| 8 |
+
|
| 9 |
+
# Virtual environments
|
| 10 |
+
.venv
|
| 11 |
+
|
| 12 |
+
# Firebase
|
| 13 |
+
firebase-credentials.json
|
| 14 |
+
|
| 15 |
+
# IDE
|
| 16 |
+
.vscode/
|
| 17 |
+
.idea/
|
| 18 |
+
*.swp
|
| 19 |
+
*.swo
|
| 20 |
+
*~
|
| 21 |
+
|
| 22 |
+
# OS
|
| 23 |
+
.DS_Store
|
| 24 |
+
Thumbs.db
|
| 25 |
+
|
| 26 |
+
# Gradio
|
| 27 |
+
gradio_cached_examples/
|
| 28 |
+
flagged/
|
| 29 |
+
|
| 30 |
+
# Logs
|
| 31 |
+
*.log
|
gradio_app.py
ADDED
|
@@ -0,0 +1,584 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
from datetime import datetime
|
| 3 |
+
import hashlib
|
| 4 |
+
import json
|
| 5 |
+
|
| 6 |
+
# Import database functions
|
| 7 |
+
from database import (
|
| 8 |
+
register_user as db_register_user,
|
| 9 |
+
login_user as db_login_user,
|
| 10 |
+
create_agent as db_create_agent,
|
| 11 |
+
get_user_agents as db_get_user_agents,
|
| 12 |
+
get_user_by_id,
|
| 13 |
+
FIREBASE_ENABLED,
|
| 14 |
+
DEFAULT_WORKSPACE_ID
|
| 15 |
+
)
|
| 16 |
+
|
| 17 |
+
# Session management
|
| 18 |
+
user_sessions = {}
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def get_chatbot_iframe(user_id):
|
| 22 |
+
"""Generate iframe HTML for chatbot webview"""
|
| 23 |
+
if not user_id:
|
| 24 |
+
print("[DEBUG] get_chatbot_iframe: user_id is None or empty")
|
| 25 |
+
return ""
|
| 26 |
+
|
| 27 |
+
chatbot_url = f"https://curious-learner-chatbot.web.app/#/chats?clientId={user_id}&workspaceId={DEFAULT_WORKSPACE_ID}"
|
| 28 |
+
print(f"[DEBUG] get_chatbot_iframe URL: {chatbot_url}")
|
| 29 |
+
return f'''
|
| 30 |
+
<iframe
|
| 31 |
+
src="{chatbot_url}"
|
| 32 |
+
style="width: 100%; height: 100%; border: none;"
|
| 33 |
+
allow="clipboard-write; clipboard-read"
|
| 34 |
+
></iframe>
|
| 35 |
+
'''
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def register_user(username, email, password, confirm_password):
|
| 39 |
+
"""Register a new user"""
|
| 40 |
+
if not username or not email or not password:
|
| 41 |
+
return "All fields are required!", None
|
| 42 |
+
|
| 43 |
+
if password != confirm_password:
|
| 44 |
+
return "Passwords do not match!", None
|
| 45 |
+
|
| 46 |
+
if len(password) < 6:
|
| 47 |
+
return "Password must be at least 6 characters!", None
|
| 48 |
+
|
| 49 |
+
success, message, user_id = db_register_user(username, email, password)
|
| 50 |
+
|
| 51 |
+
if success:
|
| 52 |
+
return message + " Please login.", "login"
|
| 53 |
+
else:
|
| 54 |
+
return message, None
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
def login_user(email, password):
|
| 58 |
+
"""Login user"""
|
| 59 |
+
if not email or not password:
|
| 60 |
+
return "Email and password are required!", None, None, None, None
|
| 61 |
+
|
| 62 |
+
success, message, user_id = db_login_user(email, password)
|
| 63 |
+
|
| 64 |
+
if success:
|
| 65 |
+
session_id = hashlib.sha256(f"{email}{datetime.now()}".encode()).hexdigest()
|
| 66 |
+
user_sessions[session_id] = user_id
|
| 67 |
+
|
| 68 |
+
# Create session data for cookie storage
|
| 69 |
+
session_data = json.dumps({
|
| 70 |
+
"session_id": session_id,
|
| 71 |
+
"user_id": user_id})
|
| 72 |
+
|
| 73 |
+
return "Login successful!", "dashboard", session_id, session_data, user_id
|
| 74 |
+
else:
|
| 75 |
+
return message, None, None, None, None
|
| 76 |
+
|
| 77 |
+
|
| 78 |
+
def logout_user():
|
| 79 |
+
"""Logout user and clear session"""
|
| 80 |
+
return "" # Return empty string to clear cookie
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
def get_username(session_id):
|
| 84 |
+
"""Get username for display"""
|
| 85 |
+
if not session_id or session_id not in user_sessions:
|
| 86 |
+
return ""
|
| 87 |
+
|
| 88 |
+
user_id = user_sessions[session_id]
|
| 89 |
+
user = get_user_by_id(user_id)
|
| 90 |
+
|
| 91 |
+
return user.get('name', 'User') if user else ""
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
def create_agent(session_id, agent_name, model_name, mcp_github_enabled, github_token, system_prompt):
|
| 95 |
+
"""Create a new React agent"""
|
| 96 |
+
if not session_id or session_id not in user_sessions:
|
| 97 |
+
return "Please login first!", None
|
| 98 |
+
|
| 99 |
+
user_id = user_sessions[session_id]
|
| 100 |
+
success, message, chatbot_id = db_create_agent(
|
| 101 |
+
user_id, agent_name, model_name, mcp_github_enabled, github_token, system_prompt
|
| 102 |
+
)
|
| 103 |
+
|
| 104 |
+
return message, chatbot_id if success else None
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
def get_user_agents(session_id):
|
| 108 |
+
"""Get all agents created by the user"""
|
| 109 |
+
if not session_id or session_id not in user_sessions:
|
| 110 |
+
return "Please login first!"
|
| 111 |
+
|
| 112 |
+
user_id = user_sessions[session_id]
|
| 113 |
+
agent_list = db_get_user_agents(user_id)
|
| 114 |
+
|
| 115 |
+
return "\n\n".join(agent_list) if agent_list else "No agents created yet."
|
| 116 |
+
|
| 117 |
+
|
| 118 |
+
# Custom CSS for better styling
|
| 119 |
+
custom_css = """
|
| 120 |
+
<style>
|
| 121 |
+
/* Desktop-friendly layout */
|
| 122 |
+
.gradio-container {
|
| 123 |
+
max-width: 1400px !important;
|
| 124 |
+
margin: 0 auto !important;
|
| 125 |
+
}
|
| 126 |
+
|
| 127 |
+
/* Larger form elements */
|
| 128 |
+
.contain {
|
| 129 |
+
max-width: 100% !important;
|
| 130 |
+
}
|
| 131 |
+
|
| 132 |
+
/* Auth forms centered but wider */
|
| 133 |
+
.auth-form {
|
| 134 |
+
max-width: 500px;
|
| 135 |
+
margin: 0 auto;
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
/* Dashboard and form containers */
|
| 139 |
+
.dashboard-container, .form-container {
|
| 140 |
+
max-width: 800px;
|
| 141 |
+
margin: 0 auto;
|
| 142 |
+
padding: 30px;
|
| 143 |
+
}
|
| 144 |
+
|
| 145 |
+
/* Create Agent Button - Large and prominent */
|
| 146 |
+
.create-agent-btn button {
|
| 147 |
+
font-size: 24px !important;
|
| 148 |
+
padding: 40px 60px !important;
|
| 149 |
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
|
| 150 |
+
color: white !important;
|
| 151 |
+
border: none !important;
|
| 152 |
+
border-radius: 15px !important;
|
| 153 |
+
min-height: 120px !important;
|
| 154 |
+
width: 100% !important;
|
| 155 |
+
margin: 20px 0 !important;
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
.create-agent-btn button:hover {
|
| 159 |
+
transform: scale(1.02) !important;
|
| 160 |
+
box-shadow: 0 8px 16px rgba(0,0,0,0.2) !important;
|
| 161 |
+
}
|
| 162 |
+
|
| 163 |
+
/* Back button styling */
|
| 164 |
+
.back-btn button {
|
| 165 |
+
background: linear-gradient(135deg, #6B7280 0%, #4B5563 100%) !important;
|
| 166 |
+
color: white !important;
|
| 167 |
+
font-size: 16px !important;
|
| 168 |
+
padding: 12px 24px !important;
|
| 169 |
+
border-radius: 8px !important;
|
| 170 |
+
}
|
| 171 |
+
|
| 172 |
+
/* Logout button styling */
|
| 173 |
+
.logout-btn button {
|
| 174 |
+
background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%) !important;
|
| 175 |
+
color: white !important;
|
| 176 |
+
font-size: 14px !important;
|
| 177 |
+
padding: 10px 20px !important;
|
| 178 |
+
border-radius: 8px !important;
|
| 179 |
+
margin-top: 30px !important;
|
| 180 |
+
}
|
| 181 |
+
|
| 182 |
+
.logout-btn button:hover {
|
| 183 |
+
background: linear-gradient(135deg, #dc2626 0%, #b91c1c 100%) !important;
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
/* MCP Config styling */
|
| 187 |
+
.mcp-config-box {
|
| 188 |
+
border: 2px solid #e5e7eb;
|
| 189 |
+
border-radius: 12px;
|
| 190 |
+
padding: 20px;
|
| 191 |
+
background: transparent !important;
|
| 192 |
+
margin: 15px 0;
|
| 193 |
+
}
|
| 194 |
+
|
| 195 |
+
/* Checkbox labels */
|
| 196 |
+
.mcp-checkbox label {
|
| 197 |
+
font-size: 16px !important;
|
| 198 |
+
font-weight: 500 !important;
|
| 199 |
+
}
|
| 200 |
+
|
| 201 |
+
/* Form inputs larger */
|
| 202 |
+
input[type="text"], input[type="email"], input[type="password"], textarea, select {
|
| 203 |
+
font-size: 16px !important;
|
| 204 |
+
padding: 12px !important;
|
| 205 |
+
}
|
| 206 |
+
|
| 207 |
+
/* Fix checkbox and password field backgrounds */
|
| 208 |
+
input[type="password"] {
|
| 209 |
+
background-color: var(--input-background-fill) !important;
|
| 210 |
+
}
|
| 211 |
+
|
| 212 |
+
input[type="checkbox"] {
|
| 213 |
+
background-color: transparent !important;
|
| 214 |
+
}
|
| 215 |
+
|
| 216 |
+
/* Buttons larger */
|
| 217 |
+
button {
|
| 218 |
+
font-size: 16px !important;
|
| 219 |
+
padding: 12px 24px !important;
|
| 220 |
+
}
|
| 221 |
+
|
| 222 |
+
/* Agent list styling */
|
| 223 |
+
.agent-list-container {
|
| 224 |
+
background: transparent !important;
|
| 225 |
+
border-radius: 12px;
|
| 226 |
+
padding: 20px;
|
| 227 |
+
margin-top: 20px;
|
| 228 |
+
}
|
| 229 |
+
|
| 230 |
+
/* Chatbot webview styling - floating chatbox */
|
| 231 |
+
#chatbot-webview {
|
| 232 |
+
position: fixed !important;
|
| 233 |
+
bottom: 20px !important;
|
| 234 |
+
right: 20px !important;
|
| 235 |
+
width: 380px !important;
|
| 236 |
+
height: 550px !important;
|
| 237 |
+
border: none !important;
|
| 238 |
+
border-radius: 16px !important;
|
| 239 |
+
overflow: hidden !important;
|
| 240 |
+
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15) !important;
|
| 241 |
+
z-index: 9999 !important;
|
| 242 |
+
background: white !important;
|
| 243 |
+
}
|
| 244 |
+
|
| 245 |
+
#chatbot-webview iframe {
|
| 246 |
+
width: 100% !important;
|
| 247 |
+
height: 100% !important;
|
| 248 |
+
border: none !important;
|
| 249 |
+
}
|
| 250 |
+
|
| 251 |
+
/* Remove top border from first block in tabs */
|
| 252 |
+
.tabitem > .column > .block:first-child {
|
| 253 |
+
border-top: none !important;
|
| 254 |
+
}
|
| 255 |
+
|
| 256 |
+
/* Remove border from blocks at the top of form containers */
|
| 257 |
+
.form-container > .block:first-child,
|
| 258 |
+
.dashboard-container > .block:first-child {
|
| 259 |
+
border-top: none !important;
|
| 260 |
+
}
|
| 261 |
+
</style>
|
| 262 |
+
"""
|
| 263 |
+
|
| 264 |
+
# Build the Gradio interface
|
| 265 |
+
with gr.Blocks(title="React Agent Builder") as app:
|
| 266 |
+
# Inject custom CSS
|
| 267 |
+
gr.HTML(custom_css)
|
| 268 |
+
|
| 269 |
+
# State variables
|
| 270 |
+
session_state = gr.State(None)
|
| 271 |
+
user_id_state = gr.State(None)
|
| 272 |
+
|
| 273 |
+
with gr.Tabs(selected="login") as tabs:
|
| 274 |
+
with gr.Tab("Login", id="login") as login_tab:
|
| 275 |
+
with gr.Column(elem_classes="auth-form"):
|
| 276 |
+
gr.Markdown("# 🔐 Login")
|
| 277 |
+
login_email = gr.Textbox(label="Email", placeholder="Enter your email", scale=1)
|
| 278 |
+
login_password = gr.Textbox(label="Password", type="password", placeholder="Enter your password",
|
| 279 |
+
scale=1)
|
| 280 |
+
login_btn = gr.Button("Login", variant="primary", size="lg", scale=1)
|
| 281 |
+
login_msg = gr.Textbox(label="Status", interactive=False, scale=1)
|
| 282 |
+
gr.Markdown("Don't have an account? Switch to the Registration tab.")
|
| 283 |
+
|
| 284 |
+
with gr.Tab("Register", id="register") as register_tab:
|
| 285 |
+
with gr.Column(elem_classes="auth-form"):
|
| 286 |
+
gr.Markdown("# 📝 Register")
|
| 287 |
+
reg_username = gr.Textbox(label="Username", placeholder="Choose a username", scale=1)
|
| 288 |
+
reg_email = gr.Textbox(label="Email", placeholder="Enter your email", scale=1)
|
| 289 |
+
reg_password = gr.Textbox(label="Password", type="password", placeholder="Choose a password", scale=1)
|
| 290 |
+
reg_confirm_password = gr.Textbox(label="Confirm Password", type="password",
|
| 291 |
+
placeholder="Confirm your password", scale=1)
|
| 292 |
+
reg_btn = gr.Button("Register", variant="primary", size="lg", scale=1)
|
| 293 |
+
reg_msg = gr.Textbox(label="Status", interactive=False, scale=1)
|
| 294 |
+
|
| 295 |
+
with gr.Tab("Dashboard", id="dashboard", visible=False) as dashboard_tab:
|
| 296 |
+
with gr.Column(elem_classes="dashboard-container"):
|
| 297 |
+
gr.Markdown("# 🚀 React Agent Dashboard")
|
| 298 |
+
|
| 299 |
+
create_agent_btn = gr.Button(
|
| 300 |
+
"➕ Create React Agent",
|
| 301 |
+
size="lg",
|
| 302 |
+
variant="primary",
|
| 303 |
+
elem_classes="create-agent-btn"
|
| 304 |
+
)
|
| 305 |
+
|
| 306 |
+
with gr.Column(elem_classes="agent-list-container"):
|
| 307 |
+
gr.Markdown("### 📋 Your Agents")
|
| 308 |
+
agents_list = gr.Textbox(
|
| 309 |
+
label="Created Agents",
|
| 310 |
+
interactive=False,
|
| 311 |
+
lines=10,
|
| 312 |
+
placeholder="Your created agents will appear here...",
|
| 313 |
+
scale=1
|
| 314 |
+
)
|
| 315 |
+
refresh_btn = gr.Button("🔄 Refresh List", size="sm")
|
| 316 |
+
|
| 317 |
+
# Logout button at the bottom of dashboard, inside the container
|
| 318 |
+
logout_btn_dashboard = gr.Button("🚪 Logout", size="sm", variant="secondary", elem_classes="logout-btn")
|
| 319 |
+
|
| 320 |
+
# Floating chatbot webview - outside the main container
|
| 321 |
+
chatbot_webview = gr.HTML(
|
| 322 |
+
value="",
|
| 323 |
+
elem_id="chatbot-webview"
|
| 324 |
+
)
|
| 325 |
+
|
| 326 |
+
with gr.Tab("Create Agent", id="create_agent", visible=False) as create_agent_tab:
|
| 327 |
+
with gr.Column(elem_classes="form-container"):
|
| 328 |
+
# Back button at the top
|
| 329 |
+
back_btn = gr.Button("← Back to Dashboard", size="lg", elem_classes="back-btn")
|
| 330 |
+
|
| 331 |
+
gr.Markdown("# 🤖 Create New React Agent")
|
| 332 |
+
|
| 333 |
+
agent_name_input = gr.Textbox(
|
| 334 |
+
label="Agent Name",
|
| 335 |
+
placeholder="Enter a name for your agent",
|
| 336 |
+
info="Give your agent a descriptive name",
|
| 337 |
+
scale=1
|
| 338 |
+
)
|
| 339 |
+
|
| 340 |
+
model_dropdown = gr.Dropdown(
|
| 341 |
+
label="Model Name",
|
| 342 |
+
choices=[
|
| 343 |
+
"gpt-4o",
|
| 344 |
+
"gpt-4o-mini"
|
| 345 |
+
],
|
| 346 |
+
value="gpt-4o",
|
| 347 |
+
info="Select the OpenAI model to use",
|
| 348 |
+
scale=1
|
| 349 |
+
)
|
| 350 |
+
|
| 351 |
+
# MCP Server Config section
|
| 352 |
+
gr.Markdown("### 🔌 MCP Server Configuration")
|
| 353 |
+
with gr.Column(elem_classes="mcp-config-box"):
|
| 354 |
+
mcp_github = gr.Checkbox(
|
| 355 |
+
label="GitHub - Functions like commit, push, pull, update etc.",
|
| 356 |
+
value=False,
|
| 357 |
+
elem_classes="mcp-checkbox"
|
| 358 |
+
)
|
| 359 |
+
|
| 360 |
+
github_token_input = gr.Textbox(
|
| 361 |
+
label="Token",
|
| 362 |
+
placeholder="ghp_xxxxxxxxxxxxxxxxxxxx",
|
| 363 |
+
type="password",
|
| 364 |
+
visible=False,
|
| 365 |
+
scale=1
|
| 366 |
+
)
|
| 367 |
+
|
| 368 |
+
system_prompt_input = gr.Textbox(
|
| 369 |
+
label="System Context Prompt",
|
| 370 |
+
placeholder="Enter the system prompt for your agent...",
|
| 371 |
+
lines=10,
|
| 372 |
+
info="Define how your agent should behave and respond",
|
| 373 |
+
scale=1
|
| 374 |
+
)
|
| 375 |
+
|
| 376 |
+
submit_btn = gr.Button("✅ Submit & Create Agent", variant="primary", size="lg", scale=1)
|
| 377 |
+
|
| 378 |
+
create_msg = gr.Textbox(label="Status", interactive=False, lines=2, scale=1)
|
| 379 |
+
agent_url_output = gr.Textbox(label="Agent URL", interactive=False, lines=3, scale=1)
|
| 380 |
+
|
| 381 |
+
# Logout button at the bottom of create agent form
|
| 382 |
+
logout_btn_create = gr.Button("🚪 Logout", size="sm", variant="secondary", elem_classes="logout-btn")
|
| 383 |
+
|
| 384 |
+
|
| 385 |
+
# Event handlers
|
| 386 |
+
def handle_login(email, password):
|
| 387 |
+
"""Handle login and return all necessary updates"""
|
| 388 |
+
msg, page, sess_id, cookie, user_id = login_user(email, password)
|
| 389 |
+
|
| 390 |
+
print(f"[DEBUG] handle_login: page={page}, sess_id={sess_id}, user_id={user_id}")
|
| 391 |
+
|
| 392 |
+
if page == "dashboard" and sess_id:
|
| 393 |
+
# Successful login - show dashboard and load agents list
|
| 394 |
+
# Use user_id directly to fetch agents
|
| 395 |
+
agent_list = db_get_user_agents(user_id)
|
| 396 |
+
agents_text = "\n\n".join(agent_list) if agent_list else "No agents created yet."
|
| 397 |
+
|
| 398 |
+
print(f"[DEBUG] handle_login: Generating chatbot iframe for user_id={user_id}")
|
| 399 |
+
chatbot_html = get_chatbot_iframe(user_id)
|
| 400 |
+
print(f"[DEBUG] handle_login: chatbot_html length={len(chatbot_html)}")
|
| 401 |
+
|
| 402 |
+
return {
|
| 403 |
+
login_msg: msg,
|
| 404 |
+
login_tab: gr.update(visible=False),
|
| 405 |
+
register_tab: gr.update(visible=False),
|
| 406 |
+
dashboard_tab: gr.update(visible=True),
|
| 407 |
+
create_agent_tab: gr.update(visible=False),
|
| 408 |
+
session_state: sess_id,
|
| 409 |
+
user_id_state: user_id,
|
| 410 |
+
agents_list: agents_text,
|
| 411 |
+
chatbot_webview: chatbot_html,
|
| 412 |
+
tabs: gr.update(selected="dashboard")
|
| 413 |
+
}
|
| 414 |
+
else:
|
| 415 |
+
# Failed login - stay on login page
|
| 416 |
+
return {
|
| 417 |
+
login_msg: msg,
|
| 418 |
+
login_tab: gr.update(),
|
| 419 |
+
register_tab: gr.update(),
|
| 420 |
+
dashboard_tab: gr.update(),
|
| 421 |
+
create_agent_tab: gr.update(),
|
| 422 |
+
session_state: None,
|
| 423 |
+
user_id_state: None,
|
| 424 |
+
agents_list: gr.update(),
|
| 425 |
+
chatbot_webview: gr.update(),
|
| 426 |
+
tabs: gr.update()
|
| 427 |
+
}
|
| 428 |
+
|
| 429 |
+
|
| 430 |
+
def handle_logout():
|
| 431 |
+
"""Handle logout"""
|
| 432 |
+
return {
|
| 433 |
+
login_tab: gr.update(visible=True),
|
| 434 |
+
register_tab: gr.update(visible=True),
|
| 435 |
+
dashboard_tab: gr.update(visible=False),
|
| 436 |
+
create_agent_tab: gr.update(visible=False),
|
| 437 |
+
session_state: None,
|
| 438 |
+
user_id_state: None,
|
| 439 |
+
login_email: "",
|
| 440 |
+
login_password: "",
|
| 441 |
+
login_msg: "",
|
| 442 |
+
chatbot_webview: "",
|
| 443 |
+
tabs: gr.update(selected="login")
|
| 444 |
+
}
|
| 445 |
+
|
| 446 |
+
|
| 447 |
+
def switch_to_create_agent():
|
| 448 |
+
return {
|
| 449 |
+
dashboard_tab: gr.update(visible=False),
|
| 450 |
+
create_agent_tab: gr.update(visible=True),
|
| 451 |
+
tabs: gr.update(selected="create_agent")
|
| 452 |
+
}
|
| 453 |
+
|
| 454 |
+
|
| 455 |
+
def switch_back_to_dashboard():
|
| 456 |
+
return {
|
| 457 |
+
dashboard_tab: gr.update(visible=True),
|
| 458 |
+
create_agent_tab: gr.update(visible=False),
|
| 459 |
+
agent_name_input: "",
|
| 460 |
+
mcp_github: False,
|
| 461 |
+
github_token_input: gr.update(value="", visible=False),
|
| 462 |
+
system_prompt_input: "",
|
| 463 |
+
create_msg: "",
|
| 464 |
+
agent_url_output: "",
|
| 465 |
+
tabs: gr.update(selected="dashboard")
|
| 466 |
+
}
|
| 467 |
+
|
| 468 |
+
|
| 469 |
+
def toggle_github_token(enabled):
|
| 470 |
+
"""Show/hide GitHub token input based on checkbox"""
|
| 471 |
+
return gr.update(visible=enabled)
|
| 472 |
+
|
| 473 |
+
|
| 474 |
+
def handle_agent_creation(sess_id, user_id, name, model, mcp_enabled, github_token, prompt):
|
| 475 |
+
msg, chatbot_id = create_agent(sess_id, name, model, mcp_enabled, github_token, prompt)
|
| 476 |
+
|
| 477 |
+
# Build the agent URL locally if creation was successful
|
| 478 |
+
agent_url = ""
|
| 479 |
+
if chatbot_id and user_id:
|
| 480 |
+
agent_url = f"https://curious-learner-chatbot.web.app/#/chats?clientId={user_id}&workspaceId={DEFAULT_WORKSPACE_ID}&chatbotId={chatbot_id}"
|
| 481 |
+
|
| 482 |
+
# Also refresh the agents list and webview after creation
|
| 483 |
+
agent_list = db_get_user_agents(user_id) if user_id else []
|
| 484 |
+
updated_agents = "\n\n".join(agent_list) if agent_list else "No agents created yet."
|
| 485 |
+
return {
|
| 486 |
+
create_msg: msg,
|
| 487 |
+
agent_url_output: agent_url,
|
| 488 |
+
agents_list: updated_agents,
|
| 489 |
+
chatbot_webview: get_chatbot_iframe(user_id)
|
| 490 |
+
}
|
| 491 |
+
|
| 492 |
+
|
| 493 |
+
# Refresh agents list function
|
| 494 |
+
def refresh_agents_list(user_id):
|
| 495 |
+
"""Refresh agents list using user_id"""
|
| 496 |
+
if not user_id:
|
| 497 |
+
return "Please login first!"
|
| 498 |
+
agent_list = db_get_user_agents(user_id)
|
| 499 |
+
return "\n\n".join(agent_list) if agent_list else "No agents created yet."
|
| 500 |
+
|
| 501 |
+
|
| 502 |
+
# Login event - chain refresh after login
|
| 503 |
+
login_btn.click(
|
| 504 |
+
fn=handle_login,
|
| 505 |
+
inputs=[login_email, login_password],
|
| 506 |
+
outputs=[login_msg, login_tab, register_tab, dashboard_tab, create_agent_tab, session_state,
|
| 507 |
+
user_id_state, agents_list, chatbot_webview, tabs]
|
| 508 |
+
).then(
|
| 509 |
+
fn=refresh_agents_list,
|
| 510 |
+
inputs=[user_id_state],
|
| 511 |
+
outputs=[agents_list]
|
| 512 |
+
)
|
| 513 |
+
|
| 514 |
+
# Logout events (both buttons do the same thing)
|
| 515 |
+
logout_outputs = [login_tab, register_tab, dashboard_tab, create_agent_tab, session_state,
|
| 516 |
+
user_id_state, login_email, login_password, login_msg, chatbot_webview, tabs]
|
| 517 |
+
|
| 518 |
+
logout_btn_dashboard.click(
|
| 519 |
+
fn=handle_logout,
|
| 520 |
+
outputs=logout_outputs
|
| 521 |
+
)
|
| 522 |
+
|
| 523 |
+
logout_btn_create.click(
|
| 524 |
+
fn=handle_logout,
|
| 525 |
+
outputs=logout_outputs
|
| 526 |
+
)
|
| 527 |
+
|
| 528 |
+
# Register event
|
| 529 |
+
reg_btn.click(
|
| 530 |
+
fn=register_user,
|
| 531 |
+
inputs=[reg_username, reg_email, reg_password, reg_confirm_password],
|
| 532 |
+
outputs=[reg_msg, gr.State()]
|
| 533 |
+
)
|
| 534 |
+
|
| 535 |
+
# Create agent button
|
| 536 |
+
create_agent_btn.click(
|
| 537 |
+
fn=switch_to_create_agent,
|
| 538 |
+
outputs=[dashboard_tab, create_agent_tab, tabs]
|
| 539 |
+
)
|
| 540 |
+
|
| 541 |
+
# Back button
|
| 542 |
+
back_btn.click(
|
| 543 |
+
fn=switch_back_to_dashboard,
|
| 544 |
+
outputs=[dashboard_tab, create_agent_tab, agent_name_input, mcp_github,
|
| 545 |
+
github_token_input, system_prompt_input, create_msg, agent_url_output, tabs]
|
| 546 |
+
)
|
| 547 |
+
|
| 548 |
+
# MCP GitHub checkbox toggle
|
| 549 |
+
mcp_github.change(
|
| 550 |
+
fn=toggle_github_token,
|
| 551 |
+
inputs=[mcp_github],
|
| 552 |
+
outputs=[github_token_input]
|
| 553 |
+
)
|
| 554 |
+
|
| 555 |
+
# Submit agent
|
| 556 |
+
submit_btn.click(
|
| 557 |
+
fn=handle_agent_creation,
|
| 558 |
+
inputs=[session_state, user_id_state, agent_name_input, model_dropdown, mcp_github,
|
| 559 |
+
github_token_input, system_prompt_input],
|
| 560 |
+
outputs=[create_msg, agent_url_output, agents_list, chatbot_webview]
|
| 561 |
+
)
|
| 562 |
+
|
| 563 |
+
# Refresh agents list button
|
| 564 |
+
refresh_btn.click(
|
| 565 |
+
fn=refresh_agents_list,
|
| 566 |
+
inputs=[user_id_state],
|
| 567 |
+
outputs=[agents_list]
|
| 568 |
+
)
|
| 569 |
+
|
| 570 |
+
if __name__ == "__main__":
|
| 571 |
+
app.launch(
|
| 572 |
+
server_name="0.0.0.0",
|
| 573 |
+
server_port=7860,
|
| 574 |
+
share=True
|
| 575 |
+
)
|
| 576 |
+
|
| 577 |
+
|
| 578 |
+
def main():
|
| 579 |
+
"""Entry point for the application"""
|
| 580 |
+
app.launch(
|
| 581 |
+
server_name="0.0.0.0",
|
| 582 |
+
server_port=7860,
|
| 583 |
+
share=True
|
| 584 |
+
)
|
pyproject.toml
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[project]
|
| 2 |
+
name = "gradio-react-agent"
|
| 3 |
+
version = "0.1.0"
|
| 4 |
+
description = "Gradio web application with authentication and React agent creation"
|
| 5 |
+
readme = "README.md"
|
| 6 |
+
requires-python = ">=3.12"
|
| 7 |
+
dependencies = [
|
| 8 |
+
"firebase-admin>=7.1.0",
|
| 9 |
+
"gradio>=6.0.1",
|
| 10 |
+
]
|
| 11 |
+
|
| 12 |
+
[dependency-groups]
|
| 13 |
+
dev = []
|
uv.lock
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|