191 lines · 5.7 KB · TypeScript
RawDownload
// CRITICALimport { Hono } from "hono";import { swaggerUI } from "@hono/swagger-ui";import { cors } from "hono/cors";import type { AppContext } from "../types/context";import { isHttpStatus } from "../core/errors";import { registerChatsRoutes } from "../routes/chats";import { registerLifecycleRoutes } from "../routes/lifecycle";import { registerLogsRoutes } from "../routes/logs";import { registerMcpRoutes } from "../routes/mcp";import { registerModelsRoutes } from "../routes/models";import { registerMonitoringRoutes } from "../routes/monitoring";import { registerProxyRoutes } from "../routes/proxy";import { registerProxyRoutesDebug } from "../routes/proxy-debug";import { registerSystemRoutes } from "../routes/system";import { registerUsageRoutes } from "../routes/usage";import { registerTokenizationRoutes } from "../routes/tokenization"; /** * Create the Hono application. * @param context - App context. * @returns Hono app instance. */export const createApp = (context: AppContext): Hono => {  const app = new Hono();   app.use("*", cors({    origin: "*",    allowMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],    allowHeaders: ["*"],  }));   app.use("*", async (ctx, next) => {    const skip = new Set(["/health", "/metrics", "/events", "/status", "/api/docs", "/api/spec"]);    if (!skip.has(ctx.req.path)) {      context.logger.debug(`${ctx.req.method} ${ctx.req.path}`);    }    await next();  });   // Register all routes  registerSystemRoutes(app, context);  registerModelsRoutes(app, context);  registerLifecycleRoutes(app, context);  registerChatsRoutes(app, context);  registerLogsRoutes(app, context);  registerMonitoringRoutes(app, context);  registerMcpRoutes(app, context);  registerProxyRoutes(app, context);  registerProxyRoutesDebug(app, context);  registerUsageRoutes(app, context);  registerTokenizationRoutes(app, context);   // OpenAPI documentation endpoints  app.get("/api/spec", (ctx) => {    return ctx.json({      openapi: "3.1.0",      info: {        title: "vLLM Studio API",        version: "0.3.1",        description: "Model lifecycle management for vLLM, SGLang, and TabbyAPI inference servers",      },      servers: [        {          url: `http://localhost:${context.config.port}`,          description: "Local development server",        },      ],      paths: {        "/health": {          get: {            summary: "Health check",            description: "Check if the controller and inference backend are healthy",            responses: {              "200": {                description: "Service is healthy",                content: {                  "application/json": {                    schema: {                      type: "object",                      properties: {                        status: { type: "string", enum: ["ok"] },                        version: { type: "string" },                        inference_ready: { type: "boolean" },                        backend_reachable: { type: "boolean" },                        running_model: { type: ["string", "null"] },                      },                    },                  },                },              },            },          },        },        "/status": {          get: {            summary: "Get status",            description: "Get current status of the inference backend",            responses: {              "200": {                description: "Status information",              },            },          },        },        "/gpus": {          get: {            summary: "List GPUs",            description: "Get GPU information including memory, utilization, temperature",            responses: {              "200": {                description: "GPU list",              },            },          },        },        "/recipes": {          get: {            summary: "List recipes",            description: "Get all model launch recipes",            responses: {              "200": {                description: "Recipe list",              },            },          },          post: {            summary: "Create recipe",            description: "Create a new model launch recipe",            responses: {              "201": {                description: "Recipe created",              },            },          },        },        "/launch/{recipe_id}": {          post: {            summary: "Launch model",            description: "Launch a model from a recipe",            parameters: [              {                name: "recipe_id",                in: "path",                required: true,                schema: { type: "string" },              },            ],            responses: {              "200": {                description: "Model launched",              },            },          },        },        "/chats": {          get: {            summary: "List chat sessions",            responses: {              "200": {                description: "Chat list",              },            },          },          post: {            summary: "Create chat session",            responses: {              "201": {                description: "Chat created",              },            },          },        },      },    });  });   app.get("/api/docs", swaggerUI({ url: "/api/spec" }));   app.notFound((ctx) => ctx.json({ detail: "Not Found" }, { status: 404 }));   app.onError((error, ctx) => {    if (isHttpStatus(error)) {      return ctx.json({ detail: error.detail }, { status: error.status });    }    context.logger.error("Unhandled error", { error: String(error) });    return ctx.json({ detail: "Internal Server Error" }, { status: 500 });  });   return app;};