Skip to content
fethiverseHire me

04RAG chat widgetClient work

AI Tutor

A chat assistant built for university course pages that answers students in Italian, and shows its sources.

Role
Lead developer, 90 of 95 commits
Built
February to July 2026
Type
Client work
Where
Deployed to University of Ferrara course pages (as of July 2026)

In short

AI Tutor is a retrieval-augmented chat widget built for the University of Ferrara's course pages, where it was deployed as of July 2026. Students ask in plain Italian; it finds passages in official course material and university pages, answers, and cites where each answer came from. A monthly job re-reads the university's sites so the answers stay current.

Students ask the same practical questions, and the answers are scattered across dozens of sites and PDFs.

A generic chatbot makes answers up; a static FAQ goes stale. The university needed answers grounded in its own pages, in Italian, that stay current as those pages change.

What it does

  • Answers with its sources

    Every answer is written from retrieved passages and rendered with citations to the pages they came from.

  • Knows which course you're on

    Each course's material is scoped to that course, and university-wide pages (fees, calls, services) are merged into every scope.

  • Keeps itself current

    A monthly job re-reads every active course's sitemap and the university site, pages and PDFs, and re-embeds only what changed.

  • Italian by design

    Prompt, interface and corpus are Italian only: a teaching choice that also shrinks the room for invented answers.

Lead developer

Built the retrieval pipeline, the backend and the monthly refresh job with its safety rules, and documented each architectural step as a decision record.

Two paths share one store: the question path, which serves students in real time, and the refresh path, which rebuilds the knowledge base once a month so the question path never has to scrape.

Two paths, one knowledge base

The answering path on top, the monthly refresh underneath.

Answeringvector searchembed the question, write theanswerreplace per site, atomicallysitemaps, pages, PDFschanged passages onlyquestionBackend APIRAG pipelineVector database: passages,sessions, coursesFirecrawlGeminiScrape-and-embed jobMonthly scheduleCourse scope plusuniversity-wide pagesStudent on a course pageChat widget
What each part does
Backend API
A Fastify and TypeScript backend with validated configuration and rate limiting.
RAG pipeline
Retrieval-augmented generation: find the right passages, then answer from them only.
Vector database: passages, sessions, courses
One managed database holds the passages with their vectors, the chat sessions and the course registry.
Firecrawl
Firecrawl turns pages and linked PDFs into clean Markdown.
Gemini
Google Gemini, for both the embeddings and the answers, so the vector space stays consistent.
Scrape-and-embed job
Re-reads the sites and updates the knowledge base; it reuses the backend's own image.
Monthly schedule
Once a month.
Course scope plus university-wide pages
The current course's material plus the university-wide pages.
Student on a course page
A student on one of the university's course pages.
Chat widget
A React chat widget embedded in the page.

One question, answered with sources

What happens between a student pressing enter and the answer appearing.

A question, in Italian1Message, session and course2Load the conversation so far3Embed the question4Question vector5Vector search in the course anduniversity scopes6Passages with their sources7Write the answer from these passagesonly8Answer in Italian9Save both messages10Answer and citations11The answer, with its sources12StudentChat widgetBackendVector databaseGemini
All 12 steps as text
What each part does
Student
The student.
Chat widget
The chat widget on the course page.
Backend
The backend.
Vector database
The managed database: passages, vectors and sessions.
Gemini
Google Gemini.

The monthly refresh, failure-safe

How the knowledge base stays current without ever losing what it had.

loop · Each active course, then the university sitealt · Scrape failed, or a wrong course addressScrapedMonthly trigger1Sitemap, pages and linked PDFs2Clean Markdown3Keep last month's copy, mark the runfailed4Split into passages, hash each one5Which hashes are already embedded?6Embed only the new passages7Save them, clear this site's orphans8Exit code: non-zero if any site failed9ScheduleRefresh jobFirecrawlGemini embeddingsVector database
All 9 steps as text
What each part does
Schedule
The monthly schedule.
Refresh job
The refresh job.
Firecrawl
Firecrawl, for pages and PDFs.
Gemini embeddings
Gemini embeddings.
Vector database
The managed database.

Decisions and trade-offs

  1. Three steps, each forced by a measured cost

    An in-memory index cost about 50 seconds of cold start and embedding quota on every start; persisted embeddings keyed by content hash turned that into a load, and retrieval then moved to the database's managed vector search. Each step is an architecture decision record.

  2. Failure can only keep things, never delete them

    A site that fails to scrape keeps its previous corpus; cleanup touches only sites that scraped successfully, and the job still exits with an error so the failure is seen.

  3. The wrong-address trap

    A mistyped course address returns the site's root links instead of an error. The job treats that as a failure, not as an empty course.

  4. One image, two jobs

    The refresh job reuses the backend's container image with a different command, so there is no second artifact to drift.

  5. One vendor for embeddings and answers

    Gemini for both keeps the embedding space aligned and the keys simple; vector dimensions are configurable so a model migration is not a breaking change.

Results

  • Monthlyself-refresh of its knowledge baseonly new or changed passages are embedded
  • 90/95commits are hislead developer
  • 4architecture decision records
  • 21test filesbackend and frontend

Stack

Backend
  • TypeScript
  • Node.js
  • Fastify
  • Zod
Retrieval
  • Managed vector search
  • Gemini embeddings
  • LangChain text splitters
  • Firecrawl
Frontend
  • React 19
  • Vite
  • Redux Toolkit
  • Tailwind CSS
Delivery
  • Docker
  • Vitest