diff --git a/frontend/src/App.vue b/frontend/src/App.vue index de8f91d..2fd2951 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -2,9 +2,15 @@
+
diff --git a/frontend/src/components/ToastContainer.vue b/frontend/src/components/ToastContainer.vue new file mode 100644 index 0000000..0b563ac --- /dev/null +++ b/frontend/src/components/ToastContainer.vue @@ -0,0 +1,54 @@ + + + diff --git a/frontend/src/components/TopAppBar.vue b/frontend/src/components/TopAppBar.vue index c8f37b4..963394d 100644 --- a/frontend/src/components/TopAppBar.vue +++ b/frontend/src/components/TopAppBar.vue @@ -1,35 +1,45 @@ diff --git a/frontend/src/composables/useToast.js b/frontend/src/composables/useToast.js new file mode 100644 index 0000000..4a5e3ac --- /dev/null +++ b/frontend/src/composables/useToast.js @@ -0,0 +1,22 @@ +import { ref } from 'vue' + +const toasts = ref([]) +let nextId = 0 + +export function useToast() { + function add(message, { type = 'default', duration = 3500 } = {}) { + const id = nextId++ + toasts.value.push({ id, message, type }) + setTimeout(() => { + toasts.value = toasts.value.filter(t => t.id !== id) + }, duration) + } + + return { + toasts, + success: (msg) => add(msg, { type: 'success' }), + error: (msg) => add(msg, { type: 'error', duration: 5000 }), + info: (msg) => add(msg, { type: 'info' }), + warn: (msg) => add(msg, { type: 'warn' }), + } +} diff --git a/frontend/src/views/AnalysisCreateView.vue b/frontend/src/views/AnalysisCreateView.vue index ca33c1e..270aab8 100644 --- a/frontend/src/views/AnalysisCreateView.vue +++ b/frontend/src/views/AnalysisCreateView.vue @@ -9,12 +9,14 @@
@@ -23,7 +25,7 @@
- +
@@ -34,18 +36,40 @@
- +
- link + link + + {{ urlState === 'valid' ? 'check_circle' : 'cancel' }} +
-

Compatible con TikTok, Instagram Reels y YouTube Shorts.

+

+ {{ urlState === 'valid' ? 'URL compatible detectada' : + urlState === 'invalid' ? 'Solo TikTok, Instagram Reels o YouTube Shorts' : + 'Compatible con TikTok, Instagram Reels y YouTube Shorts.' }} +

@@ -53,7 +77,8 @@
- +
@@ -83,12 +109,16 @@
- + @@ -101,7 +131,8 @@ v-model="form.mercado_objetivo" type="text" placeholder="Ej. Emprendedoras 25-35 años" - class="w-full bg-canvas border border-border rounded-lg px-3 py-2.5 text-sm text-ink placeholder:text-ink-3 focus:outline-none focus:ring-2 focus:ring-accent/30 transition-all" + class="w-full bg-canvas border border-border rounded-lg px-3 py-2.5 text-sm text-ink + placeholder:text-ink-3 focus:outline-none focus:ring-2 focus:ring-accent/30 transition-all" :disabled="analizando" />
@@ -109,16 +140,29 @@
- - + +
- - + +
- +
@@ -126,7 +170,7 @@ @@ -142,18 +186,20 @@ 3

Contexto del Video - (opcional) + (opcional)

- Describe la intención del creador o cualquier contexto que la transcripción no capture. GPT-4o lo usará para enriquecer el análisis. + Describe la intención del creador o cualquier contexto que la transcripción no capture.

@@ -178,23 +224,22 @@
-
{{ idx < currentStepIdx ? 'check' : s.icon }} @@ -206,27 +251,44 @@
- +
-

Tiempo estimado: ~15 segundos · GPT-4o + Whisper

+
+

GPT-4o + Whisper

+

{{ elapsed }}s

+
- -
-

Error en el pipeline

-

{{ error }}

+ +
+
+ error +
+

Error en el pipeline

+

{{ error }}

+
+
+

- Completa la URL y el nicho para iniciar. El pipeline extrae audio, transcribe y analiza los patrones de neuromarketing automáticamente. + Completa la URL y el nicho para iniciar. El pipeline extrae audio, transcribe con Whisper y analiza los patrones de neuromarketing automáticamente.

@@ -237,7 +299,7 @@ + + diff --git a/frontend/src/views/AnalysisDetailView.vue b/frontend/src/views/AnalysisDetailView.vue index aa51a57..0d9e553 100644 --- a/frontend/src/views/AnalysisDetailView.vue +++ b/frontend/src/views/AnalysisDetailView.vue @@ -5,15 +5,20 @@

Cargando análisis…

-
+
+ + +
- - west Volver al historial - -
{{ guion.niche }} {{ guion.sub_niche }} @@ -22,7 +27,6 @@ Replicabilidad {{ guion.replicabilidad }}
-

{{ guion.tema_principal || 'Análisis sin título' }}

@@ -31,23 +35,43 @@ {{ guion.angulo_unico || 'Ángulo único no especificado' }}

-
- + auto_fix_high Generar Guion
+ + +
@@ -55,7 +79,7 @@
-
+

bar_chart Métricas del Video @@ -64,61 +88,66 @@
visibility

Vistas

-

{{ formatNum(guion.vistas) }}

+

{{ formatNum(guion.vistas) }}

favorite

Likes

-

{{ formatNum(guion.likes) }}

+

{{ formatNum(guion.likes) }}

share

Compartidos

-

{{ formatNum(guion.compartidos) }}

+

{{ formatNum(guion.compartidos) }}

Engagement Rate - {{ (guion.score_engagement * 1).toFixed(2) }}% + {{ (guion.score_engagement * 1).toFixed(2) }}%
-
+

analytics Puntaje de Viralidad

- +
- {{ guion.score_virabilidad || 0 }} + + {{ guion.score_virabilidad || 0 }} + / 100

Cialdini

-

{{ guion.score_cialdini ?? 0 }}/7

+

{{ guion.score_cialdini ?? 0 }}/7

Intensidad

-

{{ guion.intensidad_emocional || 0 }}/10

+

{{ guion.intensidad_emocional || 0 }}/10

-
+

psychology_alt Ganchos Semánticos @@ -145,14 +174,14 @@
repeat {{ guion.tecnica_retencion || '—' }} - Pico: {{ guion.momento_pico_seg }}s + Pico: {{ guion.momento_pico_seg }}s

-
+

person_search Avatar & Copywriting @@ -205,7 +234,7 @@

-
+

Síntesis del Patrón Ganador

{{ guion.resumen_patron }}

@@ -227,7 +256,7 @@
-
+

key Ingredientes Clave para Replicar @@ -241,7 +270,7 @@

-
+

local_fire_department @@ -250,10 +279,10 @@
Intensidad - {{ guion.intensidad_emocional || 0 }}/10 + {{ guion.intensidad_emocional || 0 }}/10
-
+
@@ -264,7 +293,7 @@

-
+

group_work Principios de Cialdini @@ -282,7 +311,7 @@

-
+

biotech @@ -338,7 +367,7 @@

-
+

thumb_up Fortalezas @@ -373,7 +402,7 @@

-
+

tag Hashtags Sugeridos

@@ -381,32 +410,35 @@ #{{ tag.replace(/^#/, '') }} + > + {{ tagCopiado === tag ? '✓' : '#' }}{{ tag.replace(/^#/, '') }} +

Haz clic en un hashtag para copiarlo

- -
-

- lightbulb Contexto ingresado -

-

{{ guion.contexto_video }}

-
- -
+

notes Transcripción Completa

-
-
+

{{ guion.transcript || 'Video sin transcripción disponible.' }} @@ -420,16 +452,31 @@ + + diff --git a/frontend/src/views/AnalysisListView.vue b/frontend/src/views/AnalysisListView.vue index 82d81f3..247c8a6 100644 --- a/frontend/src/views/AnalysisListView.vue +++ b/frontend/src/views/AnalysisListView.vue @@ -13,14 +13,18 @@

add Nuevo Análisis @@ -35,7 +39,7 @@ v-for="f in filtrosEstado" :key="f.valor" @click="filtroActivo = f.valor; filtros.page = 1; cargarDatos()" - class="px-3 py-1.5 rounded-md text-xs font-medium transition-all" + class="px-3 py-1.5 rounded-md text-xs font-medium transition-all active:scale-[0.97]" :class="filtroActivo === f.valor ? 'bg-accent text-white shadow-sm' : 'text-ink-2 hover:bg-surface-muted'" @@ -48,7 +52,8 @@ +

Este campo es obligatorio

@@ -37,7 +46,8 @@ +

Este campo es obligatorio

- + +

Este campo es obligatorio

@@ -81,7 +109,10 @@
- @@ -91,7 +122,10 @@
- @@ -104,7 +138,10 @@
- @@ -118,43 +155,84 @@
- +
- - + +
+ + +
+ warning + Falta: {{ camposFaltantes.join(', ') }} +
+
+
-
- {{ error }} + +
+
+ error +
+

Error al generar

+

{{ error }}

+
+
+
- +
@@ -164,29 +242,38 @@

{{ resultado.guion.titulo_sugerido }}

-
+
bolt - {{ resultado.guion.score_estimado }}/100 + {{ resultado.guion.score_estimado }}/100
{{ t }}

Duración estimada

-

{{ resultado.guion.duracion_estimada_seg }}s

+

{{ resultado.guion.duracion_estimada_seg }}s

-
+

Guion Completo

- @@ -213,7 +300,11 @@ shuffle Variantes del Gancho
-
+
V{{ i + 1 }} "{{ v }}"
@@ -228,10 +319,11 @@

{{ resultado.guion.notas_produccion }}

- + @@ -239,12 +331,20 @@
-

¿Cómo funciona?

+

+ auto_fix_high + ¿Cómo funciona? +

El generador analiza los guiones de mayor rendimiento de tu base de datos y aplica sus patrones estructurales, técnicas de retención y triggers emocionales al nuevo contenido.

-
+
{{ paso.icon }}
@@ -254,8 +354,34 @@
-
-

Tiempo estimado: 5–10 segundos · Modelo: GPT-4o

+
+

Tiempo estimado: 5–10s

+ GPT-4o +
+ + +
+
+

Progreso del formulario

+

+ {{ camposCompletos }}/3 +

+
+
+
+
+
+

+ {{ campo }} +

+
@@ -264,27 +390,46 @@