PRODUCTION API

AI-Powered
Portfolio Assistant

Kenneth Andales' chatbot API. Streaming responses, live data grounded in real portfolio and GitHub data, session-aware conversations — two specialized modes.

SSE Streaming OpenRouter AI Session-Aware Tool-Grounded
terminal

$ curl -X POST /api/chat/portfolio \

-H "Content-Type: application/json" \

-d '{"message": "What are Kenneth'\''s top skills?"}'

# Response streams in real-time...

Kenneth's core expertise spans TypeScript and Node.js on the

backend, React on the frontend, PostgreSQL for data storage,

and Docker + Railway for cloud deployment...

Two Specialized Modes

Each mode runs its own persona, tool set, and strict scope enforcement.

Portfolio Mode

Skills, experience, projects, certs, services

portfolio
POST /api/chat/portfolio
  • skills_listSkills, categories, and proficiency levels
  • experience_listWork history, projects per company, skills used
  • services_listDevelopment services, offerings, and pricing
  • projects_portfolioPortfolio projects, demos, documentation links
  • certificates_listProfessional certifications and courses
  • public_profileContact links, bio, education, achievements
  • receive_email_to_developerForwards user inquiries to Kenneth via email
  • send_email_back_to_userSends an auto-reply back to the user
  • pushover_notificationPush alerts to Kenneth for out-of-scope queries
GitHub Mode

Repositories, commits, branches, contributions

github
POST /api/chat/github
  • public_repositories_listAll public repos, sorted by last update
  • get_repositoryDetailed info for a specific repository
  • get_repository_readmeFull README content for any repo
  • repository_activitiesLatest 2 activities per repository
  • contributed_repositoriesOpen-source projects Kenneth contributed to
  • forked_repositoriesList of forked repositories
  • repository_programming_languagesLanguage breakdown per repository
  • get_repository_commitsTop 10 latest commits in any repo
  • get_repository_branchesAll branches in a repository

Built for Production

Architecture decisions that matter when moving beyond a demo.

SSE Streaming

Responses arrive word-by-word via chunked plain text. No buffering — the first token lands immediately.

Session History

Full conversation context persists per browser session. PostgreSQL store in production, in-memory in development.

OpenRouter AI

Model-agnostic via OpenRouter. Swap any LLM by changing one environment variable — zero code changes needed.

Tool-Grounded

Every answer is backed by a live API call. Up to 4 tool-call rounds per response. No hallucinations about portfolio data.

Rate Limited

20 requests per 15 minutes per IP on the chat endpoint. Global cap of 100 req/15min with Helmet security headers.

Production-Ready

Pino structured logging, PostHog analytics, graceful shutdown, Docker image, and a database health check endpoint.

API Reference

One endpoint, two modes. Response is a plain-text stream — no JSON wrapper, no SSE framing.

Method Path
POST /api/chat/portfolio
POST /api/chat/github
GET /api/health

REQUEST BODY

{
  "message": "string" // 1–2000 chars
}

RESPONSE HEADERS

Content-Type: text/plain; charset=utf-8
Transfer-Encoding: chunked

// Raw text chunks, no data: prefix

EXAMPLE

curl -X POST http://localhost:5000/api/chat/portfolio \
  -H "Content-Type: application/json" \
  -d '{"message": "What are Kenneth'\''s top skills?"}' \
  --no-buffer

ERROR RESPONSES — application/json { message: string }

400 Validation error — message missing or outside 1–2000 char range
429 Rate limit exceeded — wait 15 minutes before retrying
500 Unexpected server error

Live Demo

Try the API directly — rate limited to 20 requests per 15 minutes. Conversation history persists within your browser session.

Response will stream here...
0/2000

Enter to send · Shift+Enter for newline