- Split monolithic ai-generate.ts (453 lines) into 12 focused modules with clear responsibilities - Created new directory structure with routes, services, utils, types, and config folders - Implemented AIService orchestrator with specialized generators for content, metadata, and alt text - Added centralized prompt templates and error handling - Set up parallel routing to allow gradual migration from old implementation
64 lines
1.7 KiB
TypeScript
64 lines
1.7 KiB
TypeScript
import { ResponsesAPIOutput, Source } from '../types/ai.types';
|
|
|
|
/**
|
|
* Parse JSON response from AI, handling markdown code blocks
|
|
*/
|
|
export function parseJSONResponse<T>(response: string): T {
|
|
const cleaned = response
|
|
.replace(/```json\n?/g, '')
|
|
.replace(/```\n?/g, '')
|
|
.trim();
|
|
return JSON.parse(cleaned);
|
|
}
|
|
|
|
/**
|
|
* Extract source citations from chat completion annotations
|
|
*/
|
|
export function extractSourceCitations(completion: any): Source[] {
|
|
const sources: Source[] = [];
|
|
|
|
if (completion.choices?.[0]?.message?.annotations) {
|
|
const annotations = completion.choices[0].message.annotations as any[];
|
|
for (const annotation of annotations) {
|
|
if (annotation.type === 'url_citation' && annotation.url_citation) {
|
|
sources.push({
|
|
title: annotation.url_citation.title || 'Source',
|
|
url: annotation.url_citation.url,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
return sources;
|
|
}
|
|
|
|
/**
|
|
* Parse output from Responses API
|
|
*/
|
|
export function parseResponsesAPIOutput(response: ResponsesAPIOutput): string {
|
|
// Try direct output_text field first
|
|
if (typeof response.output_text === 'string' && response.output_text.length > 0) {
|
|
return response.output_text;
|
|
}
|
|
|
|
// Fallback to parsing output array
|
|
if (Array.isArray(response.output)) {
|
|
const msg = response.output.find((o: any) => o.type === 'message');
|
|
if (msg && Array.isArray(msg.content)) {
|
|
const textPart = msg.content.find((c: any) => c.type === 'output_text');
|
|
if (textPart?.text) {
|
|
return textPart.text;
|
|
}
|
|
}
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* Strip HTML tags from content
|
|
*/
|
|
export function stripHtmlTags(html: string): string {
|
|
return html.replace(/<[^>]*>/g, ' ').replace(/\s+/g, ' ').trim();
|
|
}
|