mirror of
https://github.com/hex248/sprint.git
synced 2026-02-07 18:23:03 +00:00
/ai/models route
This commit is contained in:
@@ -33,11 +33,13 @@ const withGlobalAuthed = <T extends BunRequest>(handler: RouteHandler<T>) =>
|
|||||||
const main = async () => {
|
const main = async () => {
|
||||||
const server = Bun.serve({
|
const server = Bun.serve({
|
||||||
port: Number(PORT),
|
port: Number(PORT),
|
||||||
|
idleTimeout: 60, // 1 minute for AI chat responses
|
||||||
routes: {
|
routes: {
|
||||||
"/": withGlobal(() => new Response(`title: tnirps\ndev-mode: ${DEV}\nport: ${PORT}`)),
|
"/": withGlobal(() => new Response(`title: tnirps\ndev-mode: ${DEV}\nport: ${PORT}`)),
|
||||||
"/health": withGlobal(() => new Response("OK")),
|
"/health": withGlobal(() => new Response("OK")),
|
||||||
|
|
||||||
"/ai/chat": withGlobalAuthed(withAuth(routes.aiChat)),
|
"/ai/chat": withGlobalAuthed(withAuth(routes.aiChat)),
|
||||||
|
"/ai/models": withGlobalAuthed(withAuth(routes.aiModels)),
|
||||||
|
|
||||||
// routes that modify state require withCSRF middleware
|
// routes that modify state require withCSRF middleware
|
||||||
"/auth/register": withGlobal(routes.authRegister),
|
"/auth/register": withGlobal(routes.authRegister),
|
||||||
|
|||||||
8
packages/backend/src/routes/ai/models.ts
Normal file
8
packages/backend/src/routes/ai/models.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import type { AuthedRequest } from "../../auth/middleware";
|
||||||
|
import { getCachedFreeModels } from "./opencode";
|
||||||
|
|
||||||
|
// GET /ai/models - returns cached free models
|
||||||
|
export default function aiModels(_req: AuthedRequest) {
|
||||||
|
const models = getCachedFreeModels();
|
||||||
|
return Response.json(models);
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import aiChat from "./ai/chat";
|
import aiChat from "./ai/chat";
|
||||||
|
import aiModels from "./ai/models";
|
||||||
import authLogin from "./auth/login";
|
import authLogin from "./auth/login";
|
||||||
import authLogout from "./auth/logout";
|
import authLogout from "./auth/logout";
|
||||||
import authMe from "./auth/me";
|
import authMe from "./auth/me";
|
||||||
@@ -58,6 +59,7 @@ import userUploadAvatar from "./user/upload-avatar";
|
|||||||
|
|
||||||
export const routes = {
|
export const routes = {
|
||||||
aiChat,
|
aiChat,
|
||||||
|
aiModels,
|
||||||
|
|
||||||
authRegister,
|
authRegister,
|
||||||
authLogin,
|
authLogin,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { ChatRequest, ChatResponse } from "@sprint/shared";
|
import type { ChatRequest, ChatResponse, ModelsResponse } from "@sprint/shared";
|
||||||
import { useMutation } from "@tanstack/react-query";
|
import { useMutation } from "@tanstack/react-query";
|
||||||
import { apiClient } from "@/lib/server";
|
import { apiClient } from "@/lib/server";
|
||||||
|
|
||||||
@@ -13,3 +13,15 @@ export function useChatMutation() {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useModels() {
|
||||||
|
return useMutation<ModelsResponse, Error>({
|
||||||
|
mutationKey: ["ai", "models"],
|
||||||
|
mutationFn: async () => {
|
||||||
|
const { data, error } = await apiClient.aiModels();
|
||||||
|
if (error) throw new Error(error);
|
||||||
|
if (!data) throw new Error("failed to get models");
|
||||||
|
return data as ModelsResponse;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -683,3 +683,11 @@ export const ChatResponseSchema = z.object({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export type ChatResponse = z.infer<typeof ChatResponseSchema>;
|
export type ChatResponse = z.infer<typeof ChatResponseSchema>;
|
||||||
|
|
||||||
|
export const ModelsResponseSchema = z.array(
|
||||||
|
z.object({
|
||||||
|
name: z.string(),
|
||||||
|
id: z.string(),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
export type ModelsResponse = z.infer<typeof ModelsResponseSchema>;
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import {
|
|||||||
IssuesTypeCountQuerySchema,
|
IssuesTypeCountQuerySchema,
|
||||||
IssueUpdateRequestSchema,
|
IssueUpdateRequestSchema,
|
||||||
LoginRequestSchema,
|
LoginRequestSchema,
|
||||||
|
ModelsResponseSchema,
|
||||||
OrgAddMemberRequestSchema,
|
OrgAddMemberRequestSchema,
|
||||||
OrganisationMemberRecordSchema,
|
OrganisationMemberRecordSchema,
|
||||||
OrganisationMemberResponseSchema,
|
OrganisationMemberResponseSchema,
|
||||||
@@ -696,6 +697,15 @@ export const apiContract = c.router({
|
|||||||
404: ApiErrorSchema,
|
404: ApiErrorSchema,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
aiModels: {
|
||||||
|
method: "GET",
|
||||||
|
path: "/ai/models",
|
||||||
|
responses: {
|
||||||
|
200: ModelsResponseSchema,
|
||||||
|
400: ApiErrorSchema,
|
||||||
|
404: ApiErrorSchema,
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export type ApiContract = typeof apiContract;
|
export type ApiContract = typeof apiContract;
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ export type {
|
|||||||
IssuesTypeCountQuery,
|
IssuesTypeCountQuery,
|
||||||
IssueUpdateRequest,
|
IssueUpdateRequest,
|
||||||
LoginRequest,
|
LoginRequest,
|
||||||
|
ModelsResponse,
|
||||||
OrgAddMemberRequest,
|
OrgAddMemberRequest,
|
||||||
OrganisationMemberRecordType,
|
OrganisationMemberRecordType,
|
||||||
OrganisationMemberResponse,
|
OrganisationMemberResponse,
|
||||||
@@ -95,6 +96,7 @@ export {
|
|||||||
IssuesTypeCountQuerySchema,
|
IssuesTypeCountQuerySchema,
|
||||||
IssueUpdateRequestSchema,
|
IssueUpdateRequestSchema,
|
||||||
LoginRequestSchema,
|
LoginRequestSchema,
|
||||||
|
ModelsResponseSchema,
|
||||||
OrgAddMemberRequestSchema,
|
OrgAddMemberRequestSchema,
|
||||||
OrganisationMemberRecordSchema,
|
OrganisationMemberRecordSchema,
|
||||||
OrganisationMemberResponseSchema,
|
OrganisationMemberResponseSchema,
|
||||||
|
|||||||
Reference in New Issue
Block a user