diff --git a/DOCS.md b/DOCS.md new file mode 100644 index 0000000..a1d2246 --- /dev/null +++ b/DOCS.md @@ -0,0 +1,143 @@ +# 🎬 MovieWebProject — Guía de instalación + +Guía completa para levantar el proyecto frontend + backend, configurar las variables de entorno y preparar la base de datos. + +## 📖 Índice + +1. [🚀 Comandos principales](#-comandos-principales-post-instalación) +2. [⚙️ Instalación paso a paso](#%EF%B8%8F-instalación-paso-a-paso) +3. [🧠 Configuración del Backend](#-configuración-del-backend) +4. [🎨 Configuración del Frontend](#-configuración-de-frontend) +5. [🗄️ Base de Datos SQL (PostgreSQL)](#%EF%B8%8F-configuración-de-base-de-datos-sql-postgresql) +6. [☁️ Base de Datos NoSQL (MongoDB)](#configuración-de-base-de-datos-nosql-mongodb) +7. [🧩 Estructura del proyecto](#-estructura-del-proyecto) +8. [💡 Tips finales](#-tips-finales) +9. [🛠️ Stack Tecnológico](#%EF%B8%8F-stack-tecnológico) + + +## 🚀 Comandos principales (post instalación) + +Ejecutar todo el proyecto (frontend + backend): +```bash +npm run dev:all +``` + +Migrar la base de datos (SQL): +```bash +npm run migrate +``` + +Ejecutar sólo el cliente (Astro): +```bash +npm run dev:client +``` + +Ejecutar sólo el servidor (Express): +```bash +npm run dev:server +``` + +## ⚙️ Instalación paso a paso + +1️⃣ Clonar el repositorio +```bash +git clone https://github.com/lulibetelu/MovieWebProject.git +``` + +2️⃣ Instalar las dependencias +```bash +cd MovieWebProject +npm install # Dependencias del root +cd client && npm install # Dependencias del frontend +cd ../server && npm install # Dependencias del backend +cd .. +``` +> 💡 Es importante instalar tanto las dependencias del root como las del cliente y servidor. + +## 🧠 Configuración del Backend + +📍 Ubicación: `/server` + +Configurar las variables de entorno del __servidor__: + - Moverse a la carpeta `/server`. + - Copiar el archivo `.env.example` a `.env`. + - Configurar las variables: + - `PORT`: Puerto en el que se ejecutará el servidor (API). + - `DB_HOST`: Host de la base de datos. + - `DB_USER`: Usuario de la base de datos. + - `DB_PASSWORD`: Contraseña de la base de datos. + - `DB_PORT`: Puerto de la base de datos. + - `DEBUG`: Modo de depuración (true/false). + - `API_MODE`: Modo API o RENDER (true). + - `SECRET_KEY`: Clave secreta para la aplicación. (texto random) + - `TMDB_API_KEY`: 🔑 Clave de API para la API de The Movie Database. (Crearse una cuenta en [TMDB](https://www.themoviedb.org/) y poner la api key) + +Mas información sobre `server` en [README](README.md). + +## 🎨 Configuración de Frontend + +📍 Ubicación: `/client` + +Configurar las variables de entorno del __cliente__: + - Moverse a la carpeta `/client`. + - Copiar el archivo `.env.example` a `.env`. + - Configurar las variables: + - `PUBLIC_TMDB_API_KEY`: 🔑 Misma que en el `server`. + - `PUBLIC_API_URL`: ruta al servidor (`http://localhost:3500/api`) + - `NLPCLOUD_TOKEN`: 🔑 Crearse una cuenta en [NLPCloud](https://nlpcloud.com/) y poner el token + +Mas información sobre `client` en [README](./client/README.md). + +## 🗄️ Configuración de Base de Datos SQL (PostgreSQL) + +📍 Ubicación: `/db` + +Correr los scripts de la carpeta en orden para modificar la base de datos local. +### Primera vez + +- Ejecutar los __12 scripts base__ del profesor. +- Ejecutar el script 13 `/db/13_migration_table.sql` + +### Despues de cada __git pull__ + +Ejecutar el comando `npm run migrate` (desde root) para actualizar la base de datos. + +Mas información sobre `db` en [instrucciones](./db/instrucciones.txt). + +## Configuración de Base de Datos NoSQL (MongoDB) + +🚧 Próximamente… +La integración con MongoDB se encuentra en desarrollo. + +## 🧩 Estructura del proyecto +```sh +MovieWebProject/ +│ +├── client/ → Frontend (Astro) +│ ├── src/ +│ ├── public/ +│ └── .env +│ +├── server/ → Backend (Express + PostgreSQL) +│ ├── src/ +│ ├── db/ +│ └── .env +│ +├── db/ → Scripts SQL +├── package.json → Scripts globales +└── README.md +``` + +## 💡 Tips finales + +- 📦 Antes de correr npm run dev:all, asegurate de que PostgreSQL esté levantado. +- 🧠 Si hay errores de conexión, revisá las rutas de las variables .env. +- 🔥 El resumen automático de reseñas usa la API /api/summarize (NLPCloud). + +## 🛠️ Stack Tecnológico + +- Frontend: Astro, Tailwind CSS +- Backend: Express, Node.js +- Base de datos SQL: PostgreSQL +- Base de datos NoSQL: MongoDB (próximamente) +- APIs externas: TMDB, NLPCloud diff --git a/client/.env.example b/client/.env.example index a9cdeeb..59d61d7 100644 --- a/client/.env.example +++ b/client/.env.example @@ -1,2 +1,3 @@ -PUBLIC_TMDB_API_KEY="your_api_key" +PUBLIC_TMDB_API_KEY=your_api_key PUBLIC_API_URL="http://localhost:3500/api" +NLPCLOUD_TOKEN=your_api_key diff --git a/client/package.json b/client/package.json index 1a7f634..fef75b3 100644 --- a/client/package.json +++ b/client/package.json @@ -1,7 +1,7 @@ { - "name": "megafront", + "name": "client", "type": "module", - "version": "0.0.1", + "version": "0.1.0", "scripts": { "dev": "astro dev --no-check", "build": "astro build", @@ -20,6 +20,7 @@ "daisyui": "^5.3.7", "gsap": "^3.13.0", "motion": "^12.23.24", + "nlpcloud": "^2.0.8", "react": "^19.2.0", "react-dom": "^19.2.0", "tailwindcss": "^4.1.15", diff --git a/client/src/components/reusables/AiReview.jsx b/client/src/components/reusables/AiReview.jsx new file mode 100644 index 0000000..37579f4 --- /dev/null +++ b/client/src/components/reusables/AiReview.jsx @@ -0,0 +1,69 @@ +import { useEffect, useState } from "react"; + +const AiReview = ({ reviews = [] }) => { + const [summary, setSummary] = useState(null); + + useEffect(() => { + let ignore = false; + const controller = new AbortController(); + + async function summarize() { + console.log(null); + + if (!reviews || reviews.length === 0) { + setSummary("Sin reseñas."); + return; + } + + try { + // Unimos las reseñas en un solo string + const text = reviews.join(". "); + + const res = await fetch("http://localhost:4321/api/summarize", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ text }), + signal: controller.signal, + }); + + if (!res.ok) { + throw new Error(`HTTP ${res.status}`); + } + + const data = await res.json(); + + if (!ignore) { + setSummary(data?.summary ?? "error"); + } + } catch (err) { + if (!ignore) { + console.error("Error al conectar con la API:", err); + setSummary("error"); + } + } + } + + summarize(); + + return () => { + ignore = true; + controller.abort(); + }; + }, [reviews]); + + return summary === "error" ? ( +

+ ) : summary ? ( +
+

+ Resumen de las reseñas: +

+ +

{summary || ""}

+
+ ) : ( +
+ ); +}; + +export default AiReview; diff --git a/client/src/components/reusables/MoviesCarousel.jsx b/client/src/components/reusables/MoviesCarousel.jsx index 5707f29..533e996 100644 --- a/client/src/components/reusables/MoviesCarousel.jsx +++ b/client/src/components/reusables/MoviesCarousel.jsx @@ -78,58 +78,3 @@ const MoviesCarousel = ({ movieGroup = [], title = "", idx = 0 }) => { }; export default MoviesCarousel; - -{ - /* Carousel -
-
-
- {hasOut ? ( - out.map((movieGroup, index) => ( -
- {Array.isArray(movieGroup) && - movieGroup.length > 0 ? ( - movieGroup.map((img, idx) => ( -
- -
-

- {typeof img === "string" - ? img.slice(0, 28) - : String(img)} -

-
-
- )) - ) : ( -
- No movies in this group -
- )} -
- )) - ) : hasResult ? ( -

Loaded!

- ) : ( -
- No movies available -
- )} -
-
- -
- */ -} diff --git a/client/src/pages/api/summarize.js b/client/src/pages/api/summarize.js new file mode 100644 index 0000000..9a97a69 --- /dev/null +++ b/client/src/pages/api/summarize.js @@ -0,0 +1,37 @@ +import NLPCloudClient from "nlpcloud"; + +export const prerender = false; + +const client = new NLPCloudClient({ + model: "bart-large-cnn", + token: import.meta.env.NLPCLOUD_TOKEN, +}); + +export async function POST({ request }) { + const requestData = await request.json(); + const reviewsText = requestData.text; + + try { + const summary = await client.summarization({ + text: reviewsText, + }); + + return new Response( + JSON.stringify({ + summary: summary.data.summary_text, + }), + { + headers: { "Content-Type": "application/json" }, + }, + ); + } catch (err) { + console.error("Error al resumir:", err); + return new Response( + JSON.stringify({ + error: true, + message: err.message, + }), + { status: 500 }, + ); + } +} diff --git a/client/src/pages/pelicula/[id].astro b/client/src/pages/pelicula/[id].astro index d662c77..fc0d180 100644 --- a/client/src/pages/pelicula/[id].astro +++ b/client/src/pages/pelicula/[id].astro @@ -4,6 +4,7 @@ import { API_URL } from "../../data/config"; import DetailLayout from "../../layouts/DetailLayout.astro"; import MovieImages from "../../components/TMDB_Images/MovieImages"; import PersonImages from "../../components/TMDB_Images/PersonImages"; +import AiReview from "../../components/reusables/AiReview"; export const prerender = false; @@ -12,8 +13,6 @@ const { id } = Astro.params; let movie; const tmdbApiKey = import.meta.env.PUBLIC_TMDB_API_KEY; - - try { const res = await fetch(`${API_URL}/pelicula/${id}`); if (!res.ok) { @@ -37,6 +36,21 @@ if (movie?.release_date) { formattedDate = `${day}-${month}-${year}`; } } + +// Reviews de ejemplo (Reemplazar por reviews reales) +const reviews = [ + "Una obra maestra visual, la fotografía es impresionante y la banda sonora acompaña perfectamente cada escena.", + "La historia es buena pero el ritmo se siente lento en algunos tramos, especialmente en la primera mitad.", + "Las actuaciones son sobresalientes, especialmente la del protagonista, transmite muchísima emoción.", + "Esperaba más del final, me pareció un poco predecible aunque todo lo demás está muy bien logrado.", + "La dirección es impecable, se nota el cuidado en cada plano y el uso del color es magnífico.", + "El guion tiene momentos brillantes y diálogos muy profundos, pero algunos personajes secundarios están poco desarrollados.", + "Una experiencia cinematográfica inolvidable, me mantuvo completamente inmerso de principio a fin.", + "La película es visualmente hermosa pero algo confusa en su mensaje, cuesta entender qué quiere transmitir.", + "Excelente equilibrio entre acción y drama, no aburre en ningún momento y deja un gran mensaje final.", + "Sin duda una de las mejores películas del año, emociona, sorprende y deja pensando mucho después de los créditos." +]; + --- @@ -79,10 +93,8 @@ if (movie?.release_date) {
{ (movie?.title && tmdbApiKey) ? ( -
- +
+
) : (
@@ -104,6 +116,8 @@ if (movie?.release_date) {

{movie.tagline}

)} + +
{movie.genre && (
{movie.genre}
@@ -226,28 +240,27 @@ if (movie?.release_date) {
) } -
-
+
+ + ) + } + + +
- ) - } - - - - + diff --git a/server/.env.example b/server/.env.example new file mode 100644 index 0000000..cdca3ab --- /dev/null +++ b/server/.env.example @@ -0,0 +1,12 @@ +PORT=3500 + +DB_USER= +DB_HOST=localhost +DB_DATABASE=movies +DB_PASSWORD= +DB_PORT=5432 + +DEBUG="false" +API_MODE="true" +SECRET_KEY= +TMDB_API_KEY=