import { serve } from 'https://deno.land/std@0.168.0/http/server.ts' import { createClient } from 'https://esm.sh/@supabase/supabase-js@2' import { processAudioWithWhisper } from './whisper.ts' import { analyzeReading } from './analyzer.ts' import { createLogger } from './logger.ts' const corsHeaders = { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type', } interface AudioRecord { id: string story_id: string student_id: string audio_url: string status: 'pending_analysis' | 'processing' | 'completed' | 'error' analysis: any created_at: string transcription: string | null processed_at: string | null error_message: string | null fluency_score: number | null pronunciation_score: number | null accuracy_score: number | null comprehension_score: number | null words_per_minute: number | null pause_count: number | null error_count: number | null self_corrections: number | null strengths: string[] improvements: string[] suggestions: string | null } serve(async (req) => { if (req.method === 'OPTIONS') { return new Response('ok', { headers: corsHeaders }) } let logger: any = null try { const data = await req.json() logger = createLogger(data?.record?.id || 'unknown') logger.info('request_received', 'Iniciando processamento', { headers: Object.fromEntries(req.headers.entries()) }) // Validação if (!data?.record?.id || !data?.record?.audio_url) { logger.error('validation', new Error('Payload inválido')) throw new Error('Dados inválidos') } const audioRecord = data.record as AudioRecord logger.info('record_loaded', 'Registro carregado', audioRecord) // Processamento logger.info('processing_start', 'Iniciando processamento do áudio') const transcription = await processAudioWithWhisper(audioRecord.audio_url, logger) logger.info('transcription_complete', 'Transcrição concluída', { length: transcription.length }) const analysis = await analyzeReading(transcription, audioRecord.story_id, logger) logger.info('analysis_complete', 'Análise concluída', { scores: analysis }) const supabase = createClient( Deno.env.get('SUPABASE_URL') ?? '', Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') ?? '' ) // 1. Atualiza status para processing await supabase .from('story_recordings') .update({ status: 'processing' }) .eq('id', audioRecord.id) // 4. Atualiza o registro com os resultados const updateData = { status: 'completed', transcription, processed_at: new Date().toISOString(), fluency_score: analysis.fluency_score || 0, pronunciation_score: analysis.pronunciation_score || 0, accuracy_score: analysis.accuracy_score || 0, comprehension_score: analysis.comprehension_score || 0, words_per_minute: analysis.words_per_minute || 0, pause_count: analysis.pause_count || 0, error_count: analysis.error_count || 0, self_corrections: analysis.self_corrections || 0, strengths: Array.isArray(analysis.strengths) ? analysis.strengths : [], improvements: Array.isArray(analysis.improvements) ? analysis.improvements : [], suggestions: analysis.suggestions || '' } console.log('Dados para atualização:', updateData) console.log('AudioRecord', audioRecord) const { error: updateError } = await supabase .from('story_recordings') .update(updateData) .eq('id', audioRecord.id) if (updateError) { console.error('Erro na atualização:', updateError) throw updateError } return new Response( JSON.stringify({ message: 'Áudio processado com sucesso', data: analysis }), { headers: { ...corsHeaders, 'Content-Type': 'application/json' }, status: 200, } ) } catch (error) { console.error('Erro ao processar áudio:', error) // Só tenta atualizar o registro se tiver o ID if (data?.record?.id) { const supabase = createClient( Deno.env.get('SUPABASE_URL') ?? '', Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') ?? '' ) await supabase .from('story_recordings') .update({ status: 'error', error_message: error.message }) .eq('id', audioRecord.id) } return new Response( JSON.stringify({ error: 'Falha ao processar áudio', details: error.message }), { headers: { ...corsHeaders, 'Content-Type': 'application/json' }, status: 500, } ) } })