@djangocfg/llm 2.1.164
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +181 -0
- package/dist/index.cjs +1164 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +164 -0
- package/dist/index.d.ts +164 -0
- package/dist/index.mjs +1128 -0
- package/dist/index.mjs.map +1 -0
- package/dist/providers/index.cjs +317 -0
- package/dist/providers/index.cjs.map +1 -0
- package/dist/providers/index.d.cts +30 -0
- package/dist/providers/index.d.ts +30 -0
- package/dist/providers/index.mjs +304 -0
- package/dist/providers/index.mjs.map +1 -0
- package/dist/sdkrouter-D8GMBmTi.d.ts +171 -0
- package/dist/sdkrouter-hlQlVd0v.d.cts +171 -0
- package/dist/text-utils-DoYqMIr6.d.ts +289 -0
- package/dist/text-utils-VXWN-8Oq.d.cts +289 -0
- package/dist/translator/index.cjs +794 -0
- package/dist/translator/index.cjs.map +1 -0
- package/dist/translator/index.d.cts +24 -0
- package/dist/translator/index.d.ts +24 -0
- package/dist/translator/index.mjs +769 -0
- package/dist/translator/index.mjs.map +1 -0
- package/dist/types-D6lazgm1.d.cts +59 -0
- package/dist/types-D6lazgm1.d.ts +59 -0
- package/package.json +82 -0
- package/src/client.ts +119 -0
- package/src/index.ts +70 -0
- package/src/providers/anthropic.ts +98 -0
- package/src/providers/base.ts +90 -0
- package/src/providers/index.ts +15 -0
- package/src/providers/openai.ts +73 -0
- package/src/providers/sdkrouter.ts +279 -0
- package/src/translator/cache.ts +237 -0
- package/src/translator/index.ts +55 -0
- package/src/translator/json-translator.ts +408 -0
- package/src/translator/prompts.ts +90 -0
- package/src/translator/text-utils.ts +148 -0
- package/src/translator/types.ts +112 -0
- package/src/translator/validator.ts +181 -0
- package/src/types.ts +85 -0
- package/src/utils/env.ts +67 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/json.ts +44 -0
- package/src/utils/schema.ts +153 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/translator/text-utils.ts","../../src/translator/validator.ts","../../src/utils/json.ts","../../src/translator/types.ts","../../src/translator/prompts.ts","../../src/translator/cache.ts","../../src/translator/json-translator.ts"],"names":["validatePlaceholders"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Text utilities for translation\n */\n\n/**\n * Check if text is technical content that shouldn't be translated\n */\nexport function isTechnicalContent(text: string): boolean {\n const trimmed = text.trim();\n\n // Empty or whitespace only\n if (!trimmed) return true;\n\n // URLs\n if (/^(https?:\\/\\/|\\/\\/|www\\.)/i.test(trimmed)) return true;\n\n // Email addresses\n if (/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(trimmed)) return true;\n\n // File paths (starts with / or contains common extensions)\n if (/^\\/[a-zA-Z]/.test(trimmed)) return true;\n if (/\\.(js|ts|tsx|jsx|json|css|scss|html|md|py|go|rs)$/i.test(trimmed)) return true;\n\n // Numbers only (including decimals and percentages)\n if (/^[\\d.,]+%?$/.test(trimmed)) return true;\n\n // Technical identifiers (SCREAMING_SNAKE_CASE)\n if (/^[A-Z][A-Z0-9_]*$/.test(trimmed)) return true;\n\n // Placeholders like {name}, {{var}}, %s, $1\n if (/^(\\{[^}]+\\}|\\{\\{[^}]+\\}\\}|%[sd]|\\$\\d+)$/.test(trimmed)) return true;\n\n // Single special characters\n if (/^[!@#$%^&*()_+\\-=\\[\\]{};':\"\\\\|,.<>\\/?]+$/.test(trimmed)) return true;\n\n return false;\n}\n\n/**\n * Check if text contains CJK characters (Chinese, Japanese, Korean)\n */\nexport function containsCJK(text: string): boolean {\n // CJK Unified Ideographs, Hiragana, Katakana, Hangul\n return /[\\u4e00-\\u9fff\\u3040-\\u309f\\u30a0-\\u30ff\\uac00-\\ud7af]/.test(text);\n}\n\n/**\n * Check if text contains Cyrillic characters\n */\nexport function containsCyrillic(text: string): boolean {\n return /[\\u0400-\\u04ff]/.test(text);\n}\n\n/**\n * Check if text contains Arabic characters\n */\nexport function containsArabic(text: string): boolean {\n return /[\\u0600-\\u06ff]/.test(text);\n}\n\n/**\n * Detect script/language from text\n */\nexport function detectScript(\n text: string\n): 'cjk' | 'cyrillic' | 'arabic' | 'latin' | 'unknown' {\n if (containsCJK(text)) return 'cjk';\n if (containsCyrillic(text)) return 'cyrillic';\n if (containsArabic(text)) return 'arabic';\n if (/[a-zA-Z]/.test(text)) return 'latin';\n return 'unknown';\n}\n\n/**\n * Extract placeholders from text\n */\nexport function extractPlaceholders(text: string): string[] {\n const patterns = [\n /\\{[^}]+\\}/g, // {name}\n /\\{\\{[^}]+\\}\\}/g, // {{name}}\n /%[sd]/g, // %s, %d\n /\\$\\d+/g, // $1, $2\n ];\n\n const placeholders: string[] = [];\n for (const pattern of patterns) {\n const matches = text.match(pattern);\n if (matches) {\n placeholders.push(...matches);\n }\n }\n\n return [...new Set(placeholders)];\n}\n\n/**\n * Check if all placeholders are preserved in translation\n */\nexport function validatePlaceholders(\n original: string,\n translated: string\n): { valid: boolean; missing: string[]; extra: string[] } {\n const originalPlaceholders = extractPlaceholders(original);\n const translatedPlaceholders = extractPlaceholders(translated);\n\n const missing = originalPlaceholders.filter(\n (p) => !translatedPlaceholders.includes(p)\n );\n const extra = translatedPlaceholders.filter(\n (p) => !originalPlaceholders.includes(p)\n );\n\n return {\n valid: missing.length === 0 && extra.length === 0,\n missing,\n extra,\n };\n}\n\n/**\n * Get values that need translation from JSON\n */\nexport function extractTranslatableValues(\n obj: unknown,\n path: string = ''\n): Array<{ path: string; value: string }> {\n const values: Array<{ path: string; value: string }> = [];\n\n if (typeof obj === 'string') {\n if (!isTechnicalContent(obj)) {\n values.push({ path, value: obj });\n }\n } else if (Array.isArray(obj)) {\n obj.forEach((item, index) => {\n values.push(\n ...extractTranslatableValues(item, path ? `${path}[${index}]` : `[${index}]`)\n );\n });\n } else if (obj !== null && typeof obj === 'object') {\n for (const [key, value] of Object.entries(obj)) {\n values.push(\n ...extractTranslatableValues(value, path ? `${path}.${key}` : key)\n );\n }\n }\n\n return values;\n}\n","/**\n * Translation validation\n */\n\nimport { extractPlaceholders } from './text-utils';\n\nexport interface ValidationResult {\n valid: boolean;\n errors: string[];\n}\n\n/**\n * Validate that JSON keys are not translated\n */\nexport function validateJsonKeys(\n original: unknown,\n translated: unknown,\n path: string = ''\n): ValidationResult {\n const errors: string[] = [];\n\n // Type check\n if (typeof original !== typeof translated) {\n errors.push(`Type mismatch at ${path || 'root'}: expected ${typeof original}, got ${typeof translated}`);\n return { valid: false, errors };\n }\n\n // Null check\n if (original === null || translated === null) {\n if (original !== translated) {\n errors.push(`Null mismatch at ${path || 'root'}`);\n }\n return { valid: errors.length === 0, errors };\n }\n\n // Array\n if (Array.isArray(original)) {\n if (!Array.isArray(translated)) {\n errors.push(`Expected array at ${path || 'root'}`);\n return { valid: false, errors };\n }\n\n if (original.length !== translated.length) {\n errors.push(\n `Array length mismatch at ${path || 'root'}: expected ${original.length}, got ${translated.length}`\n );\n }\n\n const minLen = Math.min(original.length, translated.length);\n for (let i = 0; i < minLen; i++) {\n const result = validateJsonKeys(\n original[i],\n translated[i],\n `${path}[${i}]`\n );\n errors.push(...result.errors);\n }\n\n return { valid: errors.length === 0, errors };\n }\n\n // Object\n if (typeof original === 'object') {\n if (typeof translated !== 'object' || Array.isArray(translated)) {\n errors.push(`Expected object at ${path || 'root'}`);\n return { valid: false, errors };\n }\n\n const origKeys = Object.keys(original as Record<string, unknown>);\n const transKeys = Object.keys(translated as Record<string, unknown>);\n\n // Check for missing keys\n for (const key of origKeys) {\n if (!transKeys.includes(key)) {\n errors.push(`Missing key: ${path ? `${path}.${key}` : key}`);\n }\n }\n\n // Check for extra keys (keys that were translated!)\n for (const key of transKeys) {\n if (!origKeys.includes(key)) {\n errors.push(\n `Unexpected key: ${path ? `${path}.${key}` : key} (key was translated?)`\n );\n }\n }\n\n // Recurse into matching keys\n for (const key of origKeys) {\n if (transKeys.includes(key)) {\n const result = validateJsonKeys(\n (original as Record<string, unknown>)[key],\n (translated as Record<string, unknown>)[key],\n path ? `${path}.${key}` : key\n );\n errors.push(...result.errors);\n }\n }\n\n return { valid: errors.length === 0, errors };\n }\n\n // Primitives (string, number, boolean) - no validation needed for structure\n return { valid: true, errors: [] };\n}\n\n/**\n * Validate that placeholders are preserved\n */\nexport function validatePlaceholders(\n original: unknown,\n translated: unknown,\n path: string = ''\n): ValidationResult {\n const errors: string[] = [];\n\n if (typeof original === 'string' && typeof translated === 'string') {\n const origPlaceholders = extractPlaceholders(original);\n const transPlaceholders = extractPlaceholders(translated);\n\n for (const placeholder of origPlaceholders) {\n if (!transPlaceholders.includes(placeholder)) {\n errors.push(\n `Missing placeholder \"${placeholder}\" at ${path || 'root'}`\n );\n }\n }\n\n for (const placeholder of transPlaceholders) {\n if (!origPlaceholders.includes(placeholder)) {\n errors.push(\n `Extra placeholder \"${placeholder}\" at ${path || 'root'}`\n );\n }\n }\n } else if (Array.isArray(original) && Array.isArray(translated)) {\n const minLen = Math.min(original.length, translated.length);\n for (let i = 0; i < minLen; i++) {\n const result = validatePlaceholders(\n original[i],\n translated[i],\n `${path}[${i}]`\n );\n errors.push(...result.errors);\n }\n } else if (\n typeof original === 'object' &&\n original !== null &&\n typeof translated === 'object' &&\n translated !== null\n ) {\n for (const key of Object.keys(original as Record<string, unknown>)) {\n if (key in (translated as Record<string, unknown>)) {\n const result = validatePlaceholders(\n (original as Record<string, unknown>)[key],\n (translated as Record<string, unknown>)[key],\n path ? `${path}.${key}` : key\n );\n errors.push(...result.errors);\n }\n }\n }\n\n return { valid: errors.length === 0, errors };\n}\n\n/**\n * Full validation of translation\n */\nexport function validateTranslation(\n original: unknown,\n translated: unknown\n): ValidationResult {\n const keyResult = validateJsonKeys(original, translated);\n const placeholderResult = validatePlaceholders(original, translated);\n\n return {\n valid: keyResult.valid && placeholderResult.valid,\n errors: [...keyResult.errors, ...placeholderResult.errors],\n };\n}\n","/**\n * JSON parsing utilities\n */\n\n/**\n * Extract JSON from LLM response (handles markdown code blocks)\n */\nexport function extractJson<T = unknown>(text: string): T {\n let jsonStr = text.trim();\n\n // Remove markdown code blocks\n if (jsonStr.startsWith('```json')) {\n jsonStr = jsonStr.slice(7);\n } else if (jsonStr.startsWith('```')) {\n jsonStr = jsonStr.slice(3);\n }\n\n if (jsonStr.endsWith('```')) {\n jsonStr = jsonStr.slice(0, -3);\n }\n\n jsonStr = jsonStr.trim();\n\n // Try to find JSON object or array\n const jsonStart = jsonStr.search(/[\\[{]/);\n const jsonEndBracket = jsonStr.lastIndexOf(']');\n const jsonEndBrace = jsonStr.lastIndexOf('}');\n const jsonEnd = Math.max(jsonEndBracket, jsonEndBrace);\n\n if (jsonStart !== -1 && jsonEnd !== -1) {\n jsonStr = jsonStr.slice(jsonStart, jsonEnd + 1);\n }\n\n try {\n return JSON.parse(jsonStr) as T;\n } catch (error) {\n throw new Error(\n `Failed to parse JSON from LLM response: ${error instanceof Error ? error.message : 'Unknown error'}\\n\\nResponse:\\n${text}`\n );\n }\n}\n\n// Re-export from translator validator for backwards compatibility\nexport { validateJsonKeys } from '../translator/validator';\n","/**\n * Translator types\n */\n\nimport type { LLMRequestOptions } from '../types';\n\n/**\n * Language code\n */\nexport type LanguageCode =\n | 'en'\n | 'ru'\n | 'ko'\n | 'ja'\n | 'zh'\n | 'de'\n | 'fr'\n | 'es'\n | 'it'\n | 'pt'\n | 'pt-BR'\n | 'ar'\n | 'nl'\n | 'tr'\n | 'pl'\n | 'sv'\n | 'no'\n | 'da'\n | 'uk'\n | 'hi'\n | string;\n\n/**\n * Language names map\n */\nexport const LANGUAGE_NAMES: Record<string, string> = {\n en: 'English',\n ru: 'Russian',\n ko: 'Korean',\n ja: 'Japanese',\n zh: 'Chinese',\n de: 'German',\n fr: 'French',\n es: 'Spanish',\n it: 'Italian',\n pt: 'Portuguese',\n 'pt-BR': 'Brazilian Portuguese',\n ar: 'Arabic',\n nl: 'Dutch',\n tr: 'Turkish',\n pl: 'Polish',\n sv: 'Swedish',\n no: 'Norwegian',\n da: 'Danish',\n uk: 'Ukrainian',\n hi: 'Hindi',\n};\n\n/**\n * Translation options\n */\nexport interface TranslateOptions extends LLMRequestOptions {\n /** Source language (default: 'en') */\n sourceLanguage?: LanguageCode;\n /** Max retries on validation failure */\n maxRetries?: number;\n /** Preserve placeholders like {name}, {{var}} */\n preservePlaceholders?: boolean;\n}\n\n/**\n * Translation result\n */\nexport interface TranslateResult<T> {\n /** Translated data */\n data: T;\n /** Whether translation is valid (keys preserved) */\n valid: boolean;\n /** Validation errors if any */\n errors: string[];\n /** Number of retries used */\n retries: number;\n /** Source language */\n sourceLanguage: string;\n /** Target language */\n targetLanguage: string;\n}\n\n/**\n * Batch translation item\n */\nexport interface BatchTranslateItem<T> {\n /** Data to translate */\n data: T;\n /** Target language */\n targetLanguage: LanguageCode;\n /** Options override */\n options?: TranslateOptions;\n}\n\n/**\n * Cache stats\n */\nexport interface CacheStats {\n memorySize: number;\n hits: number;\n misses: number;\n languagePairs: Array<{\n pair: string;\n translations: number;\n }>;\n}\n","/**\n * Translation prompts\n */\n\nimport { LANGUAGE_NAMES } from './types';\n\n/**\n * Get language name from code\n */\nexport function getLanguageName(code: string): string {\n return LANGUAGE_NAMES[code] ?? code;\n}\n\n/**\n * Build JSON translation prompt\n */\nexport function buildJsonTranslationPrompt(\n json: string,\n sourceLanguage: string,\n targetLanguage: string\n): string {\n const sourceName = getLanguageName(sourceLanguage);\n const targetName = getLanguageName(targetLanguage);\n\n return `Translate all string VALUES in this JSON from ${sourceName} to ${targetName}.\n\nRules:\n- Translate ALL string values to ${targetName}\n- Keep JSON keys unchanged (English)\n- Skip: URLs, emails, numbers, \"SKIP\"\n- Keep placeholders: {name}, {{var}}, %s\n\n${json}\n\nReturn ONLY the JSON with all values translated to ${targetName}:`;\n}\n\n/**\n * Build text translation prompt\n */\nexport function buildTextTranslationPrompt(\n text: string,\n sourceLanguage: string,\n targetLanguage: string\n): string {\n const sourceName = getLanguageName(sourceLanguage);\n const targetName = getLanguageName(targetLanguage);\n\n return `Translate from ${sourceName} to ${targetName}.\n\nRULES:\n1. Translate ONLY the text provided\n2. Preserve formatting, numbers, URLs\n3. Keep placeholders like {name}, {{var}} unchanged\n4. Return ONLY the translation, no explanations\n\nText: ${text}\n\nTranslation:`;\n}\n\n/**\n * Build retry prompt with errors\n */\nexport function buildRetryPrompt(\n originalJson: string,\n wrongJson: string,\n errors: string[],\n targetLanguage: string\n): string {\n const targetName = getLanguageName(targetLanguage);\n\n return `Your previous translation had errors. Fix them.\n\nERRORS FOUND:\n${errors.map((e) => `- ${e}`).join('\\n')}\n\nORIGINAL JSON:\n${originalJson}\n\nYOUR WRONG TRANSLATION:\n${wrongJson}\n\nFIX THE ERRORS. Remember:\n- JSON keys must stay in English\n- Only translate string values\n- Preserve all placeholders\n\nReturn ONLY the corrected JSON translated to ${targetName}:`;\n}\n","/**\n * Translation Cache Manager\n *\n * Two-level caching: memory + localStorage/file\n * Organized by language pairs for efficient lookup\n */\n\nimport crypto from 'crypto';\n\nexport interface CacheStats {\n memorySize: number;\n hits: number;\n misses: number;\n languagePairs: Array<{\n pair: string;\n translations: number;\n }>;\n}\n\n/**\n * Translation cache with memory + persistent storage\n */\nexport class TranslationCache {\n private memoryCache = new Map<string, string>();\n private cacheOrder: string[] = [];\n private hits = 0;\n private misses = 0;\n\n constructor(\n private maxMemorySize: number = 1000,\n private storage?: Storage // localStorage in browser, undefined in Node\n ) {}\n\n /**\n * Generate hash for text\n */\n private getTextHash(text: string): string {\n return crypto.createHash('md5').update(text).digest('hex');\n }\n\n /**\n * Get storage key for language pair\n */\n private getStorageKey(sourceLang: string, targetLang: string): string {\n return `translator:${sourceLang}-${targetLang}`;\n }\n\n /**\n * Load from persistent storage\n */\n private loadFromStorage(sourceLang: string, targetLang: string): Record<string, string> {\n if (!this.storage) return {};\n\n try {\n const key = this.getStorageKey(sourceLang, targetLang);\n const data = this.storage.getItem(key);\n return data ? JSON.parse(data) : {};\n } catch {\n return {};\n }\n }\n\n /**\n * Save to persistent storage\n */\n private saveToStorage(\n sourceLang: string,\n targetLang: string,\n cache: Record<string, string>\n ): void {\n if (!this.storage) return;\n\n try {\n const key = this.getStorageKey(sourceLang, targetLang);\n this.storage.setItem(key, JSON.stringify(cache));\n } catch {\n // Storage full or unavailable\n }\n }\n\n /**\n * Evict oldest entries if memory is full\n */\n private evictIfNeeded(): void {\n while (this.memoryCache.size >= this.maxMemorySize && this.cacheOrder.length > 0) {\n const oldestKey = this.cacheOrder.shift()!;\n this.memoryCache.delete(oldestKey);\n }\n }\n\n /**\n * Get translation from cache\n */\n get(text: string, sourceLang: string, targetLang: string): string | undefined {\n const textHash = this.getTextHash(text);\n const cacheKey = `${sourceLang}-${targetLang}:${textHash}`;\n\n // Check memory cache first\n if (this.memoryCache.has(cacheKey)) {\n this.hits++;\n return this.memoryCache.get(cacheKey);\n }\n\n // Check persistent storage\n const fileCache = this.loadFromStorage(sourceLang, targetLang);\n if (textHash in fileCache) {\n const translation = fileCache[textHash];\n // Store in memory cache\n this.evictIfNeeded();\n this.memoryCache.set(cacheKey, translation);\n this.cacheOrder.push(cacheKey);\n this.hits++;\n return translation;\n }\n\n this.misses++;\n return undefined;\n }\n\n /**\n * Store translation in cache\n */\n set(text: string, sourceLang: string, targetLang: string, translation: string): void {\n const textHash = this.getTextHash(text);\n const cacheKey = `${sourceLang}-${targetLang}:${textHash}`;\n\n // Store in memory cache\n this.evictIfNeeded();\n this.memoryCache.set(cacheKey, translation);\n if (!this.cacheOrder.includes(cacheKey)) {\n this.cacheOrder.push(cacheKey);\n }\n\n // Store in persistent storage\n const fileCache = this.loadFromStorage(sourceLang, targetLang);\n fileCache[textHash] = translation;\n this.saveToStorage(sourceLang, targetLang, fileCache);\n }\n\n /**\n * Get multiple translations at once\n */\n getMany(\n texts: string[],\n sourceLang: string,\n targetLang: string\n ): { cached: Map<string, string>; uncached: string[] } {\n const cached = new Map<string, string>();\n const uncached: string[] = [];\n\n for (const text of texts) {\n const translation = this.get(text, sourceLang, targetLang);\n if (translation !== undefined) {\n cached.set(text, translation);\n } else {\n uncached.push(text);\n }\n }\n\n return { cached, uncached };\n }\n\n /**\n * Store multiple translations at once\n */\n setMany(\n translations: Map<string, string>,\n sourceLang: string,\n targetLang: string\n ): void {\n for (const [text, translation] of translations) {\n this.set(text, sourceLang, targetLang, translation);\n }\n }\n\n /**\n * Clear cache\n */\n clear(sourceLang?: string, targetLang?: string): void {\n if (sourceLang && targetLang) {\n // Clear specific language pair\n const prefix = `${sourceLang}-${targetLang}:`;\n for (const key of [...this.memoryCache.keys()]) {\n if (key.startsWith(prefix)) {\n this.memoryCache.delete(key);\n const idx = this.cacheOrder.indexOf(key);\n if (idx !== -1) this.cacheOrder.splice(idx, 1);\n }\n }\n\n if (this.storage) {\n this.storage.removeItem(this.getStorageKey(sourceLang, targetLang));\n }\n } else {\n // Clear all\n this.memoryCache.clear();\n this.cacheOrder = [];\n this.hits = 0;\n this.misses = 0;\n }\n }\n\n /**\n * Get cache statistics\n */\n getStats(): CacheStats {\n const languagePairs: CacheStats['languagePairs'] = [];\n\n // Count by language pair from memory\n const pairCounts = new Map<string, number>();\n for (const key of this.memoryCache.keys()) {\n const pair = key.split(':')[0];\n pairCounts.set(pair, (pairCounts.get(pair) || 0) + 1);\n }\n\n for (const [pair, count] of pairCounts) {\n languagePairs.push({ pair, translations: count });\n }\n\n return {\n memorySize: this.memoryCache.size,\n hits: this.hits,\n misses: this.misses,\n languagePairs,\n };\n }\n}\n\n/**\n * Create translation cache\n */\nexport function createCache(\n maxMemorySize?: number,\n storage?: Storage\n): TranslationCache {\n return new TranslationCache(maxMemorySize, storage);\n}\n","/**\n * JSON Translator using LLM\n *\n * Smart text-level caching for efficiency:\n * 1. Extract all translatable strings from JSON\n * 2. Check cache for each string\n * 3. Send only uncached strings to LLM\n * 4. Cache new translations\n * 5. Apply all translations to original structure\n */\n\nimport type { LLMClient } from '../types';\nimport { extractJson } from '../utils/json';\nimport type { TranslateOptions, TranslateResult, LanguageCode } from './types';\nimport { buildJsonTranslationPrompt } from './prompts';\nimport { isTechnicalContent, detectScript } from './text-utils';\nimport { TranslationCache, createCache } from './cache';\n\n/** Default model for translation - gpt-4o-mini is reliable and cost-effective */\nconst DEFAULT_TRANSLATION_MODEL = 'openai/gpt-4o-mini';\n\n/**\n * JSON Translator class with smart caching\n */\nexport class JsonTranslator {\n private cache: TranslationCache;\n private defaultModel: string;\n\n constructor(\n private client: LLMClient,\n cache?: TranslationCache,\n defaultModel?: string\n ) {\n this.cache = cache ?? createCache();\n this.defaultModel = defaultModel ?? DEFAULT_TRANSLATION_MODEL;\n }\n\n /**\n * Detect language from text\n */\n detectLanguage(text: string): LanguageCode {\n const script = detectScript(text);\n switch (script) {\n case 'cjk':\n // Could be zh, ja, ko - default to zh\n return 'zh';\n case 'cyrillic':\n return 'ru';\n case 'arabic':\n return 'ar';\n default:\n return 'en';\n }\n }\n\n /**\n * Check if text needs translation\n */\n needsTranslation(\n text: string,\n sourceLang: string,\n targetLang: string\n ): boolean {\n if (!text || !text.trim()) return false;\n if (isTechnicalContent(text)) return false;\n if (sourceLang === targetLang) return false;\n return true;\n }\n\n /**\n * Translate single text\n */\n async translateText(\n text: string,\n targetLanguage: LanguageCode,\n options?: TranslateOptions\n ): Promise<string> {\n if (!text || !text.trim()) return text;\n\n const sourceLang = options?.sourceLanguage ?? 'auto';\n const actualSource = sourceLang === 'auto' ? this.detectLanguage(text) : sourceLang;\n\n if (!this.needsTranslation(text, actualSource, targetLanguage)) {\n return text;\n }\n\n // Check cache\n const cached = this.cache.get(text, actualSource, targetLanguage);\n if (cached) return cached;\n\n // Call LLM\n const response = await this.client.chat(\n `Translate this text to ${targetLanguage}. Return ONLY the translation:\\n\\n${text}`,\n {\n ...options,\n model: options?.model ?? this.defaultModel,\n temperature: 0,\n }\n );\n\n const translated = response.content.trim();\n this.cache.set(text, actualSource, targetLanguage, translated);\n\n return translated;\n }\n\n /**\n * Translate JSON object with smart text-level caching\n *\n * @example\n * ```ts\n * const translator = new JsonTranslator(llm)\n * const result = await translator.translate(\n * { title: 'Hello', items: ['World', 'Earth'] },\n * 'ru'\n * )\n * // { data: { title: 'Привет', items: ['Мир', 'Земля'] }, valid: true, ... }\n * ```\n */\n async translate<T extends Record<string, unknown>>(\n data: T,\n targetLanguage: LanguageCode,\n options?: TranslateOptions\n ): Promise<TranslateResult<T>> {\n const sourceLang = options?.sourceLanguage ?? 'auto';\n\n // Extract all translatable texts\n const translatableTexts = this.extractTranslatableTexts(data, sourceLang, targetLanguage);\n\n if (translatableTexts.size === 0) {\n return {\n data,\n valid: true,\n errors: [],\n retries: 0,\n sourceLanguage: sourceLang,\n targetLanguage,\n };\n }\n\n // Detect source language from first text if auto\n let actualSource = sourceLang;\n if (sourceLang === 'auto') {\n const firstText = [...translatableTexts][0];\n actualSource = this.detectLanguage(firstText);\n }\n\n // Check cache for each text\n const { cached, uncached } = this.cache.getMany(\n [...translatableTexts],\n actualSource,\n targetLanguage\n );\n\n // If everything cached, apply and return\n if (uncached.length === 0) {\n return {\n data: this.applyTranslations(data, cached),\n valid: true,\n errors: [],\n retries: 0,\n sourceLanguage: actualSource,\n targetLanguage,\n };\n }\n\n // Create partial JSON with only uncached texts\n const partialJson = this.createPartialJson(data, new Set(uncached));\n const jsonStr = JSON.stringify(partialJson, null, 2);\n\n try {\n // Build prompt and call LLM\n const prompt = buildJsonTranslationPrompt(jsonStr, actualSource, targetLanguage);\n\n const response = await this.client.chat(prompt, {\n ...options,\n model: options?.model ?? this.defaultModel,\n temperature: 0,\n });\n\n // Parse response\n const translatedPartial = extractJson<Record<string, unknown>>(response.content);\n\n // Extract translations by comparison\n const newTranslations = this.extractTranslationsByComparison(\n partialJson,\n translatedPartial,\n uncached\n );\n\n // Cache new translations\n this.cache.setMany(newTranslations, actualSource, targetLanguage);\n\n // Combine all translations\n const allTranslations = new Map([...cached, ...newTranslations]);\n\n return {\n data: this.applyTranslations(data, allTranslations),\n valid: true,\n errors: [],\n retries: 0,\n sourceLanguage: actualSource,\n targetLanguage,\n };\n } catch (error) {\n // On error, return what we have from cache\n const errorMsg = error instanceof Error ? error.message : String(error);\n console.error('Translation failed:', errorMsg);\n\n return {\n data: cached.size > 0 ? this.applyTranslations(data, cached) : data,\n valid: false,\n errors: [errorMsg],\n retries: 0,\n sourceLanguage: actualSource,\n targetLanguage,\n };\n }\n }\n\n /**\n * Translate to multiple languages in parallel\n */\n async translateToMany<T extends Record<string, unknown>>(\n data: T,\n targetLanguages: LanguageCode[],\n options?: TranslateOptions\n ): Promise<Map<LanguageCode, TranslateResult<T>>> {\n const results = new Map<LanguageCode, TranslateResult<T>>();\n\n // Run translations in parallel\n const promises = targetLanguages.map(async (lang) => {\n const result = await this.translate(data, lang, options);\n return { lang, result };\n });\n\n const settled = await Promise.all(promises);\n for (const { lang, result } of settled) {\n results.set(lang, result);\n }\n\n return results;\n }\n\n /**\n * Extract all translatable texts from object\n */\n private extractTranslatableTexts(\n obj: unknown,\n sourceLang: string,\n targetLang: string\n ): Set<string> {\n const texts = new Set<string>();\n\n const extract = (item: unknown): void => {\n if (typeof item === 'string') {\n if (this.needsTranslation(item, sourceLang, targetLang)) {\n texts.add(item);\n }\n } else if (Array.isArray(item)) {\n for (const i of item) extract(i);\n } else if (item !== null && typeof item === 'object') {\n for (const v of Object.values(item)) extract(v);\n }\n };\n\n extract(obj);\n return texts;\n }\n\n /**\n * Apply translations to object\n */\n private applyTranslations<T>(obj: T, translations: Map<string, string>): T {\n const apply = (item: unknown): unknown => {\n if (typeof item === 'string') {\n return translations.get(item) ?? item;\n } else if (Array.isArray(item)) {\n return item.map(apply);\n } else if (item !== null && typeof item === 'object') {\n const result: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(item)) {\n result[k] = apply(v);\n }\n return result;\n }\n return item;\n };\n\n return apply(obj) as T;\n }\n\n /**\n * Create partial JSON with only texts that need translation\n */\n private createPartialJson(data: unknown, textsToInclude: Set<string>): unknown {\n const filter = (obj: unknown): unknown => {\n if (typeof obj === 'string') {\n return textsToInclude.has(obj) ? obj : 'SKIP';\n } else if (Array.isArray(obj)) {\n return obj.map(filter).filter((i) => this.hasTranslatable(i, textsToInclude));\n } else if (obj !== null && typeof obj === 'object') {\n const result: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(obj)) {\n const filtered = filter(v);\n if (this.hasTranslatable(filtered, textsToInclude)) {\n result[k] = filtered;\n }\n }\n return result;\n }\n return obj;\n };\n\n return filter(data);\n }\n\n /**\n * Check if object contains translatable text\n */\n private hasTranslatable(obj: unknown, textsSet: Set<string>): boolean {\n if (typeof obj === 'string') return textsSet.has(obj);\n if (Array.isArray(obj)) return obj.some((i) => this.hasTranslatable(i, textsSet));\n if (obj !== null && typeof obj === 'object') {\n return Object.values(obj).some((v) => this.hasTranslatable(v, textsSet));\n }\n return false;\n }\n\n /**\n * Extract translations by comparing original and translated JSON\n */\n private extractTranslationsByComparison(\n original: unknown,\n translated: unknown,\n uncachedTexts: string[]\n ): Map<string, string> {\n const translations = new Map<string, string>();\n const uncachedSet = new Set(uncachedTexts);\n\n const compare = (orig: unknown, trans: unknown): void => {\n if (typeof orig === 'string' && typeof trans === 'string') {\n // Save translation if original was in uncached list and translation is valid\n if (uncachedSet.has(orig) && trans !== 'SKIP' && trans.trim()) {\n translations.set(orig, trans);\n }\n } else if (Array.isArray(orig) && Array.isArray(trans)) {\n for (let i = 0; i < Math.min(orig.length, trans.length); i++) {\n compare(orig[i], trans[i]);\n }\n } else if (\n orig !== null &&\n typeof orig === 'object' &&\n trans !== null &&\n typeof trans === 'object'\n ) {\n for (const key of Object.keys(orig as Record<string, unknown>)) {\n if (key in (trans as Record<string, unknown>)) {\n compare(\n (orig as Record<string, unknown>)[key],\n (trans as Record<string, unknown>)[key]\n );\n }\n }\n }\n };\n\n compare(original, translated);\n return translations;\n }\n\n /**\n * Get translation statistics\n */\n getStats() {\n return this.cache.getStats();\n }\n\n /**\n * Clear translation cache\n */\n clearCache(sourceLang?: string, targetLang?: string) {\n this.cache.clear(sourceLang, targetLang);\n }\n}\n\n/**\n * Translator options\n */\nexport interface TranslatorConfig {\n cache?: TranslationCache;\n /** Model for translation (default: openai/gpt-4o-mini) */\n model?: string;\n}\n\n/**\n * Create JSON translator\n */\nexport function createTranslator(\n client: LLMClient,\n configOrCache?: TranslationCache | TranslatorConfig\n): JsonTranslator {\n // Support both old and new API\n if (configOrCache instanceof TranslationCache) {\n return new JsonTranslator(client, configOrCache);\n }\n return new JsonTranslator(client, configOrCache?.cache, configOrCache?.model);\n}\n"]}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM types
|
|
3
|
+
*/
|
|
4
|
+
type LLMProvider = 'openai' | 'anthropic' | 'sdkrouter';
|
|
5
|
+
type OpenAIModel = 'gpt-4o' | 'gpt-4o-mini' | 'gpt-4-turbo' | 'gpt-4' | 'gpt-3.5-turbo';
|
|
6
|
+
type AnthropicModel = 'claude-3-5-sonnet-latest' | 'claude-3-5-haiku-latest' | 'claude-3-opus-latest';
|
|
7
|
+
type LLMModel = OpenAIModel | AnthropicModel | string;
|
|
8
|
+
interface LLMMessage {
|
|
9
|
+
role: 'system' | 'user' | 'assistant';
|
|
10
|
+
content: string;
|
|
11
|
+
}
|
|
12
|
+
interface LLMConfig {
|
|
13
|
+
/** Provider (auto-detected from env if not specified) */
|
|
14
|
+
provider?: LLMProvider;
|
|
15
|
+
/** API key (from env if not specified) */
|
|
16
|
+
apiKey?: string;
|
|
17
|
+
/** Default model */
|
|
18
|
+
model?: LLMModel;
|
|
19
|
+
/** Default temperature (0-1) */
|
|
20
|
+
temperature?: number;
|
|
21
|
+
/** Default max tokens */
|
|
22
|
+
maxTokens?: number;
|
|
23
|
+
/** Base URL override */
|
|
24
|
+
baseUrl?: string;
|
|
25
|
+
}
|
|
26
|
+
interface LLMRequestOptions {
|
|
27
|
+
/** Model override */
|
|
28
|
+
model?: LLMModel;
|
|
29
|
+
/** Temperature override (0-1) */
|
|
30
|
+
temperature?: number;
|
|
31
|
+
/** Max tokens override */
|
|
32
|
+
maxTokens?: number;
|
|
33
|
+
/** System prompt */
|
|
34
|
+
system?: string;
|
|
35
|
+
}
|
|
36
|
+
interface LLMResponse {
|
|
37
|
+
content: string;
|
|
38
|
+
model: string;
|
|
39
|
+
usage?: {
|
|
40
|
+
promptTokens: number;
|
|
41
|
+
completionTokens: number;
|
|
42
|
+
totalTokens: number;
|
|
43
|
+
};
|
|
44
|
+
finishReason?: string;
|
|
45
|
+
}
|
|
46
|
+
interface LLMClient {
|
|
47
|
+
/** Provider name */
|
|
48
|
+
provider: LLMProvider;
|
|
49
|
+
/** Send chat message */
|
|
50
|
+
chat(prompt: string, options?: LLMRequestOptions): Promise<LLMResponse>;
|
|
51
|
+
/** Send chat messages */
|
|
52
|
+
chatMessages(messages: LLMMessage[], options?: LLMRequestOptions): Promise<LLMResponse>;
|
|
53
|
+
/** Get JSON response */
|
|
54
|
+
json<T = unknown>(prompt: string, options?: LLMRequestOptions): Promise<T>;
|
|
55
|
+
/** Get JSON response with schema hint */
|
|
56
|
+
jsonSchema<T = unknown>(prompt: string, schema: string, options?: LLMRequestOptions): Promise<T>;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export type { AnthropicModel as A, LLMConfig as L, OpenAIModel as O, LLMClient as a, LLMProvider as b, LLMRequestOptions as c, LLMResponse as d, LLMModel as e, LLMMessage as f };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM types
|
|
3
|
+
*/
|
|
4
|
+
type LLMProvider = 'openai' | 'anthropic' | 'sdkrouter';
|
|
5
|
+
type OpenAIModel = 'gpt-4o' | 'gpt-4o-mini' | 'gpt-4-turbo' | 'gpt-4' | 'gpt-3.5-turbo';
|
|
6
|
+
type AnthropicModel = 'claude-3-5-sonnet-latest' | 'claude-3-5-haiku-latest' | 'claude-3-opus-latest';
|
|
7
|
+
type LLMModel = OpenAIModel | AnthropicModel | string;
|
|
8
|
+
interface LLMMessage {
|
|
9
|
+
role: 'system' | 'user' | 'assistant';
|
|
10
|
+
content: string;
|
|
11
|
+
}
|
|
12
|
+
interface LLMConfig {
|
|
13
|
+
/** Provider (auto-detected from env if not specified) */
|
|
14
|
+
provider?: LLMProvider;
|
|
15
|
+
/** API key (from env if not specified) */
|
|
16
|
+
apiKey?: string;
|
|
17
|
+
/** Default model */
|
|
18
|
+
model?: LLMModel;
|
|
19
|
+
/** Default temperature (0-1) */
|
|
20
|
+
temperature?: number;
|
|
21
|
+
/** Default max tokens */
|
|
22
|
+
maxTokens?: number;
|
|
23
|
+
/** Base URL override */
|
|
24
|
+
baseUrl?: string;
|
|
25
|
+
}
|
|
26
|
+
interface LLMRequestOptions {
|
|
27
|
+
/** Model override */
|
|
28
|
+
model?: LLMModel;
|
|
29
|
+
/** Temperature override (0-1) */
|
|
30
|
+
temperature?: number;
|
|
31
|
+
/** Max tokens override */
|
|
32
|
+
maxTokens?: number;
|
|
33
|
+
/** System prompt */
|
|
34
|
+
system?: string;
|
|
35
|
+
}
|
|
36
|
+
interface LLMResponse {
|
|
37
|
+
content: string;
|
|
38
|
+
model: string;
|
|
39
|
+
usage?: {
|
|
40
|
+
promptTokens: number;
|
|
41
|
+
completionTokens: number;
|
|
42
|
+
totalTokens: number;
|
|
43
|
+
};
|
|
44
|
+
finishReason?: string;
|
|
45
|
+
}
|
|
46
|
+
interface LLMClient {
|
|
47
|
+
/** Provider name */
|
|
48
|
+
provider: LLMProvider;
|
|
49
|
+
/** Send chat message */
|
|
50
|
+
chat(prompt: string, options?: LLMRequestOptions): Promise<LLMResponse>;
|
|
51
|
+
/** Send chat messages */
|
|
52
|
+
chatMessages(messages: LLMMessage[], options?: LLMRequestOptions): Promise<LLMResponse>;
|
|
53
|
+
/** Get JSON response */
|
|
54
|
+
json<T = unknown>(prompt: string, options?: LLMRequestOptions): Promise<T>;
|
|
55
|
+
/** Get JSON response with schema hint */
|
|
56
|
+
jsonSchema<T = unknown>(prompt: string, schema: string, options?: LLMRequestOptions): Promise<T>;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export type { AnthropicModel as A, LLMConfig as L, OpenAIModel as O, LLMClient as a, LLMProvider as b, LLMRequestOptions as c, LLMResponse as d, LLMModel as e, LLMMessage as f };
|
package/package.json
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@djangocfg/llm",
|
|
3
|
+
"version": "2.1.164",
|
|
4
|
+
"description": "Lightweight LLM client with SDKRouter, OpenAI, Anthropic support and smart JSON translator",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"llm",
|
|
7
|
+
"openai",
|
|
8
|
+
"anthropic",
|
|
9
|
+
"sdkrouter",
|
|
10
|
+
"ai",
|
|
11
|
+
"gpt",
|
|
12
|
+
"claude",
|
|
13
|
+
"translator",
|
|
14
|
+
"i18n",
|
|
15
|
+
"json-translation"
|
|
16
|
+
],
|
|
17
|
+
"author": {
|
|
18
|
+
"name": "DjangoCFG",
|
|
19
|
+
"url": "https://djangocfg.com"
|
|
20
|
+
},
|
|
21
|
+
"homepage": "https://djangocfg.com",
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "https://github.com/markolofsen/django-cfg.git",
|
|
25
|
+
"directory": "packages/llm"
|
|
26
|
+
},
|
|
27
|
+
"bugs": {
|
|
28
|
+
"url": "https://github.com/markolofsen/django-cfg/issues"
|
|
29
|
+
},
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"type": "module",
|
|
32
|
+
"main": "./dist/index.cjs",
|
|
33
|
+
"module": "./dist/index.mjs",
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"exports": {
|
|
36
|
+
".": {
|
|
37
|
+
"types": "./dist/index.d.ts",
|
|
38
|
+
"import": "./dist/index.mjs",
|
|
39
|
+
"require": "./dist/index.cjs"
|
|
40
|
+
},
|
|
41
|
+
"./translator": {
|
|
42
|
+
"types": "./dist/translator/index.d.ts",
|
|
43
|
+
"import": "./dist/translator/index.mjs",
|
|
44
|
+
"require": "./dist/translator/index.cjs"
|
|
45
|
+
},
|
|
46
|
+
"./providers": {
|
|
47
|
+
"types": "./dist/providers/index.d.ts",
|
|
48
|
+
"import": "./dist/providers/index.mjs",
|
|
49
|
+
"require": "./dist/providers/index.cjs"
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"files": [
|
|
53
|
+
"dist",
|
|
54
|
+
"src",
|
|
55
|
+
"README.md",
|
|
56
|
+
"LICENSE"
|
|
57
|
+
],
|
|
58
|
+
"scripts": {
|
|
59
|
+
"build": "tsup",
|
|
60
|
+
"dev": "tsup --watch",
|
|
61
|
+
"clean": "rm -rf dist",
|
|
62
|
+
"lint": "eslint .",
|
|
63
|
+
"check": "tsc --noEmit",
|
|
64
|
+
"test": "vitest run",
|
|
65
|
+
"test:watch": "vitest",
|
|
66
|
+
"test:coverage": "vitest run --coverage"
|
|
67
|
+
},
|
|
68
|
+
"dependencies": {
|
|
69
|
+
"openai": "^4.77.0"
|
|
70
|
+
},
|
|
71
|
+
"devDependencies": {
|
|
72
|
+
"@djangocfg/typescript-config": "^2.1.164",
|
|
73
|
+
"@types/node": "^25.2.3",
|
|
74
|
+
"tsup": "^8.5.0",
|
|
75
|
+
"tsx": "^4.19.2",
|
|
76
|
+
"typescript": "^5.9.3",
|
|
77
|
+
"vitest": "^4.0.18"
|
|
78
|
+
},
|
|
79
|
+
"publishConfig": {
|
|
80
|
+
"access": "public"
|
|
81
|
+
}
|
|
82
|
+
}
|
package/src/client.ts
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM Client factory
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { LLMClient, LLMConfig, LLMProvider } from './types';
|
|
6
|
+
import { OpenAIProvider } from './providers/openai';
|
|
7
|
+
import { AnthropicProvider } from './providers/anthropic';
|
|
8
|
+
import { SDKRouterProvider } from './providers/sdkrouter';
|
|
9
|
+
import { detectProvider, getApiKey, getDefaultModel } from './utils/env';
|
|
10
|
+
|
|
11
|
+
export class LLMError extends Error {
|
|
12
|
+
constructor(message: string) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.name = 'LLMError';
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Create LLM client with auto-detection
|
|
20
|
+
*
|
|
21
|
+
* Priority: SDKROUTER_API_KEY > OPENAI_API_KEY > ANTHROPIC_API_KEY
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* // Auto-detect from env (sdkrouter preferred)
|
|
26
|
+
* const llm = createLLMClient()
|
|
27
|
+
*
|
|
28
|
+
* // With model alias
|
|
29
|
+
* const llm = createLLMClient({ model: '@smart+code' })
|
|
30
|
+
*
|
|
31
|
+
* // Explicit provider
|
|
32
|
+
* const llm = createLLMClient({
|
|
33
|
+
* provider: 'openai',
|
|
34
|
+
* apiKey: 'sk-...',
|
|
35
|
+
* model: 'gpt-4o-mini'
|
|
36
|
+
* })
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export function createLLMClient(config?: LLMConfig): LLMClient {
|
|
40
|
+
const provider = config?.provider ?? detectProvider();
|
|
41
|
+
|
|
42
|
+
if (!provider) {
|
|
43
|
+
throw new LLMError(
|
|
44
|
+
'No LLM provider configured. Set SDKROUTER_API_KEY, OPENAI_API_KEY, or ANTHROPIC_API_KEY environment variable.'
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const apiKey = config?.apiKey ?? getApiKey(provider);
|
|
49
|
+
|
|
50
|
+
if (!apiKey) {
|
|
51
|
+
const envVar =
|
|
52
|
+
provider === 'sdkrouter'
|
|
53
|
+
? 'SDKROUTER_API_KEY'
|
|
54
|
+
: provider === 'openai'
|
|
55
|
+
? 'OPENAI_API_KEY'
|
|
56
|
+
: 'ANTHROPIC_API_KEY';
|
|
57
|
+
throw new LLMError(
|
|
58
|
+
`No API key found for ${provider}. Set ${envVar} environment variable.`
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const model = config?.model ?? getDefaultModel(provider);
|
|
63
|
+
|
|
64
|
+
const fullConfig: LLMConfig = {
|
|
65
|
+
...config,
|
|
66
|
+
provider,
|
|
67
|
+
apiKey,
|
|
68
|
+
model,
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
if (provider === 'sdkrouter') {
|
|
72
|
+
return new SDKRouterProvider(fullConfig);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (provider === 'openai') {
|
|
76
|
+
return new OpenAIProvider(fullConfig);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (provider === 'anthropic') {
|
|
80
|
+
return new AnthropicProvider(fullConfig);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
throw new LLMError(`Unknown provider: ${provider}`);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Create SDKRouter client (recommended)
|
|
88
|
+
*/
|
|
89
|
+
export function createSDKRouterClient(config?: Omit<LLMConfig, 'provider'>): LLMClient {
|
|
90
|
+
return createLLMClient({ ...config, provider: 'sdkrouter' });
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Create OpenAI client
|
|
95
|
+
*/
|
|
96
|
+
export function createOpenAIClient(config?: Omit<LLMConfig, 'provider'>): LLMClient {
|
|
97
|
+
return createLLMClient({ ...config, provider: 'openai' });
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Create Anthropic client
|
|
102
|
+
*/
|
|
103
|
+
export function createAnthropicClient(config?: Omit<LLMConfig, 'provider'>): LLMClient {
|
|
104
|
+
return createLLMClient({ ...config, provider: 'anthropic' });
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Check if LLM is configured
|
|
109
|
+
*/
|
|
110
|
+
export function isLLMConfigured(): boolean {
|
|
111
|
+
return detectProvider() !== undefined;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Get configured provider
|
|
116
|
+
*/
|
|
117
|
+
export function getConfiguredProvider(): LLMProvider | undefined {
|
|
118
|
+
return detectProvider();
|
|
119
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// Client
|
|
2
|
+
export {
|
|
3
|
+
createLLMClient,
|
|
4
|
+
createSDKRouterClient,
|
|
5
|
+
createOpenAIClient,
|
|
6
|
+
createAnthropicClient,
|
|
7
|
+
isLLMConfigured,
|
|
8
|
+
getConfiguredProvider,
|
|
9
|
+
LLMError,
|
|
10
|
+
} from './client';
|
|
11
|
+
|
|
12
|
+
// Model aliases (SDKRouter)
|
|
13
|
+
export {
|
|
14
|
+
Model,
|
|
15
|
+
ModelPresets,
|
|
16
|
+
buildModelAlias,
|
|
17
|
+
SDKROUTER_BASE_URL,
|
|
18
|
+
type ModelTier,
|
|
19
|
+
type ModelCapability,
|
|
20
|
+
type ModelCategory,
|
|
21
|
+
type ModelOptions,
|
|
22
|
+
} from './providers/sdkrouter';
|
|
23
|
+
|
|
24
|
+
// Translator
|
|
25
|
+
export {
|
|
26
|
+
JsonTranslator,
|
|
27
|
+
createTranslator,
|
|
28
|
+
TranslationCache,
|
|
29
|
+
createCache,
|
|
30
|
+
// Validation
|
|
31
|
+
validateTranslation,
|
|
32
|
+
validateJsonKeys as validateTranslationKeys,
|
|
33
|
+
// Text utils
|
|
34
|
+
isTechnicalContent,
|
|
35
|
+
extractPlaceholders,
|
|
36
|
+
detectScript,
|
|
37
|
+
// Constants
|
|
38
|
+
LANGUAGE_NAMES,
|
|
39
|
+
// Types
|
|
40
|
+
type TranslateOptions,
|
|
41
|
+
type TranslateResult,
|
|
42
|
+
type LanguageCode,
|
|
43
|
+
type ValidationResult,
|
|
44
|
+
type CacheStats,
|
|
45
|
+
} from './translator';
|
|
46
|
+
|
|
47
|
+
// Types
|
|
48
|
+
export type {
|
|
49
|
+
LLMProvider,
|
|
50
|
+
LLMModel,
|
|
51
|
+
OpenAIModel,
|
|
52
|
+
AnthropicModel,
|
|
53
|
+
LLMConfig,
|
|
54
|
+
LLMMessage,
|
|
55
|
+
LLMRequestOptions,
|
|
56
|
+
LLMResponse,
|
|
57
|
+
LLMClient,
|
|
58
|
+
} from './types';
|
|
59
|
+
|
|
60
|
+
// Utils
|
|
61
|
+
export { extractJson, validateJsonKeys } from './utils/json';
|
|
62
|
+
export { detectProvider, getApiKey, getDefaultModel } from './utils/env';
|
|
63
|
+
export {
|
|
64
|
+
getStructuredOutput,
|
|
65
|
+
getStructuredOutputWithRetry,
|
|
66
|
+
generateSchemaFromExample,
|
|
67
|
+
schemaToPromptString,
|
|
68
|
+
type ZodLikeSchema,
|
|
69
|
+
type JsonSchemaDefinition,
|
|
70
|
+
} from './utils/schema';
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anthropic provider
|
|
3
|
+
*
|
|
4
|
+
* Uses OpenAI-compatible API endpoint for simplicity.
|
|
5
|
+
* Anthropic provides OpenAI-compatible endpoint at api.anthropic.com
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import OpenAI from 'openai';
|
|
9
|
+
import type {
|
|
10
|
+
LLMConfig,
|
|
11
|
+
LLMMessage,
|
|
12
|
+
LLMProvider,
|
|
13
|
+
LLMRequestOptions,
|
|
14
|
+
LLMResponse,
|
|
15
|
+
} from '../types';
|
|
16
|
+
import { BaseLLMProvider } from './base';
|
|
17
|
+
|
|
18
|
+
export class AnthropicProvider extends BaseLLMProvider {
|
|
19
|
+
provider: LLMProvider = 'anthropic';
|
|
20
|
+
private client: OpenAI;
|
|
21
|
+
|
|
22
|
+
constructor(config: LLMConfig) {
|
|
23
|
+
super({
|
|
24
|
+
model: config.model ?? 'claude-3-5-haiku-latest',
|
|
25
|
+
...config,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
if (!config.apiKey) {
|
|
29
|
+
throw new Error('Anthropic API key is required');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Use native Anthropic SDK approach via fetch
|
|
33
|
+
this.client = new OpenAI({
|
|
34
|
+
apiKey: config.apiKey,
|
|
35
|
+
baseURL: config.baseUrl ?? 'https://api.anthropic.com/v1',
|
|
36
|
+
defaultHeaders: {
|
|
37
|
+
'anthropic-version': '2023-06-01',
|
|
38
|
+
'x-api-key': config.apiKey,
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async chatMessages(
|
|
44
|
+
messages: LLMMessage[],
|
|
45
|
+
options?: LLMRequestOptions
|
|
46
|
+
): Promise<LLMResponse> {
|
|
47
|
+
const model = options?.model ?? this.config.model;
|
|
48
|
+
const temperature = options?.temperature ?? this.config.temperature;
|
|
49
|
+
const maxTokens = options?.maxTokens ?? this.config.maxTokens;
|
|
50
|
+
|
|
51
|
+
// Anthropic uses system separately
|
|
52
|
+
const systemMessage = options?.system
|
|
53
|
+
? options.system
|
|
54
|
+
: messages.find((m) => m.role === 'system')?.content;
|
|
55
|
+
|
|
56
|
+
const userMessages = messages.filter((m) => m.role !== 'system');
|
|
57
|
+
|
|
58
|
+
// Direct API call for Anthropic
|
|
59
|
+
const response = await fetch('https://api.anthropic.com/v1/messages', {
|
|
60
|
+
method: 'POST',
|
|
61
|
+
headers: {
|
|
62
|
+
'Content-Type': 'application/json',
|
|
63
|
+
'x-api-key': this.config.apiKey!,
|
|
64
|
+
'anthropic-version': '2023-06-01',
|
|
65
|
+
},
|
|
66
|
+
body: JSON.stringify({
|
|
67
|
+
model,
|
|
68
|
+
max_tokens: maxTokens,
|
|
69
|
+
temperature,
|
|
70
|
+
system: systemMessage,
|
|
71
|
+
messages: userMessages.map((m) => ({
|
|
72
|
+
role: m.role,
|
|
73
|
+
content: m.content,
|
|
74
|
+
})),
|
|
75
|
+
}),
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
if (!response.ok) {
|
|
79
|
+
const error = await response.text();
|
|
80
|
+
throw new Error(`Anthropic API error: ${response.status} ${error}`);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const data = await response.json();
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
content: data.content?.[0]?.text ?? '',
|
|
87
|
+
model: data.model,
|
|
88
|
+
usage: data.usage
|
|
89
|
+
? {
|
|
90
|
+
promptTokens: data.usage.input_tokens,
|
|
91
|
+
completionTokens: data.usage.output_tokens,
|
|
92
|
+
totalTokens: data.usage.input_tokens + data.usage.output_tokens,
|
|
93
|
+
}
|
|
94
|
+
: undefined,
|
|
95
|
+
finishReason: data.stop_reason ?? undefined,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
}
|