Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,34 @@ __Contributors:__
- Vincent Harkins (@vharkins1)
- Marc Vergés (@marcvergees)
- Jan Sans


## Local Development Setup (Beginner Friendly)

1. Clone your fork and enter project folder:

- git clone <your-fork-url>
cd FireForm (Terminal)

2. Create virtual environment:

- python3 -m venv venv
source venv/bin/activate

3. Install dependencies:

4. Initialize database tables:

5. Run backend server:

6. Open Swagger UI in browser: (http://127.0.0.1:8000/docs)

### Common Errors

- `sqlite3.OperationalError: no such table`
→ Run database initialization step.

- `Could not connect to Ollama`
→ Ensure Ollama server is running locally.


3 changes: 2 additions & 1 deletion api/db/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ class FormSubmission(SQLModel, table=True):
template_id: int
input_text: str
output_pdf_path: str
created_at: datetime = Field(default_factory=datetime.utcnow)
requires_review: bool = False
created_at: datetime = Field(default_factory=datetime.utcnow)
40 changes: 18 additions & 22 deletions api/routes/forms.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,23 @@
from fastapi import APIRouter, Depends
from sqlmodel import Session
from api.deps import get_db
from api.schemas.forms import FormFill, FormFillResponse
from api.db.repositories import create_form, get_template
from api.db.models import FormSubmission
from api.errors.base import AppError
from src.controller import Controller
from pydantic import BaseModel, Field, field_validator

router = APIRouter(prefix="/forms", tags=["forms"])

class FormFill(BaseModel):
template_id: int
input_text: str = Field(..., min_length=1, max_length=50000)

@router.post("/fill", response_model=FormFillResponse)
def fill_form(form: FormFill, db: Session = Depends(get_db)):
fetched_template = get_template(db, form.template_id)
if not fetched_template:
raise AppError("Template not found", status_code=404)
@field_validator("input_text")
@classmethod
def validate_input_text(cls, v):
stripped = v.strip()
if not stripped:
raise ValueError("Input text cannot be empty or only whitespace")
return stripped

controller = Controller()
path = controller.fill_form(
user_input=form.input_text,
fields=fetched_template.fields,
pdf_form_path=fetched_template.pdf_path,
)

submission = FormSubmission(**form.model_dump(), output_pdf_path=path)
return create_form(db, submission)
class FormFillResponse(BaseModel):
id: int
template_id: int
input_text: str
output_pdf_path: str

model_config = {"from_attributes": True}
Binary file added javanotes.pdf
Binary file not shown.
9 changes: 8 additions & 1 deletion src/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,14 @@ def __init__(self):
self.file_manipulator = FileManipulator()

def fill_form(self, user_input: str, fields: list, pdf_form_path: str):
return self.file_manipulator.fill_form(user_input, fields, pdf_form_path)
path, review_flag = self.file_manipulator.fill_form(
user_input=user_input,
fields=fields,
pdf_form_path=pdf_form_path
)
return path, review_flag



def create_template(self, pdf_path: str):
return self.file_manipulator.create_template(pdf_path)
18 changes: 15 additions & 3 deletions src/file_manipulator.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import os
import logging
from src.filler import Filler
from src.llm import LLM

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

class FileManipulator:
def __init__(self):
Expand All @@ -28,24 +31,33 @@ 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.")
logger.info("[1] Received request from frontend.")
print(f"[2] PDF template path: {pdf_form_path}")

if not os.path.exists(pdf_form_path):
print(f"Error: PDF template not found at {pdf_form_path}")
return None # Or raise an exception

print("[3] Starting extraction and PDF filling process...")
logger.info("[3] Starting extraction...")
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)

from src.utils.validation import requires_review

extracted_data = self.llm.get_data()

review_flag = requires_review(
extracted_data,
fields.keys()
)

print("\n----------------------------------")
print("✅ Process Complete.")
print(f"Output saved to: {output_name}")

return output_name
return output_name , review_flag

except Exception as e:
print(f"An error occurred during PDF generation: {e}")
Expand Down
Loading