mirror of
https://github.com/lucasrcsantana/story-generator.git
synced 2025-12-16 21:37:51 +00:00
- Adiciona campos para armazenar as 5 competências do ENEM na tabela essay_analyses - Atualiza função analyze-essay para salvar notas e justificativas das competências - Adiciona restrições para validar valores entre 0 e 200 pontos - Atualiza documentação com comentários nos campos patch: atualização incremental que adiciona funcionalidade sem quebrar compatibilidade
666 lines
28 KiB
TypeScript
666 lines
28 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 { getCorsHeaders } from '../_shared/cors.ts'
|
|
import { OpenAI } from "https://deno.land/x/openai@v4.24.0/mod.ts";
|
|
|
|
interface EssayAnalysisRequest {
|
|
essay_id: string;
|
|
content: string;
|
|
type_id: string;
|
|
genre_id: string;
|
|
}
|
|
|
|
interface EssayAnalysisResponse {
|
|
overall_score: number;
|
|
suggestions: string;
|
|
feedback: {
|
|
structure: string;
|
|
content: string;
|
|
language: string;
|
|
};
|
|
strengths: string[];
|
|
improvements: string[];
|
|
criteria_scores: {
|
|
adequacy: number;
|
|
coherence: number;
|
|
cohesion: number;
|
|
vocabulary: number;
|
|
grammar: number;
|
|
};
|
|
competencies: {
|
|
language_domain: {
|
|
value: number;
|
|
justification: string;
|
|
};
|
|
proposal_comprehension: {
|
|
value: number;
|
|
justification: string;
|
|
};
|
|
argument_selection: {
|
|
value: number;
|
|
justification: string;
|
|
};
|
|
linguistic_mechanisms: {
|
|
value: number;
|
|
justification: string;
|
|
};
|
|
intervention_proposal: {
|
|
value: number;
|
|
justification: string;
|
|
};
|
|
};
|
|
}
|
|
|
|
interface EssayType {
|
|
id: string;
|
|
slug: string;
|
|
title: string;
|
|
description: string;
|
|
}
|
|
|
|
interface EssayGenre {
|
|
id: string;
|
|
type_id: string;
|
|
slug: string;
|
|
title: string;
|
|
description: string;
|
|
requirements: {
|
|
min_words: number;
|
|
max_words: number;
|
|
required_elements: string[];
|
|
};
|
|
}
|
|
|
|
serve(async (req) => {
|
|
console.log(`[${new Date().toISOString()}] Nova requisição recebida`)
|
|
|
|
// Handle CORS
|
|
if (req.method === 'OPTIONS') {
|
|
console.log('Requisição OPTIONS - CORS preflight')
|
|
return new Response('ok', { headers: getCorsHeaders(req) })
|
|
}
|
|
|
|
try {
|
|
// Criar cliente Supabase
|
|
console.log('Inicializando cliente Supabase...')
|
|
const supabaseUrl = Deno.env.get('SUPABASE_URL')
|
|
const supabaseServiceKey = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')
|
|
|
|
if (!supabaseUrl || !supabaseServiceKey) {
|
|
throw new Error('Variáveis de ambiente do Supabase não configuradas')
|
|
}
|
|
|
|
const supabaseClient = createClient(supabaseUrl, supabaseServiceKey, {
|
|
auth: {
|
|
persistSession: false,
|
|
autoRefreshToken: false,
|
|
}
|
|
})
|
|
|
|
// Criar cliente OpenAI
|
|
console.log('Inicializando cliente OpenAI...')
|
|
const openaiKey = Deno.env.get('OPENAI_API_KEY')
|
|
if (!openaiKey) {
|
|
throw new Error('OPENAI_API_KEY não configurada')
|
|
}
|
|
|
|
const openai = new OpenAI({
|
|
apiKey: openaiKey,
|
|
});
|
|
|
|
// Obter dados da requisição
|
|
console.log('Obtendo dados da requisição...')
|
|
const requestData = await req.json()
|
|
console.log('Dados recebidos:', JSON.stringify(requestData, null, 2))
|
|
|
|
const { essay_id, content, type_id, genre_id }: EssayAnalysisRequest = requestData
|
|
|
|
// Validar dados obrigatórios
|
|
if (!essay_id || !content || !type_id || !genre_id) {
|
|
console.error('Dados obrigatórios faltando:', { essay_id, content: !!content, type_id, genre_id })
|
|
return new Response(
|
|
JSON.stringify({
|
|
error: 'Dados obrigatórios não fornecidos',
|
|
details: {
|
|
essay_id: !essay_id,
|
|
content: !content,
|
|
type_id: !type_id,
|
|
genre_id: !genre_id
|
|
}
|
|
}),
|
|
{ status: 400, headers: { ...getCorsHeaders(req), 'Content-Type': 'application/json' } }
|
|
)
|
|
}
|
|
|
|
// Buscar informações do tipo e gênero
|
|
console.log('Buscando informações do tipo e gênero...')
|
|
const { data: typeData, error: typeError } = await supabaseClient
|
|
.from('essay_types')
|
|
.select('*')
|
|
.eq('id', type_id)
|
|
.single()
|
|
|
|
if (typeError) {
|
|
console.error('Erro ao buscar tipo:', typeError)
|
|
}
|
|
|
|
const { data: genreData, error: genreError } = await supabaseClient
|
|
.from('essay_genres')
|
|
.select('*')
|
|
.eq('id', genre_id)
|
|
.single()
|
|
|
|
if (genreError) {
|
|
console.error('Erro ao buscar gênero:', genreError)
|
|
}
|
|
|
|
if (typeError || genreError || !typeData || !genreData) {
|
|
return new Response(
|
|
JSON.stringify({
|
|
error: 'Tipo ou gênero não encontrado',
|
|
details: {
|
|
typeError: typeError?.message,
|
|
genreError: genreError?.message
|
|
}
|
|
}),
|
|
{ status: 404, headers: { ...getCorsHeaders(req), 'Content-Type': 'application/json' } }
|
|
)
|
|
}
|
|
|
|
const essayType: EssayType = typeData
|
|
const essayGenre: EssayGenre = genreData
|
|
|
|
console.log('Tipo e gênero encontrados:', {
|
|
type: essayType.title,
|
|
genre: essayGenre.title
|
|
})
|
|
|
|
// Construir prompt para a análise
|
|
console.log('Construindo prompt para análise...')
|
|
const prompt = `Você é um professor especialista em análise de textos. Analise a redação a seguir considerando que é do tipo "${essayType.title}" e gênero "${essayGenre.title}".
|
|
|
|
Requisitos específicos do gênero:
|
|
- Mínimo de palavras: ${essayGenre.requirements.min_words}
|
|
- Máximo de palavras: ${essayGenre.requirements.max_words}
|
|
- Elementos obrigatórios: ${essayGenre.requirements.required_elements.join(', ')}
|
|
|
|
Texto para análise:
|
|
${content}
|
|
|
|
Forneça uma análise detalhada considerando:
|
|
1. Adequação ao tipo e gênero textual
|
|
2. Coerência e coesão textual
|
|
3. Vocabulário e linguagem
|
|
4. Gramática e ortografia
|
|
5. Elementos obrigatórios do gênero
|
|
6. Pontos fortes
|
|
7. Pontos a melhorar
|
|
8. Sugestões específicas para aprimoramento
|
|
|
|
Essas são as competências do ENEM para você analisar a redação:
|
|
- Competência 1: Domínio da língua
|
|
- Competência 2: Compreensão da proposta
|
|
- Competência 3: Seleção de argumentos
|
|
- Competência 4: Mecanismos linguísticos
|
|
- Competência 5: Proposta de intervenção
|
|
|
|
## Competência 1: Demonstrar domínio da modalidade escrita formal da Língua Portuguesa
|
|
|
|
| Nota | Grade de Correção | Características |
|
|
|------|------------------|-----------------|
|
|
| 200 pontos | Demonstra excelente domínio da modalidade escrita formal da Língua Portuguesa e de escolha de registro. Desvios gramaticais ou de convenções da escrita serão aceitos somente como excepcionalidade e quando não caracterizem reincidência. | • Ausência de marcas de oralidade e de registro informal<br>• Precisão vocabular<br>• Obediência às regras gramaticais<br>• Não apresenta ou apresenta pouquíssimos desvios gramaticais leves e de convenções da escrita |
|
|
| 160 pontos | Demonstra bom domínio da modalidade escrita formal da Língua Portuguesa e de escolha de registro, com poucos desvios gramaticais e de convenções da escrita. | • Poucos desvios gramaticais leves<br>• Desvios de pontuação que não comprometem o sentido<br>• Desvios de ortografia e acentuação que não comprometem o sentido |
|
|
| 120 pontos | Demonstra domínio mediano da modalidade escrita formal da Língua Portuguesa e de escolha de registro, com alguns desvios gramaticais e de convenções da escrita. | • Alguns desvios gramaticais graves<br>• Problemas de concordância<br>• Problemas de regência<br>• Problemas de estrutura sintática<br>• Marcas de oralidade |
|
|
| 80 pontos | Demonstra domínio insuficiente da modalidade escrita formal da Língua Portuguesa, com muitos desvios gramaticais, de escolha de registro e de convenções da escrita. | • Grande quantidade de desvios graves<br>• Períodos incompletos<br>• Graves problemas de pontuação<br>• Desvios graves de grafia e acentuação<br>• Presença de gíria |
|
|
| 40 pontos | Demonstra domínio precário da modalidade escrita formal da Língua Portuguesa, de forma sistemática, com diversificados e frequentes desvios gramaticais. | • Graves e frequentes desvios gramaticais<br>• Presença de gírias e marcas de oralidade<br>• Desestruturação sintática em excesso |
|
|
| 0 ponto | Demonstra desconhecimento da modalidade escrita formal da Língua Portuguesa. | • Excesso de desvios que impossibilitam a compreensão |
|
|
|
|
## Competência 2: Compreender a proposta de redação e aplicar conceitos das várias áreas de conhecimento
|
|
|
|
| Nota | Grade de Correção | Características |
|
|
|------|------------------|-----------------|
|
|
| 200 pontos | Desenvolve o tema por meio de argumentação consistente, a partir de um repertório sociocultural produtivo, e apresenta excelente domínio do texto dissertativo-argumentativo. | • Tema muito bem desenvolvido<br>• Estrutura completa (introdução, argumentos, conclusão)<br>• Argumentos originais, além dos textos motivadores |
|
|
| 160 pontos | Desenvolve o tema por meio de argumentação consistente e apresenta bom domínio do texto dissertativo-argumentativo. | • Desenvolve bem o tema<br>• Boa argumentação<br>• Não se limita aos textos motivadores |
|
|
| 120 pontos | Desenvolve o tema por meio de argumentação previsível e apresenta domínio mediano do texto dissertativo-argumentativo. | • Abordagem superficial<br>• Argumentação previsível<br>• Reproduz ideias do senso comum |
|
|
| 80 pontos | Desenvolve o tema recorrendo à cópia de trechos dos textos motivadores ou apresenta domínio insuficiente do texto dissertativo-argumentativo. | • Tendência ao tangenciamento<br>• Argumentação falha<br>• Cópia dos textos motivadores |
|
|
| 40 pontos | Apresenta o assunto, tangenciando o tema, ou demonstra domínio precário do texto dissertativo-argumentativo. | • Tangencia o tema<br>• Ausência de argumentação<br>• Pode apresentar texto narrativo |
|
|
| 0 ponto | Fuga ao tema/não atendimento à estrutura dissertativo-argumentativa. | • Desenvolve outro tema<br>• Usa outra estrutura textual |
|
|
|
|
## Competência 3: Selecionar, relacionar, organizar e interpretar informações, fatos, opiniões e argumentos
|
|
|
|
| Nota | Grade de Correção | Características |
|
|
|------|------------------|-----------------|
|
|
| 200 pontos | Apresenta informações, fatos e opiniões relacionados ao tema proposto, de forma consistente e organizada, configurando autoria. | • Seleciona e organiza informações consistentemente<br>• Explicita tese clara<br>• Argumentos comprovam a tese |
|
|
| 160 pontos | Apresenta informações, fatos e opiniões relacionados ao tema, de forma organizada, com indícios de autoria. | • Organização consistente<br>• Argumentos previsíveis mas próprios |
|
|
| 120 pontos | Apresenta informações, fatos e opiniões relacionados ao tema, limitados aos argumentos dos textos motivadores. | • Organização pouco consistente<br>• Informações aleatórias<br>• Argumentos pouco convincentes |
|
|
| 80 pontos | Apresenta informações, fatos e opiniões relacionados ao tema, mas desorganizados ou contraditórios. | • Argumentos pouco articulados<br>• Reprodução dos textos motivadores |
|
|
| 40 pontos | Apresenta informações, fatos e opiniões pouco relacionados ao tema ou incoerentes. | • Sem defesa de ponto de vista<br>• Informações desarticuladas |
|
|
| 0 ponto | Apresenta informações, fatos e opiniões não relacionados ao tema. | • Informações incoerentes<br>• Sem ponto de vista |
|
|
|
|
## Competência 4: Demonstrar conhecimento dos mecanismos linguísticos necessários para a construção da argumentação
|
|
|
|
| Nota | Grade de Correção | Características |
|
|
|------|------------------|-----------------|
|
|
| 200 pontos | Articula bem as partes do texto e apresenta repertório diversificado de recursos coesivos. | • Articulação muito boa<br>• Pleno domínio dos recursos coesivos |
|
|
| 160 pontos | Articula as partes do texto com poucas inadequações e apresenta repertório diversificado de recursos coesivos. | • Boa articulação<br>• Poucos desvios nos conectores<br>• Algumas repetições desnecessárias |
|
|
| 120 pontos | Articula as partes do texto, de forma mediana, com inadequações. | • Algumas inadequações nos recursos coesivos<br>• Frases fragmentadas ocasionais<br>• Problemas de paragrafação |
|
|
| 80 pontos | Articula as partes do texto, de forma insuficiente, com muitas inadequações. | • Muitas inadequações<br>• Frases fragmentadas frequentes<br>• Problemas de estrutura |
|
|
| 40 pontos | Articula as partes do texto de forma precária. | • Graves problemas de articulação<br>• Períodos muito longos ou fragmentados<br>• Ausência de conectores |
|
|
| 0 ponto | Apresenta informações desconexas. | • Não se configura como texto |
|
|
|
|
## Competência 5: Elaborar proposta de intervenção para o problema abordado
|
|
|
|
| Nota | Grade de Correção | Características |
|
|
|------|------------------|-----------------|
|
|
| 200 pontos | Elabora muito bem proposta de intervenção, detalhada, relacionada ao tema. | • Proposta detalhada (o que fazer, como fazer, meios e participantes) |
|
|
| 160 pontos | Elabora bem proposta de intervenção relacionada ao tema. | • Proposta relacionada mas não totalmente detalhada |
|
|
| 120 pontos | Elabora, de forma mediana, proposta de intervenção relacionada ao tema. | • Proposta relacionada mas sem detalhamento |
|
|
| 80 pontos | Elabora, de forma insuficiente, proposta de intervenção. | • Proposta não atende totalmente à discussão |
|
|
| 40 pontos | Apresenta proposta de intervenção vaga, precária ou relacionada apenas ao assunto. | • Proposta vaga ou não configurada adequadamente |
|
|
| 0 ponto | Não apresenta proposta de intervenção ou apresenta proposta não relacionada ao tema. | • Ausência de proposta<br>• Proposta foge ao tema |
|
|
|
|
|
|
Responda em formato JSON seguindo exatamente esta estrutura:
|
|
{
|
|
"overall_score": number, // 0 a 100
|
|
"suggestions": string, // Sugestões específicas
|
|
"feedback": {
|
|
"structure": string, // Feedback sobre estrutura e organização
|
|
"content": string, // Feedback sobre conteúdo e ideias
|
|
"language": string // Feedback sobre linguagem e gramática
|
|
},
|
|
"strengths": string[], // Lista de pontos fortes
|
|
"improvements": string[], // Lista de pontos a melhorar
|
|
"criteria_scores": {
|
|
"adequacy": number, // 0 a 100 - Adequação ao tema/gênero
|
|
"coherence": number, // 0 a 100 - Coerência textual
|
|
"cohesion": number, // 0 a 100 - Coesão
|
|
"vocabulary": number, // 0 a 100 - Vocabulário
|
|
"grammar": number // 0 a 100 - Gramática e ortografia
|
|
},
|
|
"competencies": {
|
|
"language_domain": {
|
|
value: number, // 0 a 200 - Competência 1
|
|
justification: string // Justificativa para a pontuação
|
|
},
|
|
"proposal_comprehension": {
|
|
value: number, // 0 a 200 - Competência 2
|
|
justification: string // Justificativa para a pontuação
|
|
},
|
|
"argument_selection": {
|
|
value: number, // 0 a 200 - Competência 3
|
|
justification: string // Justificativa para a pontuação
|
|
},
|
|
"linguistic_mechanisms": {
|
|
value: number, // 0 a 200 - Competência 4
|
|
justification: string // Justificativa para a pontuação
|
|
},
|
|
"intervention_proposal": {
|
|
value: number, // 0 a 200 - Competência 5
|
|
justification: string // Justificativa para a pontuação
|
|
}
|
|
}
|
|
}`
|
|
|
|
// Realizar análise com OpenAI
|
|
console.log('Enviando requisição para OpenAI...')
|
|
try {
|
|
const completion = await openai.chat.completions.create({
|
|
model: "gpt-4o-mini",
|
|
messages: [
|
|
{
|
|
role: "system",
|
|
content: "Você é um professor especialista em análise de textos, com vasta experiência em avaliação de redações."
|
|
},
|
|
{
|
|
role: "user",
|
|
content: prompt
|
|
}
|
|
],
|
|
response_format: {
|
|
type: "json_schema",
|
|
json_schema: {
|
|
name: "essay_analysis",
|
|
strict: true,
|
|
description: "Análise detalhada da redação",
|
|
schema: {
|
|
type: "object",
|
|
additionalProperties: false,
|
|
required: ["overall_score", "suggestions", "feedback", "strengths", "improvements", "criteria_scores", "competencies"],
|
|
properties: {
|
|
overall_score: {
|
|
type: "number",
|
|
description: "Pontuação geral da redação (0-100)"
|
|
},
|
|
suggestions: {
|
|
type: "string",
|
|
description: "Sugestões específicas para aprimoramento"
|
|
},
|
|
feedback: {
|
|
type: "object",
|
|
additionalProperties: false,
|
|
required: ["structure", "content", "language"],
|
|
properties: {
|
|
structure: {
|
|
type: "string",
|
|
description: "Feedback sobre estrutura e organização"
|
|
},
|
|
content: {
|
|
type: "string",
|
|
description: "Feedback sobre conteúdo e ideias"
|
|
},
|
|
language: {
|
|
type: "string",
|
|
description: "Feedback sobre linguagem e gramática"
|
|
}
|
|
}
|
|
},
|
|
strengths: {
|
|
type: "array",
|
|
items: {
|
|
type: "string",
|
|
description: "Ponto forte da redação"
|
|
},
|
|
description: "Lista de pontos fortes da redação"
|
|
},
|
|
improvements: {
|
|
type: "array",
|
|
items: {
|
|
type: "string",
|
|
description: "Ponto a melhorar na redação"
|
|
},
|
|
description: "Lista de pontos a melhorar na redação"
|
|
},
|
|
criteria_scores: {
|
|
type: "object",
|
|
additionalProperties: false,
|
|
required: ["adequacy", "coherence", "cohesion", "vocabulary", "grammar"],
|
|
properties: {
|
|
adequacy: {
|
|
type: "number",
|
|
description: "Adequação ao tema/gênero (0-100)"
|
|
},
|
|
coherence: {
|
|
type: "number",
|
|
description: "Coerência textual (0-100)"
|
|
},
|
|
cohesion: {
|
|
type: "number",
|
|
description: "Coesão textual (0-100)"
|
|
},
|
|
vocabulary: {
|
|
type: "number",
|
|
description: "Vocabulário (0-100)"
|
|
},
|
|
grammar: {
|
|
type: "number",
|
|
description: "Gramática e ortografia (0-100)"
|
|
}
|
|
}
|
|
},
|
|
competencies: {
|
|
type: "object",
|
|
additionalProperties: false,
|
|
required: [
|
|
"language_domain",
|
|
"proposal_comprehension",
|
|
"argument_selection",
|
|
"linguistic_mechanisms",
|
|
"intervention_proposal"
|
|
],
|
|
properties: {
|
|
language_domain: {
|
|
type: "object",
|
|
additionalProperties: false,
|
|
required: ["value", "justification"],
|
|
properties: {
|
|
value: {
|
|
type: "number",
|
|
description: "Pontuação da competência (0-200)"
|
|
},
|
|
justification: {
|
|
type: "string",
|
|
description: "Justificativa para a pontuação"
|
|
}
|
|
}
|
|
},
|
|
proposal_comprehension: {
|
|
type: "object",
|
|
additionalProperties: false,
|
|
required: ["value", "justification"],
|
|
properties: {
|
|
value: {
|
|
type: "number",
|
|
description: "Pontuação da competência (0-200)" },
|
|
justification: {
|
|
type: "string",
|
|
description: "Justificativa para a pontuação"
|
|
}
|
|
}
|
|
},
|
|
argument_selection: {
|
|
type: "object",
|
|
additionalProperties: false,
|
|
required: ["value", "justification"],
|
|
properties: {
|
|
value: {
|
|
type: "number",
|
|
description: "Pontuação da competência (0-200)"
|
|
},
|
|
justification: {
|
|
type: "string",
|
|
description: "Justificativa para a pontuação"
|
|
}
|
|
}
|
|
},
|
|
linguistic_mechanisms: {
|
|
type: "object",
|
|
additionalProperties: false,
|
|
required: ["value", "justification"],
|
|
properties: {
|
|
value: {
|
|
type: "number",
|
|
description: "Pontuação da competência (0-200)"
|
|
},
|
|
justification: {
|
|
type: "string",
|
|
description: "Justificativa para a pontuação"
|
|
}
|
|
}
|
|
},
|
|
intervention_proposal: {
|
|
type: "object",
|
|
additionalProperties: false,
|
|
required: ["value", "justification"],
|
|
properties: {
|
|
value: {
|
|
type: "number",
|
|
description: "Pontuação da competência (0-200)"
|
|
},
|
|
justification: {
|
|
type: "string",
|
|
description: "Justificativa para a pontuação"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
console.log('Resposta recebida da OpenAI')
|
|
const analysis: EssayAnalysisResponse = JSON.parse(completion.choices[0].message.content)
|
|
console.log('Análise gerada:', JSON.stringify(analysis, null, 2))
|
|
|
|
// Salvar análise no banco
|
|
console.log('Salvando análise no banco...')
|
|
|
|
// Primeiro, criar a análise principal
|
|
const { data: analysisData, error: analysisError } = await supabaseClient
|
|
.from('essay_analyses')
|
|
.insert({
|
|
essay_id,
|
|
overall_score: analysis.overall_score,
|
|
suggestions: analysis.suggestions,
|
|
// Campos de competências
|
|
language_domain_value: analysis.competencies.language_domain.value,
|
|
language_domain_justification: analysis.competencies.language_domain.justification,
|
|
proposal_comprehension_value: analysis.competencies.proposal_comprehension.value,
|
|
proposal_comprehension_justification: analysis.competencies.proposal_comprehension.justification,
|
|
argument_selection_value: analysis.competencies.argument_selection.value,
|
|
argument_selection_justification: analysis.competencies.argument_selection.justification,
|
|
linguistic_mechanisms_value: analysis.competencies.linguistic_mechanisms.value,
|
|
linguistic_mechanisms_justification: analysis.competencies.linguistic_mechanisms.justification,
|
|
intervention_proposal_value: analysis.competencies.intervention_proposal.value,
|
|
intervention_proposal_justification: analysis.competencies.intervention_proposal.justification
|
|
})
|
|
.select()
|
|
.single()
|
|
|
|
if (analysisError) {
|
|
console.error('Erro ao salvar análise principal:', analysisError)
|
|
return new Response(
|
|
JSON.stringify({
|
|
error: 'Erro ao salvar análise',
|
|
details: analysisError.message
|
|
}),
|
|
{ status: 500, headers: { ...getCorsHeaders(req), 'Content-Type': 'application/json' } }
|
|
)
|
|
}
|
|
|
|
// Salvar feedback
|
|
const { error: feedbackError } = await supabaseClient
|
|
.from('essay_analysis_feedback')
|
|
.insert({
|
|
analysis_id: analysisData.id,
|
|
structure_feedback: analysis.feedback.structure,
|
|
content_feedback: analysis.feedback.content,
|
|
language_feedback: analysis.feedback.language
|
|
})
|
|
|
|
if (feedbackError) {
|
|
console.error('Erro ao salvar feedback:', feedbackError)
|
|
return new Response(
|
|
JSON.stringify({
|
|
error: 'Erro ao salvar feedback',
|
|
details: feedbackError.message
|
|
}),
|
|
{ status: 500, headers: { ...getCorsHeaders(req), 'Content-Type': 'application/json' } }
|
|
)
|
|
}
|
|
|
|
// Salvar pontos fortes
|
|
const strengths = analysis.strengths.map(strength => ({
|
|
analysis_id: analysisData.id,
|
|
strength
|
|
}))
|
|
|
|
const { error: strengthsError } = await supabaseClient
|
|
.from('essay_analysis_strengths')
|
|
.insert(strengths)
|
|
|
|
if (strengthsError) {
|
|
console.error('Erro ao salvar pontos fortes:', strengthsError)
|
|
return new Response(
|
|
JSON.stringify({
|
|
error: 'Erro ao salvar pontos fortes',
|
|
details: strengthsError.message
|
|
}),
|
|
{ status: 500, headers: { ...getCorsHeaders(req), 'Content-Type': 'application/json' } }
|
|
)
|
|
}
|
|
|
|
// Salvar pontos a melhorar
|
|
const improvements = analysis.improvements.map(improvement => ({
|
|
analysis_id: analysisData.id,
|
|
improvement
|
|
}))
|
|
|
|
const { error: improvementsError } = await supabaseClient
|
|
.from('essay_analysis_improvements')
|
|
.insert(improvements)
|
|
|
|
if (improvementsError) {
|
|
console.error('Erro ao salvar pontos a melhorar:', improvementsError)
|
|
return new Response(
|
|
JSON.stringify({
|
|
error: 'Erro ao salvar pontos a melhorar',
|
|
details: improvementsError.message
|
|
}),
|
|
{ status: 500, headers: { ...getCorsHeaders(req), 'Content-Type': 'application/json' } }
|
|
)
|
|
}
|
|
|
|
// Salvar notas por critério
|
|
const { error: scoresError } = await supabaseClient
|
|
.from('essay_analysis_scores')
|
|
.insert({
|
|
analysis_id: analysisData.id,
|
|
adequacy: analysis.criteria_scores.adequacy,
|
|
coherence: analysis.criteria_scores.coherence,
|
|
cohesion: analysis.criteria_scores.cohesion,
|
|
vocabulary: analysis.criteria_scores.vocabulary,
|
|
grammar: analysis.criteria_scores.grammar
|
|
})
|
|
|
|
if (scoresError) {
|
|
console.error('Erro ao salvar notas:', scoresError)
|
|
return new Response(
|
|
JSON.stringify({
|
|
error: 'Erro ao salvar notas',
|
|
details: scoresError.message
|
|
}),
|
|
{ status: 500, headers: { ...getCorsHeaders(req), 'Content-Type': 'application/json' } }
|
|
)
|
|
}
|
|
|
|
// Atualizar status da redação
|
|
console.log('Atualizando status da redação...')
|
|
const { error: updateError } = await supabaseClient
|
|
.from('student_essays')
|
|
.update({ status: 'analyzed' })
|
|
.eq('id', essay_id)
|
|
|
|
if (updateError) {
|
|
console.error('Erro ao atualizar status:', updateError)
|
|
return new Response(
|
|
JSON.stringify({
|
|
error: 'Erro ao atualizar status da redação',
|
|
details: updateError.message
|
|
}),
|
|
{ status: 500, headers: { ...getCorsHeaders(req), 'Content-Type': 'application/json' } }
|
|
)
|
|
}
|
|
|
|
console.log('Análise concluída com sucesso')
|
|
// Retornar análise
|
|
return new Response(
|
|
JSON.stringify(analysis),
|
|
{ headers: { ...getCorsHeaders(req), 'Content-Type': 'application/json' } }
|
|
)
|
|
|
|
} catch (openaiError) {
|
|
console.error('Erro na chamada da OpenAI:', openaiError)
|
|
return new Response(
|
|
JSON.stringify({
|
|
error: 'Erro ao gerar análise',
|
|
details: openaiError.message
|
|
}),
|
|
{ status: 500, headers: { ...getCorsHeaders(req), 'Content-Type': 'application/json' } }
|
|
)
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error('Erro geral na função:', error)
|
|
return new Response(
|
|
JSON.stringify({
|
|
error: 'Erro interno do servidor',
|
|
details: error.message
|
|
}),
|
|
{ status: 500, headers: { ...getCorsHeaders(req), 'Content-Type': 'application/json' } }
|
|
)
|
|
}
|
|
})
|