mirror of
https://github.com/lucasrcsantana/story-generator.git
synced 2025-12-17 13:57:51 +00:00
- Cria serviço audioService para upload e processamento - Implementa componente AudioUploader com feedback visual - Adiciona componente Button reutilizável - Integra processamento de áudio na página de histórias
127 lines
3.5 KiB
TypeScript
127 lines
3.5 KiB
TypeScript
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts'
|
|
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2'
|
|
import { Configuration, OpenAIApi } from 'https://esm.sh/openai@3.1.0'
|
|
|
|
// Configurar OpenAI
|
|
const openaiConfig = new Configuration({
|
|
apiKey: Deno.env.get('OPENAI_API_KEY')
|
|
})
|
|
const openai = new OpenAIApi(openaiConfig)
|
|
|
|
// Configurar Supabase
|
|
const supabaseUrl = Deno.env.get('SUPABASE_URL')
|
|
const supabaseAnonKey = Deno.env.get('SUPABASE_ANON_KEY')
|
|
const supabase = createClient(supabaseUrl, supabaseAnonKey)
|
|
|
|
serve(async (req) => {
|
|
try {
|
|
// Extrair dados do webhook
|
|
const { record } = await req.json()
|
|
const { id, audio_url, story_id } = record
|
|
|
|
// Atualizar status para processing
|
|
await supabase
|
|
.from('story_recordings')
|
|
.update({ status: 'processing' })
|
|
.eq('id', id)
|
|
|
|
// Buscar texto original da história
|
|
const { data: storyData } = await supabase
|
|
.from('stories')
|
|
.select('content')
|
|
.eq('id', story_id)
|
|
.single()
|
|
|
|
const originalText = storyData.content.pages[0].text
|
|
|
|
// 1. Transcrever áudio com Whisper
|
|
const audioResponse = await fetch(audio_url)
|
|
const audioBlob = await audioResponse.blob()
|
|
|
|
const transcription = await openai.createTranscription(
|
|
audioBlob,
|
|
'whisper-1',
|
|
'pt',
|
|
'verbose_json'
|
|
)
|
|
|
|
// 2. Analisar com GPT-4
|
|
const analysis = await openai.createChatCompletion({
|
|
model: "gpt-4",
|
|
messages: [
|
|
{
|
|
role: "system",
|
|
content: `Você é um especialista em análise de leitura infantil.
|
|
Analise a transcrição comparando com o texto original.
|
|
Forneça uma análise detalhada em formato JSON com métricas de 0-100.`
|
|
},
|
|
{
|
|
role: "user",
|
|
content: `
|
|
Texto Original: "${originalText}"
|
|
Transcrição: "${transcription.data.text}"
|
|
|
|
Analise e retorne um JSON com:
|
|
{
|
|
"metrics": {
|
|
"fluency": number,
|
|
"pronunciation": number,
|
|
"accuracy": number,
|
|
"comprehension": number
|
|
},
|
|
"feedback": {
|
|
"strengths": string[],
|
|
"improvements": string[],
|
|
"suggestions": string
|
|
},
|
|
"details": {
|
|
"wordsPerMinute": number,
|
|
"pauseCount": number,
|
|
"errorCount": number,
|
|
"selfCorrections": number
|
|
}
|
|
}`
|
|
}
|
|
]
|
|
})
|
|
|
|
const analysisResult = JSON.parse(analysis.data.choices[0].message.content)
|
|
|
|
// 3. Atualizar registro com resultados
|
|
await supabase
|
|
.from('story_recordings')
|
|
.update({
|
|
transcription: transcription.data.text,
|
|
metrics: analysisResult.metrics,
|
|
feedback: analysisResult.feedback,
|
|
details: analysisResult.details,
|
|
status: 'analyzed',
|
|
processed_at: new Date().toISOString()
|
|
})
|
|
.eq('id', id)
|
|
|
|
return new Response(
|
|
JSON.stringify({ success: true }),
|
|
{ headers: { 'Content-Type': 'application/json' } }
|
|
)
|
|
|
|
} catch (error) {
|
|
console.error('Erro:', error)
|
|
|
|
// Atualizar registro com erro
|
|
if (error.record?.id) {
|
|
await supabase
|
|
.from('story_recordings')
|
|
.update({
|
|
status: 'error',
|
|
error_message: error.message
|
|
})
|
|
.eq('id', error.record.id)
|
|
}
|
|
|
|
return new Response(
|
|
JSON.stringify({ error: error.message }),
|
|
{ status: 500, headers: { 'Content-Type': 'application/json' } }
|
|
)
|
|
}
|
|
})
|