Skip to content

Commit 90b5ebf

Browse files
Merge pull request #2 from dikshant182004/adaption
Adaption
2 parents 53d4a92 + ffc166d commit 90b5ebf

34 files changed

Lines changed: 3706 additions & 429 deletions

.env.example

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,9 @@
11
GROQ_API_KEY =gsk_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2+
GROQ_API_KEY_2=gsk_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX # for reserve llm
23
COHERE_API_KEY=CIyXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4+
TAVILY_API_KEY=tvly-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
5+
GOOGLE_CLIENT_ID=your-google-client-id.apps.googleusercontent.com
6+
GOOGLE_CLIENT_SECRET=GOCSPX-XXXXXXXXXXXXXXXXXXXXXXXXXXXX
7+
REDIS_URL=redis://:jee_secret@localhost:6379 # when running on docker
8+
OAUTH_REDIRECT_URI=http://localhost:8501/oauth2callback
9+
GOOGLE_APPLICATION_CREDENTIALS=./secrets/XXXXXXXXXXXXXXXXXXXXXX.json

.github/workflows/tests.yml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
name: Tests
2+
3+
on:
4+
push:
5+
branches: ["master"]
6+
pull_request:
7+
branches: ["master"]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
timeout-minutes: 15
13+
14+
steps:
15+
- name: Checkout code
16+
uses: actions/checkout@v4
17+
18+
- name: Install uv
19+
uses: astral-sh/setup-uv@v5
20+
with:
21+
enable-cache: true
22+
cache-dependency-glob: "requirements-test.txt"
23+
24+
- name: Setup Python
25+
run: uv python install 3.11
26+
27+
- name: Create virtual environment
28+
run: uv venv .venv
29+
30+
- name: Install test dependencies
31+
run: uv pip install -r requirements-test.txt --python .venv/bin/python
32+
33+
- name: Run Tests (pytest)
34+
run: .venv/bin/pytest

Readme.md

Lines changed: 837 additions & 162 deletions
Large diffs are not rendered by default.

docker-compose.yml

Lines changed: 44 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,41 +4,30 @@ version: "3.9"
44
# JEE Math Tutor — Docker Compose
55
#
66
# Services:
7-
# redis Redis Stack (Redis + RedisJSON + RediSearch) for STM + LTM
8-
# app — Streamlit frontend + backend (optional, see note below)
7+
# redis Redis Stack (Redis + RedisJSON + RediSearch) for memory
8+
# redisinsight → Full RedisInsight GUI (commented out by default)
99
#
10-
# Start everything: docker compose up -d
11-
# Start only Redis: docker compose up -d redis
12-
# View logs: docker compose logs -f
13-
# Stop everything: docker compose down
10+
# Quick Start:
11+
# docker compose up -d redis # Redis only
12+
# docker compose up -d redis redisinsight # Redis + RedisInsight UI
1413
#
15-
# NOTE: The Streamlit app service is commented out by default.
16-
# Run it locally with: bash entrypoint.sh
17-
# Uncomment the `app` service only if you want to containerise the whole stack.
14+
# Access:
15+
# Redis server : redis://default:jee_secret@localhost:6379
16+
# RedisInsight UI : http://localhost:5540 (when service is enabled)
1817
# ═══════════════════════════════════════════════════════════════════════════════
1918

2019
services:
2120

2221
# ── Redis Stack ──────────────────────────────────────────────────────────────
23-
# redis-stack bundles:
24-
# • Redis 7 — core key-value store (STM via RedisSaver checkpointer)
25-
# • RedisJSON — JSON.SET / JSON.GET used by all LTM operations
26-
# • RediSearch — vector index used by RedisVL episodic memory search
27-
#
28-
# RedisInsight UI is available at http://localhost:8001 (no auth by default).
29-
# Connect it to redis://default:jee_secret@redis:6379 inside the UI.
30-
# ─────────────────────────────────────────────────────────────────────────────
3122
redis:
3223
image: redis/redis-stack:latest
3324
container_name: jee_redis
3425
restart: unless-stopped
3526
ports:
36-
- "6379:6379" # Redis
37-
- "8001:8001" # RedisInsight UI
27+
- "6379:6379" # Redis server
3828
volumes:
3929
- redis_data:/data
4030
environment:
41-
# RedisInsight does not need a password to connect internally
4231
- REDIS_ARGS=--requirepass jee_secret
4332
command: >
4433
redis-stack-server
@@ -58,6 +47,41 @@ services:
5847
retries: 5
5948
start_period: 10s
6049

50+
# ── RedisInsight UI (Recommended full-featured GUI) ──────────────────────────
51+
# Uncomment the entire block below if you want to run RedisInsight as a service.
52+
# Access it at: http://localhost:5540
53+
#
54+
# redisinsight:
55+
# image: redis/redisinsight:latest
56+
# container_name: jee_redisinsight
57+
# restart: unless-stopped
58+
# ports:
59+
# - "5540:5540" # RedisInsight web UI
60+
# environment:
61+
# - RI_REDIS_HOST=redis
62+
# - RI_REDIS_PORT=6379
63+
# - RI_REDIS_PASSWORD=jee_secret
64+
# - RI_REDIS_USER=default
65+
# depends_on:
66+
# redis:
67+
# condition: service_healthy
68+
69+
# ── Streamlit App (Optional) ─────────────────────────────────────────────────
70+
# Recommended to run locally with ./entrypoint.sh instead of Docker.
71+
# app:
72+
# build: .
73+
# container_name: jee_math_tutor
74+
# restart: unless-stopped
75+
# ports:
76+
# - "8501:8501"
77+
# depends_on:
78+
# redis:
79+
# condition: service_healthy
80+
# volumes:
81+
# - .:/app
82+
# environment:
83+
# - PYTHONPATH=/app:/app/src
84+
6185
volumes:
6286
redis_data:
6387
driver: local

entrypoint.sh

Lines changed: 59 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,12 @@
55
# What this script does (in order):
66
# 1. Loads .env into the shell environment
77
# 2. Waits until Redis is reachable (up to 30 s)
8-
# 3. Starts the Manim MCP server in the background (optional, skipped if
9-
# SKIP_MANIM=1 is set or the venv doesn't have manim installed)
10-
# 4. Starts the Streamlit app in the foreground
8+
# 3. Starts the Streamlit app in the foreground
119
#
1210
# Usage:
1311
# chmod +x entrypoint.sh
1412
# ./entrypoint.sh
1513
#
16-
# Skip Manim:
17-
# SKIP_MANIM=1 ./entrypoint.sh
18-
#
1914
# Custom port:
2015
# STREAMLIT_PORT=8502 ./entrypoint.sh
2116
#
@@ -49,27 +44,38 @@ echo -e "${NC}"
4944

5045
# ── Step 1: load .env ─────────────────────────────────────────────────────────
5146
ENV_FILE="${ENV_FILE:-.env}"
47+
5248
if [ -f "$ENV_FILE" ]; then
5349
log "Loading environment from $ENV_FILE"
54-
# Export every non-comment, non-blank line
55-
set -o allexport
56-
# shellcheck disable=SC1090
57-
source "$ENV_FILE"
58-
set +o allexport
59-
ok "Environment loaded"
50+
51+
# Export each KEY=value line safely
52+
while IFS= read -r line || [[ -n "$line" ]]; do
53+
# Skip empty lines and comments
54+
[[ -z "$line" || "$line" =~ ^[[:space:]]*# ]] && continue
55+
56+
# Export the variable
57+
if [[ "$line" =~ ^[A-Za-z_][A-Za-z0-9_]*= ]]; then
58+
key="${line%%=*}"
59+
value="${line#*=}"
60+
export "$key=$value"
61+
# Show masked value for logging
62+
if [ ${#value} -gt 12 ]; then
63+
masked="${value:0:6}...${value: -4}"
64+
else
65+
masked="$value"
66+
fi
67+
log " Set: $key=${masked}"
68+
fi
69+
done < "$ENV_FILE"
70+
71+
ok "Environment variables loaded"
6072
else
61-
warn ".env not found at $ENV_FILE — relying on existing environment variables"
73+
warn ".env file not found at $ENV_FILE"
6274
fi
6375

6476
# ── Step 2: verify required variables ─────────────────────────────────────────
6577
REQUIRED_VARS=(
66-
GROQ_API_KEY
67-
COHERE_API_KEY
68-
TAVILY_API_KEY
6978
REDIS_URL
70-
GOOGLE_CLIENT_ID
71-
GOOGLE_CLIENT_SECRET
72-
OAUTH_REDIRECT_URI
7379
)
7480

7581
MISSING=0
@@ -91,11 +97,15 @@ if [ -z "${GOOGLE_CREDENTIALS_JSON:-}" ] && [ -z "${GOOGLE_APPLICATION_CREDENTIA
9197
warn "Image (OCR) input will not work."
9298
fi
9399

100+
# ── Optional: run tests only and exit ─────────────────────────────────────────
101+
if [ "${RUN_TESTS:-0}" = "1" ]; then
102+
log "RUN_TESTS=1 detected — running pytest and exiting"
103+
exec pytest
104+
fi
105+
94106
# ── Step 3: wait for Redis ────────────────────────────────────────────────────
95107
log "Waiting for Redis at ${REDIS_URL} ..."
96108

97-
# Extract host:port from REDIS_URL for redis-cli
98-
# Handles: redis://:pass@host:port and rediss://user:pass@host:port
99109
REDIS_HOST=$(echo "$REDIS_URL" | sed -E 's|rediss?://[^@]*@([^:]+):.*|\1|')
100110
REDIS_PORT=$(echo "$REDIS_URL" | sed -E 's|rediss?://[^@]*@[^:]+:([0-9]+).*|\1|')
101111
REDIS_PASS=$(echo "$REDIS_URL" | sed -E 's|rediss?://[^:]*:([^@]*)@.*|\1|')
@@ -117,62 +127,40 @@ done
117127
echo ""
118128
ok "Redis is up (${REDIS_HOST}:${REDIS_PORT})"
119129

120-
# ── Step 4: create required directories ──────────────────────────────────────
121-
mkdir -p uploads manim_outputs logs
122-
ok "Directories ready (uploads/, manim_outputs/, logs/)"
130+
# ── Step 3.5: Check RedisInsight UI (Optional & Non-blocking) ─────────────────
131+
log "Checking RedisInsight UI (optional)..."
123132

124-
# ── Step 5: start Manim MCP server (background) ───────────────────────────────
125-
MANIM_PID=""
133+
INSIGHT_AVAILABLE=false
126134

127-
if [ "${SKIP_MANIM:-0}" = "1" ]; then
128-
warn "SKIP_MANIM=1 — skipping Manim MCP server"
135+
# Check both common ports
136+
if curl -s -f http://localhost:5540 >/dev/null 2>&1; then
137+
INSIGHT_AVAILABLE=true
138+
ok "RedisInsight UI detected on port 5540 (recommended)"
139+
elif curl -s -f http://localhost:8001 >/dev/null 2>&1; then
140+
INSIGHT_AVAILABLE=true
141+
ok "RedisInsight UI detected on port 8001 (built-in)"
129142
else
130-
MANIM_SCRIPT="src/backend/agents/nodes/tools/mcp/manim_mcp_server.py"
131-
132-
if [ ! -f "$MANIM_SCRIPT" ]; then
133-
warn "Manim MCP script not found at $MANIM_SCRIPT — skipping"
134-
elif ! python -c "import manim" 2>/dev/null; then
135-
warn "manim not installed in current Python env — skipping Manim MCP"
136-
warn "Install with: pip install manim fastmcp"
137-
elif ! python -c "import fastmcp" 2>/dev/null; then
138-
warn "fastmcp not installed — skipping Manim MCP"
139-
warn "Install with: pip install fastmcp"
140-
else
141-
MANIM_PORT="${MANIM_SERVER_PORT:-8765}"
142-
log "Starting Manim MCP server on port $MANIM_PORT ..."
143-
MANIM_OUTPUT_DIR="${MANIM_OUTPUT_DIR:-./manim_outputs}" \
144-
MANIM_SERVER_PORT="$MANIM_PORT" \
145-
MANIM_MCP_SERVER_URL="${MANIM_MCP_SERVER_URL:-http://localhost:${MANIM_PORT}/mcp}" \
146-
python "$MANIM_SCRIPT" >> logs/manim_mcp.log 2>&1 &
147-
MANIM_PID=$!
148-
149-
# Give it 3 seconds to start
150-
sleep 3
151-
if kill -0 "$MANIM_PID" 2>/dev/null; then
152-
ok "Manim MCP server started (PID $MANIM_PID, port $MANIM_PORT)"
153-
ok "Logs: logs/manim_mcp.log"
154-
else
155-
warn "Manim MCP server exited immediately — check logs/manim_mcp.log"
156-
MANIM_PID=""
157-
fi
158-
fi
143+
warn "RedisInsight UI is not running (this is optional)"
144+
echo -e "${YELLOW} Tip: Start it with → docker compose up -d redisinsight${NC}"
145+
fi
146+
147+
if [ "$INSIGHT_AVAILABLE" = true ]; then
148+
echo -e "${GREEN} → Open RedisInsight at: http://localhost:5540${NC}"
159149
fi
160150

161-
# ── Step 6: trap for clean shutdown ───────────────────────────────────────────
151+
# ── Step 4: create required directories ──────────────────────────────────────
152+
mkdir -p uploads logs
153+
ok "Directories ready (uploads/, logs/)"
154+
155+
# ── Step 5: trap for clean shutdown ───────────────────────────────────────────
162156
cleanup() {
163157
echo ""
164158
log "Shutting down..."
165-
if [ -n "$MANIM_PID" ] && kill -0 "$MANIM_PID" 2>/dev/null; then
166-
log "Stopping Manim MCP server (PID $MANIM_PID)..."
167-
kill "$MANIM_PID"
168-
wait "$MANIM_PID" 2>/dev/null || true
169-
ok "Manim MCP server stopped"
170-
fi
171159
ok "Goodbye."
172160
}
173161
trap cleanup EXIT INT TERM
174162

175-
# ── Step 7: start Streamlit ───────────────────────────────────────────────────
163+
# ── Step 6: start Streamlit ───────────────────────────────────────────────────
176164
STREAMLIT_PORT="${STREAMLIT_PORT:-8501}"
177165
APP_PATH="${APP_PATH:-src/frontend/app.py}"
178166

@@ -188,13 +176,14 @@ if [ ! -f "$SECRETS_FILE" ]; then
188176
warn "Continuing anyway — st.secrets will fall back to environment variables."
189177
fi
190178

179+
export PYTHONPATH="$(pwd):$(pwd)/src:${PYTHONPATH:-}"
180+
191181
log "Starting Streamlit on http://localhost:${STREAMLIT_PORT} ..."
182+
192183
echo ""
193-
echo -e "${BOLD} App URL: ${GREEN}http://localhost:${STREAMLIT_PORT}${NC}"
194-
if [ -n "$MANIM_PID" ]; then
195-
echo -e "${BOLD} Manim MCP: ${GREEN}http://localhost:${MANIM_SERVER_PORT:-8765}/mcp${NC}"
196-
fi
197-
echo -e "${BOLD} Redis UI: ${GREEN}http://localhost:8001${NC} (if RedisInsight is running)"
184+
echo -e "${BOLD} App URL: ${GREEN}http://localhost:${STREAMLIT_PORT}${NC}"
185+
echo -e "${BOLD} Redis server: ${GREEN}${REDIS_URL}${NC}"
186+
echo -e "${BOLD} RedisInsight UI: ${GREEN}http://localhost:5540${NC} (if running)"
198187
echo ""
199188

200189
exec streamlit run "$APP_PATH" \
250 KB
Loading

pytest.ini

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,8 @@
11
[pytest]
2+
pythonpath = src
3+
testpaths = src/tests
4+
python_files = test_*.py
5+
addopts = -q
6+
markers =
7+
unit: Fast unit tests for isolated functions.
8+
integration: Multi-module flow and contract tests.

requirements-test.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
pytest # requirement file for ci workflow caching
2+
redis
3+
langchain-core
4+
pydantic
5+
pyyaml
6+
python-dotenv
7+
numpy
8+
tiktoken
9+
redisvl

requirements.txt

436 Bytes
Binary file not shown.

run.ps1

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
1+
## To start our streamlit app manually via powershell from the project root
2+
13
$env:PYTHONPATH = "$PSScriptRoot\src"
24
streamlit run "$PSScriptRoot\src\frontend\app.py"

0 commit comments

Comments
 (0)