обавлен перевод промптов через OpenRouter API с использованием моделей LLM: 1) сновная модель: meta-llama/llama-3.3-70b-instruct:free 2) езервная модель: openchat/openchat-7b:free

This commit is contained in:
kazachilo 2025-03-14 16:47:53 +03:00
parent 7a58f26ead
commit b18acdbad5
3 changed files with 122 additions and 4 deletions

View File

@ -70,7 +70,7 @@ const Home: React.FC = () => {
// Проверяем, была ли ошибка перевода
if (response.translationFailed) {
setNotificationTitle('Ошибка перевода');
setNotificationMessage('Не удалось перевести промпт. Генерация отменена.');
setNotificationMessage('Не удалось перевести промпт. Генерация отменена. Пожалуйста, попробуйте другой промпт или повторите попытку позже.');
setIsLoading(false);
return;
}

View File

@ -149,8 +149,8 @@ async generateImage(imageData: string, style?: string, promptId?: string, userPr
if (userPrompt && promptId === 'customPrompt') {
console.log('Переводим пользовательский промпт:', userPrompt);
// Переводим промпт с 3 попытками
const translationResult = await translateService.translateToEnglish(userPrompt, 3);
// Используем новый метод перевода через LLM
const translationResult = await translateService.translateWithLLM(userPrompt);
if (translationResult.success) {
// Успешный перевод
@ -159,7 +159,7 @@ async generateImage(imageData: string, style?: string, promptId?: string, userPr
usedPrompt = translationResult.text;
} else {
// Перевод не удался после всех попыток
console.error('Не удалось перевести промпт после нескольких попыток');
console.error('Не удалось перевести промпт ни через одну из моделей');
translationFailed = true;
// Не продолжаем генерацию, возвращаем ошибку

View File

@ -1,5 +1,17 @@
// URL для LibreTranslate API (сохраняем, но не используем)
const TRANSLATE_API_URL = 'https://translate.maxdev.keenetic.pro/translate';
// URL и ключ для OpenRouter API
const OPENROUTER_API_URL = 'https://openrouter.ai/api/v1/chat/completions';
const OPENROUTER_API_KEY = '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';
// Модели для перевода
const TRANSLATION_MODELS = {
PRIMARY: 'meta-llama/llama-3.3-70b-instruct:free', // Основная модель
FALLBACK: 'openchat/openchat-7b:free', // Резервная модель
};
// Интерфейс для ответа от LibreTranslate API
interface TranslateResponse {
translatedText: string;
detectedLanguage: {
@ -9,7 +21,28 @@ interface TranslateResponse {
alternatives: string[];
}
// Интерфейс для ответа от OpenRouter API
interface OpenRouterResponse {
choices: {
message: {
content: string;
role: string;
};
index: number;
finish_reason: string;
}[];
id: string;
model: string;
object: string;
usage: {
prompt_tokens: number;
completion_tokens: number;
total_tokens: number;
};
}
const translateService = {
// Старый метод перевода через LibreTranslate (сохраняем, но не используем)
async translateToEnglish(text: string, maxRetries = 3): Promise<{ success: boolean; text: string }> {
let retries = 0;
@ -50,6 +83,91 @@ const translateService = {
// Все попытки исчерпаны, возвращаем исходный текст с флагом неудачи
console.error(`All ${maxRetries} translation attempts failed`);
return { success: false, text: text };
},
// Новый метод перевода через OpenRouter API
async translateWithLLM(text: string): Promise<{ success: boolean; text: string }> {
// Массив моделей для последовательных попыток
const models = [
TRANSLATION_MODELS.PRIMARY,
TRANSLATION_MODELS.FALLBACK
];
// Проверка, что текст не пустой
if (!text || text.trim() === '') {
console.error('Пустой текст для перевода');
return { success: false, text };
}
// Проверка, что текст не на английском языке
const isAlreadyEnglish = /^[a-zA-Z0-9\s.,!?;:()\-"']+$/.test(text.trim());
if (isAlreadyEnglish) {
console.log('Текст уже на английском языке, перевод не требуется');
return { success: true, text };
}
// Последовательно пробуем каждую модель
for (let i = 0; i < models.length; i++) {
const model = models[i];
console.log(`Попытка перевода через модель ${model} (${i + 1}/${models.length})`);
try {
const response = await fetch(OPENROUTER_API_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${OPENROUTER_API_KEY}`,
'HTTP-Referer': window.location.origin,
'X-Title': 'Sticker Generator App'
},
body: JSON.stringify({
model: model,
messages: [
{
role: 'system',
content: 'You are a professional translator. Translate the following text from any language to English. Preserve the meaning and style. Only return the translated text without any additional comments or explanations.'
},
{
role: 'user',
content: text
}
],
temperature: 0.3,
max_tokens: 200
})
});
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
console.error(`Ошибка API для модели ${model}:`, errorData);
throw new Error(`OpenRouter API failed with status: ${response.status}`);
}
const data: OpenRouterResponse = await response.json();
const translatedText = data.choices[0].message.content.trim();
// Проверка, что получили непустой ответ
if (!translatedText) {
throw new Error('Empty translation result');
}
// Проверка, что перевод отличается от исходного текста
if (translatedText.toLowerCase().trim() === text.toLowerCase().trim()) {
console.warn(`Модель ${model} вернула исходный текст без перевода`);
throw new Error('Translation returned original text');
}
console.log(`Успешный перевод через модель ${model}:`, translatedText);
return { success: true, text: translatedText };
} catch (error) {
console.error(`Ошибка перевода через модель ${model}:`, error);
// Продолжаем со следующей моделью, если она есть
}
}
// Если все модели не сработали
console.error('Все попытки перевода через LLM не удались');
return { success: false, text };
}
};