Skip to content

WhiteRow33/OpenRouter-AI-Chat-Platform

Repository files navigation

OpenRouter AI Chat Platform

Local, front-to-back chat experience that talks to OpenRouter as the model gateway. React + TypeScript on the frontend, Express + TypeScript on the backend, and OpenTelemetry traces flowing to a local Jaeger instance.

Contents

  • Project Introduction
  • Technical Architecture
  • Installation & Setup
  • Running Jaeger
  • OpenTelemetry Tracing
  • Usage Guide
  • Project Structure
  • Developer Experience Notes
  • Bonus Features
  • Conclusion

Project Introduction

  • Local chat UI that sends messages through OpenRouter to any supported model.
  • Features: send and receive messages, view and manage chat history, choose models exposed by the backend, and (optionally) include multimodal uploads when wired in.
  • Ships with sensible defaults: in-memory history, a health endpoint, and friendly fallbacks if a model is temporarily unavailable.

Technical Architecture

  • Backend (apps/backend): Node.js + Express + TypeScript. Routes for chat, model discovery, and history. In-memory session store, graceful shutdown, and a health endpoint at /health.
  • Frontend (apps/frontend): React + TypeScript (Create React App). Chat UI with history sidebar, inline rename, delete confirmation, and auto-scrolling composer.
  • Telemetry: OpenTelemetry NodeSDK with auto-instrumentation (Express + HTTP) plus custom spans for chat processing, OpenRouter calls, history operations, and in-memory storage.
  • Tracing backend: Jaeger (local Docker container) receiving OTLP/HTTP on http://localhost:4318/v1/traces with UI on http://localhost:16686.

Installation & Setup

Prerequisites

  • Node.js 18+ and npm 9+.
  • Docker (for Jaeger).
  • An OpenRouter API key.

Clone the project

git clone https://github.com/<your-org>/OpenRouter-AI-Chat-Platform.git
cd OpenRouter-AI-Chat-Platform

Install dependencies

The repo uses npm workspaces with a shared types package.

npm install          # installs backend, frontend, and shared types

If you prefer installing individually:

cd apps/backend && npm install
cd ../frontend && npm install

Configure environment

Create apps/backend/.env:

OPENROUTER_API_KEY=sk-***your-key***
PORT=3001
APP_URL=http://localhost:3000
JAEGER_ENDPOINT=http://localhost:4318/v1/traces

Optional frontend override (only if your backend is not on http://localhost:3001):

# apps/frontend/.env
REACT_APP_API_URL=http://localhost:3001

Start services

  1. Start Jaeger (see the dedicated section below).
  2. Start the backend:
cd apps/backend
npm run dev        
# or production mode:
npm run build
npm start

Health check: curl http://localhost:3001/health.

  1. Start the frontend:
cd apps/frontend
npm start

The UI runs at http://localhost:3000 and proxies requests to the backend URL.

Docker Compose option

Bring up Jaeger and the backend together (frontend still runs with npm start):

OPENROUTER_API_KEY=sk-***your-key*** docker compose up -d jaeger backend

Backend will listen on http://localhost:3001 and send traces to the Jaeger collector in the compose network.

Running Jaeger

  • Start Jaeger only:
docker compose up -d jaeger
  • UI: http://localhost:16686
  • OTLP/HTTP collector (what the backend uses): http://localhost:4318/v1/traces
  • After sending a few chat requests, open Jaeger UI, search for service openrouter-chat-backend, and inspect traces by endpoint (/api/chat, /api/history, /api/models).

OpenTelemetry Tracing

  • What is collected
    • Server spans for every HTTP request (method, route, status, user agent, client IP) via requestTracingMiddleware.
    • Auto-instrumented spans for Express and outbound HTTP (OpenRouter fetch calls).
    • Custom spans for:
      • openrouter.chat and openrouter.getModels (API calls, model id, token usage, response id).
      • Chat flow (chat.sendMessage) including validation, session stitching, and fallback responses.
      • History flows (history.listSessions, history.getSession, history.updateTitle, history.deleteSession, history.clearAll).
      • In-memory store operations (memoryStore.*) so cache behavior is traceable.
    • Resource metadata includes service name/version and environment for clear attribution in Jaeger.

Usage Guide

  • Send a message: Open http://localhost:3000, click “New Chat”, type in the composer, press Enter or the send button. Messages stream through the backend to OpenRouter; responses appear in the thread.
  • Switch models: The backend exposes /api/models. Update the model passed in apps/frontend/src/hooks/useChatStore.tsx (default is amazon/nova-2-lite-v1:free) or wire a dropdown that calls backendClient.getModels() and passes the selected model to sendUiMessages.
  • View history: Sidebar lists sessions with last-updated timestamp. Click to load a session, double-click to rename, use the trash icon (with confirmation) to delete.
  • Optional multimodal upload: If you enable file/image uploads, pass OpenRouter’s multimodal message shape to the backend (for example, content as an array with type: "text" and type: "image_url" items). Extend ApiMessage in packages/shared accordingly, allow the UI composer to attach files, and the backend will forward the enriched messages to routingService.chat unchanged.
  • Reset session: Use the “New Chat” button to start a fresh conversation; history persists in-memory until the backend restarts.

Project Structure

apps/
  backend/
    src/
      index.ts                # Express entrypoint + health + shutdown
      middleware/requestTracingMiddleware.ts
      routes/{chat,models,history}.ts
      services/{routingService,telemetryService,tracingUtils,openrouter-types}.ts
      db/memoryStore.ts
    Dockerfile
  frontend/
    src/
      api/backendClient.ts    # REST client
      components/{ChatPage,ChatWindow,Sidebar,ChatTitle}
      hooks/useChatStore.tsx  # chat state, history, sending
packages/
  shared/                     # reused API/UI types
docker-compose.yml            # Jaeger + backend

Developer Experience Notes

  • TypeScript everywhere: Shared types ensure backend responses and frontend usage stay aligned.
  • Auto-instrumentation first: Express and HTTP spans are automatic; runWithSpan and runWithSpanSync add business-level spans where it matters.
  • Stability and error handling: Backend returns friendly fallbacks if OpenRouter is unreachable and marks spans with exceptions for observability. Health endpoint is lightweight.
  • Graceful shutdown: SIGINT/SIGTERM handlers stop the HTTP server and flush/shutdown the OpenTelemetry SDK to avoid span loss.

Bonus Features

  • UX polish: inline rename, keyboard shortcuts (F2 to rename, Ctrl/Cmd+Shift+O for new chat, Delete to remove), image upload support, confirmation modal, and sidebar collapse.
  • The application automatically generates a conversation title based on the user's first message, providing cleaner session organization without requiring manual naming.
  • Better errors: user-facing fallback message when the model is unavailable; traced exceptions for operators.
  • Extra tracing detail: spans for cache/history operations and model metadata counts for faster debugging.

About

Local AI chat app using OpenRouter with React, Express, and OpenTelemetry tracing.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors