mirror of
https://github.com/Jeuners/agenttwo-tools.git
synced 2026-09-09 23:12:31 +02:00
feat: Frontend im Produktionsbetrieb ausliefern, TTFT bei OpenRouter
npm start baute web/dist, aber niemand lieferte es aus — der Server stellte nur die API bereit. Jetzt registriert er @fastify/static, wenn ein Build vorliegt, und die App läuft komplett unter :8788. Ohne web/dist bleibt alles wie bisher (Vite übernimmt im Dev-Betrieb); der Start sagt, welcher Fall vorliegt. /api und /ws behalten Vorrang, unbekannte /api-Pfade antworten weiterhin mit JSON statt mit index.html. OpenRouter, beim Verifizieren gegen ein Gratis-Modell gefunden: - ttftMs wurde nie gesetzt — evalMs wurde aus firstTokenAt gerechnet, das Feld selbst blieb null - die Zeitmessung startete erst nach dem fetch und ließ damit die Wartezeit auf den Anbieter aus. Startet jetzt davor, wie bei Ollama Geprüft im Produktionsmodus: /, /assets/*.js, SPA-Fallback, JSON-404 auf /api, WebSocket aus Origin :8788 und :5174 verbunden, fremde Origin 403. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015AUP4R3rgq4XwVs4bVf7uh
This commit is contained in:
parent
ed3c01303b
commit
da1d8be426
5 changed files with 309 additions and 9 deletions
|
|
@ -11,6 +11,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@fastify/cors": "^10.0.1",
|
||||
"@fastify/static": "^10.1.3",
|
||||
"defuddle": "^0.19.3",
|
||||
"fastify": "^5.2.1",
|
||||
"linkedom": "^0.18.13",
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import Fastify from "fastify";
|
||||
import cors from "@fastify/cors";
|
||||
import fastifyStatic from "@fastify/static";
|
||||
import { WebSocketServer, WebSocket } from "ws";
|
||||
import type { IncomingMessage } from "node:http";
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { existsSync, readFileSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
import * as dbmod from "./db.js";
|
||||
import * as mem from "./memory.js";
|
||||
|
|
@ -309,6 +310,25 @@ app.get("/api/ollama/models", async () => {
|
|||
}
|
||||
});
|
||||
|
||||
// --- Gebautes Frontend ---
|
||||
//
|
||||
// Nur wenn web/dist existiert: im Entwicklungsbetrieb liefert der
|
||||
// Vite-Server das Frontend aus, dann soll hier nichts danebenstehen.
|
||||
// Registrierung nach den API-Routen, damit /api und /ws Vorrang behalten.
|
||||
const WEB_DIST = path.join(import.meta.dirname, "..", "..", "web", "dist");
|
||||
const hasBuild = existsSync(path.join(WEB_DIST, "index.html"));
|
||||
|
||||
if (hasBuild) {
|
||||
await app.register(fastifyStatic, { root: WEB_DIST });
|
||||
app.setNotFoundHandler((req, reply) => {
|
||||
// API-Fehler bleiben JSON; alles andere bekommt die App.
|
||||
if (req.url.startsWith("/api")) {
|
||||
return reply.code(404).send({ error: "not found" });
|
||||
}
|
||||
return reply.sendFile("index.html");
|
||||
});
|
||||
}
|
||||
|
||||
// --- WebSocket ---
|
||||
interface ChatOptionsPayload {
|
||||
think: boolean;
|
||||
|
|
@ -677,4 +697,9 @@ server.on("upgrade", (req, socket, head) => {
|
|||
|
||||
app.listen({ port: PORT, host: "127.0.0.1" }, () => {
|
||||
console.log(`[agenttwo-tools] Server läuft auf http://127.0.0.1:${PORT}`);
|
||||
console.log(
|
||||
hasBuild
|
||||
? "[agenttwo-tools] Frontend aus web/dist wird mit ausgeliefert"
|
||||
: "[agenttwo-tools] Kein web/dist — Frontend über 'npm run dev:web' (:5174)",
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -76,6 +76,10 @@ export async function streamOpenRouter(
|
|||
cb: StreamCallbacks,
|
||||
signal: AbortSignal,
|
||||
): Promise<void> {
|
||||
// Vor dem fetch: TTFT soll die Wartezeit auf den Anbieter enthalten, nicht
|
||||
// erst ab dem Eintreffen der Antwort-Header zählen (so misst es auch Ollama).
|
||||
const startedAt = Date.now();
|
||||
|
||||
const res = await fetch("https://openrouter.ai/api/v1/chat/completions", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
|
|
@ -108,7 +112,6 @@ export async function streamOpenRouter(
|
|||
const decoder = new TextDecoder();
|
||||
let buffer = "";
|
||||
|
||||
const startedAt = Date.now();
|
||||
let firstTokenAt: number | null = null;
|
||||
const stats: ChatStats = {
|
||||
promptTokens: 0,
|
||||
|
|
@ -125,6 +128,7 @@ export async function streamOpenRouter(
|
|||
*/
|
||||
function finish(): void | Promise<void> {
|
||||
stats.totalMs = Date.now() - startedAt;
|
||||
stats.ttftMs = firstTokenAt === null ? null : firstTokenAt - startedAt;
|
||||
stats.evalMs = firstTokenAt === null ? 0 : Date.now() - firstTokenAt;
|
||||
return cb.onStats?.(stats);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue