story-generator/supabase/functions/process-audio/analyzer.ts
2024-12-27 15:56:41 -03:00

175 lines
5.1 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'
import { createLogger } from './logger.ts'
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,
logger: Logger
): Promise<ReadingAnalysis> {
try {
logger.info('analysis_start', 'Iniciando análise', { 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) {
logger.error('story_fetch', storyError)
throw storyError
}
logger.info('story_loaded', 'História carregada', {
pageCount: storyPages?.length
})
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
}
}