mirror of
https://github.com/lucasrcsantana/story-generator.git
synced 2025-12-16 21:37:51 +00:00
- Implementa Edge Function para processamento de áudio - Adiciona integração com OpenAI Whisper e GPT-4 - Configura Database Trigger para story_recordings - Implementa análise automática de leitura - Atualiza documentação e variáveis de ambiente
169 lines
5.0 KiB
TypeScript
169 lines
5.0 KiB
TypeScript
import { OpenAI } from 'https://deno.land/x/openai@v4.20.1/mod.ts'
|
|
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2'
|
|
|
|
const openai = new OpenAI({
|
|
apiKey: Deno.env.get('OPENAI_API_KEY')
|
|
})
|
|
|
|
interface ReadingAnalysis {
|
|
fluency_score: number
|
|
pronunciation_score: number
|
|
accuracy_score: number
|
|
comprehension_score: number
|
|
words_per_minute: number
|
|
pause_count: number
|
|
error_count: number
|
|
self_corrections: number
|
|
strengths: string[]
|
|
improvements: string[]
|
|
suggestions: string
|
|
raw_data: any
|
|
}
|
|
|
|
export async function analyzeReading(
|
|
transcription: string,
|
|
storyId: string
|
|
): Promise<ReadingAnalysis> {
|
|
try {
|
|
console.log('Analisando leitura para story_id:', storyId)
|
|
|
|
const supabase = createClient(
|
|
Deno.env.get('SUPABASE_URL') ?? '',
|
|
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') ?? ''
|
|
)
|
|
|
|
// Busca a história com o texto da página
|
|
const { data: storyPages, error: storyError } = await supabase
|
|
.from('story_pages')
|
|
.select('text')
|
|
.eq('story_id', storyId)
|
|
.order('page_number', { ascending: true })
|
|
|
|
if (storyError) {
|
|
console.error('Erro ao buscar história:', storyError)
|
|
throw storyError
|
|
}
|
|
|
|
if (!storyPages || storyPages.length === 0) {
|
|
console.error('Dados da história inválidos:', storyPages)
|
|
throw new Error('Texto da história não encontrado')
|
|
}
|
|
|
|
// Concatena todos os textos das páginas
|
|
const originalText = storyPages.map(page => page.text).join(' ')
|
|
console.log('Texto original:', originalText)
|
|
console.log('Transcrição:', transcription)
|
|
|
|
// Análise com GPT-4
|
|
const analysis = await openai.chat.completions.create({
|
|
model: "gpt-4o-mini",
|
|
messages: [
|
|
{
|
|
role: "system",
|
|
content: `Você é um especialista em análise de leitura infantil.
|
|
Analise a transcrição comparando com o texto original.
|
|
Forneça métricas detalhadas e feedback construtivo.
|
|
Retorne apenas o JSON solicitado, sem texto adicional.`
|
|
},
|
|
{
|
|
role: "user",
|
|
content: `
|
|
Texto Original: "${originalText}"
|
|
Transcrição: "${transcription}"
|
|
|
|
Analise e retorne as métricas no formato JSON.`
|
|
}
|
|
],
|
|
response_format: { type: "json_object" },
|
|
temperature: 0.7,
|
|
max_tokens: 1000,
|
|
functions: [
|
|
{
|
|
name: "analyze_reading",
|
|
description: "Analisa a leitura e retorna métricas",
|
|
parameters: {
|
|
type: "object",
|
|
properties: {
|
|
fluency_score: {
|
|
type: "number",
|
|
description: "Pontuação de fluência (0-100)"
|
|
},
|
|
pronunciation_score: {
|
|
type: "number",
|
|
description: "Pontuação de pronúncia (0-100)"
|
|
},
|
|
accuracy_score: {
|
|
type: "number",
|
|
description: "Pontuação de precisão (0-100)"
|
|
},
|
|
comprehension_score: {
|
|
type: "number",
|
|
description: "Pontuação de compreensão (0-100)"
|
|
},
|
|
words_per_minute: {
|
|
type: "number",
|
|
description: "Palavras por minuto"
|
|
},
|
|
pause_count: {
|
|
type: "number",
|
|
description: "Número de pausas"
|
|
},
|
|
error_count: {
|
|
type: "number",
|
|
description: "Número de erros"
|
|
},
|
|
self_corrections: {
|
|
type: "number",
|
|
description: "Número de autocorreções"
|
|
},
|
|
strengths: {
|
|
type: "array",
|
|
items: { type: "string" },
|
|
description: "3-5 pontos fortes"
|
|
},
|
|
improvements: {
|
|
type: "array",
|
|
items: { type: "string" },
|
|
description: "3-5 pontos para melhorar"
|
|
},
|
|
suggestions: {
|
|
type: "string",
|
|
description: "Sugestão personalizada"
|
|
}
|
|
},
|
|
required: [
|
|
"fluency_score",
|
|
"pronunciation_score",
|
|
"accuracy_score",
|
|
"comprehension_score",
|
|
"words_per_minute",
|
|
"pause_count",
|
|
"error_count",
|
|
"self_corrections",
|
|
"strengths",
|
|
"improvements",
|
|
"suggestions"
|
|
]
|
|
}
|
|
}
|
|
]
|
|
})
|
|
|
|
if (!analysis.choices[0]?.message?.function_call?.arguments) {
|
|
throw new Error('Análise vazia do GPT')
|
|
}
|
|
|
|
console.log('Resposta do GPT:', analysis.choices[0].message.function_call.arguments)
|
|
|
|
const result = JSON.parse(analysis.choices[0].message.function_call.arguments)
|
|
|
|
return {
|
|
...result,
|
|
raw_data: analysis
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error('Erro detalhado na análise:', error)
|
|
throw error
|
|
}
|
|
}
|