File size: 5,008 Bytes
5835ecd
 
 
 
 
 
 
 
47fea40
 
5835ecd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47fea40
 
5835ecd
47fea40
5835ecd
 
 
 
 
47fea40
 
 
5835ecd
 
 
47fea40
 
 
 
 
 
 
 
 
5835ecd
 
 
47fea40
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5835ecd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47fea40
 
 
 
5835ecd
 
 
 
 
 
 
 
 
 
 
47fea40
 
 
 
 
 
 
5835ecd
 
 
 
47fea40
5835ecd
 
 
 
47fea40
5835ecd
 
 
 
 
47fea40
5835ecd
 
 
 
 
 
 
 
 
47fea40
5835ecd
 
 
 
 
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
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' }
      }
    );
  }
});