File size: 6,160 Bytes
eee3ce2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
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
}

</html>