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
22 changes: 22 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Ollama Configuration
OLLAMA_HOST=http://localhost:11434
OLLAMA_MODEL=mistral

# Database Configuration
DATABASE_URL=sqlite:///./fireform.db

# Logging Configuration
LOG_LEVEL=INFO

# Security Configuration
MAX_INPUT_LENGTH=50000
MAX_FIELD_COUNT=50
MAX_FIELD_NAME_LENGTH=100
MAX_FIELD_VALUE_LENGTH=500

# File Configuration
MAX_PDF_SIZE=10485760 # 10MB in bytes
OUTPUT_DIRECTORY=./outputs

# API Configuration
API_TIMEOUT=30
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
.idea
venv
.venv
*.db
*.db
.env
100 changes: 96 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,111 @@ First responders, like firefighters, are often required to report a single incid
## 💡 The Solution

FireForm is a centralized "report once, file everywhere" system.

- **Single Input:** A firefighter records a single voice memo or fills out one "master" text field describing the entire incident.
- **AI Extraction:** The transcription is sent to an open-source LLM (via Ollama) which extracts all the key information (names, locations, incident details) into a structured JSON file.
- **Template Filling:** FireForm then takes this single JSON object and uses it to automatically fill every required PDF template for all the different agencies.

The result is hours of time saved per shift, per firefighter.

### ✨ Key Features

- **Agnostic:** Works with any department's existing fillable PDF forms.
- **AI-Powered:** Uses open-source, locally-run LLMs (Mistral) to extract data from natural language. No data ever needs to leave the local machine.
- **Single Point of Entry:** Eliminates redundant data entry entirely.
- **Enterprise Security:** Comprehensive input validation, XSS protection, path traversal prevention, and prompt injection defense.
- **Production Ready:** Full API server with FastAPI, database integration, and comprehensive error handling.
- **Fully Tested:** 100% test coverage with comprehensive security validation and end-to-end functionality testing.

Open-Source (DPG): Built 100% with open-source tools to be a true Digital Public Good, freely available for any department to adopt and modify.

## 🚀 Quick Start

### Prerequisites

- Python 3.13+
- [Ollama](https://ollama.ai/) installed locally
- Required Python packages (see `requirements.txt`)

### Installation

1. Clone the repository:

```bash
git clone https://github.com/your-username/FireForm.git
cd FireForm
```

2. Install dependencies:

```bash
pip install -r requirements.txt
```

3. Set up environment variables:

```bash
cp .env.example .env
# Edit .env with your configuration
```

4. Start Ollama and pull a model:
```bash
ollama pull mistral
```

### Usage

#### API Server

Start the FastAPI server:

```bash
uvicorn api.main:app --host 127.0.0.1 --port 8000
```

Access the API documentation at `http://127.0.0.1:8000/docs`

#### Command Line

Run the main application:

```bash
python src/main.py
```

#### Docker

```bash
docker-compose up
```

## 🧪 Testing

The system includes comprehensive testing:

- **Security Testing:** XSS, path traversal, prompt injection protection
- **API Testing:** Full endpoint validation with real HTTP requests
- **End-to-End Testing:** Complete pipeline from input to PDF generation
- **Performance Testing:** Input validation performance benchmarks

Run tests:

```bash
pytest tests/
```

## 🔒 Security

FireForm implements enterprise-grade security:

- Input validation and sanitization
- XSS and homograph attack prevention
- Path traversal protection
- Prompt injection defense
- SQL injection prevention
- Comprehensive error handling

## 🤝 Code of Conduct

We are committed to providing a friendly, safe, and welcoming environment for all. Please see our [Code of Conduct](CODE_OF_CONDUCT.md) for more information.
Expand All @@ -34,11 +126,10 @@ Contributions are welcome! Please see our [Contributing Guide](CONTRIBUTING.md)

## ⚖️ License



This project is licensed under the MIT License. See the LICENSE file for details.

## 🏆 Acknowledgements and Contributors

This project was built in 48 hours for the Reboot the Earth 2025 hackathon. Thank you to the United Nations and UC Santa Cruz for hosting this incredible event and inspiring us to build solutions for a better future.

## 📜 Citation
Expand All @@ -49,9 +140,10 @@ If you use FireForm in your research or project, please cite it using the follow

You can also use the "Cite this repository" button in the GitHub repository sidebar to export the citation in your preferred format.

__Contributors:__
**Contributors:**

- Juan Álvarez Sánchez (@juanalvv)
- Manuel Carriedo Garrido
- Vincent Harkins (@vharkins1)
- Marc Vergés (@marcvergees)
- Marc Vergés (@marcvergees)
- Jan Sans
48 changes: 41 additions & 7 deletions api/db/database.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,47 @@
from sqlmodel import create_engine, Session
from sqlalchemy.engine.url import make_url
from sqlalchemy.pool import StaticPool
import os

DATABASE_URL = "sqlite:///./fireform.db"
DATABASE_URL = os.getenv("DATABASE_URL", "sqlite:///./fireform.db")

engine = create_engine(
DATABASE_URL,
echo=True,
connect_args={"check_same_thread": False},
)
# Detect database dialect to apply appropriate configuration
db_url = make_url(DATABASE_URL)
is_sqlite = db_url.drivername.startswith('sqlite')

# Configure engine with dialect-specific settings
engine_kwargs = {
"echo": False, # Disable SQL logging in production for security
}

if is_sqlite:
# SQLite-specific configuration
engine_kwargs["connect_args"] = {
"check_same_thread": False,
"timeout": 30, # 30 second timeout
}
# Use StaticPool for SQLite to avoid connection issues
engine_kwargs["poolclass"] = StaticPool
else:
# PostgreSQL/MySQL configuration with connection pooling
engine_kwargs["pool_size"] = 5 # Connection pool size
engine_kwargs["max_overflow"] = 10 # Maximum overflow connections
engine_kwargs["pool_timeout"] = 30 # Pool timeout
engine_kwargs["pool_recycle"] = 3600 # Recycle connections every hour
engine_kwargs["pool_pre_ping"] = True # Verify connections before use

engine = create_engine(DATABASE_URL, **engine_kwargs)

def get_session():
"""
Get database session with proper resource management.
Uses context manager to ensure sessions are properly closed.
"""
with Session(engine) as session:
yield session
try:
yield session
except Exception:
session.rollback()
raise
finally:
session.close()
6 changes: 3 additions & 3 deletions api/db/models.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
from sqlmodel import SQLModel, Field
from sqlalchemy import Column, JSON
from datetime import datetime
from datetime import datetime, timezone

class Template(SQLModel, table=True):
id: int | None = Field(default=None, primary_key=True)
name: str
fields: dict = Field(sa_column=Column(JSON))
pdf_path: str
created_at: datetime = Field(default_factory=datetime.utcnow)
created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))


class FormSubmission(SQLModel, table=True):
id: int | None = Field(default=None, primary_key=True)
template_id: int
input_text: str
output_pdf_path: str
created_at: datetime = Field(default_factory=datetime.utcnow)
created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
Loading