Felix Zieger commited on
Commit
5bd3ab2
·
1 Parent(s): bf1b7c7

fallback AI model

Browse files
supabase/functions/detect-fraud/index.ts CHANGED
@@ -27,7 +27,7 @@ serve(async (req) => {
27
  while (retryCount < maxRetries) {
28
  try {
29
  const response = await client.chat.complete({
30
- model: "mistral-large-latest",
31
  messages: [
32
  {
33
  role: "system",
 
27
  while (retryCount < maxRetries) {
28
  try {
29
  const response = await client.chat.complete({
30
+ model: "mistral-medium-latest",
31
  messages: [
32
  {
33
  role: "system",
supabase/functions/generate-themed-word/index.ts CHANGED
@@ -30,56 +30,104 @@ const languagePrompts = {
30
  }
31
  };
32
 
33
- serve(async (req) => {
34
- if (req.method === 'OPTIONS') {
35
- return new Response(null, { headers: corsHeaders });
36
- }
 
 
37
 
38
- try {
39
- const { theme, usedWords = [], language = 'en' } = await req.json();
40
- console.log('Generating word for theme:', theme, 'language:', language, 'excluding:', usedWords);
 
41
 
42
- const client = new Mistral({
43
- apiKey: Deno.env.get('MISTRAL_API_KEY'),
44
- });
45
 
46
- const prompts = languagePrompts[language as keyof typeof languagePrompts] || languagePrompts.en;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
 
48
- const response = await client.chat.complete({
49
- model: "mistral-large-latest",
 
 
 
 
 
 
 
 
50
  messages: [
51
  {
52
  role: "system",
53
  content: `${prompts.systemPrompt} "${theme}".\n${prompts.requirements} ${usedWords.join(', ')}\n\nRespond with just the word in UPPERCASE, nothing else.`
54
  }
55
- ],
56
- maxTokens: 300,
57
- temperature: 0.99
58
- });
59
 
60
- const word = response.choices[0].message.content.trim();
61
- console.log('Generated word:', word);
 
62
 
63
- return new Response(
64
- JSON.stringify({ word }),
65
- {
66
- headers: {
67
- ...corsHeaders,
68
- 'Content-Type': 'application/json'
69
- }
70
- }
71
- );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  } catch (error) {
73
  console.error('Error generating themed word:', error);
74
  return new Response(
75
  JSON.stringify({ error: error.message }),
76
  {
77
  status: 500,
78
- headers: {
79
- ...corsHeaders,
80
- 'Content-Type': 'application/json'
81
- }
82
  }
83
  );
84
  }
85
- });
 
30
  }
31
  };
32
 
33
+ const openRouterModels = [
34
+ 'sophosympatheia/rogue-rose-103b-v0.2:free',
35
+ 'google/gemini-2.0-flash-exp:free',
36
+ 'meta-llama/llama-3.1-70b-instruct:free',
37
+ 'microsoft/phi-3-medium-128k-instruct:free'
38
+ ];
39
 
40
+ async function tryMistral(theme: string, usedWords: string[], language: string) {
41
+ const client = new Mistral({
42
+ apiKey: Deno.env.get('MISTRAL_API_KEY'),
43
+ });
44
 
45
+ const prompts = languagePrompts[language as keyof typeof languagePrompts] || languagePrompts.en;
 
 
46
 
47
+ const response = await client.chat.complete({
48
+ model: "mistral-medium-latest",
49
+ messages: [
50
+ {
51
+ role: "system",
52
+ content: `${prompts.systemPrompt} "${theme}".\n${prompts.requirements} ${usedWords.join(', ')}\n\nRespond with just the word in UPPERCASE, nothing else.`
53
+ }
54
+ ],
55
+ maxTokens: 300,
56
+ temperature: 0.99
57
+ });
58
+
59
+ return response.choices[0].message.content.trim();
60
+ }
61
+
62
+ async function tryOpenRouter(theme: string, usedWords: string[], language: string) {
63
+ const prompts = languagePrompts[language as keyof typeof languagePrompts] || languagePrompts.en;
64
+ const randomModel = openRouterModels[Math.floor(Math.random() * openRouterModels.length)];
65
+
66
+ console.log('Trying OpenRouter with model:', randomModel);
67
 
68
+ const response = await fetch("https://openrouter.ai/api/v1/chat/completions", {
69
+ method: "POST",
70
+ headers: {
71
+ "Authorization": `Bearer ${Deno.env.get('OPENROUTER_API_KEY')}`,
72
+ "HTTP-Referer": "https://think-in-sync.com",
73
+ "X-Title": "Think in Sync",
74
+ "Content-Type": "application/json"
75
+ },
76
+ body: JSON.stringify({
77
+ model: randomModel,
78
  messages: [
79
  {
80
  role: "system",
81
  content: `${prompts.systemPrompt} "${theme}".\n${prompts.requirements} ${usedWords.join(', ')}\n\nRespond with just the word in UPPERCASE, nothing else.`
82
  }
83
+ ]
84
+ })
85
+ });
 
86
 
87
+ if (!response.ok) {
88
+ throw new Error(`OpenRouter API error: ${response.status}`);
89
+ }
90
 
91
+ const data = await response.json();
92
+ return data.choices[0].message.content.trim();
93
+ }
94
+
95
+ serve(async (req) => {
96
+ if (req.method === 'OPTIONS') {
97
+ return new Response(null, { headers: corsHeaders });
98
+ }
99
+
100
+ try {
101
+ const { theme, usedWords = [], language = 'en' } = await req.json();
102
+ console.log('Generating word for theme:', theme, 'language:', language, 'excluding:', usedWords);
103
+
104
+ try {
105
+ console.log('Attempting with Mistral...');
106
+ const word = await tryMistral(theme, usedWords, language);
107
+ console.log('Successfully generated word with Mistral:', word);
108
+ return new Response(
109
+ JSON.stringify({ word }),
110
+ { headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
111
+ );
112
+ } catch (mistralError) {
113
+ console.error('Mistral error:', mistralError);
114
+ console.log('Falling back to OpenRouter...');
115
+
116
+ const word = await tryOpenRouter(theme, usedWords, language);
117
+ console.log('Successfully generated word with OpenRouter:', word);
118
+ return new Response(
119
+ JSON.stringify({ word }),
120
+ { headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
121
+ );
122
+ }
123
  } catch (error) {
124
  console.error('Error generating themed word:', error);
125
  return new Response(
126
  JSON.stringify({ error: error.message }),
127
  {
128
  status: 500,
129
+ headers: { ...corsHeaders, 'Content-Type': 'application/json' }
 
 
 
130
  }
131
  );
132
  }
133
+ });
supabase/functions/generate-word/index.ts CHANGED
@@ -34,6 +34,82 @@ const languagePrompts = {
34
  }
35
  };
36
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  serve(async (req) => {
38
  if (req.method === 'OPTIONS') {
39
  return new Response(null, { headers: corsHeaders });
@@ -44,79 +120,34 @@ serve(async (req) => {
44
  console.log('Generating word for:', { currentWord, currentSentence, language });
45
 
46
  const existingSentence = currentSentence || '';
47
- const prompts = languagePrompts[language as keyof typeof languagePrompts] || languagePrompts.en;
48
-
49
- const client = new Mistral({
50
- apiKey: Deno.env.get('MISTRAL_API_KEY'),
51
- });
52
-
53
- const maxRetries = 3;
54
- let retryCount = 0;
55
- let lastError = null;
56
-
57
- while (retryCount < maxRetries) {
58
- try {
59
- const response = await client.chat.complete({
60
- model: "mistral-large-latest",
61
- messages: [
62
- {
63
- role: "system",
64
- content: `${prompts.systemPrompt} "${currentWord}". ${prompts.task} ${prompts.instruction} "${existingSentence}". Do not add quotes or backticks. Just answer with the sentence.`
65
- }
66
- ],
67
- maxTokens: 300,
68
- temperature: 0.5
69
- });
70
-
71
- const aiResponse = response.choices[0].message.content.trim();
72
- console.log('AI full response:', aiResponse);
73
-
74
- const newWord = aiResponse
75
- .slice(existingSentence.length)
76
- .trim()
77
- .split(' ')[0]
78
- .replace(/[.,!?]$/, '');
79
-
80
- console.log('Extracted new word:', newWord);
81
-
82
- return new Response(
83
- JSON.stringify({ word: newWord }),
84
- { headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
85
- );
86
- } catch (error) {
87
- console.error(`Attempt ${retryCount + 1} failed:`, error);
88
- lastError = error;
89
-
90
- if (error.message?.includes('rate limit') || error.status === 429) {
91
- const waitTime = Math.pow(2, retryCount) * 1000;
92
- console.log(`Rate limit hit, waiting ${waitTime}ms before retry`);
93
- await new Promise(resolve => setTimeout(resolve, waitTime));
94
- retryCount++;
95
- continue;
96
- }
97
-
98
- throw error;
99
- }
100
- }
101
-
102
- throw new Error(`Failed after ${maxRetries} attempts. Last error: ${lastError?.message}`);
103
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  } catch (error) {
105
  console.error('Error generating word:', error);
106
-
107
- const errorMessage = error.message?.includes('rate limit')
108
- ? "The AI service is currently busy. Please try again in a few moments."
109
- : "Sorry, there was an error generating the word. Please try again.";
110
-
111
  return new Response(
112
- JSON.stringify({
113
- error: errorMessage,
114
- details: error.message
115
- }),
116
  {
117
- status: error.message?.includes('rate limit') ? 429 : 500,
118
  headers: { ...corsHeaders, 'Content-Type': 'application/json' }
119
  }
120
  );
121
  }
122
- });
 
34
  }
35
  };
36
 
37
+ const openRouterModels = [
38
+ 'sophosympatheia/rogue-rose-103b-v0.2:free',
39
+ 'google/gemini-2.0-flash-exp:free',
40
+ 'meta-llama/llama-3.1-70b-instruct:free',
41
+ 'microsoft/phi-3-medium-128k-instruct:free'
42
+ ];
43
+
44
+ async function tryMistral(currentWord: string, existingSentence: string, language: string) {
45
+ const client = new Mistral({
46
+ apiKey: Deno.env.get('MISTRAL_API_KEY'),
47
+ });
48
+
49
+ const prompts = languagePrompts[language as keyof typeof languagePrompts] || languagePrompts.en;
50
+
51
+ const response = await client.chat.complete({
52
+ model: "mistral-medium-latest",
53
+ messages: [
54
+ {
55
+ role: "system",
56
+ content: `${prompts.systemPrompt} "${currentWord}". ${prompts.task} ${prompts.instruction} "${existingSentence}". Do not add quotes or backticks. Just answer with the sentence.`
57
+ }
58
+ ],
59
+ maxTokens: 300,
60
+ temperature: 0.5
61
+ });
62
+
63
+ const aiResponse = response.choices[0].message.content.trim();
64
+ console.log('Mistral full response:', aiResponse);
65
+
66
+ return aiResponse
67
+ .slice(existingSentence.length)
68
+ .trim()
69
+ .split(' ')[0]
70
+ .replace(/[.,!?]$/, '');
71
+ }
72
+
73
+ async function tryOpenRouter(currentWord: string, existingSentence: string, language: string) {
74
+ const prompts = languagePrompts[language as keyof typeof languagePrompts] || languagePrompts.en;
75
+ const randomModel = openRouterModels[Math.floor(Math.random() * openRouterModels.length)];
76
+
77
+ console.log('Trying OpenRouter with model:', randomModel);
78
+
79
+ const response = await fetch("https://openrouter.ai/api/v1/chat/completions", {
80
+ method: "POST",
81
+ headers: {
82
+ "Authorization": `Bearer ${Deno.env.get('OPENROUTER_API_KEY')}`,
83
+ "HTTP-Referer": "https://think-in-sync.com",
84
+ "X-Title": "Think in Sync",
85
+ "Content-Type": "application/json"
86
+ },
87
+ body: JSON.stringify({
88
+ model: randomModel,
89
+ messages: [
90
+ {
91
+ role: "system",
92
+ content: `${prompts.systemPrompt} "${currentWord}". ${prompts.task} ${prompts.instruction} "${existingSentence}". Do not add quotes or backticks. Just answer with the sentence.`
93
+ }
94
+ ]
95
+ })
96
+ });
97
+
98
+ if (!response.ok) {
99
+ throw new Error(`OpenRouter API error: ${response.status}`);
100
+ }
101
+
102
+ const data = await response.json();
103
+ const aiResponse = data.choices[0].message.content.trim();
104
+ console.log('OpenRouter full response:', aiResponse);
105
+
106
+ return aiResponse
107
+ .slice(existingSentence.length)
108
+ .trim()
109
+ .split(' ')[0]
110
+ .replace(/[.,!?]$/, '');
111
+ }
112
+
113
  serve(async (req) => {
114
  if (req.method === 'OPTIONS') {
115
  return new Response(null, { headers: corsHeaders });
 
120
  console.log('Generating word for:', { currentWord, currentSentence, language });
121
 
122
  const existingSentence = currentSentence || '';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
 
124
+ try {
125
+ console.log('Attempting with Mistral...');
126
+ const word = await tryMistral(currentWord, existingSentence, language);
127
+ console.log('Successfully generated word with Mistral:', word);
128
+ return new Response(
129
+ JSON.stringify({ word }),
130
+ { headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
131
+ );
132
+ } catch (mistralError) {
133
+ console.error('Mistral error:', mistralError);
134
+ console.log('Falling back to OpenRouter...');
135
+
136
+ const word = await tryOpenRouter(currentWord, existingSentence, language);
137
+ console.log('Successfully generated word with OpenRouter:', word);
138
+ return new Response(
139
+ JSON.stringify({ word }),
140
+ { headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
141
+ );
142
+ }
143
  } catch (error) {
144
  console.error('Error generating word:', error);
 
 
 
 
 
145
  return new Response(
146
+ JSON.stringify({ error: error.message }),
 
 
 
147
  {
148
+ status: 500,
149
  headers: { ...corsHeaders, 'Content-Type': 'application/json' }
150
  }
151
  );
152
  }
153
+ });
supabase/functions/guess-word/index.ts CHANGED
@@ -29,85 +29,112 @@ const languagePrompts = {
29
  }
30
  };
31
 
32
- serve(async (req) => {
33
- // Handle CORS preflight requests
34
- if (req.method === 'OPTIONS') {
35
- return new Response(null, { headers: corsHeaders });
36
- }
 
37
 
38
- try {
39
- const { sentence, language = 'en' } = await req.json();
40
- console.log('Trying to guess word from sentence:', sentence, 'language:', language);
 
41
 
42
- const client = new Mistral({
43
- apiKey: Deno.env.get('MISTRAL_API_KEY'),
44
- });
45
 
46
- const prompts = languagePrompts[language as keyof typeof languagePrompts] || languagePrompts.en;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
 
48
- const maxRetries = 3;
49
- let retryCount = 0;
50
- let lastError = null;
51
 
52
- while (retryCount < maxRetries) {
53
- try {
54
- const response = await client.chat.complete({
55
- model: "mistral-large-latest",
56
- messages: [
57
- {
58
- role: "system",
59
- content: `${prompts.systemPrompt} Respond with ONLY the word you think is being described, in uppercase letters. Do not add any explanation or punctuation.`
60
- },
61
- {
62
- role: "user",
63
- content: `${prompts.instruction} "${sentence}"`
64
- }
65
- ],
66
- maxTokens: 50,
67
- temperature: 0.1
68
- });
69
 
70
- const guess = response.choices[0].message.content.trim().toUpperCase();
71
- console.log('AI guess:', guess);
72
 
73
- return new Response(
74
- JSON.stringify({ guess }),
75
- { headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
76
- );
77
- } catch (error) {
78
- console.error(`Attempt ${retryCount + 1} failed:`, error);
79
- lastError = error;
80
-
81
- if (error.message?.includes('rate limit') || error.status === 429) {
82
- const waitTime = Math.pow(2, retryCount) * 1000;
83
- console.log(`Rate limit hit, waiting ${waitTime}ms before retry`);
84
- await new Promise(resolve => setTimeout(resolve, waitTime));
85
- retryCount++;
86
- continue;
 
 
 
 
87
  }
88
-
89
- throw error;
90
- }
91
- }
 
 
 
92
 
93
- throw new Error(`Failed after ${maxRetries} attempts. Last error: ${lastError?.message}`);
 
 
94
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
  } catch (error) {
96
  console.error('Error generating guess:', error);
97
-
98
- const errorMessage = error.message?.includes('rate limit')
99
- ? "The AI service is currently busy. Please try again in a few moments."
100
- : "Sorry, there was an error generating the guess. Please try again.";
101
-
102
  return new Response(
103
- JSON.stringify({
104
- error: errorMessage,
105
- details: error.message
106
- }),
107
  {
108
- status: error.message?.includes('rate limit') ? 429 : 500,
109
  headers: { ...corsHeaders, 'Content-Type': 'application/json' }
110
  }
111
  );
112
  }
113
- });
 
29
  }
30
  };
31
 
32
+ const openRouterModels = [
33
+ 'sophosympatheia/rogue-rose-103b-v0.2:free',
34
+ 'google/gemini-2.0-flash-exp:free',
35
+ 'meta-llama/llama-3.1-70b-instruct:free',
36
+ 'microsoft/phi-3-medium-128k-instruct:free'
37
+ ];
38
 
39
+ async function tryMistral(sentence: string, language: string) {
40
+ const client = new Mistral({
41
+ apiKey: Deno.env.get('MISTRAL_API_KEY'),
42
+ });
43
 
44
+ const prompts = languagePrompts[language as keyof typeof languagePrompts] || languagePrompts.en;
 
 
45
 
46
+ const response = await client.chat.complete({
47
+ model: "mistral-medium-latest",
48
+ messages: [
49
+ {
50
+ role: "system",
51
+ content: `${prompts.systemPrompt} Respond with ONLY the word you think is being described, in uppercase letters. Do not add any explanation or punctuation.`
52
+ },
53
+ {
54
+ role: "user",
55
+ content: `${prompts.instruction} "${sentence}"`
56
+ }
57
+ ],
58
+ maxTokens: 50,
59
+ temperature: 0.1
60
+ });
61
 
62
+ return response.choices[0].message.content.trim().toUpperCase();
63
+ }
 
64
 
65
+ async function tryOpenRouter(sentence: string, language: string) {
66
+ const prompts = languagePrompts[language as keyof typeof languagePrompts] || languagePrompts.en;
67
+ const randomModel = openRouterModels[Math.floor(Math.random() * openRouterModels.length)];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
 
69
+ console.log('Trying OpenRouter with model:', randomModel);
 
70
 
71
+ const response = await fetch("https://openrouter.ai/api/v1/chat/completions", {
72
+ method: "POST",
73
+ headers: {
74
+ "Authorization": `Bearer ${Deno.env.get('OPENROUTER_API_KEY')}`,
75
+ "HTTP-Referer": "https://think-in-sync.com",
76
+ "X-Title": "Think in Sync",
77
+ "Content-Type": "application/json"
78
+ },
79
+ body: JSON.stringify({
80
+ model: randomModel,
81
+ messages: [
82
+ {
83
+ role: "system",
84
+ content: `${prompts.systemPrompt} Respond with ONLY the word you think is being described, in uppercase letters. Do not add any explanation or punctuation.`
85
+ },
86
+ {
87
+ role: "user",
88
+ content: `${prompts.instruction} "${sentence}"`
89
  }
90
+ ]
91
+ })
92
+ });
93
+
94
+ if (!response.ok) {
95
+ throw new Error(`OpenRouter API error: ${response.status}`);
96
+ }
97
 
98
+ const data = await response.json();
99
+ return data.choices[0].message.content.trim().toUpperCase();
100
+ }
101
 
102
+ serve(async (req) => {
103
+ if (req.method === 'OPTIONS') {
104
+ return new Response(null, { headers: corsHeaders });
105
+ }
106
+
107
+ try {
108
+ const { sentence, language = 'en' } = await req.json();
109
+ console.log('Trying to guess word from sentence:', sentence, 'language:', language);
110
+
111
+ try {
112
+ console.log('Attempting with Mistral...');
113
+ const guess = await tryMistral(sentence, language);
114
+ console.log('Successfully generated guess with Mistral:', guess);
115
+ return new Response(
116
+ JSON.stringify({ guess }),
117
+ { headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
118
+ );
119
+ } catch (mistralError) {
120
+ console.error('Mistral error:', mistralError);
121
+ console.log('Falling back to OpenRouter...');
122
+
123
+ const guess = await tryOpenRouter(sentence, language);
124
+ console.log('Successfully generated guess with OpenRouter:', guess);
125
+ return new Response(
126
+ JSON.stringify({ guess }),
127
+ { headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
128
+ );
129
+ }
130
  } catch (error) {
131
  console.error('Error generating guess:', error);
 
 
 
 
 
132
  return new Response(
133
+ JSON.stringify({ error: error.message }),
 
 
 
134
  {
135
+ status: 500,
136
  headers: { ...corsHeaders, 'Content-Type': 'application/json' }
137
  }
138
  );
139
  }
140
+ });
supabase/functions/validate-sentence/index.ts CHANGED
@@ -20,7 +20,7 @@ serve(async (req) => {
20
  });
21
 
22
  const response = await client.chat.complete({
23
- model: "mistral-large-latest",
24
  messages: [
25
  {
26
  role: "system",
 
20
  });
21
 
22
  const response = await client.chat.complete({
23
+ model: "mistral-medium-latest",
24
  messages: [
25
  {
26
  role: "system",