diff --git a/backend/src/business/ai/AiService.ts b/backend/src/business/ai/AiService.ts index d2ee44c83..904c3cc1f 100644 --- a/backend/src/business/ai/AiService.ts +++ b/backend/src/business/ai/AiService.ts @@ -1,4 +1,5 @@ import OpenAI from 'openai'; +import * as Sentry from '@sentry/node'; import createStoryTitlePrompt from './createStoryTitlePrompt'; const openai = new OpenAI({ @@ -7,9 +8,36 @@ const openai = new OpenAI({ }); export async function suggestStoryTitle(storyContent: string): Promise { - const response = await openai.chat.completions.create( - createStoryTitlePrompt(storyContent) - ); + const prompt = createStoryTitlePrompt(storyContent); + const model = typeof prompt.model === 'string' ? prompt.model : 'unknown'; + const aiSpan = Sentry.getCurrentHub() + .getScope() + ?.getTransaction() + ?.startChild({ + op: 'gen_ai.request', + description: `OpenAI chat completion (${model})`, + }); + aiSpan?.setData('gen_ai.request.model', model); - return response.choices[0].message.content?.trim() ?? ''; + try { + const response = await openai.chat.completions.create(prompt); + + if (response.usage) { + aiSpan?.setData( + 'gen_ai.usage.input_tokens', + response.usage.prompt_tokens + ); + aiSpan?.setData( + 'gen_ai.usage.output_tokens', + response.usage.completion_tokens + ); + } + + return response.choices[0].message.content?.trim() ?? ''; + } catch (error) { + aiSpan?.setStatus('internal_error'); + throw error; + } finally { + aiSpan?.finish(); + } }