import type OpenAI from 'openai' import { SSE } from 'sse.js' import { type Message } from './utils' import { BASE_PATH } from '../shared/constants' /** * Perform a one-off query to AI based on a snapshot of messages */ export function queryAi(messages: Message[], timeout = 0) { return new Promise((resolve, reject) => { const eventSource = new SSE(`${BASE_PATH}/api/ai/docs`, { headers: { apikey: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY ?? '', Authorization: `Bearer ${process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY}`, 'Content-Type': 'application/json', }, payload: JSON.stringify({ messages: messages.map(({ role, content }) => ({ role, content })), }), }) let timeoutId: number | undefined function handleError(err: T) { if (timeoutId) { clearTimeout(timeoutId) } console.error(err) reject(err) } if (timeout > 0) { timeoutId = window.setTimeout(() => { handleError(new Error('AI query timed out')) }, timeout) } let answer = '' eventSource.addEventListener('error', handleError) eventSource.addEventListener('message', (e: MessageEvent) => { try { if (e.data === '[DONE]') { if (timeoutId) { clearTimeout(timeoutId) } resolve(answer) return } const completionChunk: OpenAI.Chat.Completions.ChatCompletionChunk = JSON.parse(e.data) const [ { delta: { content }, }, ] = completionChunk.choices if (content) { answer += content } } catch (err) { handleError(err) } }) eventSource.stream() }) }