File size: 6,729 Bytes
55a034a 1a45d5d 55a034a 831f7e7 a64b653 831f7e7 a64b653 831f7e7 81e6964 a64b653 831f7e7 a64b653 831f7e7 a64b653 2d83648 831f7e7 5bd3ab2 1a45d5d 5bd3ab2 65676ec 1a45d5d 5bd3ab2 65676ec 5bd3ab2 65676ec 5bd3ab2 1a45d5d 5bd3ab2 65676ec 5bd3ab2 a64b653 5bd3ab2 1a45d5d 5bd3ab2 1a45d5d 5bd3ab2 1a45d5d a64b653 1a45d5d 5bd3ab2 1a45d5d 65676ec 5bd3ab2 55a034a 65676ec 55a034a 0ce34cb 55a034a 5bd3ab2 65676ec 5bd3ab2 65676ec 5bd3ab2 1a45d5d a64b653 5bd3ab2 1a45d5d 5bd3ab2 55a034a 1a45d5d 55a034a 1a45d5d a64b653 5bd3ab2 55a034a 5bd3ab2 |
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 181 182 |
import { serve } from "https://deno.land/[email protected]/http/server.ts";
import * as Sentry from "https://deno.land/x/sentry/index.mjs";
Sentry.init({
dsn: "https://ca41c3f96489cc1b3e69c9a44704f7ee@o4508722276007936.ingest.de.sentry.io/4508772265558096",
defaultIntegrations: false,
// Performance Monitoring
tracesSampleRate: 1.0,
// Set sampling rate for profiling - this is relative to tracesSampleRate
profilesSampleRate: 1.0,
});
Sentry.setTag('region', Deno.env.get('SB_REGION'));
Sentry.setTag('execution_id', Deno.env.get('SB_EXECUTION_ID'));
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
};
const languagePrompts = {
en: {
systemPrompt: "You are helping in a word game. The secret word is",
task: "Your task is to find a sentence to describe this word without using it directly.",
instruction: "Answer with a description for this word. Start your answer with",
noQuotes: "Do not add quotes or backticks. Just answer with the sentence."
},
fr: {
systemPrompt: "Vous aidez dans un jeu de mots. Le mot secret est",
task: "Votre tâche est de trouver une phrase pour décrire ce mot sans l'utiliser directement.",
instruction: "Répondez avec une phrase qui commence par",
noQuotes: "Ne rajoutez pas de guillemets ni de backticks. Répondez simplement par la phrase."
},
de: {
systemPrompt: "Sie helfen bei einem Wortspiel. Das geheime Wort ist",
task: "Ihre Aufgabe ist es, eine Beschreibung zu finden, der dieses Wort beschreibt, ohne es direkt zu verwenden.",
instruction: "Beginnen sie ihre Antwort mit",
noQuotes: "Fügen Sie keine Anführungszeichen oder Backticks hinzu. Antworten Sie einfach mit dem Satz."
},
it: {
systemPrompt: "Stai aiutando in un gioco di parole. La parola segreta è",
task: "Il tuo compito è trovare una frase per descrivere questa parola senza usarla direttamente.",
instruction: "Rispondi con una frase completa e grammaticalmente corretta che inizia con",
noQuotes: "Non aggiungere virgolette o backticks. Rispondi semplicemente con la frase."
},
es: {
systemPrompt: "Estás ayudando en un juego de palabras. La palabra secreta es",
task: "Tu tarea es encontrar una frase para describir esta palabra sin usarla directamente.",
instruction: "Responde con una frase completa y gramaticalmente correcta que comience con",
noQuotes: "No añadas comillas ni backticks. Simplemente responde con la frase."
},
pt: {
systemPrompt: "Você está ajudando em um jogo de palavras. A palavra secreta é",
task: "Sua tarefa é encontrar uma frase para descrever esta palavra sem usá-la diretamente.",
instruction: "Responda com uma frase completa e gramaticalmente correta que comece com",
noQuotes: "Não adicione aspas nem backticks. Simplesmente responda com a frase."
}
};
const openRouterModels = [
'google/gemini-2.0-flash-exp:free',
'mistralai/mistral-nemo'
];
async function generateWord(currentWord: string, existingSentence: string, language: string, model?: 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 selectedModel = model || openRouterModels[Math.floor(Math.random() * openRouterModels.length)];
console.log('Using OpenRouter with model:', selectedModel);
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: selectedModel,
messages: [
{
role: "system",
content: `${prompts.systemPrompt} "${currentWord}". ${prompts.task} ${prompts.instruction} "${existingSentence}". ${prompts.noQuotes}`
}
]
})
});
if (!response.ok) {
const errorText = await response.text();
console.error('OpenRouter API error response:', {
status: response.status,
statusText: response.statusText,
body: errorText
});
throw new Error(`OpenRouter API error (${response.status}): ${errorText}`);
}
const data = await response.json();
console.log('OpenRouter raw response:', data);
if (!data?.choices?.[0]?.message?.content) {
console.error('Invalid OpenRouter API response structure:', data);
throw new Error('Received invalid response structure from OpenRouter API');
}
const aiResponse = data.choices[0].message.content.trim();
console.log('OpenRouter processed response:', aiResponse);
const word = aiResponse
.slice(existingSentence.length)
.trim()
.split(' ')[0]
.replace(/[.,!?]$/, '');
return { word, model: selectedModel };
}
serve(async (req) => {
if (req.method === 'OPTIONS') {
return new Response(null, { headers: corsHeaders });
}
try {
const { currentWord, currentSentence, language = 'en', model } = await req.json();
console.log('Generating word for:', { currentWord, currentSentence, language, model });
const existingSentence = currentSentence || '';
try {
const { word, model: usedModel } = await generateWord(currentWord, existingSentence, language, model);
console.log('Successfully generated word:', word, 'using model:', usedModel);
return new Response(
JSON.stringify({ word, model: usedModel }),
{ headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
);
} catch (error) {
console.error('OpenRouter API error:', {
error: error,
message: error.message,
stack: error.stack
});
Sentry.captureException(error);
return new Response(
JSON.stringify({
error: 'Failed to generate word',
details: error.message
}),
{
status: 500,
headers: { ...corsHeaders, 'Content-Type': 'application/json' }
}
);
}
} catch (error) {
console.error('Fatal error in generate-word function:', {
error: error,
message: error.message,
stack: error.stack
});
Sentry.captureException(error);
return new Response(
JSON.stringify({
error: error.message,
details: process.env.NODE_ENV === 'development' ? error.stack : undefined
}),
{
status: 500,
headers: { ...corsHeaders, 'Content-Type': 'application/json' }
}
);
}
});
|