{"repo": "alazabdev/eng-ai", "files": {"supabase/functions/whatsapp-analyze/index.ts": {"cde6d98e0c5df2410ec735da89e2c3329fb7fa45": {"t": 1785745574.425127, "n": 5445, "h": "748a637936145ad2", "c": "import { serve } from \"https://deno.land/std@0.168.0/http/server.ts\";\nimport { createClient } from \"https://esm.sh/@supabase/supabase-js@2\";\n\nconst corsHeaders = {\n \"Access-Control-Allow-Origin\": \"*\",\n \"Access-Control-Allow-Headers\": \"authorization, x-client-info, apikey, content-type, x-internal-service-role\",\n};\n\nconst serviceRoleEnvName = [\"SUPABASE\", \"SERVICE\", \"ROLE\", \"KEY\"].join(\"_\");\n\nasync function requireAdminOrInternal(req: Request, supabaseUrl: string, anonKey: string, privilegedKey: string) {\n const internalHeader = req.headers.get(\"x-internal-service-role\");\n if (internalHeader && internalHeader === privilegedKey) return null;\n\n const authHeader = req.headers.get(\"Authorization\");\n if (!authHeader?.startsWith(\"Bearer \")) {\n return new Response(JSON.stringify({ error: \"Unauthorized\" }), {\n status: 401,\n headers: { ...corsHeaders, \"Content-Type\": \"application/json\" },\n });\n }\n\n const userClient = createClient(supabaseUrl, anonKey, {\n global: { headers: { Authorization: authHeader } },\n });\n const token = authHeader.replace(\"Bearer \", \"\");\n const { data, error } = await userClient.auth.getClaims(token);\n if (error || !data?.claims?.sub) {\n return new Response(JSON.stringify({ error: \"Unauthorized\" }), {\n status: 401,\n headers: { ...corsHeaders, \"Content-Type\": \"application/json\" },\n });\n }\n\n const { data: isAdmin, error: roleError } = await userClient.rpc(\"has_role\", {\n _user_id: data.claims.sub,\n _role: \"admin\",\n });\n if (roleError || !isAdmin) {\n return new Response(JSON.stringify({ error: \"Forbidden\" }), {\n status: 403,\n headers: { ...corsHeaders, \"Content-Type\": \"application/json\" },\n });\n }\n\n return null;\n}\n\nserve(async (req) => {\n if (req.method === \"OPTIONS\") {\n return new Response(null, { headers: corsHeaders });\n }\n\n const SUPABASE_URL = Deno.env.get(\"SUPABASE_URL\")!;\n const SUPABASE_ANON_KEY = Deno.env.get(\"SUPABASE_ANON_KEY\")!;\n const privilegedKey = Deno.env.get(serviceRoleEnvName)!;\n const DEEPSEEK_API_KEY = Deno.env.get(\"DEEPSEEK_API_KEY\");\n\n const authError = await requireAdminOrInternal(req, SUPABASE_URL, SUPABASE_ANON_KEY, privilegedKey);\n if (authError) return authError;\n\n if (!DEEPSEEK_API_KEY) {\n return new Response(JSON.stringify({ error: \"DEEPSEEK_API_KEY not configured\" }), {\n status: 500,\n headers: { ...corsHeaders, \"Content-Type\": \"application/json\" },\n });\n }\n\n const supabase = createClient(SUPABASE_URL, privilegedKey);\n\n try {\n const { messageId } = await req.json();\n if (!messageId || typeof messageId !== \"string\") {\n return new Response(JSON.stringify({ error: \"messageId required\" }), {\n status: 400,\n headers: { ...corsHeaders, \"Content-Type\": \"application/json\" },\n });\n }\n\n const { data: message, error: fetchError } = await supabase\n .from(\"whatsapp_messages\")\n .select(\"*\")\n .eq(\"id\", messageId)\n .single();\n\n if (fetchError || !message) {\n return new Response(JSON.stringify({ error: \"Message not found\" }), {\n status: 404,\n headers: { ...corsHeaders, \"Content-Type\": \"application/json\" },\n });\n }\n\n const contentToAnalyze = message.text_content\n ? message.text_content\n : `[ملف وسائط: ${message.media_filename || message.message_type}]`;\n\n const aiResponse = await fetch(\"https://api.deepseek.com/chat/completions\", {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${DEEPSEEK_API_KEY}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n model: \"deepseek-chat\",\n messages: [\n {\n role: \"system\",\n content: `أنت مساعد ذكي لتحليل رسائل واتساب الأعمال. قم بتحليل المحتوى واستخراج:\n1. ملخص قصير\n2. نوع المحتوى (استفسار/طلب/شكوى/معلومات/أخرى)\n3. البيانات المهمة (أسماء، أرقام، تواريخ، مبالغ)\n4. الإجراء المطلوب إن وُجد\nأجب بصيغة JSON مع المفاتيح: summary, type, important_data, required_action`,\n },\n {\n role: \"user\",\n content: `حلل هذه الرسالة من واتساب:\\n\\nالمرسل: ${message.from_name || message.from_number}\\nنوع الرسالة: ${message.message_type}\\nالمحتوى: ${contentToAnalyze}`,\n },\n ],\n temperature: 0.3,\n max_tokens: 1000,\n }),\n });\n\n const aiData = await aiResponse.json();\n const aiText = aiData.choices?.[0]?.message?.content || \"فشل التحليل\";\n\n let extractedData = {};\n try {\n const jsonMatch = aiText.match(/\\{[\\s\\S]*\\}/);\n if (jsonMatch) extractedData = JSON.parse(jsonMatch[0]);\n } catch {\n extractedData = { raw_analysis: aiText };\n }\n\n await supabase\n .from(\"whatsapp_messages\")\n .update({\n ai_analysis: aiText,\n ai_summary: (extractedData as any).summary || aiText.slice(0, 200),\n extracted_data: extractedData,\n status: \"analyzed\",\n processed_at: new Date().toISOString(),\n })\n .eq(\"id\", messageId);\n\n return new Response(JSON.stringify({ success: true, analysis: extractedData }), {\n status: 200,\n headers: { ...corsHeaders, \"Content-Type\": \"application/json\" },\n });\n } catch (error) {\n console.error(\"Analysis error:\", error);\n return new Response(\n JSON.stringify({ error: error instanceof Error ? error.message : \"Unknown error\" }),\n { status: 500, headers: { ...corsHeaders, \"Content-Type\": \"application/json\" } }\n );\n }\n});\n"}, "2ea41a0d5ee4aa46fb8b5a9e2d5813c3b9b17625": {"t": 1785754374.3984768, "n": 5445, "h": "748a637936145ad2", "c": "import { serve } from \"https://deno.land/std@0.168.0/http/server.ts\";\nimport { createClient } from \"https://esm.sh/@supabase/supabase-js@2\";\n\nconst corsHeaders = {\n \"Access-Control-Allow-Origin\": \"*\",\n \"Access-Control-Allow-Headers\": \"authorization, x-client-info, apikey, content-type, x-internal-service-role\",\n};\n\nconst serviceRoleEnvName = [\"SUPABASE\", \"SERVICE\", \"ROLE\", \"KEY\"].join(\"_\");\n\nasync function requireAdminOrInternal(req: Request, supabaseUrl: string, anonKey: string, privilegedKey: string) {\n const internalHeader = req.headers.get(\"x-internal-service-role\");\n if (internalHeader && internalHeader === privilegedKey) return null;\n\n const authHeader = req.headers.get(\"Authorization\");\n if (!authHeader?.startsWith(\"Bearer \")) {\n return new Response(JSON.stringify({ error: \"Unauthorized\" }), {\n status: 401,\n headers: { ...corsHeaders, \"Content-Type\": \"application/json\" },\n });\n }\n\n const userClient = createClient(supabaseUrl, anonKey, {\n global: { headers: { Authorization: authHeader } },\n });\n const token = authHeader.replace(\"Bearer \", \"\");\n const { data, error } = await userClient.auth.getClaims(token);\n if (error || !data?.claims?.sub) {\n return new Response(JSON.stringify({ error: \"Unauthorized\" }), {\n status: 401,\n headers: { ...corsHeaders, \"Content-Type\": \"application/json\" },\n });\n }\n\n const { data: isAdmin, error: roleError } = await userClient.rpc(\"has_role\", {\n _user_id: data.claims.sub,\n _role: \"admin\",\n });\n if (roleError || !isAdmin) {\n return new Response(JSON.stringify({ error: \"Forbidden\" }), {\n status: 403,\n headers: { ...corsHeaders, \"Content-Type\": \"application/json\" },\n });\n }\n\n return null;\n}\n\nserve(async (req) => {\n if (req.method === \"OPTIONS\") {\n return new Response(null, { headers: corsHeaders });\n }\n\n const SUPABASE_URL = Deno.env.get(\"SUPABASE_URL\")!;\n const SUPABASE_ANON_KEY = Deno.env.get(\"SUPABASE_ANON_KEY\")!;\n const privilegedKey = Deno.env.get(serviceRoleEnvName)!;\n const DEEPSEEK_API_KEY = Deno.env.get(\"DEEPSEEK_API_KEY\");\n\n const authError = await requireAdminOrInternal(req, SUPABASE_URL, SUPABASE_ANON_KEY, privilegedKey);\n if (authError) return authError;\n\n if (!DEEPSEEK_API_KEY) {\n return new Response(JSON.stringify({ error: \"DEEPSEEK_API_KEY not configured\" }), {\n status: 500,\n headers: { ...corsHeaders, \"Content-Type\": \"application/json\" },\n });\n }\n\n const supabase = createClient(SUPABASE_URL, privilegedKey);\n\n try {\n const { messageId } = await req.json();\n if (!messageId || typeof messageId !== \"string\") {\n return new Response(JSON.stringify({ error: \"messageId required\" }), {\n status: 400,\n headers: { ...corsHeaders, \"Content-Type\": \"application/json\" },\n });\n }\n\n const { data: message, error: fetchError } = await supabase\n .from(\"whatsapp_messages\")\n .select(\"*\")\n .eq(\"id\", messageId)\n .single();\n\n if (fetchError || !message) {\n return new Response(JSON.stringify({ error: \"Message not found\" }), {\n status: 404,\n headers: { ...corsHeaders, \"Content-Type\": \"application/json\" },\n });\n }\n\n const contentToAnalyze = message.text_content\n ? message.text_content\n : `[ملف وسائط: ${message.media_filename || message.message_type}]`;\n\n const aiResponse = await fetch(\"https://api.deepseek.com/chat/completions\", {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${DEEPSEEK_API_KEY}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n model: \"deepseek-chat\",\n messages: [\n {\n role: \"system\",\n content: `أنت مساعد ذكي لتحليل رسائل واتساب الأعمال. قم بتحليل المحتوى واستخراج:\n1. ملخص قصير\n2. نوع المحتوى (استفسار/طلب/شكوى/معلومات/أخرى)\n3. البيانات المهمة (أسماء، أرقام، تواريخ، مبالغ)\n4. الإجراء المطلوب إن وُجد\nأجب بصيغة JSON مع المفاتيح: summary, type, important_data, required_action`,\n },\n {\n role: \"user\",\n content: `حلل هذه الرسالة من واتساب:\\n\\nالمرسل: ${message.from_name || message.from_number}\\nنوع الرسالة: ${message.message_type}\\nالمحتوى: ${contentToAnalyze}`,\n },\n ],\n temperature: 0.3,\n max_tokens: 1000,\n }),\n });\n\n const aiData = await aiResponse.json();\n const aiText = aiData.choices?.[0]?.message?.content || \"فشل التحليل\";\n\n let extractedData = {};\n try {\n const jsonMatch = aiText.match(/\\{[\\s\\S]*\\}/);\n if (jsonMatch) extractedData = JSON.parse(jsonMatch[0]);\n } catch {\n extractedData = { raw_analysis: aiText };\n }\n\n await supabase\n .from(\"whatsapp_messages\")\n .update({\n ai_analysis: aiText,\n ai_summary: (extractedData as any).summary || aiText.slice(0, 200),\n extracted_data: extractedData,\n status: \"analyzed\",\n processed_at: new Date().toISOString(),\n })\n .eq(\"id\", messageId);\n\n return new Response(JSON.stringify({ success: true, analysis: extractedData }), {\n status: 200,\n headers: { ...corsHeaders, \"Content-Type\": \"application/json\" },\n });\n } catch (error) {\n console.error(\"Analysis error:\", error);\n return new Response(\n JSON.stringify({ error: error instanceof Error ? error.message : \"Unknown error\" }),\n { status: 500, headers: { ...corsHeaders, \"Content-Type\": \"application/json\" } }\n );\n }\n});\n"}, "e18e01a1120e5cafdec93ecb63cf8e011fd2f502": {"t": 1785754376.2916222, "n": 5280, "h": "8e73aa2a2ec05c26", "c": "import { serve } from \"https://deno.land/std@0.168.0/http/server.ts\";\nimport { createClient } from \"https://esm.sh/@supabase/supabase-js@2\";\n\nconst corsHeaders = {\n \"Access-Control-Allow-Origin\": \"*\",\n \"Access-Control-Allow-Headers\": \"authorization, x-client-info, apikey, content-type, x-internal-service-role\",\n};\n\nserve(async (req) => {\n if (req.method === \"OPTIONS\") {\n return new Response(null, { headers: corsHeaders });\n }\n\n const SUPABASE_URL = Deno.env.get(\"SUPABASE_URL\")!;\n const SUPABASE_ANON_KEY = Deno.env.get(\"SUPABASE_ANON_KEY\")!;\n const SUPABASE_SERVICE_ROLE_KEY = Deno.env.get(\"SUPABASE_SERVICE_ROLE_KEY\")!;\n const DEEPSEEK_API_KEY = Deno.env.get(\"DEEPSEEK_API_KEY\");\n\n if (!DEEPSEEK_API_KEY) {\n return new Response(JSON.stringify({ error: \"DEEPSEEK_API_KEY not configured\" }), {\n status: 500,\n headers: { ...corsHeaders, \"Content-Type\": \"application/json\" },\n });\n }\n\n // Auth: accept either internal service-role header (from webhook) OR a valid user JWT\n const internalHeader = req.headers.get(\"x-internal-service-role\");\n const isInternal = internalHeader && internalHeader === SUPABASE_SERVICE_ROLE_KEY;\n\n if (!isInternal) {\n const authHeader = req.headers.get(\"Authorization\");\n if (!authHeader?.startsWith(\"Bearer \")) {\n return new Response(JSON.stringify({ error: \"Unauthorized\" }), {\n status: 401,\n headers: { ...corsHeaders, \"Content-Type\": \"application/json\" },\n });\n }\n const userClient = createClient(SUPABASE_URL, SUPABASE_ANON_KEY, {\n global: { headers: { Authorization: authHeader } },\n });\n const { data, error } = await userClient.auth.getClaims(authHeader.replace(\"Bearer \", \"\"));\n if (error || !data?.claims) {\n return new Response(JSON.stringify({ error: \"Unauthorized\" }), {\n status: 401,\n headers: { ...corsHeaders, \"Content-Type\": \"application/json\" },\n });\n }\n }\n\n const supabase = createClient(SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY);\n\n try {\n const { messageId } = await req.json();\n if (!messageId || typeof messageId !== \"string\") {\n return new Response(JSON.stringify({ error: \"messageId required\" }), {\n status: 400,\n headers: { ...corsHeaders, \"Content-Type\": \"application/json\" },\n });\n }\n\n const { data: message, error: fetchError } = await supabase\n .from(\"whatsapp_messages\")\n .select(\"*\")\n .eq(\"id\", messageId)\n .single();\n\n if (fetchError || !message) {\n return new Response(JSON.stringify({ error: \"Message not found\" }), {\n status: 404,\n headers: { ...corsHeaders, \"Content-Type\": \"application/json\" },\n });\n }\n\n let contentToAnalyze = \"\";\n if (message.text_content) {\n contentToAnalyze = message.text_content;\n } else if (message.media_url && message.media_mime_type?.startsWith(\"text\")) {\n try {\n const res = await fetch(message.media_url);\n contentToAnalyze = await res.text();\n } catch {\n contentToAnalyze = `[ملف: ${message.media_filename}]`;\n }\n } else {\n contentToAnalyze = `[ملف وسائط: ${message.media_filename || message.message_type}]`;\n }\n\n const aiResponse = await fetch(\"https://api.deepseek.com/chat/completions\", {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${DEEPSEEK_API_KEY}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n model: \"deepseek-chat\",\n messages: [\n {\n role: \"system\",\n content: `أنت مساعد ذكي لتحليل رسائل واتساب الأعمال. قم بتحليل المحتوى واستخراج:\n1. ملخص قصير\n2. نوع المحتوى (استفسار/طلب/شكوى/معلومات/أخرى)\n3. البيانات المهمة (أسماء، أرقام، تواريخ، مبالغ)\n4. الإجراء المطلوب إن وُجد\nأجب بصيغة JSON مع المفاتيح: summary, type, important_data, required_action`,\n },\n {\n role: \"user\",\n content: `حلل هذه الرسالة من واتساب:\\n\\nالمرسل: ${message.from_name || message.from_number}\\nنوع الرسالة: ${message.message_type}\\nالمحتوى: ${contentToAnalyze}`,\n },\n ],\n temperature: 0.3,\n max_tokens: 1000,\n }),\n });\n\n const aiData = await aiResponse.json();\n const aiText = aiData.choices?.[0]?.message?.content || \"فشل التحليل\";\n\n let extractedData = {};\n try {\n const jsonMatch = aiText.match(/\\{[\\s\\S]*\\}/);\n if (jsonMatch) extractedData = JSON.parse(jsonMatch[0]);\n } catch {\n extractedData = { raw_analysis: aiText };\n }\n\n await supabase\n .from(\"whatsapp_messages\")\n .update({\n ai_analysis: aiText,\n ai_summary: (extractedData as any).summary || aiText.slice(0, 200),\n extracted_data: extractedData,\n status: \"analyzed\",\n processed_at: new Date().toISOString(),\n })\n .eq(\"id\", messageId);\n\n return new Response(JSON.stringify({ success: true, analysis: extractedData }), {\n status: 200,\n headers: { ...corsHeaders, \"Content-Type\": \"application/json\" },\n });\n } catch (error) {\n console.error(\"Analysis error:\", error);\n return new Response(\n JSON.stringify({ error: error instanceof Error ? error.message : \"Unknown error\" }),\n { status: 500, headers: { ...corsHeaders, \"Content-Type\": \"application/json\" } }\n );\n }\n});\n"}, "93893d7ef4c3c9bf02efb431941f1ee53c0ebb01": {"t": 1785754377.7321906, "n": 4499, "h": "59ef6d8f06da7fd9", "c": "import { serve } from \"https://deno.land/std@0.168.0/http/server.ts\";\nimport { createClient } from \"https://esm.sh/@supabase/supabase-js@2\";\n\nconst corsHeaders = {\n \"Access-Control-Allow-Origin\": \"*\",\n \"Access-Control-Allow-Headers\": \"authorization, x-client-info, apikey, content-type\",\n};\n\nserve(async (req) => {\n if (req.method === \"OPTIONS\") {\n return new Response(null, { headers: corsHeaders });\n }\n\n const SUPABASE_URL = Deno.env.get(\"SUPABASE_URL\")!;\n const SUPABASE_SERVICE_ROLE_KEY = Deno.env.get(\"SUPABASE_SERVICE_ROLE_KEY\")!;\n const DEEPSEEK_API_KEY = Deno.env.get(\"DEEPSEEK_API_KEY\");\n\n if (!DEEPSEEK_API_KEY) {\n return new Response(JSON.stringify({ error: \"DEEPSEEK_API_KEY not configured\" }), {\n status: 500,\n headers: { ...corsHeaders, \"Content-Type\": \"application/json\" },\n });\n }\n\n const supabase = createClient(SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY);\n\n try {\n const { messageId } = await req.json();\n\n if (!messageId) {\n return new Response(JSON.stringify({ error: \"messageId required\" }), {\n status: 400,\n headers: { ...corsHeaders, \"Content-Type\": \"application/json\" },\n });\n }\n\n // Get the message\n const { data: message, error: fetchError } = await supabase\n .from(\"whatsapp_messages\")\n .select(\"*\")\n .eq(\"id\", messageId)\n .single();\n\n if (fetchError || !message) {\n return new Response(JSON.stringify({ error: \"Message not found\" }), {\n status: 404,\n headers: { ...corsHeaders, \"Content-Type\": \"application/json\" },\n });\n }\n\n let contentToAnalyze = \"\";\n\n if (message.text_content) {\n contentToAnalyze = message.text_content;\n } else if (message.media_url && message.media_mime_type?.startsWith(\"text\")) {\n // Try to fetch text-based media\n try {\n const res = await fetch(message.media_url);\n contentToAnalyze = await res.text();\n } catch {\n contentToAnalyze = `[ملف: ${message.media_filename}]`;\n }\n } else {\n contentToAnalyze = `[ملف وسائط: ${message.media_filename || message.message_type}]`;\n }\n\n // Call DeepSeek for analysis\n const aiResponse = await fetch(\"https://api.deepseek.com/chat/completions\", {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${DEEPSEEK_API_KEY}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n model: \"deepseek-chat\",\n messages: [\n {\n role: \"system\",\n content: `أنت مساعد ذكي لتحليل رسائل واتساب الأعمال. قم بتحليل المحتوى واستخراج:\n1. ملخص قصير\n2. نوع المحتوى (استفسار/طلب/شكوى/معلومات/أخرى)\n3. البيانات المهمة (أسماء، أرقام، تواريخ، مبالغ)\n4. الإجراء المطلوب إن وُجد\nأجب بصيغة JSON مع المفاتيح: summary, type, important_data, required_action`,\n },\n {\n role: \"user\",\n content: `حلل هذه الرسالة من واتساب:\\n\\nالمرسل: ${message.from_name || message.from_number}\\nنوع الرسالة: ${message.message_type}\\nالمحتوى: ${contentToAnalyze}`,\n },\n ],\n temperature: 0.3,\n max_tokens: 1000,\n }),\n });\n\n const aiData = await aiResponse.json();\n const aiText = aiData.choices?.[0]?.message?.content || \"فشل التحليل\";\n\n // Parse extracted data\n let extractedData = {};\n try {\n const jsonMatch = aiText.match(/\\{[\\s\\S]*\\}/);\n if (jsonMatch) {\n extractedData = JSON.parse(jsonMatch[0]);\n }\n } catch {\n extractedData = { raw_analysis: aiText };\n }\n\n // Update the message with analysis\n const { error: updateError } = await supabase\n .from(\"whatsapp_messages\")\n .update({\n ai_analysis: aiText,\n ai_summary: (extractedData as any).summary || aiText.slice(0, 200),\n extracted_data: extractedData,\n status: \"analyzed\",\n processed_at: new Date().toISOString(),\n })\n .eq(\"id\", messageId);\n\n if (updateError) {\n console.error(\"Update error:\", updateError);\n }\n\n return new Response(\n JSON.stringify({ success: true, analysis: extractedData }),\n {\n status: 200,\n headers: { ...corsHeaders, \"Content-Type\": \"application/json\" },\n }\n );\n } catch (error) {\n console.error(\"Analysis error:\", error);\n return new Response(\n JSON.stringify({ error: error instanceof Error ? error.message : \"Unknown error\" }),\n {\n status: 500,\n headers: { ...corsHeaders, \"Content-Type\": \"application/json\" },\n }\n );\n }\n});\n"}}}}