videofolxtv/server/aiService.ts
sebastjanartic 6b80ac00c6 Improve AI description generation to prevent repetitive content and support German
Enhance the AI service to include memory for previously generated descriptions, implement German language support for prompts, and refine prompt instructions to avoid mentioning unknown information.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 170e18f0-0f13-4eca-8643-546bba1dd8cc
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/8cc42625-c1f5-4e43-99bd-77f2c4dedee2/170e18f0-0f13-4eca-8643-546bba1dd8cc/LY6xmBI
2025-09-02 13:16:05 +00:00

144 lines
5.1 KiB
TypeScript

import OpenAI from "openai";
// the newest OpenAI model is "gpt-5" which was released August 7, 2025. do not change this unless explicitly requested by the user
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
// Memory for generated descriptions to avoid repetition
const generatedDescriptions = new Map<string, Set<string>>();
function getArtistFromTitle(title: string): string {
// Extract artist name from title (everything before the first " - ")
const match = title.match(/^([^-]+)/);
return match ? match[1].trim() : "";
}
function addToMemory(artist: string, description: string) {
if (!generatedDescriptions.has(artist)) {
generatedDescriptions.set(artist, new Set());
}
generatedDescriptions.get(artist)!.add(description);
}
function getPreviousDescriptions(artist: string): string[] {
return Array.from(generatedDescriptions.get(artist) || []);
}
export interface DescriptionGenerationOptions {
maxCharacters?: number;
language?: string;
includeArtistInfo?: boolean;
includeLabelInfo?: boolean;
}
export async function generateVideoDescription(
title: string,
options: DescriptionGenerationOptions = {}
): Promise<string> {
const {
maxCharacters = 500,
language = "slovenian",
includeArtistInfo = true,
includeLabelInfo = true
} = options;
try {
// Extract artist name for memory checking
const artist = getArtistFromTitle(title);
const previousDescriptions = getPreviousDescriptions(artist);
const avoidRepetition = previousDescriptions.length > 0
? `\n\nWICHTIG: Für diesen Künstler wurden bereits folgende Beschreibungen erstellt:\n${previousDescriptions.map((desc, i) => `${i+1}. ${desc.substring(0, 100)}...`).join('\n')}\n\nErstelle eine VÖLLIG ANDERE Beschreibung mit anderen Worten, Fokus und Stil.`
: '';
const prompt = `Analysiere diesen Musikvideo-Titel: "${title}"
Schreibe auf DEUTSCH eine informative Beschreibung.
Aus dem Titel extrahieren:
- Name des Interpreten/Künstlers
- Titel des Liedes/Stücks
- Art des Inhalts (Lied, Instrumental, Live-Auftritt, etc.)
Erstelle eine informative Beschreibung, die Folgendes beinhaltet:
${includeArtistInfo ? '- Informationen über den Interpreten (Musikstil, kurze Geschichte, bekannte Stücke)' : ''}
- Beschreibung des Musikstils und Genres
- Kurzer Hintergrund zum Stück, falls bekannt
- Wofür es gedacht ist (Tanz, Zuhören, Konzert, etc.)
NUR wenn du SICHERE Informationen hast, erwähne:
${includeLabelInfo ? '- Label/Plattenfirma (nur wenn du es sicher weißt)' : ''}
Wenn du keine sicheren Informationen zu einem Punkt hast, lasse ihn WEG. Schreibe NIEMALS "Label unbekannt" oder ähnliches.
Die Beschreibung soll maximal ${maxCharacters} Zeichen lang sein.
Schreibe in einem freundlichen, informativen Ton.
Verwende nicht die Wörter "Video" oder "Aufnahme" - schreibe über die Musik selbst.
Schreibe nur die Beschreibung, keine zusätzlichen Erklärungen.${avoidRepetition}";`
console.log("Sending request to OpenAI with title:", title); // Debug log
const response = await openai.chat.completions.create({
model: "gpt-4o", // Use gpt-4o instead of gpt-5 for better reliability
messages: [
{
role: "system",
content: "Du bist ein Musikexperte und hilfst bei der Erstellung hochwertiger Beschreibungen für Musikinhalte. Du antwortest immer auf Deutsch und vermeidest Wiederholungen."
},
{
role: "user",
content: prompt
}
],
max_tokens: Math.ceil(maxCharacters / 2), // Use max_tokens for gpt-4o
temperature: 0.7, // gpt-4o supports temperature
});
console.log("OpenAI response received:", response.choices[0]?.message?.content); // Debug log
const description = response.choices[0].message.content?.trim() || "";
// Add to memory for this artist
if (artist && description) {
addToMemory(artist, description);
}
console.log("Generated description:", description); // Debug log
// Ensure we don't exceed character limit
if (description.length > maxCharacters) {
return description.substring(0, maxCharacters - 3) + "...";
}
return description;
} catch (error: any) {
console.error("Error generating video description:", error);
console.error("Error details:", error?.message || error); // More detailed error logging
throw new Error("Napaka pri generiranju opisa s strani AI");
}
}
export async function generateBulkDescriptions(
videos: Array<{ id: string; title: string }>,
options: DescriptionGenerationOptions = {}
): Promise<Array<{ id: string; description: string; error?: string }>> {
const results = [];
for (const video of videos) {
try {
const description = await generateVideoDescription(video.title, options);
results.push({ id: video.id, description });
// Add small delay to respect API rate limits
await new Promise(resolve => setTimeout(resolve, 100));
} catch (error) {
results.push({
id: video.id,
description: "",
error: error instanceof Error ? error.message : "Unknown error"
});
}
}
return results;
}