feat: implementa geração de histórias com IA

- Adiciona edge function para geração de histórias
- Integra OpenAI GPT para criação de texto
- Integra DALL-E para geração de imagens
- Implementa fluxo de seleção de categorias
- Adiciona logs detalhados para monitoramento
- Melhora tratamento de erros e validações
- Adiciona feedback visual do processo de geração

Principais mudanças:
- Cria edge function generate-story
- Implementa StoryGenerator com seleção de categorias
- Adiciona integração com OpenAI e DALL-E
- Implementa logs estruturados para debug
- Adiciona tratamento de erros robusto
This commit is contained in:
Lucas Santana 2024-12-23 09:22:45 -03:00
parent 03732de610
commit 7e3b4551ec
3 changed files with 38 additions and 31 deletions

View File

@ -11,7 +11,6 @@ import { User, Theme } from './types';
import { AuthProvider } from './contexts/AuthContext'
import { useNavigate } from 'react-router-dom';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { Router } from './Router'
type AppStep =
| 'welcome'
@ -26,7 +25,7 @@ const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 1000 * 60 * 5, // 5 minutos
cacheTime: 1000 * 60 * 30, // 30 minutos
gcTime: 1000 * 60 * 30, // 30 minutos (antes era cacheTime)
refetchOnWindowFocus: false,
},
},

View File

@ -8,8 +8,8 @@ import './index.css';
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 1000 * 60 * 5, // 5 minutos
cacheTime: 1000 * 60 * 30, // 30 minutos
staleTime: 1000 * 60 * 5,
gcTime: 1000 * 60 * 30,
refetchOnWindowFocus: false,
},
},

View File

@ -16,15 +16,16 @@ interface StoryPrompt {
serve(async (req) => {
const { record } = await req.json()
console.log('[Request]', record)
try {
// Criar cliente Supabase
const supabase = createClient(
Deno.env.get('SUPABASE_URL') ?? '',
Deno.env.get('SUPABASE_ANON_KEY') ?? ''
)
console.log('[Supabase] Cliente inicializado')
// Buscar detalhes das categorias selecionadas
console.log('[DB] Buscando categorias...')
const [themeResult, subjectResult, characterResult, settingResult] = await Promise.all([
supabase.from('story_themes').select('*').eq('id', record.theme_id).single(),
supabase.from('story_subjects').select('*').eq('id', record.subject_id).single(),
@ -32,21 +33,18 @@ serve(async (req) => {
supabase.from('story_settings').select('*').eq('id', record.setting_id).single()
])
// Log para debug
console.log('Resultados das consultas:', {
console.log('[DB] Resultados das consultas:', {
theme: themeResult,
subject: subjectResult,
character: characterResult,
setting: settingResult
});
})
// Verificar erros nas consultas
if (themeResult.error) throw new Error(`Erro ao buscar tema: ${themeResult.error.message}`);
if (subjectResult.error) throw new Error(`Erro ao buscar disciplina: ${subjectResult.error.message}`);
if (characterResult.error) throw new Error(`Erro ao buscar personagem: ${characterResult.error.message}`);
if (settingResult.error) throw new Error(`Erro ao buscar cenário: ${settingResult.error.message}`);
// Verificar se os dados existem
if (!themeResult.data) throw new Error(`Tema não encontrado: ${record.theme_id}`);
if (!subjectResult.data) throw new Error(`Disciplina não encontrada: ${record.subject_id}`);
if (!characterResult.data) throw new Error(`Personagem não encontrado: ${record.character_id}`);
@ -57,16 +55,9 @@ serve(async (req) => {
const character = characterResult.data;
const setting = settingResult.data;
// Log dos dados recebidos
console.log('Record recebido:', record);
console.log('Dados encontrados:', {
theme,
subject,
character,
setting
});
console.log('[Validation] Categorias validadas com sucesso')
// Construir o prompt para o GPT
console.log('[GPT] Construindo prompt...')
const prompt = `
Crie uma história educativa para crianças com as seguintes características:
@ -98,8 +89,9 @@ serve(async (req) => {
]
}
`
console.log('[GPT] Prompt construído:', prompt)
// Gerar história com GPT-4 Turbo
console.log('[GPT] Iniciando geração da história...')
const completion = await openai.chat.completions.create({
model: "gpt-4o-mini",
messages: [
@ -114,27 +106,32 @@ serve(async (req) => {
],
temperature: 0.7,
max_tokens: 1000
});
})
const storyContent = JSON.parse(completion.choices[0].message.content || '{}');
console.log('[GPT] História gerada:', completion.choices[0].message)
const storyContent = JSON.parse(completion.choices[0].message.content || '{}')
// Gerar imagens com DALL-E
console.log('[DALL-E] Iniciando geração de imagens...')
const pages = await Promise.all(
storyContent.pages.map(async (page: any) => {
storyContent.pages.map(async (page: any, index: number) => {
console.log(`[DALL-E] Gerando imagem ${index + 1}/${storyContent.pages.length}...`)
const imageResponse = await openai.images.generate({
prompt: `${page.image_prompt}. Style: children's book illustration, colorful, educational, safe for kids`,
n: 1,
size: "1024x1024"
});
})
console.log(`[DALL-E] Imagem ${index + 1} gerada com sucesso`)
return {
text: page.text,
image: imageResponse.data[0].url
}
})
);
)
// Atualizar história no Supabase
console.log('[DALL-E] Todas as imagens geradas com sucesso')
console.log('[DB] Salvando história...')
await supabase
.from('stories')
.update({
@ -152,16 +149,27 @@ serve(async (req) => {
})
.eq('id', record.id)
console.log('[DB] História salva com sucesso')
return new Response(
JSON.stringify({ success: true }),
JSON.stringify({
success: true,
message: 'História gerada e salva com sucesso',
storyId: record.id
}),
{ headers: { 'Content-Type': 'application/json' } }
)
} catch (error) {
console.error('Erro ao gerar história:', error)
console.error('[Error] Erro ao gerar história:', error)
console.error('[Error] Stack trace:', error.stack)
return new Response(
JSON.stringify({ error: error.message }),
JSON.stringify({
error: error.message,
stack: error.stack,
timestamp: new Date().toISOString()
}),
{
headers: { 'Content-Type': 'application/json' },
status: 500