import api from '../../api'; import type { AiApiResponse, AiAttachment, AiConversation, AiMessageFeedback, AiMessagePage, AiSkill, } from './types'; const basePath = '/ai/chat/conversations'; export const aiChatApi = { listSkills: async () => (await api.get>('/ai/chat/skills')).data, listConversations: async () => (await api.get>(basePath)).data, createConversation: async (input?: { title?: string; lockedSkillKey?: string | null }) => (await api.post>(basePath, input ?? {})).data, updateConversation: async ( id: number, input: { title?: string; lockedSkillKey?: string | null }, ) => (await api.patch>(`${basePath}/${id}`, input)).data, deleteConversation: (id: number) => api.delete(`${basePath}/${id}`), uploadAttachment: async (file: File): Promise => { const form = new FormData(); form.append('file', file); return ( await api.post>('/ai/chat/attachments', form, { headers: { 'Content-Type': 'multipart/form-data' }, timeout: 120_000, }) ).data; }, deleteAttachment: (id: number) => api.delete(`/ai/chat/attachments/${id}`), setFeedback: async ( messageId: number, feedback: AiMessageFeedback, reason?: string, ) => ( await api.patch>( `/ai/chat/messages/${messageId}/feedback`, { feedback, reason }, ) ).data, listMessages: async (id: number): Promise => { const first = ( await api.get>(`${basePath}/${id}/messages`, { params: { page: 1, limit: 100 }, }) ).data; const pageCount = Math.ceil(first.total / first.limit); if (pageCount <= 1) return first; const rest = await Promise.all( Array.from({ length: pageCount - 1 }, (_, index) => api .get>(`${basePath}/${id}/messages`, { params: { page: index + 2, limit: first.limit }, }) .then((response) => response.data), ), ); return { ...first, items: [first, ...rest].flatMap((page) => page.items) }; }, }; export function conversationStreamUrl(id: number): string { return `/api${basePath}/${id}/stream`; } export function regenerateStreamUrl(conversationId: number, messageId: number): string { return `/api${basePath}/${conversationId}/messages/${messageId}/regenerate/stream`; }