diff --git a/api/main.py b/api/main.py index d0b8c79..64dcad3 100644 --- a/api/main.py +++ b/api/main.py @@ -1,7 +1,34 @@ -from fastapi import FastAPI +import logging +import time +from fastapi import FastAPI, Request from api.routes import templates, forms +from api.errors.handlers import register_exception_handlers -app = FastAPI() +logger = logging.getLogger("fireform.api") + +app = FastAPI(title="FireForm API", version="1.0.0") + +register_exception_handlers(app) app.include_router(templates.router) -app.include_router(forms.router) \ No newline at end of file +app.include_router(forms.router) + + +@app.middleware("http") +async def log_requests(request: Request, call_next): + start = time.time() + response = await call_next(request) + duration_ms = (time.time() - start) * 1000 + logger.info( + "%s %s -> %s (%.1fms)", + request.method, + request.url.path, + response.status_code, + duration_ms, + ) + return response + + +@app.get("/health", tags=["health"]) +def health_check(): + return {"status": "ok"} \ No newline at end of file diff --git a/src/file_manipulator.py b/src/file_manipulator.py index b7815cc..ad84f14 100644 --- a/src/file_manipulator.py +++ b/src/file_manipulator.py @@ -1,8 +1,11 @@ import os from src.filler import Filler from src.llm import LLM +from src.logger import setup_logger from commonforms import prepare_form +logger = setup_logger(__name__) + class FileManipulator: def __init__(self): @@ -22,26 +25,23 @@ def fill_form(self, user_input: str, fields: list, pdf_form_path: str): It receives the raw data, runs the PDF filling logic, and returns the path to the newly created file. """ - print("[1] Received request from frontend.") - print(f"[2] PDF template path: {pdf_form_path}") + logger.info("Received request from frontend.") + logger.info("PDF template path: %s", pdf_form_path) if not os.path.exists(pdf_form_path): - print(f"Error: PDF template not found at {pdf_form_path}") + logger.error("PDF template not found at %s", pdf_form_path) return None # Or raise an exception - print("[3] Starting extraction and PDF filling process...") + logger.info("Starting extraction and PDF filling process...") try: self.llm._target_fields = fields self.llm._transcript_text = user_input output_name = self.filler.fill_form(pdf_form=pdf_form_path, llm=self.llm) - print("\n----------------------------------") - print("✅ Process Complete.") - print(f"Output saved to: {output_name}") + logger.info("Process complete. Output saved to: %s", output_name) return output_name except Exception as e: - print(f"An error occurred during PDF generation: {e}") - # Re-raise the exception so the frontend can handle it + logger.exception("An error occurred during PDF generation: %s", e) raise e diff --git a/src/llm.py b/src/llm.py index 70937f9..e49b981 100644 --- a/src/llm.py +++ b/src/llm.py @@ -1,6 +1,9 @@ import json import os import requests +from src.logger import setup_logger + +logger = setup_logger(__name__) class LLM: @@ -76,10 +79,9 @@ def main_loop(self): # print(parsed_response) self.add_response_to_json(field, parsed_response) - print("----------------------------------") - print("\t[LOG] Resulting JSON created from the input text:") - print(json.dumps(self._json, indent=2)) - print("--------- extracted data ---------") + logger.info("Resulting JSON created from the input text:") + logger.info(json.dumps(self._json, indent=2)) + logger.debug("--------- extracted data ---------") return self @@ -115,9 +117,7 @@ def handle_plural_values(self, plural_value): f"Value is not plural, doesn't have ; separator, Value: {plural_value}" ) - print( - f"\t[LOG]: Formating plural values for JSON, [For input {plural_value}]..." - ) + logger.debug("Formatting plural values for JSON, input: %s", plural_value) values = plural_value.split(";") # Remove trailing leading whitespace @@ -127,7 +127,7 @@ def handle_plural_values(self, plural_value): clean_value = values[current].lstrip() values[current] = clean_value - print(f"\t[LOG]: Resulting formatted list of values: {values}") + logger.debug("Resulting formatted list of values: %s", values) return values diff --git a/src/logger.py b/src/logger.py new file mode 100644 index 0000000..0bf4990 --- /dev/null +++ b/src/logger.py @@ -0,0 +1,26 @@ +import logging +import sys + +LOG_FORMAT = "%(asctime)s | %(levelname)-8s | %(name)s | %(message)s" +DATE_FORMAT = "%Y-%m-%d %H:%M:%S" + + +def setup_logger(name: str = "fireform", level: int = logging.INFO) -> logging.Logger: + """ + Create and return a configured logger. + + Usage: + from src.logger import setup_logger + logger = setup_logger(__name__) + logger.info("Hello from %s", __name__) + """ + logger = logging.getLogger(name) + + # Avoid adding duplicate handlers if called more than once + if not logger.handlers: + handler = logging.StreamHandler(sys.stdout) + handler.setFormatter(logging.Formatter(LOG_FORMAT, datefmt=DATE_FORMAT)) + logger.addHandler(handler) + + logger.setLevel(level) + return logger diff --git a/src/main.py b/src/main.py index 5bb632b..9f549fb 100644 --- a/src/main.py +++ b/src/main.py @@ -1,8 +1,11 @@ import os -# from backend import Fill +from typing import Union from commonforms import prepare_form from pypdf import PdfReader from controller import Controller +from logger import setup_logger + +logger = setup_logger(__name__) def input_fields(num_fields: int): fields = [] @@ -11,39 +14,38 @@ def input_fields(num_fields: int): fields.append(field) return fields -def run_pdf_fill_process(user_input: str, definitions: list, pdf_form_path: Union[str, os.PathLike]): +def run_pdf_fill_process(user_input: str, definitions: Union[dict, list], pdf_form_path: Union[str, os.PathLike]): """ This function is called by the frontend server. It receives the raw data, runs the PDF filling logic, and returns the path to the newly created file. """ - print("[1] Received request from frontend.") - print(f"[2] PDF template path: {pdf_form_path}") + logger.info("Received request from frontend.") + logger.info("PDF template path: %s", pdf_form_path) # Normalize Path/PathLike to a plain string for downstream code pdf_form_path = os.fspath(pdf_form_path) if not os.path.exists(pdf_form_path): - print(f"Error: PDF template not found at {pdf_form_path}") + logger.error("PDF template not found at %s", pdf_form_path) return None # Or raise an exception - print("[3] Starting extraction and PDF filling process...") + logger.info("Starting extraction and PDF filling process...") try: - output_name = Fill.fill_form( + controller = Controller() + output_name = controller.fill_form( user_input=user_input, - definitions=definitions, - pdf_form=pdf_form_path + fields=definitions, + pdf_form_path=pdf_form_path ) - print("\n----------------------------------") - print(f"✅ Process Complete.") - print(f"Output saved to: {output_name}") + logger.info("Process complete. Output saved to: %s", output_name) return output_name except Exception as e: - print(f"An error occurred during PDF generation: {e}") + logger.exception("An error occurred during PDF generation: %s", e) # Re-raise the exception so the frontend can handle it raise e