from fastapi import APIRouter, Depends, HTTPException, Query from sqlalchemy.orm import Session from sqlalchemy.sql import func from database import get_db from models import NewsItem from pydantic import BaseModel from datetime import datetime, UTC import logging # Configuración del logging LOG_FILE = "app.log" logging.basicConfig( filename=LOG_FILE, # Archivo de logs level=logging.INFO, # Nivel de logging (DEBUG, INFO, WARNING, ERROR, CRITICAL) format="%(asctime)s - %(levelname)s - %(message)s", # Formato de los logs ) router = APIRouter() # Modelo de datos de entrada class NewsItemCreate(BaseModel): titulo: str contenido: str autor: str | None = None fuente: str | None = None fecha: datetime | None = None link: str keyword: str | None = None @router.post("/news/") def create_news_item(item: NewsItemCreate, db: Session = Depends(get_db)): # Verificar si el título ya existe existing_item = db.query(NewsItem).filter(NewsItem.titulo == item.titulo).first() if existing_item: logging.info("Título ya en la base de datos") # Crear nuevo objeto new_item = NewsItem( titulo=item.titulo, contenido=item.contenido, autor=item.autor, fuente=item.fuente, fecha=item.fecha or datetime.now(UTC), # Nueva forma recomendada link=item.link, keyword=item.keyword ) db.add(new_item) db.commit() db.refresh(new_item) return {"message": "Noticia creada con éxito", "id": new_item.id, "titulo": new_item.titulo} @router.get("/news/count/by-source") def count_news_by_source(db: Session = Depends(get_db)): results = ( db.query(NewsItem.fuente, func.count(NewsItem.id)) .group_by(NewsItem.fuente) .all() ) # Convertir resultados en una lista de diccionarios response = [{"fuente": fuente, "count": count} for fuente, count in results] return {"count_by_fuente": response} @router.get("/news/count/by-author") def count_news_by_author(db: Session = Depends(get_db)): results = ( db.query(NewsItem.autor, func.count(NewsItem.id)) .group_by(NewsItem.autor) .all() ) # Convertir resultados en una lista de diccionarios response = [{"autor": autor, "count": count} for autor, count in results] return {"count_by_author": response} @router.get("/news/{news_id}") def get_news_by_id(news_id: int, db: Session = Depends(get_db)): news_item = db.query(NewsItem).filter(NewsItem.id == news_id).first() if not news_item: raise HTTPException(status_code=404, detail="Noticia no encontrada") return { "id": news_item.id, "titulo": news_item.titulo, "contenido": news_item.contenido, "autor": news_item.autor, "fuente": news_item.fuente, "fecha": news_item.fecha, "link": news_item.link, "keyword": news_item.keyword, } @router.get("/news/count/by-keyword") def count_news_by_keyword( fechaInicio: datetime | None = None, fechaFin: datetime | None = None, db: Session = Depends(get_db)): query = db.query(NewsItem.keyword, func.count(NewsItem.id)).filter(NewsItem.keyword.isnot(None)) if fechaInicio and fechaFin: query = query.filter(NewsItem.fecha >= fechaInicio, NewsItem.fecha <= fechaFin) results = query.group_by(NewsItem.keyword).all() return {keyword: count for keyword, count in results} @router.get("/news/keywords/") def get_all_keywords(db: Session = Depends(get_db)): results = db.query(NewsItem.keyword).distinct().all() # Extraer solo las keywords y filtrar valores nulos keywords = [keyword[0] for keyword in results if keyword[0] is not None] return {"keywords": keywords} @router.get("/news/count/by-source/keyword/date-range") def count_news_by_source_for_keyword_in_range( keyword: str, fechaInicio: datetime, fechaFin: datetime, db: Session = Depends(get_db) ): results = ( db.query(NewsItem.fuente, func.count(NewsItem.id)) .filter( NewsItem.keyword == keyword, NewsItem.fecha >= fechaInicio, NewsItem.fecha <= fechaFin ) .group_by(NewsItem.fuente) .all() ) formatted_results = {fuente: count for fuente, count in results} return {"count_by_source_keyword": formatted_results} @router.get("/news/titles/by-keyword/date-range") def get_titles_by_keyword_in_range( keyword: str, fecha_inicio: datetime, fecha_fin: datetime, db: Session = Depends(get_db) ): results = ( db.query(NewsItem.titulo) .filter( NewsItem.keyword == keyword, NewsItem.fecha >= fecha_inicio, NewsItem.fecha <= fecha_fin ) .all() ) # # Convertir resultados en una sola cadena separada por comas # titles = ", ".join([titulo[0] for titulo in results if titulo[0]]) titles = [titulo[0] for titulo in results if titulo[0]] return {"titles": titles} # @router.get("/news-summary") # def get_news_summary( # keyword: str, # fecha_inicio: datetime, # fecha_fin: datetime, # db: Session = Depends(get_db) # ): # results = get_titles_by_keyword_in_range(keyword,fecha_inicio, fecha_fin, db) # data = { # "model":"llama3", # "prompt": f"A continuación tienes los titulares de muchas noticias, resume lo que encuentres más destacado. Noticias: {results}", # } # try: # response = requests.post( # "http://host.docker.internal:11434/api/generate", json=data # ) # response.raise_for_status() # except requests.RequestException as e: # logging.error(f"Request error: {e}") # return response @router.get("/news/titles/") def get_news_titles( fechaInicio: datetime | None = None, fechaFin: datetime | None = None, db: Session = Depends(get_db), ): query = db.query(NewsItem.titulo) if fechaInicio and fechaFin: query = query.filter(NewsItem.fecha >= fechaInicio, NewsItem.fecha <= fechaFin) results = query.all() return {"titles": [titulo[0] for titulo in results]} @router.get("/news/") def get_all_news( fechaInicio: datetime | None = None, fechaFin: datetime | None = None, page:int = Query(1, alias="page", ge=1), pageSize: int = Query(10, alias="pageSize", ge=1, le=100), db: Session = Depends(get_db), ): query = db.query(NewsItem.id, NewsItem.titulo, NewsItem.link) # Solo seleccionamos id y titulo if fechaInicio and fechaFin: query = query.filter(NewsItem.fecha >= fechaInicio, NewsItem.fecha <= fechaFin) totalCount = query.count() results = query.offset((page - 1) * pageSize).limit(pageSize).all() return { "totalCount": totalCount, "page": page, "pageSize": pageSize, "totalPages": (totalCount + pageSize - 1) // pageSize, "news": [{"id": news_id, "titulo": titulo, "url":link} for news_id, titulo, link in results] # Devolvemos solo id y titulo }