NeonClary Cursor commited on
Commit
fddd8f4
·
1 Parent(s): 7a97213

Switch LLM provider from Gemini to OpenAI GPT-5.4-mini

Browse files

The live app ran the Gemini provider with no fallback, so any key/quota
issue made chat silently fail with no response. Switch the orchestrator
and personas to OpenAI gpt-5.4-mini:

- bootstrap.py: add an explicit "openai" provider branch so the OpenAI
client is used as the primary LLM (not just a vLLM fallback).
- muscle_growth_config.yaml: llm.provider=openai, openai.model=gpt-5.4-mini.
- .env.example / README: document OPENAI_API_KEY as the primary secret;
keep GEMINI_API_KEY as an optional fallback.

Key is supplied via the OPENAI_API_KEY env var / HF Space secret and is
never committed. Verified locally end-to-end (signup + chat-stream) with
all personas returning responses.

Co-authored-by: Cursor <cursoragent@cursor.com>

README.md CHANGED
@@ -8,36 +8,102 @@ pinned: false
8
  app_port: 7860
9
  ---
10
 
11
- # MuscleGrowthAI
12
 
13
- An AI-powered bodybuilding advisor panel that helps gym-goers build personalized muscle-building plans. Get guidance on hypertrophy programming, nutrition, recovery, form, and progress tracking from five specialized fitness AI advisors. Built on Neon AI's Collaborative Conversational AI (CCAI) framework.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
  ## Hugging Face Spaces deployment
16
 
17
- This Space ships as a single Docker image built from the repository root [`Dockerfile`](Dockerfile). The container:
 
18
 
19
- 1. Builds the React frontend at image-build time with `REACT_APP_API_URL=""` so every `fetch` uses relative URLs.
20
- 2. Serves the bundled SPA from FastAPI at `/`, with the API on `/api/...`, `/auth/...`, etc., on the same `:7860` origin.
21
- 3. Persists user data in **SQLite via `aiosqlite`** at `${DATA_DIR}/` (default `/home/user/data` in the Docker image). Mount a Hugging Face Storage Bucket there to survive Space rebuilds.
 
 
 
 
 
22
 
23
  ### Required Space secrets
24
 
25
  | Secret | Purpose |
26
  |--------|---------|
27
- | `JWT_SECRET_KEY` | Signs auth tokens. Set to a long random string. |
28
- | `GEMINI_API_KEY` | Powers the default Gemini provider (`gemini-2.5-flash`). |
 
29
 
30
- ### Optional secrets
31
 
32
- | Secret | Purpose |
33
- |--------|---------|
34
- | `OPENAI_API_KEY` | Only if switching to the OpenAI provider. |
35
- | `VLLM_API_KEY` | Only if pointing at a Neon vLLM endpoint. |
36
 
37
- ## Advisors
 
38
 
39
- 1. **Hypertrophy Coach** — splits, sets/reps, programming
40
- 2. **Nutrition Strategist** — protein, macros, fueling
41
- 3. **Recovery Specialist** — rest, mobility, post-workout care
42
- 4. **Form & Safety Coach** — technique, breathing, injury prevention
43
- 5. **Program Planner** — scheduling, tracking, progression
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  app_port: 7860
9
  ---
10
 
11
+ # MuscleGrowthAI Panel
12
 
13
+ An AI personalized bodybuilding assistant built on Neon AI's Collaborative
14
+ Conversational AI (CCAI) framework. Ask about hypertrophy programming,
15
+ nutrition, recovery, form, and progress tracking and get diverse perspectives
16
+ from a panel of five fitness AI advisors.
17
+
18
+ This repository is a **complete, deployable application** — the CCAI
19
+ multi-advisor stack (FastAPI backend + React frontend) wired to the
20
+ MuscleGrowthAI configuration in [`muscle_growth_config.yaml`](muscle_growth_config.yaml)
21
+ and the personas in [`personas/fitness_advisors/`](personas/fitness_advisors).
22
+
23
+ ## Advisors
24
+
25
+ 1. **Hypertrophy Coach** — splits, sets/reps, muscle-group programming
26
+ 2. **Nutrition Strategist** — protein, macros, meal timing
27
+ 3. **Recovery Specialist** — rest, stretching, soreness management
28
+ 4. **Form & Safety Coach** — technique, breathing, injury prevention
29
+ 5. **Program Planner** — scheduling, tracking, progression
30
 
31
  ## Hugging Face Spaces deployment
32
 
33
+ This Space ships as a single Docker image built from the repository-root
34
+ [`Dockerfile`](Dockerfile). The container:
35
 
36
+ 1. Builds the React frontend (CRA) at image-build time with `REACT_APP_API_URL=""`
37
+ so every `fetch` issues a relative URL.
38
+ 2. Serves the bundled SPA from FastAPI at `/`, with the API on `/api/...`,
39
+ `/auth/...`, etc. — all on the same `:7860` origin.
40
+ 3. Persists user data (auth, profiles, chat sessions) in **SQLite via
41
+ `aiosqlite`** at `${DATA_DIR}/muscle_growth_panel.db`. Mount a Hugging Face
42
+ Storage Bucket at `/data` to make the database survive Space rebuilds.
43
+ There is **no MongoDB** and no third-party data plane.
44
 
45
  ### Required Space secrets
46
 
47
  | Secret | Purpose |
48
  |--------|---------|
49
+ | `JWT_SECRET_KEY` | Signs auth tokens. Set this to a long random string. |
50
+ | `OPENAI_API_KEY` | Powers the default OpenAI provider (`gpt-5.4-mini`). Get a key from Clary, or use your own OpenAI key. |
51
+ | `GEMINI_API_KEY` | Optional — only if you switch `llm.provider` back to `gemini` (`gemini-2.5-flash`). |
52
 
53
+ Set these under **Settings → Variables and secrets** on the Space.
54
 
55
+ ## Local deployment
 
 
 
56
 
57
+ **Do you need Docker?** No — Docker is optional. There are two supported paths,
58
+ and neither requires MongoDB (persistence is SQLite):
59
 
60
+ ### Option A — Docker (simplest, mirrors the Space exactly)
61
+
62
+ Requires **Docker Desktop** only.
63
+
64
+ ```bash
65
+ # From the repo root, create a .env with at least:
66
+ # JWT_SECRET_KEY=some-long-random-string
67
+ # OPENAI_API_KEY=your-openai-key
68
+ docker compose up --build
69
+ ```
70
+
71
+ Open <http://localhost:7860>. Override the host port with `MUSCLE_HOST_PORT` if
72
+ 7860 is taken.
73
+
74
+ ### Option B — Native (no Docker)
75
+
76
+ Requires **Python 3.12** and **Node.js 20+** (no Docker, no MongoDB).
77
+
78
+ **Backend** (terminal 1):
79
+
80
+ ```bash
81
+ cd multi_llm_chatbot_backend
82
+ python -m venv venv
83
+ # Windows: venv\Scripts\activate • macOS/Linux: source venv/bin/activate
84
+ pip install -r requirements.txt
85
+ cp .env.example .env # then edit JWT_SECRET_KEY + OPENAI_API_KEY
86
+ uvicorn app.main:app --reload --port 8000
87
+ ```
88
+
89
+ **Frontend** (terminal 2):
90
+
91
+ ```bash
92
+ cd phd-advisor-frontend
93
+ npm install
94
+ # point the SPA at the backend from step above:
95
+ # Windows PowerShell: $env:REACT_APP_API_URL="http://localhost:8000"; npm start
96
+ # macOS/Linux: REACT_APP_API_URL=http://localhost:8000 npm start
97
+ npm start
98
+ ```
99
+
100
+ Open <http://localhost:3000> — you should see **AI Personalized Bodybuilding
101
+ Plan** with the five fitness advisors.
102
+
103
+ ## Configuration
104
+
105
+ All branding, login fields, chat examples, orchestrator keywords, and LLM/RAG
106
+ settings live in [`muscle_growth_config.yaml`](muscle_growth_config.yaml). The
107
+ backend resolves `personas.personas_dir` relative to that file, so the advisor
108
+ YAMLs in `personas/fitness_advisors/` load automatically. Point the app at a
109
+ different config with the `CONFIG_PATH` environment variable.
multi_llm_chatbot_backend/.env.example CHANGED
@@ -1,16 +1,24 @@
1
- # Path to app config (use cybersecurity_config.yaml for this branch)
2
- CONFIG_PATH=../cybersecurity_config.yaml
3
 
4
- MONGODB_CONNECTION_STRING=mongodb://localhost:27017
5
- JWT_SECRET_KEY=change-me
6
 
7
- # From C:\Users\dream\.secrets\shared.env or set here:
8
- VLLM_API_KEY=
 
 
 
 
 
 
 
9
  OPENAI_API_KEY=
10
- GEMINI_API_KEY=
11
 
12
- # Include every frontend origin you use locally (React default is 3000)
13
- CORS_ORIGINS=http://localhost:3010,http://127.0.0.1:3010,http://localhost:3000,http://127.0.0.1:3000
 
14
 
15
- # Optional override; default is %USERPROFILE%\.secrets\shared.env
16
- # SHARED_ENV=C:\Users\dream\.secrets\shared.env
 
 
1
+ # Copy this file to `.env` (same directory) for a native, non-Docker local run.
2
+ # The backend auto-loads it on startup.
3
 
4
+ # Path to the app config, relative to this backend directory.
5
+ CONFIG_PATH=../muscle_growth_config.yaml
6
 
7
+ # Where the SQLite database + uploaded docs live. Any writable folder works;
8
+ # on a native run this replaces the container's /data mount.
9
+ DATA_DIR=./local_data
10
+
11
+ # Signs auth tokens — set to a long random string.
12
+ JWT_SECRET_KEY=change-me-to-a-long-random-string
13
+
14
+ # Default provider is OpenAI GPT-5.4-mini (see muscle_growth_config.yaml -> llm.provider).
15
+ # Set your OpenAI API key here (get one from Clary, or use your own).
16
  OPENAI_API_KEY=
 
17
 
18
+ # Optional alternatives:
19
+ # GEMINI_API_KEY= # only if you switch llm.provider back to "gemini"
20
+ VLLM_API_KEY=
21
 
22
+ # Frontend origins allowed to call this backend during native dev
23
+ # (CRA dev server defaults to port 3000).
24
+ CORS_ORIGINS=http://localhost:3000,http://127.0.0.1:3000
multi_llm_chatbot_backend/app/core/bootstrap.py CHANGED
@@ -18,7 +18,7 @@ from app.models.default_personas import get_default_personas
18
  settings = get_settings()
19
 
20
  current_provider = settings.llm.provider or "vllm"
21
- available_providers = ["ollama", "gemini", "vllm"]
22
 
23
 
24
  def _load_shared_env_var(name: str) -> str:
@@ -114,6 +114,11 @@ def _wrap_resilient(primary: ImprovedVllmClient, fallback: OpenAIFallbackClient,
114
  def create_llm_client(provider=None):
115
  if provider is None:
116
  provider = current_provider
 
 
 
 
 
117
  if provider == "gemini":
118
  return ImprovedGeminiClient(model_name=settings.llm.gemini.model)
119
  if provider == "vllm":
 
18
  settings = get_settings()
19
 
20
  current_provider = settings.llm.provider or "vllm"
21
+ available_providers = ["ollama", "gemini", "vllm", "openai"]
22
 
23
 
24
  def _load_shared_env_var(name: str) -> str:
 
114
  def create_llm_client(provider=None):
115
  if provider is None:
116
  provider = current_provider
117
+ if provider == "openai":
118
+ # Standalone OpenAI (GPT) client. OpenAIFallbackClient implements the same
119
+ # LLMClient interface as the Gemini client, so it works as the primary
120
+ # orchestrator/persona LLM, not just a vLLM fallback.
121
+ return _build_openai(settings.llm.openai.orchestrator_reasoning_effort)
122
  if provider == "gemini":
123
  return ImprovedGeminiClient(model_name=settings.llm.gemini.model)
124
  if provider == "vllm":
muscle_growth_config.yaml CHANGED
@@ -169,7 +169,7 @@ mongodb:
169
  database_name: "muscle_growth_advisor"
170
 
171
  llm:
172
- provider: "gemini"
173
  gemini:
174
  model: "gemini-2.5-flash"
175
  ollama:
@@ -182,8 +182,9 @@ llm:
182
  neon_persona_orchestrator: "vanilla"
183
  neon_persona_advisors: "vanilla"
184
  openai:
 
185
  api_key: ""
186
- model: "gpt-5.4"
187
  orchestrator_reasoning_effort: "low"
188
  persona_reasoning_effort: "none"
189
  resilient:
 
169
  database_name: "muscle_growth_advisor"
170
 
171
  llm:
172
+ provider: "openai"
173
  gemini:
174
  model: "gemini-2.5-flash"
175
  ollama:
 
182
  neon_persona_orchestrator: "vanilla"
183
  neon_persona_advisors: "vanilla"
184
  openai:
185
+ # Key comes from the OPENAI_API_KEY env var / HF Space secret (never committed).
186
  api_key: ""
187
+ model: "gpt-5.4-mini"
188
  orchestrator_reasoning_effort: "low"
189
  persona_reasoning_effort: "none"
190
  resilient: