File size: 6,971 Bytes
fe9a0c4 831f7e7 5bd3ab2 fe9a0c4 5bd3ab2 47fea40 5bd3ab2 47fea40 5bd3ab2 fe9a0c4 5bd3ab2 fe9a0c4 5bd3ab2 47fea40 5bd3ab2 47fea40 5bd3ab2 47fea40 5bd3ab2 47fea40 5bd3ab2 831f7e7 5bd3ab2 47fea40 5bd3ab2 fe9a0c4 831f7e7 fe9a0c4 5bd3ab2 fe9a0c4 5bd3ab2 47fea40 5bd3ab2 fe9a0c4 5bd3ab2 47fea40 5bd3ab2 47fea40 5bd3ab2 47fea40 5bd3ab2 47fea40 5bd3ab2 47fea40 5bd3ab2 47fea40 fe9a0c4 47fea40 fe9a0c4 5bd3ab2 fe9a0c4 47fea40 |
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 |
import "https://deno.land/x/[email protected]/mod.ts";
import { serve } from "https://deno.land/[email protected]/http/server.ts";
import { Mistral } from 'npm:@mistralai/mistralai';
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
};
const languagePrompts = {
en: {
systemPrompt: "You are helping generate words for a word-guessing game. Generate a single word in English related to the theme",
requirements: "The word should be:\n- A single word (no spaces or hyphens)\n- Common enough that people would know it\n- Specific enough to be interesting\n- Related to the theme\n- Between 4 and 12 letters\n- A noun\n- NOT be any of these previously used words:"
},
fr: {
systemPrompt: "Vous aidez à générer des mots pour un jeu de devinettes. Générez un seul mot en français lié au thème",
requirements: "Le mot doit être :\n- Un seul mot (pas d'espaces ni de traits d'union)\n- Assez courant pour que les gens le connaissent\n- Suffisamment spécifique pour être intéressant\n- En rapport avec le thème\n- Entre 4 et 12 lettres\n- Un nom\n- NE PAS être l'un de ces mots déjà utilisés :"
},
de: {
systemPrompt: "Sie helfen bei der Generierung von Wörtern für ein Worträtselspiel. Generieren Sie ein einzelnes Wort auf Deutsch zum Thema",
requirements: "Das Wort sollte:\n- Ein einzelnes Wort sein (keine Leerzeichen oder Bindestriche)\n- Häufig genug, dass Menschen es kennen\n- Spezifisch genug, um interessant zu sein\n- Zum Thema passen\n- Zwischen 4 und 12 Buchstaben lang sein\n- Ein Substantiv sein\n- NICHT eines dieser bereits verwendeten Wörter sein:"
},
it: {
systemPrompt: "Stai aiutando a generare parole per un gioco di indovinelli. Genera una singola parola in italiano legata al tema",
requirements: "La parola deve essere:\n- Una singola parola (senza spazi o trattini)\n- Abbastanza comune da essere conosciuta\n- Sufficientemente specifica da essere interessante\n- Correlata al tema\n- Tra 4 e 12 lettere\n- Un sostantivo\n- NON essere una di queste parole già utilizzate:"
},
es: {
systemPrompt: "Estás ayudando a generar palabras para un juego de adivinanzas. Genera una sola palabra en español relacionada con el tema",
requirements: "La palabra debe ser:\n- Una sola palabra (sin espacios ni guiones)\n- Lo suficientemente común para que la gente la conozca\n- Lo suficientemente específica para ser interesante\n- Relacionada con el tema\n- Entre 4 y 12 letras\n- Un sustantivo\n- NO ser ninguna de estas palabras ya utilizadas:"
}
};
const openRouterModels = [
'sophosympatheia/rogue-rose-103b-v0.2:free',
'google/gemini-2.0-flash-exp:free',
'meta-llama/llama-3.1-70b-instruct:free',
'microsoft/phi-3-medium-128k-instruct:free'
];
async function tryMistral(theme: string, usedWords: string[], language: string) {
const mistralKey = Deno.env.get('MISTRAL_API_KEY');
if (!mistralKey) {
throw new Error('Mistral API key not configured');
}
const client = new Mistral({
apiKey: mistralKey,
});
const prompts = languagePrompts[language as keyof typeof languagePrompts] || languagePrompts.en;
const response = await client.chat.complete({
model: "mistral-large-latest",
messages: [
{
role: "system",
content: `${prompts.systemPrompt} "${theme}".\n${prompts.requirements} ${usedWords.join(', ')}\n\nRespond with just the word in UPPERCASE, nothing else.`
}
],
maxTokens: 50,
temperature: 0.99
});
if (!response?.choices?.[0]?.message?.content) {
throw new Error('Invalid response from Mistral API');
}
return response.choices[0].message.content.trim();
}
async function tryOpenRouter(theme: string, usedWords: string[], language: string) {
const openRouterKey = Deno.env.get('OPENROUTER_API_KEY');
if (!openRouterKey) {
throw new Error('OpenRouter API key not configured');
}
const prompts = languagePrompts[language as keyof typeof languagePrompts] || languagePrompts.en;
const randomModel = openRouterModels[Math.floor(Math.random() * openRouterModels.length)];
console.log('Trying OpenRouter with model:', randomModel);
const response = await fetch("https://openrouter.ai/api/v1/chat/completions", {
method: "POST",
headers: {
"Authorization": `Bearer ${openRouterKey}`,
"HTTP-Referer": "https://think-in-sync.com",
"X-Title": "Think in Sync",
"Content-Type": "application/json"
},
body: JSON.stringify({
model: randomModel,
messages: [
{
role: "system",
content: `${prompts.systemPrompt} "${theme}".\n${prompts.requirements} ${usedWords.join(', ')}\n\nRespond with just the word in UPPERCASE, nothing else.`
}
]
})
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`OpenRouter API error: ${response.status} - ${errorText}`);
}
const data = await response.json();
if (!data?.choices?.[0]?.message?.content) {
throw new Error('Invalid response from OpenRouter API');
}
return data.choices[0].message.content.trim();
}
serve(async (req) => {
if (req.method === 'OPTIONS') {
return new Response(null, { headers: corsHeaders });
}
try {
const { theme, usedWords = [], language = 'en' } = await req.json();
console.log('Generating word for theme:', theme, 'language:', language, 'excluding:', usedWords);
let word;
let error;
try {
console.log('Attempting with Mistral...');
word = await tryMistral(theme, usedWords, language);
console.log('Successfully generated word with Mistral:', word);
} catch (mistralError) {
console.error('Mistral error:', mistralError);
console.log('Falling back to OpenRouter...');
try {
word = await tryOpenRouter(theme, usedWords, language);
console.log('Successfully generated word with OpenRouter:', word);
} catch (openRouterError) {
console.error('OpenRouter error:', openRouterError);
error = openRouterError;
}
}
if (!word) {
return new Response(
JSON.stringify({
error: 'Failed to generate word with both Mistral and OpenRouter',
details: error?.message || 'Unknown error'
}),
{
status: 500,
headers: { ...corsHeaders, 'Content-Type': 'application/json' }
}
);
}
return new Response(
JSON.stringify({ word }),
{ headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
);
} catch (error) {
console.error('Error generating themed word:', error);
return new Response(
JSON.stringify({
error: 'Error generating themed word',
details: error.message
}),
{
status: 500,
headers: { ...corsHeaders, 'Content-Type': 'application/json' }
}
);
}
}); |