Felix Zieger
larger models again
47fea40
raw
history blame
5.01 kB
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 sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
serve(async (req) => {
// Handle CORS preflight requests
if (req.method === 'OPTIONS') {
return new Response(null, { headers: corsHeaders });
}
try {
const { sentence, targetWord, language } = await req.json();
console.log('Checking for fraud:', { sentence, targetWord, language });
const client = new Mistral({
apiKey: Deno.env.get('MISTRAL_API_KEY'),
});
const maxRetries = 3;
let retryCount = 0;
let lastError = null;
while (retryCount < maxRetries) {
try {
console.log(`Attempt ${retryCount + 1} to check for fraud`);
const response = await client.chat.complete({
model: "mistral-large-latest",
messages: [
{
role: "system",
content: `You are a fraud detection system for a word guessing game.
The game is being played in ${language}.
Your task is to detect if a player is trying to cheat by one of two methods:
1. The Player's description is a misspelling of the target word
2. The Player's description is a sentence without spaces
Examples for cheating:
Target word: hand
Player's description: hnd
Language: en
CORRECT ANSWER: cheating
Target word: barfuß
Player's description: germanwordforbarefoot
Language: de
CORRECT ANSWER: cheating
Synonyms and names of instances of a class are legitimate descriptions.
Target word: laptop
Player's description: notebook
Language: en
CORRECT ANSWER: legitimate
Target word: play
Player's description: children often
Language: en
CORRECT ANSWER: legitimate
Target word: Pfankuchen
Player's description: Berliner
Language: de
CORRECT ANSWER: legitimate
Target word: Burrito
Player's description: Wrap
Language: es
CORRECT ANSWER: legitimate
Respond with ONLY "cheating" or "legitimate" (no punctuation or explanation).`
},
{
role: "user",
content: `Target word: "${targetWord}"
Player's description: "${sentence}"
Language: ${language}
Is this a legitimate description or an attempt to cheat?`
}
],
maxTokens: 20,
temperature: 0.1
});
if (!response?.choices?.[0]?.message?.content) {
throw new Error('Invalid response format from Mistral API');
}
const verdict = response.choices[0].message.content.trim().toLowerCase();
console.log('Fraud detection verdict:', verdict);
return new Response(
JSON.stringify({ verdict }),
{ headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
);
} catch (error) {
console.error(`Attempt ${retryCount + 1} failed:`, error);
lastError = error;
// Check if it's a rate limit or service unavailable error
if (error.message?.includes('rate limit') ||
error.message?.includes('503') ||
error.message?.includes('Service unavailable')) {
const waitTime = Math.pow(2, retryCount) * 1000; // Exponential backoff
console.log(`Service unavailable or rate limited, waiting ${waitTime}ms before retry`);
await sleep(waitTime);
retryCount++;
continue;
}
// If it's not a retryable error, throw immediately
throw error;
}
}
// If we've exhausted all retries
throw new Error(`Failed after ${maxRetries} attempts. Last error: ${lastError?.message}`);
} catch (error) {
console.error('Error in fraud detection:', error);
const errorMessage = error.message?.includes('rate limit') || error.message?.includes('503')
? "The AI service is currently busy. Please try again in a few moments."
: "Sorry, there was an error checking for fraud. Please try again.";
return new Response(
JSON.stringify({
error: errorMessage,
details: error.message
}),
{
status: error.message?.includes('rate limit') || error.message?.includes('503') ? 429 : 500,
headers: { ...corsHeaders, 'Content-Type': 'application/json' }
}
);
}
});