DasilvaKareem/my-website

Personal website built with Next.js, TypeScript, and Tailwind CSS

0

stars

39

commits

TypeScript

primary language

Jan 26, 2026

updated

README

Touristy - AI-Powered San Francisco Tour Guide

An AI-powered San Francisco tour guide and itinerary planning platform built with a fully local AI stack using NVIDIA Nemotron models, RAG (Retrieval Augmented Generation), and real-time voice processing.

Live Site: https://touristy.urbantech.dev


Built With Local AI - 100% Offline Development

This entire application was coded and developed using OpenCode with Ollama running NVIDIA Nemotron 30B locally. No cloud AI APIs were used during development - the entire codebase was generated, debugged, and refined using a fully local AI coding assistant.

Development Stack

ToolPurpose
OpenCodeAI-powered coding assistant (local)
OllamaLocal LLM inference runtime
NVIDIA Nemotron 30BLarge language model for code generation
Claude CodeAdditional AI pair programming

Why Local AI Development?

  • Privacy - All code and prompts stay on your machine
  • No API Costs - Zero cloud API expenses
  • Offline Capable - Develop anywhere without internet
  • Full Control - No rate limits, no data sharing
  • Fast Iteration - Low latency local inference

OpenCode + Ollama Setup Used

# Install Ollama
curl -fsSL https://ollama.com/install.sh | sh

# Pull Nemotron 30B for code generation
ollama pull nemotron:30b
# or the smaller variant
ollama pull nemotron-3-nano-64k

# OpenCode automatically connects to local Ollama
# Configure in ~/.config/opencode/config.yaml:
#   provider: ollama
#   model: nemotron:30b
#   endpoint: http://localhost:11434

Code Generation Capabilities

The Nemotron 30B model excels at:

  • Full-stack TypeScript/React development
  • Python backend services and AI pipelines
  • Database schema design (Prisma)
  • API route implementation
  • Component architecture
  • Bug fixing and refactoring
  • Documentation generation

Table of Contents


Features

  • Interactive Map Exploration - Leaflet-based map with POI markers, searchable locations, and event visualization
  • AI Chat Assistant - Conversational AI using LangGraph agent with tool access powered by local Nemotron models
  • Walking Tour Generator - AI-generated detailed walking tour narratives with images and text-to-speech narration
  • Voice Interaction - Real-time speech-to-text and text-to-speech for hands-free exploration via WebSocket pipeline
  • Event Discovery - Browse and filter local San Francisco events by category, date, and price
  • Itinerary Management - Create, save, edit, and share custom itineraries with GeoJSON routes
  • Social Features - Follow users, like/review/comment on itineraries and POIs
  • RAG-Powered Recommendations - Vector similarity search over 1K+ SF landmarks for contextual recommendations

Architecture Overview

Touristy is built as a microservices architecture with all AI inference running locally:

┌─────────────────────────────────────────────────────────────────────────┐
│                           CLIENT (Browser)                              │
│  ┌─────────────┐  ┌──────────────┐  ┌─────────────────────────────────┐ │
│  │ React 19    │  │ Leaflet Maps │  │ WebSocket Audio (VoiceMicrophone)│ │
│  │ Next.js 16  │  │ react-leaflet│  │ Web Audio API                    │ │
│  └─────────────┘  └──────────────┘  └─────────────────────────────────┘ │
└───────────────────────────────┬─────────────────────────────────────────┘
                                │
                                ▼
┌─────────────────────────────────────────────────────────────────────────┐
│                         NEXT.JS API ROUTES (Port 3000)                   │
│  ┌─────────────┐  ┌──────────────┐  ┌─────────────┐  ┌───────────────┐  │
│  │ /api/chat   │  │ /api/walking │  │ /api/events │  │ /api/itinerary│  │
│  │ LangGraph   │  │ -tour/generate│  │ CRUD + Scrape│  │ CRUD + Social │  │
│  └─────────────┘  └──────────────┘  └─────────────┘  └───────────────┘  │
└───────────────────────────────┬─────────────────────────────────────────┘
                                │
        ┌───────────────────────┼───────────────────────┐
        ▼                       ▼                       ▼
┌───────────────┐    ┌──────────────────┐    ┌──────────────────┐
│  FASTAPI      │    │  FASTAPI STS     │    │   POSTGRESQL     │
│  RAG AGENT    │    │  Voice Pipeline  │    │   + PRISMA ORM   │
│  (Port 8001)  │    │  (Port 8000)     │    │   (Port 5432)    │
│               │    │                  │    │                  │
│ ┌───────────┐ │    │ ┌──────────────┐ │    │ ┌──────────────┐ │
│ │ FAISS     │ │    │ │ Whisper STT  │ │    │ │ 20+ Models   │ │
│ │ VectorDB  │ │    │ │ VITS TTS     │ │    │ │ Users, POIs, │ │
│ │           │ │    │ │ WebSocket    │ │    │ │ Itineraries  │ │
│ └───────────┘ │    │ └──────────────┘ │    │ └──────────────┘ │
└───────┬───────┘    └────────┬─────────┘    └──────────────────┘
        │                     │
        └──────────┬──────────┘
                   ▼
        ┌──────────────────────┐
        │   OLLAMA LOCAL LLM   │
        │     (Port 11434)     │
        │                      │
        │ ┌──────────────────┐ │
        │ │ nemotron-3-nano  │ │
        │ │     -64k         │ │
        │ │ NVIDIA Nemotron  │ │
        │ │ 3B Parameters    │ │
        │ └──────────────────┘ │
        └──────────────────────┘

Technology Stack

Frontend

TechnologyVersionPurpose
Next.js16.1.4React meta-framework with App Router
React19.2.3UI library with JSX
TypeScript5.xType-safe JavaScript
Tailwind CSS4.xUtility-first CSS framework
Leaflet1.9.4Interactive mapping library
react-leaflet5.0.0React wrapper for Leaflet
react-markdown10.1.0Markdown rendering
SuperTokens Auth React0.51.1Frontend authentication
supertokens-web-js0.16.0Web SDK for authentication

Backend

TechnologyVersionPurpose
Next.js API Routes16.1.4Serverless backend functions (42+ routes)
Prisma ORM5.22.0Database ORM with type-safe queries
PostgreSQLLatestPrimary relational database
SuperTokens Node24.0.0Backend session management
bcryptjs3.0.3Password hashing
FastAPILatestPython async web framework
uvicornLatestASGI server

Python AI/ML Services

TechnologyPurpose
OllamaLocal LLM runtime/inference engine
LangChainLLM orchestration framework
langchain-communityCommunity integrations
langchain-coreCore abstractions
langchain_huggingfaceHuggingFace embeddings
FAISSFacebook AI Similarity Search (Vector DB)
PyTorchDeep learning framework
transformersHuggingFace Transformers
sentence-transformersSentence embeddings for RAG
DSPyDeclarative Self-Improving prompts
accelerateDistributed inference utilities

AI/ML Technologies

NVIDIA Nemotron Models (Local via Ollama)

The application uses NVIDIA Nemotron 3 Nano models running entirely locally through Ollama:

# Primary model for tour generation and content
Model: nemotron-3-nano-64k:latest
Context Window: 64,000 tokens
Parameters: ~3B
Runtime: Ollama (http://localhost:11434)

# Model capabilities:
- Walking tour narrative generation
- Conversational AI responses
- POI description generation
- Itinerary planning
- Natural language understanding

Why Nemotron?

  • Fully local - No API calls, no data leaves your machine
  • 64K context window - Can process entire tour histories
  • Optimized for NVIDIA GPUs - Efficient inference on consumer hardware
  • Open weights - Full control over the model

NVIDIA NeMo Toolkit Integration

The codebase supports the NVIDIA NeMo Toolkit for advanced model capabilities:

# Available in requirements
nemo-toolkit[all]

# Provides:
- Advanced speech recognition models
- Neural text-to-speech
- Speaker diarization
- Language models

Ollama Configuration

# Start Ollama service
ollama serve

# Pull the Nemotron model
ollama pull nemotron-3-nano-64k

# Verify model
ollama list

LangGraph Agent

The AI chat assistant uses LangGraph for tool-augmented conversations:

# Agent Tools Available:
- POI search and recommendations
- Restaurant finder
- Neighborhood guide
- Route planning (walking, cycling, transit)
- Event discovery
- Weather information
- Distance calculations

RAG System

Overview

The RAG (Retrieval Augmented Generation) system provides contextual recommendations by searching a vector database of 1,000+ San Francisco landmarks.

Components

┌─────────────────────────────────────────────────────────────┐
│                    RAG PIPELINE                              │
│                                                              │
│  User Query                                                  │
│      │                                                       │
│      ▼                                                       │
│  ┌──────────────────────────────────────────────────────┐   │
│  │           QUERY EMBEDDING                             │   │
│  │  HuggingFace Sentence Transformers                    │   │
│  │  Model: all-MiniLM-L6-v2 (or similar)                │   │
│  │  Dimensions: 384                                      │   │
│  └──────────────────────────────────────────────────────┘   │
│      │                                                       │
│      ▼                                                       │
│  ┌──────────────────────────────────────────────────────┐   │
│  │           FAISS VECTOR SEARCH                         │   │
│  │  Index: /agent/vectorstore/index.faiss               │   │
│  │  Metadata: /agent/vectorstore/index.pkl              │   │
│  │  Algorithm: Approximate Nearest Neighbors             │   │
│  │  Top-K: 5-10 relevant documents                      │   │
│  └──────────────────────────────────────────────────────┘   │
│      │                                                       │
│      ▼                                                       │
│  ┌──────────────────────────────────────────────────────┐   │
│  │           CONTEXT AUGMENTATION                        │   │
│  │  Retrieved POIs + User Query → Prompt                │   │
│  └──────────────────────────────────────────────────────┘   │
│      │                                                       │
│      ▼                                                       │
│  ┌──────────────────────────────────────────────────────┐   │
│  │           NEMOTRON GENERATION                         │   │
│  │  Model: nemotron-3-nano-64k                          │   │
│  │  Context: Query + Retrieved Documents                │   │
│  │  Output: Contextual recommendations                   │   │
│  └──────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────┘

Vector Store

# Location: /agent/vectorstore/
# Files:
#   - index.faiss    (Vector embeddings)
#   - index.pkl      (Document metadata)

# Embedding Model
from langchain_huggingface import HuggingFaceEmbeddings
embeddings = HuggingFaceEmbeddings()

# Vector Store Loading
from langchain.vectorstores import FAISS
vectorstore = FAISS.load_local("vectorstore", embeddings)

# Similarity Search
docs = vectorstore.similarity_search(query, k=5)

RAG Agent Components

FilePurpose
agent/rag_agent.pyMain RAG agent with vector search
agent/location_extractor.pyConstrained entity extraction (prevents hallucination)
agent/location_service.pyUnified POI lookup from Prisma database
agent/restaurant_service.pyPOI-based restaurant recommendations
agent/neighborhood_guide.pyCurated SF neighborhood data
agent/routing.pyTurn-by-turn navigation via ORS/OSRM

Constrained Extraction

To prevent LLM hallucinations, the system uses constrained extraction:

# location_extractor.py
# Only returns POIs that exist in the database
# Normalizes queries for fuzzy matching
# Falls back to vector search for unknown queries

Voice Processing Pipeline

Architecture

┌─────────────────────────────────────────────────────────────────────┐
│                  REAL-TIME VOICE PIPELINE                            │
│                                                                      │
│  Browser (VoiceMicrophone.tsx)                                       │
│      │                                                               │
│      │ WebSocket: wss://touristyvoice.urbantech.dev                 │
│      │            (or ws://localhost:8000)                          │
│      ▼                                                               │
│  ┌─────────────────────────────────────────────────────────────────┐│
│  │              FASTAPI STS SERVICE (Port 8000)                     ││
│  │                                                                  ││
│  │  ┌──────────────────────────────────────────────────────────┐   ││
│  │  │  1. SPEECH-TO-TEXT (STT)                                  │   ││
│  │  │     Model: openai/whisper-small                           │   ││
│  │  │     Library: transformers (WhisperForConditionalGeneration)│   ││
│  │  │     Input: Raw audio bytes                                 │   ││
│  │  │     Output: Transcribed text                               │   ││
│  │  └──────────────────────────────────────────────────────────┘   ││
│  │                           │                                      ││
│  │                           ▼                                      ││
│  │  ┌──────────────────────────────────────────────────────────┐   ││
│  │  │  2. RAG AGENT API CALL                                    │   ││
│  │  │     Endpoint: http://localhost:8001/api/chat              │   ││
│  │  │     Payload: { "message": transcribed_text }              │   ││
│  │  │     Response: AI-generated tour guide response            │   ││
│  │  └──────────────────────────────────────────────────────────┘   ││
│  │                           │                                      ││
│  │                           ▼                                      ││
│  │  ┌──────────────────────────────────────────────────────────┐   ││
│  │  │  3. TEXT-TO-SPEECH (TTS)                                  │   ││
│  │  │     Model: Baghdad99/english_voice_tts                    │   ││
│  │  │     Library: transformers (VitsModel)                     │   ││
│  │  │     Input: Agent response text                            │   ││
│  │  │     Output: WAV audio stream                              │   ││
│  │  └──────────────────────────────────────────────────────────┘   ││
│  │                           │                                      ││
│  └───────────────────────────┼──────────────────────────────────────┘│
│                              ▼                                       │
│      WebSocket Audio Stream → Browser AudioContext → Speaker         │
└─────────────────────────────────────────────────────────────────────┘

Speech-to-Text (STT)

# Model: OpenAI Whisper Small
# Library: HuggingFace Transformers

from transformers import WhisperProcessor, WhisperForConditionalGeneration

model_name = "openai/whisper-small"
processor = WhisperProcessor.from_pretrained(model_name)
model = WhisperForConditionalGeneration.from_pretrained(model_name)

# Features:
# - Multi-language support
# - Real-time streaming
# - Voice Activity Detection (webrtcvad)

Text-to-Speech (TTS)

# Model: Baghdad99/english_voice_tts
# Library: HuggingFace Transformers (VITS)

from transformers import VitsModel, VitsTokenizer

model_name = "Baghdad99/english_voice_tts"
tokenizer = VitsTokenizer.from_pretrained(model_name)
model = VitsModel.from_pretrained(model_name)

# Features:
# - Natural sounding English voice
# - 16kHz WAV output
# - Real-time streaming via WebSocket

Audio Processing Libraries

LibraryPurpose
librosaAudio analysis and feature extraction
soundfileWAV file I/O
pyaudioAudio input/output
webrtcvad-wheelsVoice Activity Detection
scipySignal processing
numpyNumerical operations

Prompt Optimization (DSPy)

Overview

The system uses DSPy for declarative, self-improving prompts:

# DSPy Configuration
import dspy

# Define structured signatures
class TourGuideSignature(dspy.Signature):
    """Generate helpful tour guide responses"""
    query: str = dspy.InputField()
    context: str = dspy.InputField()
    response: str = dspy.OutputField()

# Create predictor
predictor = dspy.Predict(TourGuideSignature)

Batch Evaluation System

# batch_evaluator.py
# Automated prompt optimization pipeline:

# 1. Fetch recent conversations from PostgreSQL
# 2. Sample 10% for evaluation
# 3. Calculate GEPA (Graph-based Efficiency-Preserving Automated) scores
# 4. Compare against baseline
# 5. Auto-update prompts when 5%+ improvement detected
# 6. Track prompt versions in database

Evaluation Metrics

MetricDescription
GEPA ScoreGraph-based efficiency metric for prompt quality
Response RelevanceHow well the response matches the query
Factual AccuracyGrounding in retrieved documents
User SatisfactionImplicit feedback from conversation flow

Database Schema

PostgreSQL + Prisma ORM

// Core Models

model User {
  id            String   @id @default(uuid())
  email         String   @unique
  passwordHash  String
  createdAt     DateTime @default(now())
  superTokensId String?  @unique
  // Relations
  savedRoutes   SavedRoute[]
  trips         Trip[]
  following     Follow[] @relation("follower")
  followers     Follow[] @relation("following")
}

model POI {
  id          String   @id @default(uuid())
  name        String
  description String?
  latitude    Float
  longitude   Float
  address     String?
  rating      Float?
  priceLevel  Int?
  categoryId  String?
  // Relations
  category    Category?
  routeStops  RouteStop[]
  likes       POILike[]
  comments    POIComment[]
}

model Category {
  id    String @id @default(uuid())
  name  String @unique
  icon  String?
  color String?
  pois  POI[]
}

model Route {
  id          String      @id @default(uuid())
  name        String
  description String?
  geojson     Json?
  createdAt   DateTime    @default(now())
  stops       RouteStop[]
}

model Event {
  id          String   @id @default(uuid())
  title       String
  description String?
  startTime   DateTime
  endTime     DateTime?
  venue       String?
  latitude    Float?
  longitude   Float?
  price       Float?
  category    String?
  sourceUrl   String?
  imageUrl    String?
}

model Message {
  id             String   @id @default(uuid())
  conversationId String
  role           String
  content        String
  gepaScore      Float?   // For prompt optimization
  createdAt      DateTime @default(now())
}

model PromptVersion {
  id        String   @id @default(uuid())
  name      String
  content   String
  version   Int
  score     Float?
  isActive  Boolean  @default(false)
  createdAt DateTime @default(now())
}

API Reference

Authentication

EndpointMethodDescription
/api/auth/[...path]ALLSuperTokens auth routes
/api/userGET/PUTUser profile

AI & Chat

EndpointMethodDescription
/api/chatPOSTLangGraph agent conversation
/api/conversations/[id]GET/DELETEConversation management
/api/conversations/[id]/messagesGETMessage history

Walking Tours

EndpointMethodDescription
/api/walking-tour/generatePOSTGenerate tour with Nemotron
/api/walking-tour/ttsPOSTText-to-speech for tour
/api/walking-tour/generate-imagePOSTCover image generation

POIs & Routes

EndpointMethodDescription
/api/poisGETList all POIs
/api/categoriesGETPOI categories
/api/routesGET/POSTRoute CRUD
/api/routeGET/POST/DELETESingle route ops

Events

EndpointMethodDescription
/api/eventsGETEvent listing
/api/events/[id]GETEvent details
/api/events/scrapePOSTTrigger event scraping
/api/events/todayGETToday's events

Itineraries

EndpointMethodDescription
/api/itinerariesGET/POSTItinerary CRUD
/api/itineraries/[id]GET/PUT/DELETESingle itinerary
/api/itineraries/[id]/likePOSTLike itinerary
/api/itineraries/[id]/commentsGET/POSTComments

Python Services

ServiceEndpointDescription
RAG Agenthttp://localhost:8001/api/chatTour guide RAG
TTShttp://localhost:8000/v1/audio/ttsText-to-speech
STT WebSocketws://localhost:8000/v1/audio/speech_to_speech/realtimeReal-time voice
Metricshttp://localhost:8000/v1/metricsToken usage stats

Getting Started

Prerequisites

  • Node.js 18+ (for Next.js)
  • Python 3.10+ (for AI services)
  • PostgreSQL (database)
  • Ollama (local LLM inference)
  • NVIDIA GPU (recommended for faster inference)

1. Clone & Install Dependencies

# Clone repository
git clone https://github.com/yourusername/touristy.git
cd touristy

# Install Node.js dependencies
npm install

# Create Python virtual environment
python -m venv .venv
source .venv/bin/activate  # Linux/Mac
# .venv\Scripts\activate   # Windows

# Install Python dependencies
pip install -r requirements.txt
pip install -r agent/requirements.txt
pip install -r sts/requirements.txt

2. Setup Ollama & Nemotron

# Install Ollama (Linux)
curl -fsSL https://ollama.com/install.sh | sh

# Start Ollama service
ollama serve

# Pull Nemotron model
ollama pull nemotron-3-nano-64k

# Verify
ollama list

3. Setup Database

# Create PostgreSQL database
createdb touristy

# Run migrations
npx prisma migrate dev

# Seed data
npm run db:seed

4. Configure Environment

# Copy environment template
cp .env.example .env.local

# Edit with your values
nano .env.local

5. Start Services

# Terminal 1: Next.js
npm run dev

# Terminal 2: RAG Agent
cd agent && python main.py

# Terminal 3: Voice Service
cd sts && python Touristy.py

# Terminal 4: Ollama (if not running as service)
ollama serve

6. Access Application


Environment Variables

# Database
DATABASE_URL=postgresql://touristy:touristy123@localhost:5432/touristy

# Authentication (SuperTokens)
NEXT_PUBLIC_API_DOMAIN=http://localhost:3000
NEXT_PUBLIC_WEBSITE_DOMAIN=http://localhost:3000

# Ollama (Local LLM)
OLLAMA_URL=http://localhost:11434/api/generate
OLLAMA_MODEL=nemotron-3-nano-64k:latest

# Text-to-Speech Service
LOCAL_TTS_URL=http://localhost:8000/v1/audio/tts

# RAG Agent Service
AGENT_API_URL=http://localhost:8001/api/chat

# Image Generation (Optional - Stable Diffusion)
IMAGE_API_URL=http://localhost:7860/sdapi/v1/txt2img
USE_PLACEHOLDER_IMAGES=true

# NVIDIA API (Optional - for cloud inference)
NVIDIA_API_KEY=your_key_here

# Offline Mode (disable external network)
OFFLINE_MODE=false

Project Structure

touristy/
├── src/
│   ├── app/                    # Next.js App Router pages
│   │   ├── explore/            # Main exploration hub
│   │   ├── events/             # Event discovery
│   │   ├── itinerary/          # Itinerary viewing/editing
│   │   ├── landmarks/          # SF landmarks browser
│   │   └── api/                # API routes (42+ endpoints)
│   │       ├── chat/           # LangGraph agent
│   │       ├── walking-tour/   # Tour generation
│   │       ├── events/         # Event CRUD
│   │       ├── itineraries/    # Itinerary CRUD
│   │       └── ...
│   ├── components/             # React components
│   │   ├── MapView.tsx         # Interactive Leaflet map
│   │   ├── VoiceMicrophone.tsx # Voice interaction
│   │   ├── WalkingTourPresentation.tsx
│   │   ├── MapSearchBar.tsx    # Search with autocomplete
│   │   └── ChatSidebar.tsx     # AI chat interface
│   ├── lib/                    # Utilities and helpers
│   └── services/               # External service integrations
│
├── agent/                      # Python RAG Agent Service
│   ├── main.py                 # FastAPI entry point
│   ├── rag_agent.py            # RAG agent implementation
│   ├── location_extractor.py   # Constrained extraction
│   ├── location_service.py     # POI database service
│   ├── restaurant_service.py   # Restaurant recommendations
│   ├── neighborhood_guide.py   # SF neighborhoods data
│   ├── routing.py              # ORS/OSRM routing
│   ├── batch_evaluator.py      # DSPy prompt optimization
│   ├── vectorstore/            # FAISS vector database
│   │   ├── index.faiss
│   │   └── index.pkl
│   └── requirements.txt
│
├── sts/                        # Speech-to-Speech Service
│   ├── Touristy.py             # FastAPI voice server
│   ├── generated_audio/        # Audio cache
│   └── requirements.txt
│
├── prisma/
│   ├── schema.prisma           # Database schema
│   └── migrations/             # Migration history
│
├── scripts/
│   ├── run-agent.sh            # Start agent service
│   ├── setup-agent.sh          # Setup agent environment
│   └── scrape-events.sh        # Event scraping
│
├── public/                     # Static assets
├── ecosystem.config.js         # PM2 configuration
├── Caddyfile                   # Caddy reverse proxy
├── vercel.json                 # Vercel cron jobs
├── package.json
├── tsconfig.json
└── .env.local                  # Environment variables

Development Scripts

Node.js Scripts

npm run dev        # Start development server (port 3000)
npm run build      # Build for production
npm run start      # Run production build
npm run lint       # Run ESLint
npm run db:seed    # Seed database with POIs

Python Services

# RAG Agent
cd agent
python main.py     # Start on port 8001

# Voice Service
cd sts
python Touristy.py # Start on port 8000

Shell Scripts

./scripts/run-agent.sh     # Start agent with venv
./scripts/setup-agent.sh   # Setup Python environment
./scripts/scrape-events.sh # Trigger event scraping

Deployment

PM2 Process Management

// ecosystem.config.js
module.exports = {
  apps: [{
    name: 'my-website',
    script: 'npm',
    args: 'start',
    cwd: '/home/dell/my-website',
    env: {
      NODE_ENV: 'production',
      PORT: 3000
    },
    max_memory_restart: '500M'
  }]
};

Caddy Reverse Proxy

# Caddyfile
touristy.urbantech.dev {
    reverse_proxy localhost:3000
}

touristyvoice.urbantech.dev {
    reverse_proxy localhost:8000
}

Vercel Cron Jobs

{
  "crons": [
    {
      "path": "/api/events/scrape",
      "schedule": "0 6 * * *"
    }
  ]
}

External Integrations

ServicePurposeLocal/Remote
OllamaLLM inferenceLocal
FAISSVector similarity searchLocal
WhisperSpeech-to-textLocal
VITS TTSText-to-speechLocal
NominatimGeocodingRemote (OSM)
OpenRouteServiceRoutingRemote (or self-hosted)
OSRMRouting fallbackRemote (or self-hosted)
SuperTokensAuth sessionsRemote (free tier)

Hardware Requirements

Minimum (CPU-only)

  • CPU: 8+ cores
  • RAM: 16GB
  • Storage: 20GB for models
  • GPU: NVIDIA RTX 3060+ (8GB VRAM)
  • RAM: 32GB
  • Storage: 50GB SSD

Models Storage

~2GB   - nemotron-3-nano-64k (Ollama)
~500MB - whisper-small (HuggingFace)
~200MB - VITS TTS model (HuggingFace)
~100MB - Sentence embeddings (HuggingFace)

Local AI Development Workflow

This project demonstrates a fully local AI-powered development workflow where the entire codebase was written using local LLMs without any cloud API dependencies.

OpenCode + Ollama + Nemotron Stack

┌─────────────────────────────────────────────────────────────────┐
│                    LOCAL AI DEVELOPMENT STACK                    │
│                                                                  │
│  Developer                                                       │
│      │                                                           │
│      ▼                                                           │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │                      OPENCODE                             │   │
│  │  AI-Powered Coding Assistant                              │   │
│  │  - Code generation & completion                           │   │
│  │  - Debugging & error fixing                               │   │
│  │  - Refactoring suggestions                                │   │
│  │  - Documentation generation                               │   │
│  │  - Architecture planning                                  │   │
│  └──────────────────────────────────────────────────────────┘   │
│      │                                                           │
│      ▼                                                           │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │                       OLLAMA                              │   │
│  │  Local LLM Runtime (http://localhost:11434)              │   │
│  │  - Model management                                       │   │
│  │  - GPU acceleration (CUDA/ROCm)                          │   │
│  │  - Context window management                              │   │
│  │  - Streaming responses                                    │   │
│  └──────────────────────────────────────────────────────────┘   │
│      │                                                           │
│      ▼                                                           │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │              NVIDIA NEMOTRON 30B                          │   │
│  │  Large Language Model for Code Generation                │   │
│  │  - 30 billion parameters                                  │   │
│  │  - Optimized for code understanding                       │   │
│  │  - Multi-language support (TS, Python, SQL, etc.)        │   │
│  │  - Long context for full-file analysis                    │   │
│  └──────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────┘

Models Used for Development

ModelSizePurpose
nemotron:30b~18GBPrimary code generation, complex logic
nemotron:70b~40GBArchitecture decisions, large refactors
nemotron-3-nano-64k~2GBQuick edits, documentation, simple fixes

OpenCode Configuration

# ~/.config/opencode/config.yaml
provider: ollama
model: nemotron:30b
endpoint: http://localhost:11434

# Ollama-specific settings
options:
  num_ctx: 32768        # Context window
  num_gpu: 99           # GPU layers (all)
  temperature: 0.1      # Low for consistent code
  top_p: 0.9
  repeat_penalty: 1.1

Development Workflow

# 1. Start Ollama with Nemotron
ollama serve

# 2. Verify model is loaded
ollama list
# NAME                    SIZE
# nemotron:30b            18GB

# 3. Launch OpenCode in project directory
cd /path/to/touristy
opencode .

# 4. OpenCode connects to local Ollama
# All code generation happens locally
# No API keys needed, no data sent to cloud

What Was Built With Local AI

The following components were entirely generated using OpenCode + Nemotron 30B:

Frontend (Next.js/React)

  • All React components (40+ components)
  • TypeScript interfaces and types
  • Tailwind CSS styling
  • Leaflet map integration
  • WebSocket audio handling
  • State management

Backend (Next.js API Routes)

  • 42+ API endpoints
  • Prisma database queries
  • Authentication flows
  • File upload handling
  • Event scraping logic

Python AI Services

  • RAG agent implementation
  • FAISS vector store setup
  • Speech-to-text pipeline
  • Text-to-speech integration
  • LangChain orchestration
  • DSPy prompt optimization

Database

  • Prisma schema design (20+ models)
  • Migration scripts
  • Seed data generation
  • Query optimization

DevOps

  • PM2 configuration
  • Caddy reverse proxy setup
  • Docker configurations
  • Shell scripts

Benefits of Local AI Development

BenefitDescription
Zero API CostsNo OpenAI/Anthropic/Google API fees
Complete PrivacyCode never leaves your machine
No Rate LimitsGenerate as much code as needed
Offline DevelopmentWork anywhere without internet
CustomizableFine-tune models for your codebase
Fast IterationLow latency local inference
ReproducibleSame model version, same results

Hardware Used for Development

Development Machine:
- GPU: NVIDIA RTX 4090 (24GB VRAM)
- CPU: AMD Ryzen 9 7950X
- RAM: 64GB DDR5
- Storage: 2TB NVMe SSD

Inference Performance:
- nemotron:30b: ~30 tokens/sec
- nemotron-3-nano-64k: ~100 tokens/sec

Reproducing This Development Setup

# 1. Install Ollama
curl -fsSL https://ollama.com/install.sh | sh

# 2. Pull Nemotron models
ollama pull nemotron:30b           # Primary development
ollama pull nemotron-3-nano-64k    # Quick tasks

# 3. Install OpenCode
# Follow instructions at: https://github.com/opencode-ai/opencode

# 4. Configure OpenCode for Ollama
mkdir -p ~/.config/opencode
cat > ~/.config/opencode/config.yaml << 'EOF'
provider: ollama
model: nemotron:30b
endpoint: http://localhost:11434
options:
  num_ctx: 32768
  temperature: 0.1
EOF

# 5. Start coding!
opencode /path/to/your/project

License

MIT


Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Run tests: npm run lint
  5. Submit a pull request

Support

Contributors

DasilvaKareem

28 commits

claude

8 commits

Greesan

2 commits

kopias

1 commits

DasilvaKareem/my-website

Personal website built with Next.js, TypeScript, and Tailwind CSS

0

stars

39

commits

TypeScript

primary language

Jan 26, 2026

updated

README

Touristy - AI-Powered San Francisco Tour Guide

An AI-powered San Francisco tour guide and itinerary planning platform built with a fully local AI stack using NVIDIA Nemotron models, RAG (Retrieval Augmented Generation), and real-time voice processing.

Live Site: https://touristy.urbantech.dev


Built With Local AI - 100% Offline Development

This entire application was coded and developed using OpenCode with Ollama running NVIDIA Nemotron 30B locally. No cloud AI APIs were used during development - the entire codebase was generated, debugged, and refined using a fully local AI coding assistant.

Development Stack

ToolPurpose
OpenCodeAI-powered coding assistant (local)
OllamaLocal LLM inference runtime
NVIDIA Nemotron 30BLarge language model for code generation
Claude CodeAdditional AI pair programming

Why Local AI Development?

  • Privacy - All code and prompts stay on your machine
  • No API Costs - Zero cloud API expenses
  • Offline Capable - Develop anywhere without internet
  • Full Control - No rate limits, no data sharing
  • Fast Iteration - Low latency local inference

OpenCode + Ollama Setup Used

# Install Ollama
curl -fsSL https://ollama.com/install.sh | sh

# Pull Nemotron 30B for code generation
ollama pull nemotron:30b
# or the smaller variant
ollama pull nemotron-3-nano-64k

# OpenCode automatically connects to local Ollama
# Configure in ~/.config/opencode/config.yaml:
#   provider: ollama
#   model: nemotron:30b
#   endpoint: http://localhost:11434

Code Generation Capabilities

The Nemotron 30B model excels at:

  • Full-stack TypeScript/React development
  • Python backend services and AI pipelines
  • Database schema design (Prisma)
  • API route implementation
  • Component architecture
  • Bug fixing and refactoring
  • Documentation generation

Table of Contents


Features

  • Interactive Map Exploration - Leaflet-based map with POI markers, searchable locations, and event visualization
  • AI Chat Assistant - Conversational AI using LangGraph agent with tool access powered by local Nemotron models
  • Walking Tour Generator - AI-generated detailed walking tour narratives with images and text-to-speech narration
  • Voice Interaction - Real-time speech-to-text and text-to-speech for hands-free exploration via WebSocket pipeline
  • Event Discovery - Browse and filter local San Francisco events by category, date, and price
  • Itinerary Management - Create, save, edit, and share custom itineraries with GeoJSON routes
  • Social Features - Follow users, like/review/comment on itineraries and POIs
  • RAG-Powered Recommendations - Vector similarity search over 1K+ SF landmarks for contextual recommendations

Architecture Overview

Touristy is built as a microservices architecture with all AI inference running locally:

┌─────────────────────────────────────────────────────────────────────────┐
│                           CLIENT (Browser)                              │
│  ┌─────────────┐  ┌──────────────┐  ┌─────────────────────────────────┐ │
│  │ React 19    │  │ Leaflet Maps │  │ WebSocket Audio (VoiceMicrophone)│ │
│  │ Next.js 16  │  │ react-leaflet│  │ Web Audio API                    │ │
│  └─────────────┘  └──────────────┘  └─────────────────────────────────┘ │
└───────────────────────────────┬─────────────────────────────────────────┘
                                │
                                ▼
┌─────────────────────────────────────────────────────────────────────────┐
│                         NEXT.JS API ROUTES (Port 3000)                   │
│  ┌─────────────┐  ┌──────────────┐  ┌─────────────┐  ┌───────────────┐  │
│  │ /api/chat   │  │ /api/walking │  │ /api/events │  │ /api/itinerary│  │
│  │ LangGraph   │  │ -tour/generate│  │ CRUD + Scrape│  │ CRUD + Social │  │
│  └─────────────┘  └──────────────┘  └─────────────┘  └───────────────┘  │
└───────────────────────────────┬─────────────────────────────────────────┘
                                │
        ┌───────────────────────┼───────────────────────┐
        ▼                       ▼                       ▼
┌───────────────┐    ┌──────────────────┐    ┌──────────────────┐
│  FASTAPI      │    │  FASTAPI STS     │    │   POSTGRESQL     │
│  RAG AGENT    │    │  Voice Pipeline  │    │   + PRISMA ORM   │
│  (Port 8001)  │    │  (Port 8000)     │    │   (Port 5432)    │
│               │    │                  │    │                  │
│ ┌───────────┐ │    │ ┌──────────────┐ │    │ ┌──────────────┐ │
│ │ FAISS     │ │    │ │ Whisper STT  │ │    │ │ 20+ Models   │ │
│ │ VectorDB  │ │    │ │ VITS TTS     │ │    │ │ Users, POIs, │ │
│ │           │ │    │ │ WebSocket    │ │    │ │ Itineraries  │ │
│ └───────────┘ │    │ └──────────────┘ │    │ └──────────────┘ │
└───────┬───────┘    └────────┬─────────┘    └──────────────────┘
        │                     │
        └──────────┬──────────┘
                   ▼
        ┌──────────────────────┐
        │   OLLAMA LOCAL LLM   │
        │     (Port 11434)     │
        │                      │
        │ ┌──────────────────┐ │
        │ │ nemotron-3-nano  │ │
        │ │     -64k         │ │
        │ │ NVIDIA Nemotron  │ │
        │ │ 3B Parameters    │ │
        │ └──────────────────┘ │
        └──────────────────────┘

Technology Stack

Frontend

TechnologyVersionPurpose
Next.js16.1.4React meta-framework with App Router
React19.2.3UI library with JSX
TypeScript5.xType-safe JavaScript
Tailwind CSS4.xUtility-first CSS framework
Leaflet1.9.4Interactive mapping library
react-leaflet5.0.0React wrapper for Leaflet
react-markdown10.1.0Markdown rendering
SuperTokens Auth React0.51.1Frontend authentication
supertokens-web-js0.16.0Web SDK for authentication

Backend

TechnologyVersionPurpose
Next.js API Routes16.1.4Serverless backend functions (42+ routes)
Prisma ORM5.22.0Database ORM with type-safe queries
PostgreSQLLatestPrimary relational database
SuperTokens Node24.0.0Backend session management
bcryptjs3.0.3Password hashing
FastAPILatestPython async web framework
uvicornLatestASGI server

Python AI/ML Services

TechnologyPurpose
OllamaLocal LLM runtime/inference engine
LangChainLLM orchestration framework
langchain-communityCommunity integrations
langchain-coreCore abstractions
langchain_huggingfaceHuggingFace embeddings
FAISSFacebook AI Similarity Search (Vector DB)
PyTorchDeep learning framework
transformersHuggingFace Transformers
sentence-transformersSentence embeddings for RAG
DSPyDeclarative Self-Improving prompts
accelerateDistributed inference utilities

AI/ML Technologies

NVIDIA Nemotron Models (Local via Ollama)

The application uses NVIDIA Nemotron 3 Nano models running entirely locally through Ollama:

# Primary model for tour generation and content
Model: nemotron-3-nano-64k:latest
Context Window: 64,000 tokens
Parameters: ~3B
Runtime: Ollama (http://localhost:11434)

# Model capabilities:
- Walking tour narrative generation
- Conversational AI responses
- POI description generation
- Itinerary planning
- Natural language understanding

Why Nemotron?

  • Fully local - No API calls, no data leaves your machine
  • 64K context window - Can process entire tour histories
  • Optimized for NVIDIA GPUs - Efficient inference on consumer hardware
  • Open weights - Full control over the model

NVIDIA NeMo Toolkit Integration

The codebase supports the NVIDIA NeMo Toolkit for advanced model capabilities:

# Available in requirements
nemo-toolkit[all]

# Provides:
- Advanced speech recognition models
- Neural text-to-speech
- Speaker diarization
- Language models

Ollama Configuration

# Start Ollama service
ollama serve

# Pull the Nemotron model
ollama pull nemotron-3-nano-64k

# Verify model
ollama list

LangGraph Agent

The AI chat assistant uses LangGraph for tool-augmented conversations:

# Agent Tools Available:
- POI search and recommendations
- Restaurant finder
- Neighborhood guide
- Route planning (walking, cycling, transit)
- Event discovery
- Weather information
- Distance calculations

RAG System

Overview

The RAG (Retrieval Augmented Generation) system provides contextual recommendations by searching a vector database of 1,000+ San Francisco landmarks.

Components

┌─────────────────────────────────────────────────────────────┐
│                    RAG PIPELINE                              │
│                                                              │
│  User Query                                                  │
│      │                                                       │
│      ▼                                                       │
│  ┌──────────────────────────────────────────────────────┐   │
│  │           QUERY EMBEDDING                             │   │
│  │  HuggingFace Sentence Transformers                    │   │
│  │  Model: all-MiniLM-L6-v2 (or similar)                │   │
│  │  Dimensions: 384                                      │   │
│  └──────────────────────────────────────────────────────┘   │
│      │                                                       │
│      ▼                                                       │
│  ┌──────────────────────────────────────────────────────┐   │
│  │           FAISS VECTOR SEARCH                         │   │
│  │  Index: /agent/vectorstore/index.faiss               │   │
│  │  Metadata: /agent/vectorstore/index.pkl              │   │
│  │  Algorithm: Approximate Nearest Neighbors             │   │
│  │  Top-K: 5-10 relevant documents                      │   │
│  └──────────────────────────────────────────────────────┘   │
│      │                                                       │
│      ▼                                                       │
│  ┌──────────────────────────────────────────────────────┐   │
│  │           CONTEXT AUGMENTATION                        │   │
│  │  Retrieved POIs + User Query → Prompt                │   │
│  └──────────────────────────────────────────────────────┘   │
│      │                                                       │
│      ▼                                                       │
│  ┌──────────────────────────────────────────────────────┐   │
│  │           NEMOTRON GENERATION                         │   │
│  │  Model: nemotron-3-nano-64k                          │   │
│  │  Context: Query + Retrieved Documents                │   │
│  │  Output: Contextual recommendations                   │   │
│  └──────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────┘

Vector Store

# Location: /agent/vectorstore/
# Files:
#   - index.faiss    (Vector embeddings)
#   - index.pkl      (Document metadata)

# Embedding Model
from langchain_huggingface import HuggingFaceEmbeddings
embeddings = HuggingFaceEmbeddings()

# Vector Store Loading
from langchain.vectorstores import FAISS
vectorstore = FAISS.load_local("vectorstore", embeddings)

# Similarity Search
docs = vectorstore.similarity_search(query, k=5)

RAG Agent Components

FilePurpose
agent/rag_agent.pyMain RAG agent with vector search
agent/location_extractor.pyConstrained entity extraction (prevents hallucination)
agent/location_service.pyUnified POI lookup from Prisma database
agent/restaurant_service.pyPOI-based restaurant recommendations
agent/neighborhood_guide.pyCurated SF neighborhood data
agent/routing.pyTurn-by-turn navigation via ORS/OSRM

Constrained Extraction

To prevent LLM hallucinations, the system uses constrained extraction:

# location_extractor.py
# Only returns POIs that exist in the database
# Normalizes queries for fuzzy matching
# Falls back to vector search for unknown queries

Voice Processing Pipeline

Architecture

┌─────────────────────────────────────────────────────────────────────┐
│                  REAL-TIME VOICE PIPELINE                            │
│                                                                      │
│  Browser (VoiceMicrophone.tsx)                                       │
│      │                                                               │
│      │ WebSocket: wss://touristyvoice.urbantech.dev                 │
│      │            (or ws://localhost:8000)                          │
│      ▼                                                               │
│  ┌─────────────────────────────────────────────────────────────────┐│
│  │              FASTAPI STS SERVICE (Port 8000)                     ││
│  │                                                                  ││
│  │  ┌──────────────────────────────────────────────────────────┐   ││
│  │  │  1. SPEECH-TO-TEXT (STT)                                  │   ││
│  │  │     Model: openai/whisper-small                           │   ││
│  │  │     Library: transformers (WhisperForConditionalGeneration)│   ││
│  │  │     Input: Raw audio bytes                                 │   ││
│  │  │     Output: Transcribed text                               │   ││
│  │  └──────────────────────────────────────────────────────────┘   ││
│  │                           │                                      ││
│  │                           ▼                                      ││
│  │  ┌──────────────────────────────────────────────────────────┐   ││
│  │  │  2. RAG AGENT API CALL                                    │   ││
│  │  │     Endpoint: http://localhost:8001/api/chat              │   ││
│  │  │     Payload: { "message": transcribed_text }              │   ││
│  │  │     Response: AI-generated tour guide response            │   ││
│  │  └──────────────────────────────────────────────────────────┘   ││
│  │                           │                                      ││
│  │                           ▼                                      ││
│  │  ┌──────────────────────────────────────────────────────────┐   ││
│  │  │  3. TEXT-TO-SPEECH (TTS)                                  │   ││
│  │  │     Model: Baghdad99/english_voice_tts                    │   ││
│  │  │     Library: transformers (VitsModel)                     │   ││
│  │  │     Input: Agent response text                            │   ││
│  │  │     Output: WAV audio stream                              │   ││
│  │  └──────────────────────────────────────────────────────────┘   ││
│  │                           │                                      ││
│  └───────────────────────────┼──────────────────────────────────────┘│
│                              ▼                                       │
│      WebSocket Audio Stream → Browser AudioContext → Speaker         │
└─────────────────────────────────────────────────────────────────────┘

Speech-to-Text (STT)

# Model: OpenAI Whisper Small
# Library: HuggingFace Transformers

from transformers import WhisperProcessor, WhisperForConditionalGeneration

model_name = "openai/whisper-small"
processor = WhisperProcessor.from_pretrained(model_name)
model = WhisperForConditionalGeneration.from_pretrained(model_name)

# Features:
# - Multi-language support
# - Real-time streaming
# - Voice Activity Detection (webrtcvad)

Text-to-Speech (TTS)

# Model: Baghdad99/english_voice_tts
# Library: HuggingFace Transformers (VITS)

from transformers import VitsModel, VitsTokenizer

model_name = "Baghdad99/english_voice_tts"
tokenizer = VitsTokenizer.from_pretrained(model_name)
model = VitsModel.from_pretrained(model_name)

# Features:
# - Natural sounding English voice
# - 16kHz WAV output
# - Real-time streaming via WebSocket

Audio Processing Libraries

LibraryPurpose
librosaAudio analysis and feature extraction
soundfileWAV file I/O
pyaudioAudio input/output
webrtcvad-wheelsVoice Activity Detection
scipySignal processing
numpyNumerical operations

Prompt Optimization (DSPy)

Overview

The system uses DSPy for declarative, self-improving prompts:

# DSPy Configuration
import dspy

# Define structured signatures
class TourGuideSignature(dspy.Signature):
    """Generate helpful tour guide responses"""
    query: str = dspy.InputField()
    context: str = dspy.InputField()
    response: str = dspy.OutputField()

# Create predictor
predictor = dspy.Predict(TourGuideSignature)

Batch Evaluation System

# batch_evaluator.py
# Automated prompt optimization pipeline:

# 1. Fetch recent conversations from PostgreSQL
# 2. Sample 10% for evaluation
# 3. Calculate GEPA (Graph-based Efficiency-Preserving Automated) scores
# 4. Compare against baseline
# 5. Auto-update prompts when 5%+ improvement detected
# 6. Track prompt versions in database

Evaluation Metrics

MetricDescription
GEPA ScoreGraph-based efficiency metric for prompt quality
Response RelevanceHow well the response matches the query
Factual AccuracyGrounding in retrieved documents
User SatisfactionImplicit feedback from conversation flow

Database Schema

PostgreSQL + Prisma ORM

// Core Models

model User {
  id            String   @id @default(uuid())
  email         String   @unique
  passwordHash  String
  createdAt     DateTime @default(now())
  superTokensId String?  @unique
  // Relations
  savedRoutes   SavedRoute[]
  trips         Trip[]
  following     Follow[] @relation("follower")
  followers     Follow[] @relation("following")
}

model POI {
  id          String   @id @default(uuid())
  name        String
  description String?
  latitude    Float
  longitude   Float
  address     String?
  rating      Float?
  priceLevel  Int?
  categoryId  String?
  // Relations
  category    Category?
  routeStops  RouteStop[]
  likes       POILike[]
  comments    POIComment[]
}

model Category {
  id    String @id @default(uuid())
  name  String @unique
  icon  String?
  color String?
  pois  POI[]
}

model Route {
  id          String      @id @default(uuid())
  name        String
  description String?
  geojson     Json?
  createdAt   DateTime    @default(now())
  stops       RouteStop[]
}

model Event {
  id          String   @id @default(uuid())
  title       String
  description String?
  startTime   DateTime
  endTime     DateTime?
  venue       String?
  latitude    Float?
  longitude   Float?
  price       Float?
  category    String?
  sourceUrl   String?
  imageUrl    String?
}

model Message {
  id             String   @id @default(uuid())
  conversationId String
  role           String
  content        String
  gepaScore      Float?   // For prompt optimization
  createdAt      DateTime @default(now())
}

model PromptVersion {
  id        String   @id @default(uuid())
  name      String
  content   String
  version   Int
  score     Float?
  isActive  Boolean  @default(false)
  createdAt DateTime @default(now())
}

API Reference

Authentication

EndpointMethodDescription
/api/auth/[...path]ALLSuperTokens auth routes
/api/userGET/PUTUser profile

AI & Chat

EndpointMethodDescription
/api/chatPOSTLangGraph agent conversation
/api/conversations/[id]GET/DELETEConversation management
/api/conversations/[id]/messagesGETMessage history

Walking Tours

EndpointMethodDescription
/api/walking-tour/generatePOSTGenerate tour with Nemotron
/api/walking-tour/ttsPOSTText-to-speech for tour
/api/walking-tour/generate-imagePOSTCover image generation

POIs & Routes

EndpointMethodDescription
/api/poisGETList all POIs
/api/categoriesGETPOI categories
/api/routesGET/POSTRoute CRUD
/api/routeGET/POST/DELETESingle route ops

Events

EndpointMethodDescription
/api/eventsGETEvent listing
/api/events/[id]GETEvent details
/api/events/scrapePOSTTrigger event scraping
/api/events/todayGETToday's events

Itineraries

EndpointMethodDescription
/api/itinerariesGET/POSTItinerary CRUD
/api/itineraries/[id]GET/PUT/DELETESingle itinerary
/api/itineraries/[id]/likePOSTLike itinerary
/api/itineraries/[id]/commentsGET/POSTComments

Python Services

ServiceEndpointDescription
RAG Agenthttp://localhost:8001/api/chatTour guide RAG
TTShttp://localhost:8000/v1/audio/ttsText-to-speech
STT WebSocketws://localhost:8000/v1/audio/speech_to_speech/realtimeReal-time voice
Metricshttp://localhost:8000/v1/metricsToken usage stats

Getting Started

Prerequisites

  • Node.js 18+ (for Next.js)
  • Python 3.10+ (for AI services)
  • PostgreSQL (database)
  • Ollama (local LLM inference)
  • NVIDIA GPU (recommended for faster inference)

1. Clone & Install Dependencies

# Clone repository
git clone https://github.com/yourusername/touristy.git
cd touristy

# Install Node.js dependencies
npm install

# Create Python virtual environment
python -m venv .venv
source .venv/bin/activate  # Linux/Mac
# .venv\Scripts\activate   # Windows

# Install Python dependencies
pip install -r requirements.txt
pip install -r agent/requirements.txt
pip install -r sts/requirements.txt

2. Setup Ollama & Nemotron

# Install Ollama (Linux)
curl -fsSL https://ollama.com/install.sh | sh

# Start Ollama service
ollama serve

# Pull Nemotron model
ollama pull nemotron-3-nano-64k

# Verify
ollama list

3. Setup Database

# Create PostgreSQL database
createdb touristy

# Run migrations
npx prisma migrate dev

# Seed data
npm run db:seed

4. Configure Environment

# Copy environment template
cp .env.example .env.local

# Edit with your values
nano .env.local

5. Start Services

# Terminal 1: Next.js
npm run dev

# Terminal 2: RAG Agent
cd agent && python main.py

# Terminal 3: Voice Service
cd sts && python Touristy.py

# Terminal 4: Ollama (if not running as service)
ollama serve

6. Access Application


Environment Variables

# Database
DATABASE_URL=postgresql://touristy:touristy123@localhost:5432/touristy

# Authentication (SuperTokens)
NEXT_PUBLIC_API_DOMAIN=http://localhost:3000
NEXT_PUBLIC_WEBSITE_DOMAIN=http://localhost:3000

# Ollama (Local LLM)
OLLAMA_URL=http://localhost:11434/api/generate
OLLAMA_MODEL=nemotron-3-nano-64k:latest

# Text-to-Speech Service
LOCAL_TTS_URL=http://localhost:8000/v1/audio/tts

# RAG Agent Service
AGENT_API_URL=http://localhost:8001/api/chat

# Image Generation (Optional - Stable Diffusion)
IMAGE_API_URL=http://localhost:7860/sdapi/v1/txt2img
USE_PLACEHOLDER_IMAGES=true

# NVIDIA API (Optional - for cloud inference)
NVIDIA_API_KEY=your_key_here

# Offline Mode (disable external network)
OFFLINE_MODE=false

Project Structure

touristy/
├── src/
│   ├── app/                    # Next.js App Router pages
│   │   ├── explore/            # Main exploration hub
│   │   ├── events/             # Event discovery
│   │   ├── itinerary/          # Itinerary viewing/editing
│   │   ├── landmarks/          # SF landmarks browser
│   │   └── api/                # API routes (42+ endpoints)
│   │       ├── chat/           # LangGraph agent
│   │       ├── walking-tour/   # Tour generation
│   │       ├── events/         # Event CRUD
│   │       ├── itineraries/    # Itinerary CRUD
│   │       └── ...
│   ├── components/             # React components
│   │   ├── MapView.tsx         # Interactive Leaflet map
│   │   ├── VoiceMicrophone.tsx # Voice interaction
│   │   ├── WalkingTourPresentation.tsx
│   │   ├── MapSearchBar.tsx    # Search with autocomplete
│   │   └── ChatSidebar.tsx     # AI chat interface
│   ├── lib/                    # Utilities and helpers
│   └── services/               # External service integrations
│
├── agent/                      # Python RAG Agent Service
│   ├── main.py                 # FastAPI entry point
│   ├── rag_agent.py            # RAG agent implementation
│   ├── location_extractor.py   # Constrained extraction
│   ├── location_service.py     # POI database service
│   ├── restaurant_service.py   # Restaurant recommendations
│   ├── neighborhood_guide.py   # SF neighborhoods data
│   ├── routing.py              # ORS/OSRM routing
│   ├── batch_evaluator.py      # DSPy prompt optimization
│   ├── vectorstore/            # FAISS vector database
│   │   ├── index.faiss
│   │   └── index.pkl
│   └── requirements.txt
│
├── sts/                        # Speech-to-Speech Service
│   ├── Touristy.py             # FastAPI voice server
│   ├── generated_audio/        # Audio cache
│   └── requirements.txt
│
├── prisma/
│   ├── schema.prisma           # Database schema
│   └── migrations/             # Migration history
│
├── scripts/
│   ├── run-agent.sh            # Start agent service
│   ├── setup-agent.sh          # Setup agent environment
│   └── scrape-events.sh        # Event scraping
│
├── public/                     # Static assets
├── ecosystem.config.js         # PM2 configuration
├── Caddyfile                   # Caddy reverse proxy
├── vercel.json                 # Vercel cron jobs
├── package.json
├── tsconfig.json
└── .env.local                  # Environment variables

Development Scripts

Node.js Scripts

npm run dev        # Start development server (port 3000)
npm run build      # Build for production
npm run start      # Run production build
npm run lint       # Run ESLint
npm run db:seed    # Seed database with POIs

Python Services

# RAG Agent
cd agent
python main.py     # Start on port 8001

# Voice Service
cd sts
python Touristy.py # Start on port 8000

Shell Scripts

./scripts/run-agent.sh     # Start agent with venv
./scripts/setup-agent.sh   # Setup Python environment
./scripts/scrape-events.sh # Trigger event scraping

Deployment

PM2 Process Management

// ecosystem.config.js
module.exports = {
  apps: [{
    name: 'my-website',
    script: 'npm',
    args: 'start',
    cwd: '/home/dell/my-website',
    env: {
      NODE_ENV: 'production',
      PORT: 3000
    },
    max_memory_restart: '500M'
  }]
};

Caddy Reverse Proxy

# Caddyfile
touristy.urbantech.dev {
    reverse_proxy localhost:3000
}

touristyvoice.urbantech.dev {
    reverse_proxy localhost:8000
}

Vercel Cron Jobs

{
  "crons": [
    {
      "path": "/api/events/scrape",
      "schedule": "0 6 * * *"
    }
  ]
}

External Integrations

ServicePurposeLocal/Remote
OllamaLLM inferenceLocal
FAISSVector similarity searchLocal
WhisperSpeech-to-textLocal
VITS TTSText-to-speechLocal
NominatimGeocodingRemote (OSM)
OpenRouteServiceRoutingRemote (or self-hosted)
OSRMRouting fallbackRemote (or self-hosted)
SuperTokensAuth sessionsRemote (free tier)

Hardware Requirements

Minimum (CPU-only)

  • CPU: 8+ cores
  • RAM: 16GB
  • Storage: 20GB for models
  • GPU: NVIDIA RTX 3060+ (8GB VRAM)
  • RAM: 32GB
  • Storage: 50GB SSD

Models Storage

~2GB   - nemotron-3-nano-64k (Ollama)
~500MB - whisper-small (HuggingFace)
~200MB - VITS TTS model (HuggingFace)
~100MB - Sentence embeddings (HuggingFace)

Local AI Development Workflow

This project demonstrates a fully local AI-powered development workflow where the entire codebase was written using local LLMs without any cloud API dependencies.

OpenCode + Ollama + Nemotron Stack

┌─────────────────────────────────────────────────────────────────┐
│                    LOCAL AI DEVELOPMENT STACK                    │
│                                                                  │
│  Developer                                                       │
│      │                                                           │
│      ▼                                                           │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │                      OPENCODE                             │   │
│  │  AI-Powered Coding Assistant                              │   │
│  │  - Code generation & completion                           │   │
│  │  - Debugging & error fixing                               │   │
│  │  - Refactoring suggestions                                │   │
│  │  - Documentation generation                               │   │
│  │  - Architecture planning                                  │   │
│  └──────────────────────────────────────────────────────────┘   │
│      │                                                           │
│      ▼                                                           │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │                       OLLAMA                              │   │
│  │  Local LLM Runtime (http://localhost:11434)              │   │
│  │  - Model management                                       │   │
│  │  - GPU acceleration (CUDA/ROCm)                          │   │
│  │  - Context window management                              │   │
│  │  - Streaming responses                                    │   │
│  └──────────────────────────────────────────────────────────┘   │
│      │                                                           │
│      ▼                                                           │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │              NVIDIA NEMOTRON 30B                          │   │
│  │  Large Language Model for Code Generation                │   │
│  │  - 30 billion parameters                                  │   │
│  │  - Optimized for code understanding                       │   │
│  │  - Multi-language support (TS, Python, SQL, etc.)        │   │
│  │  - Long context for full-file analysis                    │   │
│  └──────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────┘

Models Used for Development

ModelSizePurpose
nemotron:30b~18GBPrimary code generation, complex logic
nemotron:70b~40GBArchitecture decisions, large refactors
nemotron-3-nano-64k~2GBQuick edits, documentation, simple fixes

OpenCode Configuration

# ~/.config/opencode/config.yaml
provider: ollama
model: nemotron:30b
endpoint: http://localhost:11434

# Ollama-specific settings
options:
  num_ctx: 32768        # Context window
  num_gpu: 99           # GPU layers (all)
  temperature: 0.1      # Low for consistent code
  top_p: 0.9
  repeat_penalty: 1.1

Development Workflow

# 1. Start Ollama with Nemotron
ollama serve

# 2. Verify model is loaded
ollama list
# NAME                    SIZE
# nemotron:30b            18GB

# 3. Launch OpenCode in project directory
cd /path/to/touristy
opencode .

# 4. OpenCode connects to local Ollama
# All code generation happens locally
# No API keys needed, no data sent to cloud

What Was Built With Local AI

The following components were entirely generated using OpenCode + Nemotron 30B:

Frontend (Next.js/React)

  • All React components (40+ components)
  • TypeScript interfaces and types
  • Tailwind CSS styling
  • Leaflet map integration
  • WebSocket audio handling
  • State management

Backend (Next.js API Routes)

  • 42+ API endpoints
  • Prisma database queries
  • Authentication flows
  • File upload handling
  • Event scraping logic

Python AI Services

  • RAG agent implementation
  • FAISS vector store setup
  • Speech-to-text pipeline
  • Text-to-speech integration
  • LangChain orchestration
  • DSPy prompt optimization

Database

  • Prisma schema design (20+ models)
  • Migration scripts
  • Seed data generation
  • Query optimization

DevOps

  • PM2 configuration
  • Caddy reverse proxy setup
  • Docker configurations
  • Shell scripts

Benefits of Local AI Development

BenefitDescription
Zero API CostsNo OpenAI/Anthropic/Google API fees
Complete PrivacyCode never leaves your machine
No Rate LimitsGenerate as much code as needed
Offline DevelopmentWork anywhere without internet
CustomizableFine-tune models for your codebase
Fast IterationLow latency local inference
ReproducibleSame model version, same results

Hardware Used for Development

Development Machine:
- GPU: NVIDIA RTX 4090 (24GB VRAM)
- CPU: AMD Ryzen 9 7950X
- RAM: 64GB DDR5
- Storage: 2TB NVMe SSD

Inference Performance:
- nemotron:30b: ~30 tokens/sec
- nemotron-3-nano-64k: ~100 tokens/sec

Reproducing This Development Setup

# 1. Install Ollama
curl -fsSL https://ollama.com/install.sh | sh

# 2. Pull Nemotron models
ollama pull nemotron:30b           # Primary development
ollama pull nemotron-3-nano-64k    # Quick tasks

# 3. Install OpenCode
# Follow instructions at: https://github.com/opencode-ai/opencode

# 4. Configure OpenCode for Ollama
mkdir -p ~/.config/opencode
cat > ~/.config/opencode/config.yaml << 'EOF'
provider: ollama
model: nemotron:30b
endpoint: http://localhost:11434
options:
  num_ctx: 32768
  temperature: 0.1
EOF

# 5. Start coding!
opencode /path/to/your/project

License

MIT


Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Run tests: npm run lint
  5. Submit a pull request

Support

Contributors

DasilvaKareem

28 commits

claude

8 commits

Greesan

2 commits

kopias

1 commits

Languages

TypeScript

63.6%

Python

35.6%