Primeiro Commit

This commit is contained in:
luisfepsale
2025-10-22 12:52:23 -03:00
parent 27820254e7
commit 235fb538e1
19 changed files with 2132 additions and 426 deletions
+218
View File
@@ -0,0 +1,218 @@
import { apiService } from './api';
/**
* Tamanhos de imagem disponíveis
*/
export type ImageSize = '1024x1024' | '1024x1792' | '1792x1024';
/**
* Interface para a resposta da API de geração de imagens
*/
export interface ImageGenerationResponse {
success: boolean;
image_url: string; // URL da imagem gerada
image_generation_id: string;
message: string; // Descrição original
}
/**
* Interface para os dados necessários para geração de imagem
*/
export interface ImageGenerationRequest {
description: string;
size: ImageSize;
userEmail?: string;
estabelecimentoId?: number;
}
/**
* Informações sobre cada tamanho de imagem disponível
*/
export const IMAGE_SIZE_OPTIONS = {
'1024x1024': {
label: 'Quadrado',
dimensions: '1024x1024',
aspectRatio: '1:1',
description: 'Ideal para avatares, ícones e posts em redes sociais',
},
'1024x1792': {
label: 'Retrato',
dimensions: '1024x1792',
aspectRatio: '9:16',
description: 'Perfeito para stories, wallpapers verticais e reels',
},
'1792x1024': {
label: 'Paisagem',
dimensions: '1792x1024',
aspectRatio: '16:9',
description: 'Ótimo para banners, capas e thumbnails de vídeos',
},
} as const;
/**
* Serviço de geração de imagens com IA
*/
class ImageGenerationService {
private readonly IMAGE_GENERATION_ENDPOINT = '/webhook/codex/image_generator';
/**
* Gera uma imagem a partir de uma descrição em texto
*
* @param request - Dados da requisição (descrição, tamanho, email, estabelecimento)
* @returns Promise com a resposta da API
*/
async generateImage(request: ImageGenerationRequest): Promise<ImageGenerationResponse> {
const { description, size, userEmail, estabelecimentoId } = request;
// Usa valores do .env se não forem fornecidos
const email = userEmail || import.meta.env.VITE_USER_EMAIL || '';
const estabId = estabelecimentoId || parseInt(import.meta.env.VITE_ESTABELECIMENTO_ID) || 1;
// Valida a descrição
if (!description || description.trim().length === 0) {
throw {
success: false,
message: 'A descrição não pode estar vazia',
};
}
// Valida o tamanho
if (!this.isValidSize(size)) {
throw {
success: false,
message: `Tamanho inválido. Opções disponíveis: ${Object.keys(IMAGE_SIZE_OPTIONS).join(', ')}`,
};
}
// Log para debug (remover em produção se necessário)
console.log('Gerando imagem:', {
descriptionLength: description.length,
size,
userEmail: email,
estabelecimentoId: estabId,
});
try {
// Faz a requisição usando o serviço de API
// Nota: O campo no body é "estabelecito_id" (com typo na API)
const response = await apiService.post<ImageGenerationResponse>(
this.IMAGE_GENERATION_ENDPOINT,
{
estabelecimento_id: estabId, // Mantém o typo da API original
user_email: email,
description: description,
size: size,
}
);
return response.data;
} catch (error: any) {
// Trata erros específicos
console.error('Erro na geração de imagem:', error);
throw {
success: false,
message: error.message || 'Erro ao gerar imagem',
status: error.status,
};
}
}
/**
* Valida se o tamanho selecionado é suportado
*
* @param size - Tamanho a ser validado
* @returns true se o tamanho é válido
*/
isValidSize(size: string): size is ImageSize {
return Object.keys(IMAGE_SIZE_OPTIONS).includes(size);
}
/**
* Obtém informações sobre um tamanho específico
*
* @param size - Tamanho da imagem
* @returns Informações do tamanho
*/
getSizeInfo(size: ImageSize) {
return IMAGE_SIZE_OPTIONS[size];
}
/**
* Lista todos os tamanhos disponíveis
*
* @returns Array com todas as opções de tamanho
*/
getAllSizes() {
return Object.entries(IMAGE_SIZE_OPTIONS).map(([key, info]) => ({
value: key as ImageSize,
...info,
}));
}
/**
* Valida a descrição para geração de imagem
*
* @param description - Descrição a ser validada
* @param minLength - Comprimento mínimo (padrão: 3 caracteres)
* @param maxLength - Comprimento máximo (padrão: 1000 caracteres)
* @returns Objeto com resultado da validação
*/
validateDescription(
description: string,
minLength: number = 3,
maxLength: number = 1000
): { valid: boolean; error?: string } {
if (!description || description.trim().length === 0) {
return {
valid: false,
error: 'A descrição não pode estar vazia',
};
}
if (description.trim().length < minLength) {
return {
valid: false,
error: `A descrição deve ter pelo menos ${minLength} caracteres`,
};
}
if (description.length > maxLength) {
return {
valid: false,
error: `A descrição é muito longa. Máximo: ${maxLength} caracteres`,
};
}
return { valid: true };
}
/**
* Faz download de uma imagem gerada
*
* @param imageUrl - URL da imagem
* @param filename - Nome do arquivo (opcional)
*/
async downloadImage(imageUrl: string, filename?: string): Promise<void> {
try {
const response = await fetch(imageUrl);
const blob = await response.blob();
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename || `imagem_${Date.now()}.png`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
} catch (error) {
console.error('Erro ao baixar imagem:', error);
throw new Error('Não foi possível baixar a imagem');
}
}
}
// Exporta instância única (Singleton)
export const imageGenerationService = new ImageGenerationService();