Skip to content
All work

Case study. Next.js / GenAI.

MIA

10-persona educational AI assistant

Role
Solo: persona system, streaming chat, search tool-calling, auth, deployment
Status
Livev1.1.0August 2026
Context
2026, personal
AI personas
10
Languages (ES / EN)
2
Conversations kept per agent
10
File types parsed
5
MIA multimodal intelligent assistant interface

The problem

One generic chatbot can't serve a 9-year-old on the Peruvian primary curriculum, a student prepping for the UNI entrance exam, a small-business owner navigating SUNAT paperwork, and an engineer debugging SQL — the tone, language, and guardrails are different for each. And a frozen model can't answer 'what are the current requirements?' questions that Peruvian bureaucracy personas get asked constantly.

Architecture

  1. 1.Personas
    • 10 agents · 4 categories
    • Per-agent system prompt
    • ES / EN per persona
  2. 2.Input
    • Text · voice (Web Speech)
    • PDF · DOCX · XLSX · CSV
    • Server-side extraction
  3. 3.Chat runtime
    • OpenAI streaming
    • Function calling
    • Markdown render
  4. 4.Tools
    • Google Custom Search
    • Model decides when
  5. 5.Persistence
    • S3 conversations
    • Last 10 per agent
    • HTML export · TTS out
MIA — persona-routed streaming chat with on-demand searchSearch is a tool call, not a habit — the model invokes it only when a question needs current information.

How it is kept honest

Persona system prompts set tone, language and guardrails per audience. The model calls Google Custom Search through function calling only when it decides a question needs current information, so most turns cost nothing extra.

Guardrails
  • Public signup disabled; only admins create accounts, bootstrapped by a CLI script
  • Voice input language detection matched to the persona
  • File extraction happens server-side; five file types are parsed
Where it can still be wrong
  • A general model can still be wrong about exam dates or paperwork; the search tool exists for exactly those questions, and it is the model that decides to call it

What it does

MIA is a bilingual educational assistant with 10 specialized personas across four categories — Education (primary school, pre-university exam prep, English certification), Business (MYPE consulting, Peruvian bureaucracy), Programming (R, Python, SQL) and General (learning companion, evidence-based parenting). Each persona carries its own system prompt and language, and conversations stream in real time with markdown rendering.

  • Agent grid landing page grouped by category
  • Last 10 conversations per agent auto-saved to S3
  • Chat export as formatted HTML; installable PWA with full dark/light OKLCH theming

Rebuilt from R Shiny

v1.0.0 is a full migration of an earlier R Shiny chatbot — MIA v1, still live on shinyapps.io and listed below — onto Next.js 16 with React 19 and TypeScript: streaming-first, mobile-installable, and cheap to host on Vercel instead of a Shiny server.

Search when the model decides

The chat route exposes Google Custom Search via OpenAI function calling — the model chooses when a question needs current information (exam dates, government requirements) and when it doesn't, so most turns cost nothing extra and searches happen only on demand.

Voice and documents

  • Web Speech API voice input with Spanish/English detection matched to the persona
  • Per-message text-to-speech playback
  • File uploads with server-side extraction — PDF (pdf-parse), DOCX (mammoth), XLSX/CSV (xlsx), and images

Accounts done properly

  • Public signup disabled — only admins create accounts, bootstrapped by a CLI script
  • Role-based admin panel to add, edit and remove users
  • JWT (jose) with bcrypt and httpOnly cookies
  • All user and conversation state in S3 under a key prefix — no database
  • v1.1.0 (August 2026): language selection, upload and login fixes, a Vitest suite (23 tests) and GitHub Actions CI on every push

Stack

  • Next.js 16
  • React 19
  • TypeScript
  • OpenAI (streaming + function calling)
  • Google Custom Search
  • Web Speech API
  • AWS S3
  • JWT (jose)

Related work