voxblog/apps/api/src/utils/responseParser.ts
Ender c69863a593 refactor: restructure AI generation into modular architecture
- 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
2025-10-25 21:13:42 +02:00

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();
}