Repository navigation
chore: runnable baseline (monorepo, seedable RAG, streaming fixes, tests, CI) - #5
Draft
Sal-Fakoya wants to merge 52 commits into
Draft
Sal-Fakoya wants to merge 52 commits into
Sal-Fakoya wants to merge 52 commits into
Conversation
Web Scraper - -Scrapes from https://catalog.utdallas.edu/2025/undergraduate/home -Uses DOM pattern matching to get requirements & example degree plan for all majors
new file: CHANGES.md new file: DATABASE_API_DOCS.md new file: IMPLEMENTATION_STATUS.md new file: IMPLEMENTATION_SUMMARY.md new file: QUICK_START.md new file: app/api/endpoints/dashboard.py new file: app/api/endpoints/documents.py new file: app/api/endpoints/pinecone.py new file: app/db/__init__.py new file: app/db/database.py new file: app/db/models.py new file: app/db/services.py modified: app/main.py new file: app/schemas/db_schemas.py new file: app/services/document_management.py new file: app/services/pinecone_service.py modified: requirements.txt
…to requirements.txt
…g, and web scraping
…ain service, and retriever
- Added `app/services/data_ingestion_service.py` for ChromaDB ingestion of university program data - Processes 116 program files into 1483 chunks with proper metadata and embeddings - Implements ingestion logging and retrieval test verification - Connected ChromaDB RAG pipeline to `asktemoc.db` with Ollama embeddings - Enhanced streaming API endpoint (`rag_endpoint.py`) with real-time streaming and async flow - Added `.env` file with Ollama, ChromaDB, and FastAPI configuration - Updated `.gitignore` to exclude `chroma_db/` persistence directory - Documented implementation details and changelog updates in `CHANGES.md` Includes: - Fixes for import paths (relative → absolute) - Improved retrieval and streaming reliability
This script verifies ChromaDB contents and data ingestion status by counting source files, checking document count, and testing retrieval functionality. It helps ensure the RAG system has properly ingested data and is operational.
* Add `/api/health` endpoint for basic backend liveness checks
* Return simple JSON `{ "status": "healthy" }` with HTTP 200
* Register health router in main FastAPI app
* Enable CORS middleware for local frontend (`http://localhost:3000`)
* Temporarily allow credentials, all headers, and all HTTP methods (need to restrict for prod)
* Add ChromaDB persist directory and collection name to `.env.example` * Update app `.env` to use consistent ChromaDB storage path * Read ChromaDB config from environment variables in ingestion service * Remove hardcoded ChromaDB paths from retriever service * Standardize ChromaDB setup across ingestion and retrieval layers
* Remove all Pinecone configuration from `.env` and `.env.example` * Delete Pinecone API endpoints, services, and schemas * Rename Pinecone-related fields to ChromaDB equivalents across models and services * Update embedding sync logic to reference `chroma_id` * Adjust dashboard and document APIs to reflect ChromaDB usage * Swap Pinecone router for Chroma router in main app * Clean up obsolete ChromaDB verification script `check_chromadb.py` now that pipeline is stable
* Add detailed migration entry to `CHANGES.md` (Pinecone → ChromaDB)
* Revise Quick Start, workflow examples, and troubleshooting steps for ChromaDB
* Replace all Pinecone references with ChromaDB in implementation docs
* Update service names (PineconeExportService → ChromaService)
* Update API routes (`/api/pinecone` → `/api/chroma`)
* Rename config variables to `CHROMA_PERSIST_DIRECTORY` and `CHROMA_COLLECTION_NAME`
* Update database schema examples (`pinecone_id` → `chroma_id`)
…nt flow * Add explicit system requirements (Python 3.13+, pip, Git, Ollama) * Include repository cloning step * Add virtual environment setup instructions * Clarify dependency installation process * Document Ollama installation and local model check * Improve FastAPI server startup instructions * Add link to Swagger UI (`/docs`) * Reorganize sections for clearer step-by-step onboarding
housing scraper
Made-with: Cursor
added openai support and put into docker container
The chat UI had several defects found while running the app end to end. - SSE parsing dropped any event whose `data:` line straddled a network chunk boundary, and decoded each chunk independently so multi-byte UTF-8 split at a boundary corrupted. A dropped `source` event permanently loses a citation link. Buffer the trailing partial line and use a streaming TextDecoder. - `npm run dev` could not reach any backend: the dev default pointed at localhost:8000, which no process in this repo serves. Default to the same-origin /api/proxy rewrite instead, which `next dev` also serves. - Assistant markdown rendered literally, so answers showed `**Communication**`. Add inline **bold**, *italic* and `code` rendering, composed with the existing citation pills. Underscore emphasis is unsupported on purpose so course codes and URLs stay literal. - A 5s health check timeout reported a healthy backend as down, since Cloud Run cold starts were measured over 20s. Raise it to 35s, drop the redundant pre-flight check before each send, and stop disabling the composer on a failed probe so a cold start can't lock the UI. - Use onKeyDown rather than the deprecated onKeyPress. - Bump Next.js to 15.5.26, clearing the critical App Router proxy-bypass advisory. The scraper turned footnote anchors into programs: `…/programs#footnote-1` has link text "1", producing an output directory named "1" holding the whole index page (visible as test_output/1, 2, 3). Skip footnote anchors, numeric link text and the index page itself, while keeping URL fragments so concentrations of the same degree stay distinct. Live discovery goes from 118 links to 115, keeping all 18 concentrations. Both READMEs were inaccurate. frontend/README.md was untouched create-next-app boilerplate; it now documents the proxy architecture, env vars, SSE format and deployment. backend/README.md described test_scraper.py as a single-page test when it scrapes every program, and omitted that `playwright install` must match the venv's Playwright version. Both now note that the chat API lives in the separate AskTemoc_Backend repository. Co-authored-by: Cursor <cursoragent@cursor.com>
…btree Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- scraper -> backend/scrapers/catalog (README updated for the new layout) - drop backend/app/services/data (byte-identical copy of data/catalog); housing scrape moves to data/housing - untrack backend/app/.env; root .gitignore replaces backend/.gitignore, whose t*.py and /test_* patterns hid test files Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
requirements.txt is now the pinned runtime set the Dockerfile installs. Playwright/Crawl4AI/docling/torch move to requirements-scrape.txt; pytest and httpx to requirements-dev.txt. Add .dockerignore so .env, chroma_db and SQLite files never enter the image. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
build_sources.py reuses the scraper's link discovery and folder naming, so seeded chunks can cite the real catalog page. 113/116 folders mapped; the three numeric folders are footnote artefacts with no page. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ices - app/core/config.py: typed Settings read from env and backend/.env; all os.getenv calls go through it; relative paths resolve against backend/ - retriever and chain are built on first use and cached, so importing the app never touches Chroma, OpenAI or Ollama - one embeddings factory for retrieval and ingestion; Ollama clients now honour OLLAMA_BASE_URL (langchain-ollama instead of deprecated community classes); warn when the collection was seeded with another model - CORS origins from CORS_ORIGINS Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- /api/chat uses chain.astream: sources as soon as retrieval finishes, then
token deltas instead of O(n^2) cumulative prefixes; final {type: done}
- GET /api/health answers without the trailing-slash redirect
- frontend appends text deltas and ignores unknown event types
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Seeds data/catalog into the collection the retriever reads, with the same splitter and embeddings, stable chunk ids, and catalog URLs as sources. Rebuilds the collection when the embedding provider/model changed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…failures A local Ollama runner crashed on 256-chunk batches; 64 completes the full catalog. Embedding errors (e.g. exhausted OpenAI quota) now exit with a hint instead of a traceback. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- get_current_user verifies HS256 tokens minted by the web app (required aud/iss/exp/iat/sub, small leeway); 401 on missing/invalid/expired tokens, 403 for emails outside ALLOWED_EMAIL_DOMAIN - users table (provider_sub, email unique) upserted on each request; portable SQLAlchemy types, so Postgres works by changing DATABASE_URL - AUTH_DISABLED dev escape hatch; config refuses to load it outside ENVIRONMENT=development, and requires BACKEND_JWT_SECRET (>=32 chars) outside development - health stays public; admin routers unchanged Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A startup refusal (e.g. AUTH_DISABLED outside development) printed the settings input, including the start of OPENAI_API_KEY, to the log. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Auth.js v5 (JWT sessions) with Microsoft Entra ID and/or Google, each enabled by its env vars; signIn allows only verified @ALLOWED_EMAIL_DOMAIN emails (ALLOWED_EMAILS extra addresses under next dev only); Entra must use a single-tenant issuer and the token's tid must match it - middleware sends signed-out visitors of /chat to /signin; sign-in on the landing page, name + sign-out in the navbar - /api/chat and /api/health route handlers check the session, mint a 5-minute HS256 token (jose) and stream the backend response through - api.ts always calls same-origin routes and redirects to sign-in on 401; NEXT_PUBLIC_API_BASE_URL and the /api/proxy rewrites are removed since they bypassed auth Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
38 offline tests: health with/without slash, duplicate-route guard, lazy services, 401 for missing/garbage/forged/expired/alg-none/wrong aud-iss tokens, 403 for other domains, well-formed SSE deltas + done with a fake chain, user upsert, AUTH_DISABLED guard, secret hiding, seed metadata and stable chunk ids. Settings are pinned so a local backend/.env never leaks in. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…Ollama Chroma and SQLite live in a named volume, data/ is mounted read-only for seeding, and host Ollama is reachable via host.docker.internal; an ollama service is available under the 'ollama' profile. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
scripts/dev.sh and scripts/dev.ps1 share one task list; the Makefile delegates to dev.sh. Shell scripts are pinned to LF endings. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The deployed API (AskTemoc_Backend 'speedrun' branch) sends text events with a delta plus a cumulative message. Prefer delta when present so the web app renders correctly whichever API it is paired with during rollout. Also pin the Makefile to LF endings. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- README: what Ask Temoc is, architecture, quickstart matching the definition of done, Docker and AUTH_DISABLED usage, SSE contract, deployment env vars for Vercel and Cloud Run - docs/AUTH_SETUP.md: Entra app registration (UTD tenant issuer, OIT consent), Google OAuth client, secret generation, troubleshooting - docs/KNOWN_ISSUES.md: everything deliberately left for the 10-week plan - backend/frontend READMEs rewritten for the monorepo layout Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This reverts commit 4f9c7fd. Sign-in moves out of the baseline: auth is a teammate's assignment in the 10-week plan (Weeks 2-4). The work is kept on reference/auth-oauth. Restores the /api/proxy rewrites, NEXT_PUBLIC_API_BASE_URL and the placeholder 401/403 branch in api.ts. The delta-event support added later (34e2019) is kept. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…users" This reverts commit 23a0f07. Removes get_current_user, PyJWT, the users table, AUTH_DISABLED and the auth settings; /api/chat is unauthenticated again, as before the baseline. The work is kept on reference/auth-oauth. The validation-error secret hiding from f6c4036 is kept. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With sign-in removed, the /api/proxy rewrites are back, but their default origin was Cloud Run, so 'npm run dev' sent local chat to production. Default to http://localhost:8000; production builds still take the Cloud Run origin from .env.production and vercel.json. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Chat tests call /api/chat without a token; user/upsert and AUTH_DISABLED tests go with the feature (kept on reference/auth-oauth). The secret-hiding test now triggers a validation error on OPENAI_API_KEY itself. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- README quickstart no longer needs secrets or an OAuth app: pick a model provider, seed, run; chat API and deployment notes without auth - KNOWN_ISSUES: no sign-in (planned for Weeks 2-4; earlier implementation on reference/auth-oauth), UTD email is Microsoft 365 so utdallas.edu- restricted Google OAuth won't work for most students, open admin routes, placeholder 401/403 handling - remove docs/AUTH_SETUP.md (kept on reference/auth-oauth) - frontend/backend READMEs match the proxy setup Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Makes AskTemoc runnable from one repo. A teammate clones it, picks a model provider (OpenAI or a local Ollama), seeds the vector store with one command, starts the API and the web app, and gets a streamed answer with sources at http://localhost:3000. No sign-in is needed. This is not the 10-week plan; anything left for that plan is listed in
docs/KNOWN_ISSUES.md.What was tested
dev.ps1 setup, thenseed(193 docs, 2047 chunks), thenapiandweb./chatloads with no sign-in.POST /api/proxy/chat(the path the browser uses) streams 4 sources, the answer anddonefrom the local API on Ollama.GET /api/healthworks with and without the trailing slash.pytestpasses 13 offline tests;npm run lintandnpm run buildpass. CI runs the same checks.docker compose up apicomes up healthy, and seeding and chat work in the container.llama3.1:8b, the BS CS question retrieves the right program page but its "Goals" and "Objectives" chunks rather than the course list, so the answer is weak. That's retrieval work for the 10-week plan.What changed
backend/is AskTemoc_Backendmain, added withgit subtreeand its full history.backend/scrapers/catalog/and the scraped programs todata/catalog/. The backend had its own byte-identical copy of the catalog, which is removed; its housing pages moved todata/housing/and aren't seeded.backend/app/.envis untracked.requirements.txtis now UTF-8 and holds only the pinned runtime set. Scraping packages are inrequirements-scrape.txtand test tools inrequirements-dev.txt.app/core/config.py(pydantic-settings), and validation errors never echo setting values such as API keys./api/healthanswers with or without the trailing slash./api/chatstreams answer pieces withastreaminstead of cumulative prefixes, then a finaldoneevent. The frontend appends the pieces, also accepts the olderdeltaevent shape, and ignores unknown types.CORS_ORIGINS.backend/scripts/seed_catalog.pycan be re-run safely and cites real catalog URLs fromdata/catalog/sources.json, which was generated once with the scraper's own link discovery./api/proxy/*rewrites andNEXT_PUBLIC_API_BASE_URLare unchanged from before, except thatnext devnow proxies tohttp://localhost:8000by default. Production builds still use Cloud Run from.env.productionandvercel.json.docker-compose.yml(with optional Ollama),scripts/dev.sh/scripts/dev.ps1plus a Makefile, the backend pytest suite, and.github/workflows/ci.yml.README.mdanddocs/KNOWN_ISSUES.md.Auth work
Sign-in isn't part of the baseline; it's a teammate's assignment in Weeks 2-4 of the 10-week plan. An implementation was built here and then removed with
git revert:@utdallas.edu.userstable and anAUTH_DISABLEDdev escape hatch.It's preserved on
reference/auth-oauth(at4a162a7), which also has its tests anddocs/AUTH_SETUP.md.4f9c7fdfeat(web): UTD sign-in with Auth.js and authenticated API proxy7216e1823a0f07feat(api): require signed bearer token on /api/chat, persist users9a22e04To restore it, revert the reverts (newest first):
The API half reapplies cleanly. The web half stops with conflicts in
frontend/next.config.ts,frontend/src/lib/api.tsandfrontend/.env.example(checked with a dry run), because they changed after the reverts; resolve them, then rungit revert --continue. The auth tests anddocs/AUTH_SETUP.mdwere removed in separate commits; bring them back with:Merging
reference/auth-oauthwill NOT bring auth back. Its commits are already in this branch's history, so git considers them merged and the reverts win.Before merging
Before the next Cloud Run deploy
speedrunbranch (12 commits ahead ofmain: a[n, "verbatim"]citation prompt, lower temperature, anddeltaplus cumulativemessageevents), notmain, which is what this PR imports.speedrun, port its citation prompt and streaming changes in a follow-up PR first. Otherwise the next deploy silently drops the citation links in answers. The frontend already accepts both streaming formats.What still has to be done by hand
OPENAI_API_KEYset.davis118/AskTemoc_Backend, or point its README here, after this merges.Deployment notes
Vercel (frontend): no new variables.
ASKTEMOC_API_ORIGINis committed invercel.jsonand.env.production. Until app-level sign-in exists, keep Vercel Deployment Protection on.Cloud Run (API)
ENVIRONMENTproductionOPENAI_API_KEYCORS_ORIGINShttps://<vercel domain>DATABASE_URLCHROMA_PERSIST_DIRECTORYpython scripts/seed_catalog.pyThe API has no authentication, so anyone with its URL can call it. See
docs/KNOWN_ISSUES.md.🤖 Generated with Claude Code