mirror of
https://github.com/lucasrcsantana/story-generator.git
synced 2025-12-18 14:27:51 +00:00
fix: corrigindo salvamento da história no banco de dados
This commit is contained in:
parent
7e3b4551ec
commit
8af9950ed7
47
CHANGELOG.md
Normal file
47
CHANGELOG.md
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
Todas as mudanças notáveis neste projeto serão documentadas neste arquivo.
|
||||||
|
|
||||||
|
O formato é baseado em [Keep a Changelog](https://keepachangelog.com/pt-BR/1.0.0/),
|
||||||
|
e este projeto adere ao [Semantic Versioning](https://semver.org/lang/pt-BR/).
|
||||||
|
|
||||||
|
## [0.1.0] - 2024-03-23
|
||||||
|
|
||||||
|
### Adicionado
|
||||||
|
- Edge function `generate-story` para geração de histórias com IA
|
||||||
|
- Integração com OpenAI GPT para criação de texto
|
||||||
|
- Integração com DALL-E para geração de imagens
|
||||||
|
- Sistema de logs estruturados para monitoramento
|
||||||
|
- Tratamento robusto de erros e validações
|
||||||
|
|
||||||
|
- Componente `StoryGenerator` para interface de criação
|
||||||
|
- Fluxo de seleção de categorias (tema, disciplina, personagem, cenário)
|
||||||
|
- Feedback visual do processo de geração
|
||||||
|
- Validações de campos obrigatórios
|
||||||
|
- Navegação automática entre etapas
|
||||||
|
- Tratamento de erros com feedback visual
|
||||||
|
|
||||||
|
### Modificado
|
||||||
|
- Atualização do schema do banco para suportar novas categorias
|
||||||
|
- Adição de tabelas para temas, disciplinas, personagens e cenários
|
||||||
|
- Relacionamentos entre histórias e categorias
|
||||||
|
- Índices para otimização de consultas
|
||||||
|
|
||||||
|
### Técnico
|
||||||
|
- Implementação de logs estruturados com prefixos por contexto
|
||||||
|
- Validações de dados em múltiplas camadas
|
||||||
|
- Tratamento de respostas da IA com fallbacks
|
||||||
|
- Otimização de queries no banco de dados
|
||||||
|
- Feedback em tempo real do processo de geração
|
||||||
|
|
||||||
|
### Segurança
|
||||||
|
- Validação de dados de entrada na edge function
|
||||||
|
- Verificação de permissões do usuário
|
||||||
|
- Sanitização de prompts para a IA
|
||||||
|
- Proteção contra dados sensíveis nos logs
|
||||||
|
|
||||||
|
### Próximos Passos
|
||||||
|
- [ ] Implementar cache de respostas da IA
|
||||||
|
- [ ] Adicionar retry policy para falhas de geração
|
||||||
|
- [ ] Melhorar prompts para histórias mais educativas
|
||||||
|
- [ ] Adicionar métricas de uso e performance
|
||||||
@ -14,7 +14,26 @@ interface StoryPrompt {
|
|||||||
context?: string;
|
context?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ALLOWED_ORIGINS = [
|
||||||
|
'http://localhost:5173', // Vite dev server
|
||||||
|
'http://localhost:3000', // Caso use outro port
|
||||||
|
'https://historiasmagicas.netlify.app' // Produção
|
||||||
|
];
|
||||||
|
|
||||||
serve(async (req) => {
|
serve(async (req) => {
|
||||||
|
const origin = req.headers.get('origin') || '';
|
||||||
|
const corsHeaders = {
|
||||||
|
'Access-Control-Allow-Origin': ALLOWED_ORIGINS.includes(origin) ? origin : ALLOWED_ORIGINS[0],
|
||||||
|
'Access-Control-Allow-Methods': 'POST, OPTIONS',
|
||||||
|
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
|
||||||
|
'Access-Control-Max-Age': '86400', // 24 horas
|
||||||
|
};
|
||||||
|
|
||||||
|
// Preflight request
|
||||||
|
if (req.method === 'OPTIONS') {
|
||||||
|
return new Response('ok', { headers: corsHeaders })
|
||||||
|
}
|
||||||
|
|
||||||
const { record } = await req.json()
|
const { record } = await req.json()
|
||||||
console.log('[Request]', record)
|
console.log('[Request]', record)
|
||||||
|
|
||||||
@ -111,6 +130,11 @@ serve(async (req) => {
|
|||||||
console.log('[GPT] História gerada:', completion.choices[0].message)
|
console.log('[GPT] História gerada:', completion.choices[0].message)
|
||||||
const storyContent = JSON.parse(completion.choices[0].message.content || '{}')
|
const storyContent = JSON.parse(completion.choices[0].message.content || '{}')
|
||||||
|
|
||||||
|
// Validar estrutura do retorno da IA
|
||||||
|
if (!storyContent.title || !Array.isArray(storyContent.pages)) {
|
||||||
|
throw new Error('Formato inválido retornado pela IA');
|
||||||
|
}
|
||||||
|
|
||||||
console.log('[DALL-E] Iniciando geração de imagens...')
|
console.log('[DALL-E] Iniciando geração de imagens...')
|
||||||
const pages = await Promise.all(
|
const pages = await Promise.all(
|
||||||
storyContent.pages.map(async (page: any, index: number) => {
|
storyContent.pages.map(async (page: any, index: number) => {
|
||||||
@ -131,10 +155,8 @@ serve(async (req) => {
|
|||||||
|
|
||||||
console.log('[DALL-E] Todas as imagens geradas com sucesso')
|
console.log('[DALL-E] Todas as imagens geradas com sucesso')
|
||||||
|
|
||||||
console.log('[DB] Salvando história...')
|
// Preparar dados para salvar
|
||||||
await supabase
|
const storyData = {
|
||||||
.from('stories')
|
|
||||||
.update({
|
|
||||||
title: storyContent.title,
|
title: storyContent.title,
|
||||||
content: {
|
content: {
|
||||||
title: storyContent.title,
|
title: storyContent.title,
|
||||||
@ -143,21 +165,43 @@ serve(async (req) => {
|
|||||||
subject: subject.title,
|
subject: subject.title,
|
||||||
character: character.title,
|
character: character.title,
|
||||||
setting: setting.title,
|
setting: setting.title,
|
||||||
context: record.context
|
context: record.context,
|
||||||
|
original_prompt: prompt,
|
||||||
|
ai_response: completion.choices[0].message.content
|
||||||
},
|
},
|
||||||
status: 'published'
|
status: 'published',
|
||||||
})
|
theme_id: theme.id,
|
||||||
.eq('id', record.id)
|
subject_id: subject.id,
|
||||||
|
character_id: character.id,
|
||||||
|
setting_id: setting.id,
|
||||||
|
updated_at: new Date().toISOString()
|
||||||
|
}
|
||||||
|
|
||||||
console.log('[DB] História salva com sucesso')
|
console.log('[DB] Dados para salvar:', storyData)
|
||||||
|
|
||||||
|
// Atualizar história no Supabase
|
||||||
|
console.log('[DB] Salvando história...')
|
||||||
|
const { data: savedStory, error: updateError } = await supabase
|
||||||
|
.from('stories')
|
||||||
|
.update(storyData)
|
||||||
|
.eq('id', record.id)
|
||||||
|
.select()
|
||||||
|
.single()
|
||||||
|
|
||||||
|
if (updateError) {
|
||||||
|
throw new Error(`Erro ao salvar história: ${updateError.message}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('[DB] História salva com sucesso:', savedStory)
|
||||||
|
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
success: true,
|
success: true,
|
||||||
message: 'História gerada e salva com sucesso',
|
message: 'História gerada e salva com sucesso',
|
||||||
storyId: record.id
|
storyId: record.id,
|
||||||
|
story: savedStory
|
||||||
}),
|
}),
|
||||||
{ headers: { 'Content-Type': 'application/json' } }
|
{ headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
|
||||||
)
|
)
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -171,7 +215,7 @@ serve(async (req) => {
|
|||||||
timestamp: new Date().toISOString()
|
timestamp: new Date().toISOString()
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
|
||||||
status: 500
|
status: 500
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user