mirror of
https://github.com/lucasrcsantana/story-generator.git
synced 2025-12-17 05:47:52 +00:00
208 lines
6.2 KiB
TypeScript
208 lines
6.2 KiB
TypeScript
import { serve } from 'https://deno.fresh.run/std@0.168.0/http/server.ts'
|
|
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2'
|
|
import { corsHeaders } 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;
|
|
feedback: {
|
|
structure: string;
|
|
content: string;
|
|
language: string;
|
|
};
|
|
strengths: string[];
|
|
improvements: string[];
|
|
suggestions: string;
|
|
criteria_scores: {
|
|
adequacy: number; // Adequação ao tema/gênero
|
|
coherence: number; // Coerência textual
|
|
cohesion: number; // Coesão
|
|
vocabulary: number; // Vocabulário
|
|
grammar: number; // Gramática/ortografia
|
|
};
|
|
}
|
|
|
|
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) => {
|
|
// Handle CORS
|
|
if (req.method === 'OPTIONS') {
|
|
return new Response('ok', { headers: corsHeaders })
|
|
}
|
|
|
|
try {
|
|
// Criar cliente Supabase
|
|
const supabaseClient = createClient(
|
|
Deno.env.get('SUPABASE_URL') ?? '',
|
|
Deno.env.get('SUPABASE_ANON_KEY') ?? ''
|
|
)
|
|
|
|
// Criar cliente OpenAI
|
|
const openai = new OpenAI({
|
|
apiKey: Deno.env.get('OPENAI_API_KEY'),
|
|
});
|
|
|
|
// Obter dados da requisição
|
|
const { essay_id, content, type_id, genre_id }: EssayAnalysisRequest = await req.json()
|
|
|
|
// Validar dados obrigatórios
|
|
if (!essay_id || !content || !type_id || !genre_id) {
|
|
return new Response(
|
|
JSON.stringify({ error: 'Dados obrigatórios não fornecidos' }),
|
|
{ status: 400, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
|
|
)
|
|
}
|
|
|
|
// Buscar informações do tipo e gênero
|
|
const { data: typeData, error: typeError } = await supabaseClient
|
|
.from('essay_types')
|
|
.select('*')
|
|
.eq('id', type_id)
|
|
.single()
|
|
|
|
const { data: genreData, error: genreError } = await supabaseClient
|
|
.from('essay_genres')
|
|
.select('*')
|
|
.eq('id', genre_id)
|
|
.single()
|
|
|
|
if (typeError || genreError || !typeData || !genreData) {
|
|
return new Response(
|
|
JSON.stringify({ error: 'Tipo ou gênero não encontrado' }),
|
|
{ status: 404, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
|
|
)
|
|
}
|
|
|
|
const essayType: EssayType = typeData
|
|
const essayGenre: EssayGenre = genreData
|
|
|
|
// Construir prompt para a 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
|
|
|
|
Responda em formato JSON seguindo exatamente esta estrutura:
|
|
{
|
|
"overall_score": number, // 0 a 100
|
|
"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
|
|
"suggestions": string, // Sugestões específicas
|
|
"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/ortografia
|
|
}
|
|
}`
|
|
|
|
// Realizar análise com OpenAI
|
|
const completion = await openai.chat.completions.create({
|
|
model: "gpt-4-turbo-preview",
|
|
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_object" }
|
|
});
|
|
|
|
const analysis: EssayAnalysisResponse = JSON.parse(completion.choices[0].message.content)
|
|
|
|
// Salvar análise no banco
|
|
const { error: saveError } = await supabaseClient
|
|
.from('essay_analyses')
|
|
.insert({
|
|
essay_id,
|
|
overall_score: analysis.overall_score,
|
|
feedback: analysis.feedback,
|
|
strengths: analysis.strengths,
|
|
improvements: analysis.improvements,
|
|
suggestions: analysis.suggestions,
|
|
criteria_scores: analysis.criteria_scores
|
|
})
|
|
|
|
if (saveError) {
|
|
return new Response(
|
|
JSON.stringify({ error: 'Erro ao salvar análise' }),
|
|
{ status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
|
|
)
|
|
}
|
|
|
|
// Atualizar status da redação
|
|
const { error: updateError } = await supabaseClient
|
|
.from('student_essays')
|
|
.update({ status: 'analyzed' })
|
|
.eq('id', essay_id)
|
|
|
|
if (updateError) {
|
|
return new Response(
|
|
JSON.stringify({ error: 'Erro ao atualizar status da redação' }),
|
|
{ status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
|
|
)
|
|
}
|
|
|
|
// Retornar análise
|
|
return new Response(
|
|
JSON.stringify(analysis),
|
|
{ headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
|
|
)
|
|
|
|
} catch (error) {
|
|
return new Response(
|
|
JSON.stringify({ error: error.message }),
|
|
{ status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
|
|
)
|
|
}
|
|
})
|