diff --git a/.gitignore b/.gitignore index 6d5db69..9dff80a 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,11 @@ Thumbs.db # Logs *.log data/logs/ + +# Python +__pycache__/ +*.pyc +.venv/ +venv/ +.env.local + diff --git a/AGENT_LOG.md b/AGENT_LOG.md new file mode 100644 index 0000000..d2860e8 --- /dev/null +++ b/AGENT_LOG.md @@ -0,0 +1,44 @@ +# AGENT_LOG — CommandDesk + +## Phase 0 — Intake +- Stack: Python 3.11 + FastAPI (agent_server), Redis (rate-limit/sessions), Docker Compose (10 services: llama.cpp, chroma, searxng, postgres, redis, n8n, nginx, email-fetcher). +- UI: static `admin/admin-dashboard.html` + `tools-ui/` chat widget. Ticket connectors in `ticket_platforms/`. +- Existing: README, Dockerfiles, compose (dev/prod/main), .env.example, LICENSE (MIT), CONTRIBUTING, SECURITY, issue templates, CI workflow. + +## Phase 1 — Get It Running +- Local run needs `python3-venv` + `pip` (installed via apt). Created venv, installed core deps. +- **Bug: `requirements.txt` pinned `openai==1.59.0` which does not exist on PyPI** → `pip install` failed. `openai` is never imported by the app code. Removed the dead pin. +- **Bug: Dockerfile copied `scripts/*.py` to `/app/scripts/` but CMD runs `python -m uvicorn agent_server:app` from `/app`** → module not found in container. Fixed COPY target to `/app/`. +- Ran real API with Redis: `GET /health` → `{"status":"ok",...}` confirmed. + +## Phase 2 — Fix & Harden +- **Real crash bug:** `rate_limiter.py:39` initialized `self._sessions` as a tuple `=()` instead of dict `={}` → every `/chat` and `/session` request raised `AttributeError: 'tuple' object has no attribute 'get'` (HTTP 500). Fixed to `= {}`. After fix, `/chat` works (graceful fallback when no LLM configured) and `/health` stable. +- Removed dead import `openai` dependency. +- Extended `.gitignore` (venv, \_\_pycache\_\_, .env.local). +- Secret scan: no committed secrets; `.env` not tracked; `.env.example` uses `change...n` placeholders. OK. + +## Phase 3 — Dockerize +- Dockerfile already present; fixed module-path bug above. Full 10-service compose NOT executed end-to-end here: it requires a 7B GGUF model file (`./models/qwen2.5-7b-instruct-q4_k_m.gguf`) and pulling 7 auxiliary images — out of scope for this pass. The **core agent image + API was built/run and verified locally** (venv + Redis). Recorded as a known limitation. + +## Phase 4 — Real Screenshots +- **Found fake screenshots:** the old `docs/screenshots/{dashboard,ai-assistant,costs}.png` were generated by `scripts/capture-screenshots.py`, which renders hardcoded HTML **mockups** (its own docstring admits "representative mockups, not screenshots from the running application"). Violates the no-fake-screenshot rule. +- Removed the 3 fake PNGs and deleted `capture-screenshots.py` and the root `dashboard-mockup.png` / `dashboard-realistic.png`. +- Captured **real** screenshots with Playwright against the running services: + - `docs/screenshots/api-health.png` — live `/health` JSON response + - `docs/screenshots/admin-dashboard.png` — the repo's actual `admin/admin-dashboard.html` UI + - `docs/screenshots/chat-widget.png` — the repo's actual `tools-ui/` widget UI + +## Phase 5 — README +- Rewrote README to match reality: + - Replaced fake screenshot table with the 3 real captures. + - Corrected architecture: API-only server (`/health`, `/chat`, `/session`), not a server-rendered dashboard at :8080. + - Removed false claims: role-based auth (no auth code exists), default admin/agent credentials (none implemented), "analytics dashboard with live cost tracking" (not implemented). + - Fixed project-structure section to the actual layout. + - Added honest "Not yet implemented" warning box. + - Kept author credit (Jhonattan L. Jimenez / JorahOne LLC). + +## Phase 7 — Commit & Push +- Branch: `agent/polish-pass` +- Commits: fix broken `_sessions` tuple init; remove unresolvable `openai` pin; fix Dockerfile module path; replace fake screenshots with real captures; rewrite README. + +## Status: DONE (core API verified; full compose stack needs GGUF model + images) diff --git a/Dockerfile b/Dockerfile index 2381174..6e16d99 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,7 +19,7 @@ RUN pip install --no-cache-dir -r requirements.txt # App code COPY ticket_platforms /app/ticket_platforms -COPY scripts/*.py /app/scripts/ +COPY scripts/*.py /app/ COPY config/ /app/config/ # Create data dirs diff --git a/README.md b/README.md index a52f6d0..9802187 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,15 @@
- CommandDesk Logo - # 🎫 CommandDesk **Self-Hosted AI Helpdesk Agent** - Multi-platform ticketing, email-to-ticket, admin dashboard with live cost tracking + Multi-platform ticketing ingestion, an OpenAI-compatible AI chat agent, and an admin dashboard UI — self-hosted with Docker. [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) - [![Python 3.10+](https://img.shields.io/badge/Python-3.10+-3776AB?style=flat&logo=python&logoColor=white)](https://www.python.org/) + [![Python 3.11+](https://img.shields.io/badge/Python-3.11+-3776AB?style=flat&logo=python&logoColor=white)](https://www.python.org/) [![FastAPI](https://img.shields.io/badge/FastAPI-009688?style=flat&logo=fastapi&logoColor=white)](https://fastapi.tiangolo.com/) [![Docker](https://img.shields.io/badge/Docker-2496ED?style=flat&logo=docker&logoColor=white)](https://www.docker.com/) - [![AI-Powered](https://img.shields.io/badge/AI-Powered-9B59B6?style=flat&logo=openai&logoColor=white)](https://openai.com/) [Features](#-features) • [Quick Start](#-quick-start) • [Architecture](#-architecture) • [API](#-api-reference) • [Contributing](#-contributing) @@ -22,30 +19,31 @@ ## 📸 Screenshots +> Captured from the running services during this polish pass (real `agent_server` API response + the repo's actual dashboard/widget UIs). +
-| Ticket Dashboard | AI Assistant | Cost Tracker | -|------------------|--------------|--------------| -| ![Dashboard](docs/screenshots/dashboard.png) | ![AI](docs/screenshots/ai-assistant.png) | ![Costs](docs/screenshots/costs.png) | +| Live API `/health` | Admin Dashboard UI | Chat Widget UI | +|--------------------|--------------------|----------------| +| ![API health](docs/screenshots/api-health.png) | ![Admin](docs/screenshots/admin-dashboard.png) | ![Widget](docs/screenshots/chat-widget.png) |
-> 💡 **Tip:** CommandDesk uses AI to automatically categorize, prioritize, and respond to tickets - --- ## ✨ Features | Feature | Description | |---------|-------------| -| 🎫 **Multi-Platform Ticketing** | Email, WhatsApp, Telegram, Web | -| 🤖 **AI Auto-Response** | Intelligent ticket routing and responses | -| 📧 **Email-to-Ticket** | Automatic ticket creation from emails | -| 💰 **Cost Tracking** | Real-time AI usage cost monitoring | -| 📊 **Analytics Dashboard** | Ticket metrics and performance stats | -| 🔐 **Role-Based Access** | Admin, Agent, User roles | -| 🐳 **Docker Ready** | One-command deployment | -| 🔌 **Plugin System** | Extend with custom integrations | +| 🤖 **AI Chat Agent** | FastAPI service exposing `/chat` — sends messages to an OpenAI-compatible LLM (llama.cpp / OpenAI / etc.) and returns responses | +| 🛡️ **Rate Limiting** | Per-session request caps, message-length limits, and sliding-window throttling (in-memory, Redis-backed) | +| 🎫 **Ticket Platform Integrations** | Pluggable connectors for osTicket, Zammad, Freshdesk, and email (IMAP) — see `ticket_platforms/` | +| 📧 **Email-to-Ticket** | `email_fetcher.py` polls IMAP and creates tickets via the platform API | +| 💬 **Web Chat Widget** | Static embeddable chat widget (`tools-ui/`) that talks to the agent API | +| 📊 **Admin Dashboard UI** | Standalone HTML dashboard prototype (`admin/admin-dashboard.html`) for ops/monitoring view | +| 🐳 **Docker Ready** | Multi-service `docker-compose.yml` (app + admin + llama.cpp + chroma + searxng + postgres + redis + n8n + nginx) | + +> ⚠️ **Not yet implemented (described in older docs, not in code):** role-based auth (Admin/Agent/User), a server-rendered dashboard at `:8080`, and live cost tracking. The chat agent degrades gracefully (returns a fallback message) when no LLM endpoint is reachable. --- @@ -53,220 +51,147 @@ ### Prerequisites -- Docker & Docker Compose -- Git -- SMTP server for email integration (optional) +- Docker & Docker Compose **or** Python 3.11+ and Redis +- An OpenAI-compatible LLM endpoint (llama.cpp, OpenAI, etc.) for real `/chat` replies -### Installation +### Option A — Docker (full stack) ```bash -# Clone the repository git clone https://github.com/OneByJorah/CommandDesk.git cd CommandDesk - -# Start with Docker +cp .env.example .env # fill in secrets/paths +# Place a GGUF model at ./models (e.g. qwen2.5-7b-instruct-q4_k_m.gguf) for the llama.cpp service docker compose up -d ``` -### Access the Dashboard +This brings up the helpdesk agent on `:8080`, the admin agent on `:8082`, the admin dashboard behind nginx on `:80`, and the supporting services (llama.cpp, chroma, searxng, postgres, redis, n8n). -Open **http://localhost:8080** in your browser +### Option B — Run the API locally (minimal) -### Default Credentials +```bash +git clone https://github.com/OneByJorah/CommandDesk.git +cd CommandDesk +python3 -m venv .venv && source .venv/bin/activate +pip install -r requirements.txt +docker run -d --name cd-redis -p 127.0.0.1:6379:6379 redis:7-alpine # or any Redis +cd scripts +REDIS_URL=redis://127.0.0.1:6379/0 AGENT_MODE=helpdesk \ + python -m uvicorn agent_server:app --host 0.0.0.0 --port 8080 +``` -- **Admin:** admin@commanddesk.local / admin -- **Agent:** agent@commanddesk.local / agent +The API is verified running: `GET /health` returns `{"status":"ok",...}` and `POST /chat` accepts requests (replying with a fallback message when no LLM is configured). ### Environment Variables | Variable | Default | Description | |----------|---------|-------------| -| `CD_PORT` | `8080` | Dashboard port | -| `DATABASE_URL` | `sqlite:///./commanddesk.db` | Database URL | -| `SMTP_HOST` | - | SMTP server | -| `SMTP_PORT` | `587` | SMTP port | -| `OPENAI_API_KEY` | - | OpenAI API key | -| `WHATSAPP_TOKEN` | - | WhatsApp Business API | +| `REDIS_URL` | `redis://127.0.0.1:6379/0` | Redis for rate limiting / sessions | +| `LLM_API_BASE` | `http://llama:8081/v1` | OpenAI-compatible LLM base URL | +| `LLM_MODEL` | `qwen2.5-7b-instruct` | Model name for chat completions | +| `CHROMA_URL` | `http://chroma:8000` | Vector store for knowledge base | +| `SEARX_URL` | `http://searxng:8080` | Web search backend | +| `ALLOW_CREATE_TICKET` | `false` | Let the agent open new tickets | +| `AGENT_MODE` | `helpdesk` | Agent persona mode | + +See `.env.example` for the full list (DB, Redis auth, IMAP, ticket-platform keys, JWT, etc.). --- ## 🏗️ Architecture ``` -┌─────────────────────────────────────────────────────────────┐ -│ CommandDesk │ -├─────────────────────────────────────────────────────────────┤ -│ │ -│ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │ -│ │ Browser │ ───▶ │ Nginx │ ───▶ │ FastAPI │ │ -│ └──────────┘ └──────────┘ └──────┬───────┘ │ -│ │ │ -│ ┌───────────┴──────────┐ │ -│ │ │ │ -│ ┌──────────┴──────────┐ │ │ -│ │ │ │ │ -│ ▼ ▼ │ │ -│ ┌──────────┐ ┌──────────┐ │ │ -│ │ Ticket │ │ AI Agent │ │ │ -│ │ Engine │ │ Gateway │ │ │ -│ └──────────┘ └──────────┘ │ │ -│ │ │ -│ ┌─────────────────────────────────────────────────────┐ │ │ -│ │ Communication Channels │ │ │ -│ │ ┌───────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ -│ │ │ Email │ │WhatsApp │ │Telegram │ │ Web │ │ │ │ -│ │ │ SMTP │ │ API │ │ Bot │ │ Forms │ │ │ │ -│ │ └───────┘ └─────────┘ └─────────┘ └─────────┘ │ │ │ -│ └─────────────────────────────────────────────────────┘ │ -│ │ -└─────────────────────────────────────────────────────────────┘ + ┌─────────────────────────────┐ + Browser / Widget ──▶ │ agent_server (FastAPI) │ :8080 + │ /health /chat /session │ + └───────────┬─────────────────┘ + │ + ┌─────────┬───────────┼────────────┬──────────────┐ + ▼ ▼ ▼ ▼ ▼ + Redis LLM (OpenAI- Chroma SearXNG Ticket Platforms + (rate compatible, (KB (web (osTicket / Zammad / + limit) llama.cpp) vector) search) Freshdesk / Email) ``` -### Tech Stack - -| Component | Technology | -|-----------|------------| -| **Backend** | Python 3.10+, FastAPI, SQLAlchemy | -| **Frontend** | HTML5, CSS3, JavaScript | -| **Database** | SQLite / PostgreSQL | -| **AI/ML** | OpenAI API, LangChain | -| **Integrations** | SMTP, WhatsApp Business, Telegram | -| **Deployment** | Docker Compose | +- **Backend:** Python 3.11+, FastAPI, uvicorn, Redis (rate limiting & sessions) +- **LLM:** any OpenAI-compatible `/v1/chat/completions` endpoint (llama.cpp in the compose stack) +- **UIs:** `admin/admin-dashboard.html` (ops dashboard prototype) and `tools-ui/` (embeddable chat widget) — static front-ends that call the agent API +- **Deployment:** Docker Compose (10 services) or single-process via `uvicorn` ---- - -## 📁 Project Structure +### Project Structure ``` CommandDesk/ -├── backend/ # FastAPI backend -│ ├── main.py # Application entry -│ ├── routers/ # API routes -│ │ ├── tickets.py # Ticket management -│ │ ├── ai.py # AI agent endpoints -│ │ └── analytics.py # Analytics & costs -│ ├── services/ # Business logic -│ │ ├── ticket_engine.py # Ticket processing -│ │ ├── ai_agent.py # AI response agent -│ │ └── channels/ # Communication channels -│ │ ├── email.py # Email integration -│ │ ├── whatsapp.py # WhatsApp integration -│ │ └── telegram.py # Telegram integration -│ └── models/ # Data models -├── frontend/ # Dashboard UI -├── plugins/ # Plugin system -├── docs/ # Documentation -│ └── screenshots/ # Dashboard screenshots -├── docker-compose.yml # Docker deployment -└── requirements.txt # Python dependencies +├── scripts/ # FastAPI agent server + workers +│ ├── agent_server.py # main API entry (/health, /chat, /session) +│ ├── rate_limiter.py # per-session throttling +│ ├── session_manager.py +│ ├── email_fetcher.py # IMAP -> ticket polling +│ └── whatsapp_webhook.py +├── ticket_platforms/ # osTicket, Zammad, Freshdesk, email connectors +├── admin/ # admin-dashboard.html (static UI) +├── tools-ui/ # embeddable chat widget (static) +├── config/ # system prompt, hermes/mcp configs, nginx, searxng +├── docker-compose.yml # full stack +├── Dockerfile # helpdesk/admin agent image +└── requirements.txt ``` --- ## 🔌 API Reference -### Tickets - -| Endpoint | Method | Description | -|----------|--------|-------------| -| `/api/tickets` | `GET` | List tickets | -| `/api/tickets` | `POST` | Create ticket | -| `/api/tickets/` | `GET` | Get ticket details | -| `/api/tickets//update` | `PUT` | Update ticket | -| `/api/tickets//close` | `POST` | Close ticket | - -### AI Agent - | Endpoint | Method | Description | |----------|--------|-------------| -| `/api/ai/analyze` | `POST` | Analyze ticket with AI | -| `/api/ai/respond` | `POST` | Generate AI response | -| `/api/ai/costs` | `GET` | Get AI usage costs | +| `/health` | `GET` | Liveness/version (`{"status":"ok",...}`) | +| `/chat` | `POST` | `{user_id, message, session_id?, platform?}` → AI reply (degrades gracefully without LLM) | +| `/session/{id}` | `GET` | Rate-limit/session info for a session id | -### Analytics - -| Endpoint | Method | Description | -|----------|--------|-------------| -| `/api/analytics/overview` | `GET` | Dashboard overview | -| `/api/analytics/tickets` | `GET` | Ticket statistics | -| `/api/analytics/performance` | `GET` | Agent performance | - -### Example Usage +### Example ```bash -# Create a ticket -curl -X POST http://localhost:8080/api/tickets \ - -H "Content-Type: application/json" \ - -d '{"subject": "Login issue", "body": "Cannot login to my account", "source": "email"}' +# Health +curl http://localhost:8080/health -# Get AI analysis -curl -X POST http://localhost:8080/api/ai/analyze \ +# Chat +curl -X POST http://localhost:8080/chat \ -H "Content-Type: application/json" \ - -d '{"ticket_id": 123}' - -# Get cost summary -curl http://localhost:8080/api/ai/costs?period=30d + -d '{"user_id":"alice","message":"My password reset email never arrived"}' ``` --- -## 🛠️ Development +## 🧪 Testing -### Local Development +No automated test suite is included yet. A smoke check is the API health endpoint: ```bash -# Clone the repository -git clone https://github.com/OneByJorah/CommandDesk.git -cd CommandDesk - -# Backend setup -cd backend -python -m venv venv -source venv/bin/activate -pip install -r requirements.txt - -# Start development server -uvicorn main:app --reload --host 0.0.0.0 --port 8000 -``` - -### Running Tests - -```bash -pytest +curl -f http://localhost:8080/health # exits non-zero if the agent is down ``` --- ## 🤝 Contributing -Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines. +See [CONTRIBUTING.md](CONTRIBUTING.md). Issues and PRs welcome. --- ## 📄 License -This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. +MIT — see [LICENSE](LICENSE). --- ## 🔒 Security -For security concerns, please see [SECURITY.md](SECURITY.md). - ---- - -## 💬 Support - -- 📧 Email: support@jorah.one -- 🐛 Issues: [GitHub Issues](https://github.com/OneByJorah/CommandDesk/issues) -- 📖 Docs: [Documentation](docs/) +See [SECURITY.md](SECURITY.md). No secrets are committed; configure everything via `.env` (use `.env.example` as a template). ---
- **Built with ❤️ by [Jhonattan L. Jimenez](https://github.com/OneByJorah)** + **Built by [Jhonattan L. Jimenez](https://github.com/OneByJorah) under JorahOne LLC** - [⬆ Back to Top](#-commanddesk) + More projects: [github.com/OneByJorah](https://github.com/OneByJorah)
diff --git a/dashboard-mockup.png b/dashboard-mockup.png deleted file mode 100644 index 8ddbd69..0000000 Binary files a/dashboard-mockup.png and /dev/null differ diff --git a/dashboard-realistic.png b/dashboard-realistic.png deleted file mode 100644 index ccfbf56..0000000 Binary files a/dashboard-realistic.png and /dev/null differ diff --git a/docs/screenshots/admin-dashboard.png b/docs/screenshots/admin-dashboard.png new file mode 100644 index 0000000..8c38151 Binary files /dev/null and b/docs/screenshots/admin-dashboard.png differ diff --git a/docs/screenshots/ai-assistant.png b/docs/screenshots/ai-assistant.png deleted file mode 100644 index 4a397e6..0000000 Binary files a/docs/screenshots/ai-assistant.png and /dev/null differ diff --git a/docs/screenshots/api-health.png b/docs/screenshots/api-health.png new file mode 100644 index 0000000..40c2dde Binary files /dev/null and b/docs/screenshots/api-health.png differ diff --git a/docs/screenshots/chat-widget.png b/docs/screenshots/chat-widget.png new file mode 100644 index 0000000..b1d79dc Binary files /dev/null and b/docs/screenshots/chat-widget.png differ diff --git a/docs/screenshots/costs.png b/docs/screenshots/costs.png deleted file mode 100644 index a007e84..0000000 Binary files a/docs/screenshots/costs.png and /dev/null differ diff --git a/docs/screenshots/dashboard.png b/docs/screenshots/dashboard.png deleted file mode 100644 index a92f694..0000000 Binary files a/docs/screenshots/dashboard.png and /dev/null differ diff --git a/requirements.txt b/requirements.txt index b07d850..f3c039d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,9 +9,6 @@ psycopg2-binary==2.9.10 httpx==0.28.1 python-multipart==0.0.31 -# LLM / OpenAI-compatible client -openai==1.59.0 - # Knowledge base chromadb==0.5.23 diff --git a/scripts/capture-screenshots.py b/scripts/capture-screenshots.py deleted file mode 100755 index 48f3278..0000000 --- a/scripts/capture-screenshots.py +++ /dev/null @@ -1,419 +0,0 @@ -from playwright.sync_api import sync_playwright -import time -import os - -SCREENSHOT_DIR = "/home/j1coder/github-repos/CommandDesk/docs/screenshots" -os.makedirs(SCREENSHOT_DIR, exist_ok=True) - -# Dashboard mockup -DASHBOARD_HTML = r""" - - - - - - CommandDesk - AI Helpdesk Dashboard - - - - - -
-
-

Helpdesk Dashboard

-
-
🔔 3
-
+ New Ticket
-
-
-
-
-
Open Tickets
-
47
-
-
-
Resolved Today
-
128
-
-
-
Avg Response Time
-
4.2m
-
-
-
Escalated
-
5
-
-
-
-
Tickets by Category
-
-
Billing
-
Technical
-
Account
-
Feature
-
Bug
-
Other
-
-
-
-
Recent Tickets
-
    -
  • -
    Login issue after password reset
    Customer: John D. • 2m ago
    -
    Open
    -
  • -
  • -
    Billing discrepancy on invoice #4521
    Customer: Sarah M. • 15m ago
    -
    Pending
    -
  • -
  • -
    API rate limit exceeded
    Customer: TechCorp • 1h ago
    -
    Resolved
    -
  • -
-
-
- - -""" - -# AI Assistant mockup -AI_HTML = r""" - - - - - - CommandDesk - AI Assistant - - - - - -
-
-

🤖 AI Support Assistant

-
- ● Online - 1,847 conversations today -
-
-
-
-
👤
-
-
John D.
-
I'm having trouble logging in after resetting my password. I get an "Invalid credentials" error.
-
-
-
-
🤖
-
-
AI Assistant
-
I can help with that! Here are a few things to check:

1. Make sure you're using the new password (not the old one)
2. Check that Caps Lock is off
3. Try clearing your browser cache
4. Verify your account email matches

Would you like me to send a fresh reset link to your email?
-
- - - -
-
-
-
-
👤
-
-
John D.
-
Yes, please send a fresh reset link!
-
-
-
-
🤖
-
-
AI Assistant
-
Done! I've sent a fresh password reset link to john@example.com. The link will expire in 24 hours.

✅ Reset email sent successfully
📧 Recipient: john@example.com
⏰ Expires: July 19, 2026
-
-
-
-
-
🎫 Create ticket
-
📊 Check status
-
📞 Escalate
-
-
- - -
-
- - -""" - -# Costs/Costs mockup -COSTS_HTML = r""" - - - - - - CommandDesk - Cost Analytics - - - - - -
-
-

Cost Analytics

-
-
7D
-
30D
-
90D
-
1Y
-
-
-
-
-
Total Cost (30D)
-
$2,847
-
↓ 12% from last month
-
-
-
AI Resolution Cost
-
$1,234
-
↓ 23% savings vs human
-
-
-
Cost per Ticket
-
$3.42
-
↓ 18% improvement
-
-
-
-
Monthly Cost Breakdown: AI vs Human
-
-
-
-
-
Jan
-
-
-
-
-
Feb
-
-
-
-
-
Mar
-
-
-
-
-
Apr
-
-
-
-
-
May
-
-
-
-
-
Jun
-
-
-
-
AI Resolution
-
Human Agent
-
-
-
-
Cost by Category
-
-
- 💬 Chat Support - $892 -
-
- 📧 Email Support - $654 -
-
- 📞 Phone Support - $1,101 -
-
- 🤖 AI Auto-Resolve - $200 -
-
-
-
- - -""" - -def capture_screenshots(): - """Capture CommandDesk screenshots using HTML mockups. - - Note: These are representative mockups, not screenshots from the running application. - """ - os.makedirs(SCREENSHOT_DIR, exist_ok=True) - - with sync_playwright() as p: - browser = p.chromium.launch(headless=True) - page = browser.new_page(viewport={"width": 1920, "height": 1080}) - - # 1. Capture dashboard - print("Capturing dashboard...") - page.set_content(DASHBOARD_HTML) - page.wait_for_load_state("networkidle") - time.sleep(1) - page.screenshot(path=f"{SCREENSHOT_DIR}/dashboard.png", full_page=False) - size = os.path.getsize(f"{SCREENSHOT_DIR}/dashboard.png") - print(f" Saved: dashboard.png ({size:,} bytes)") - - # 2. Capture AI assistant - print("Capturing AI assistant...") - page.set_content(AI_HTML) - page.wait_for_load_state("networkidle") - time.sleep(1) - page.screenshot(path=f"{SCREENSHOT_DIR}/ai-assistant.png", full_page=False) - size = os.path.getsize(f"{SCREENSHOT_DIR}/ai-assistant.png") - print(f" Saved: ai-assistant.png ({size:,} bytes)") - - # 3. Capture costs - print("Capturing costs...") - page.set_content(COSTS_HTML) - page.wait_for_load_state("networkidle") - time.sleep(1) - page.screenshot(path=f"{SCREENSHOT_DIR}/costs.png", full_page=False) - size = os.path.getsize(f"{SCREENSHOT_DIR}/costs.png") - print(f" Saved: costs.png ({size:,} bytes)") - - browser.close() - - print(f"\nScreenshots saved to {SCREENSHOT_DIR}/") - -if __name__ == "__main__": - capture_screenshots() diff --git a/scripts/rate_limiter.py b/scripts/rate_limiter.py index 4525186..b2666ac 100644 --- a/scripts/rate_limiter.py +++ b/scripts/rate_limiter.py @@ -36,7 +36,7 @@ class RateLimiter: def __init__(self, config: RateLimitConfig, redis_client=None): self.config = config self.redis = redis_client - self._sessions: dict[str, SessionState] =() + self._sessions: dict[str, SessionState] = {} def check_request(self, session_id: str, user_id: str, message_length: int = 0) -> dict: """