SPB Git

spb/chat-spboucher Public

Private universal chat interface over the OpenRouter ecosystem — 400+ models, branching, streaming, usage tracking. Next.js 16 + SQLite, PWA, deployed on m4m64a at chat.spboucher.ai

TypeScript 78.8% CSS 15.1% JavaScript 4.9% Shell 1.2%
1.7 KB · 50 lines typescript
Raw Blame History
1// Author: Simon-Pierre Boucher2// Contact: contact@spboucher.ai3// Project: chat.spboucher.ai45import { orGet } from "./client";6import { parseModelsResponse, type ORModelRaw } from "./schemas";7import { deriveCapabilities } from "./capabilities";8import { derivePricing } from "./pricing";9import type { ModelDefinition } from "./types";1011/** Provider is the human-readable prefix of the display name ("Anthropic: Claude ..."), never parsed from the ID for behavior. */12function deriveProvider(raw: ORModelRaw): string | undefined {13  const name = raw.name ?? "";14  const colon = name.indexOf(":");15  if (colon > 0) return name.slice(0, colon).trim();16  const slash = raw.id.indexOf("/");17  if (slash > 0) return raw.id.slice(0, slash);18  return undefined;19}2021function displayName(raw: ORModelRaw): string {22  const name = raw.name ?? raw.id;23  const colon = name.indexOf(":");24  return colon > 0 ? name.slice(colon + 1).trim() : name;25}2627export function normalizeModel(raw: ORModelRaw): ModelDefinition {28  return {29    id: raw.id,30    name: displayName(raw),31    provider: deriveProvider(raw),32    description: raw.description,33    contextLength: raw.context_length ?? raw.top_provider?.context_length,34    pricing: derivePricing(raw),35    capabilities: deriveCapabilities(raw),36    metadata: {37      architecture: raw.architecture?.modality,38      tokenizer: raw.architecture?.tokenizer,39      createdAt: raw.created,40      raw,41    },42  };43}4445/** Fetch and normalize the full OpenRouter model catalog. */46export async function fetchModels(signal?: AbortSignal): Promise<ModelDefinition[]> {47  const json = await orGet("/models", signal);48  return parseModelsResponse(json).map(normalizeModel);49}50