integratedhub/utils/normalizeQuestionMedia.ts
2026-01-20 09:02:26 -06:00

89 lines
2.7 KiB
TypeScript

// utils/normalizeQuestionMedia.ts
// Shared helper for normalizing media URLs in quiz questions.
// Call before saving to KV/SQL to ensure consistent data format.
import { hashText } from "../services/stateMiddleware.ts";
/**
* Question structure with media fields
*/
export interface QuizQuestion {
id: string;
text_1: string;
text_2: string;
background_file: string;
background_image_data: string;
audio_file_1: string;
audio_file_2: string;
}
/**
* Normalizes media URLs in a question to the expected local format.
* Call this BEFORE saving to KV/SQL to ensure consistent data.
*
* Expected output formats:
* - background_image_data: "/api/ai-images/file/{filename}" or "/api/image-blob/{hashName}" or base64
* (legacy http URLs are left unchanged - they'll be handled by the serving layer)
* - audio_file_1/2: "{hashName}" or "{hashName}.webm" (just the hash, not a URL)
*
* Note: background_file stores the user's description (not a filename).
* The actual filename is embedded in the background_image_data URL path.
*
* @param question - The question object to normalize (mutated in place)
* @returns true if any field was modified
*/
export async function normalizeQuestionMedia(
question: QuizQuestion | null | undefined,
): Promise<boolean> {
let changed = false;
if (!question) {
return false;
}
// Note: We no longer try to derive background_image_data from background_file
// because background_file now stores the user's description, not a filename.
// Legacy http URLs in background_image_data are left as-is.
// New images should already have correct /api/... URLs when saved.
// Normalize audio_file_1
if (question.text_1 && question.audio_file_1) {
if (question.audio_file_1.startsWith("http")) {
// Convert to hash-based local reference
const hash = await hashText(question.id + ":" + question.text_1);
question.audio_file_1 = hash + "";
changed = true;
}
}
// Normalize audio_file_2
if (question.text_2 && question.audio_file_2) {
if (question.audio_file_2.startsWith("http")) {
const hash = await hashText(question.id + ":" + question.text_2);
question.audio_file_2 = hash + "";
changed = true;
}
}
return changed;
}
/**
* Normalizes all questions in a quiz config.
* @param questions - Array of questions to normalize (mutated in place)
* @returns true if any question was modified
*/
export async function normalizeQuizMedia(
questions: Array<QuizQuestion | null | undefined>,
): Promise<boolean> {
let anyChanged = false;
for (const question of questions) {
if (!question) continue;
const changed = await normalizeQuestionMedia(question);
anyChanged = anyChanged || changed;
}
return anyChanged;
}