ts import { PromptValidation, CharacterWarning } from '@/types' import { CHARACTER_LIMITS } from './constants' /** * Validates user prompt input * @param prompt - The prompt to validate * @returns Validation result with errors, warnings, and suggestions */ export function validatePrompt(prompt: string): PromptValidation { const trimmedPrompt = prompt.trim() const errors: string[] = [] const warnings: string[] = [] const suggestions: string[] = [] // Check for empty or very short prompts if (trimmedPrompt.length === 0) { suggestions.push('Gib hier deinen Prompt ein, den du optimieren möchtest...') } else if (trimmedPrompt.length < CHARACTER_LIMITS.MINIMUM) { warnings.push('Prompt ist sehr kurz. Mehr Details können zu besseren Ergebnissen führen.') suggestions.push('Erwäge folgende Elemente hinzuzufügen:') suggestions.push('• Kontext und Hintergrundinformationen') suggestions.push('• Spezifische Anforderungen') suggestions.push('• Gewünschtes Ausgabeformat') } // Check for questionable content if (isQuestionablePrompt(trimmedPrompt)) { warnings.push('Prompt enthält nur Fragenzeichen oder ist unklar formuliert.') suggestions.push('Formuliere deine Anfrage als klare Anweisung:') suggestions.push('• Verwende aktive Sprache ("Erstelle..." statt "Kannst du erstellen...")') suggestions.push('• Sei spezifisch über das gewünschte Ergebnis') suggestions.push('• Füge Beispiele oder Referenzen hinzu') } // Check character limits if (trimmedPrompt.length > CHARACTER_LIMITS.INPUT) { errors.push(`Prompt überschreitet die maximale Länge von ${CHARACTER_LIMITS.INPUT} Zeichen.`) } else if (trimmedPrompt.length > CHARACTER_LIMITS.WARNING) { warnings.push(`Prompt ist sehr lang (${trimmedPrompt.length} Zeichen). Einige KIs haben Token-Limits.`) } // Check for control characters if (hasControlCharacters(trimmedPrompt)) { warnings.push('Prompt enthält Steuerzeichen, die entfernt wurden.') } // Check for repetitive content if (isRepetitiveContent(trimmedPrompt)) { warnings.push('Prompt scheint repetitive Inhalte zu haben.') suggestions.push('Entferne Wiederholungen für klarere Anweisungen.') } // Check for proper structure for different prompt types const structureSuggestions = analyzePromptStructure(trimmedPrompt) suggestions.push(...structureSuggestions) return { isValid: errors.length === 0 && trimmedPrompt.length > 0, errors, warnings, suggestions } } /** * Sanitizes prompt input by removing unwanted characters * @param prompt - The prompt to sanitize * @returns Sanitized prompt */ export function sanitizePrompt(prompt: string): string { return prompt .replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, '') // Remove control characters .replace(/\r\n/g, '\n') // Normalize line endings .replace(/\t/g, ' ') // Replace tabs with spaces .replace(/[^\S\n]+$/gm, '') // Remove trailing spaces .trim() } /** * Checks if prompt contains only question marks or similar unclear content */ function isQuestionablePrompt(prompt: string): boolean { const cleaned = prompt.toLowerCase().replace(/[^?]/g, '') const questionMarkRatio = cleaned.length / Math.max(prompt.length, 1) return questionMarkRatio > 0.7 || prompt.length < 10 || /^\?+$/.test(prompt.trim()) } /** * Checks for control characters in prompt */ function hasControlCharacters(prompt: string): boolean { return /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/.test(prompt) } /** * Checks for repetitive content patterns */ function isRepetitiveContent(prompt: string): boolean { const words = prompt.toLowerCase().split(/\s+/) const wordCount = words.length const uniqueWords = new Set(words).size // If less than 30% unique words, likely repetitive return wordCount > 10 && (uniqueWords / wordCount) < 0.3 } /** * Analyzes prompt structure and suggests improvements */ function analyzePromptStructure(prompt: string): string[] { const suggestions: string[] = [] // Check for missing role/context/task structure const hasRole = /^(du bist|sie sind|you are|act as|role:|als)/i.test(prompt) const hasContext = /^(kontext|context|background:|background situation:|bei)/i.test(prompt) const hasTask = /^(aufgabe|task|erstelle|erstellen|create|schreibe|write)/i.test(prompt) if (!hasRole && !hasContext && !hasTask && prompt.length > 50) { suggestions.push('Strukturiere deinen Prompt nach dem Schema:') suggestions.push('1. Rolle (wer bist du?)') suggestions.push('2. Kontext (worüber?)') suggestions.push('3. Aufgabe (was ist zu tun?)') } // Check for missing output format specification const hasOutputFormat = /(formatiere|format|ausgabe als|output as|strukturiere)/i.test(prompt) if (!hasOutputFormat && prompt.length > 100) { suggestions.push('Spezifiziere das gewünschte Ausgabeformat:') suggestions.push('• Liste, Tabelle, Absatz, JSON, etc.') suggestions.push('• Gewünschte Länge (kurz, detailliert, etc.)') } return suggestions } /** * Estimates token count from character count */ export function estimateTokenCount(characterCount: number): number { return Math.ceil(characterCount / CHARACTER_LIMITS.TOKEN_ESTIMATE_FACTOR) } /** * Gets character count warnings */ export function getCharacterWarnings(count: number): CharacterWarning[] { const warnings: CharacterWarning[] = [] if (count === 0) return warnings if (count < CHARACTER_LIMITS.MINIMUM) { warnings.push({ type: 'warning', message: 'Prompt ist sehr kurz. Erwäge mehr Details hinzuzufügen.' }) } if (count > CHARACTER_LIMITS.WARNING) { warnings.push({ type: 'warning', message: `Achtung: Sehr langer Prompt (${count} Zeichen) könnte Token-Limits überschreiten.`, threshold: CHARACTER_LIMITS.WARNING }) } if (count > CHARACTER_LIMITS.INPUT) { warnings.push({ type: 'error', message: `Prompt überschreitet die maximale Länge von ${CHARACTER_LIMITS.INPUT} Zeichen.` }) } return warnings }