Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/holzerjm/civichacks-demo/llms.txt

Use this file to discover all available pages before exploring further.

Overview

The CivicHacks Demo supports three deployment modes:
  1. Local only (default) — Runs on localhost, no data leaves your machine
  2. Gradio share — Temporary public URL via tunneling (72-hour limit)
  3. Hugging Face Spaces — Free cloud hosting (requires model swap)
Local deployment is recommended for hackathons and demos. It’s private, fast, and requires zero configuration.

Local deployment (default)

The app runs entirely on your machine. No data is sent to the cloud, and no API keys are required.

Step 3: Full web app

# Start the app
python scripts/demo_step3_app.py

# Opens at http://localhost:7860
Access points:
  • Same machine: http://localhost:7860
  • Other devices on same network: http://YOUR_IP:7860
macOS/Linux:
# Get your local IP
ipconfig getifaddr en0    # WiFi
ipconfig getifaddr en1    # Ethernet
Windows:
ipconfig | findstr IPv4
Then share http://YOUR_IP:7860 with others on your network.

Step 5: BYOD web app

# Start the BYOD app
python scripts/demo_step5_byod_app.py

# Opens at http://localhost:8861
Different port: Step 5 uses port 8861 to avoid conflicts with Step 3.

Custom port

Change the port if needed:
# Step 3 on custom port
python scripts/demo_step3_app.py --port 8080

# Step 5 on custom port
python scripts/demo_step5_byod_app.py --port 9000

Server configuration

Both apps bind to 0.0.0.0 by default, making them accessible on your local network:
app.launch(
    server_name="0.0.0.0",  # Listen on all interfaces
    server_port=7860,
    # ...
)
If deploying on a public network, be aware that anyone on the network can access your app. Use a firewall or restrict server_name to "127.0.0.1" for localhost-only access.

Gradio share (temporary public URL)

Gradio can create a temporary public URL that tunnels to your local machine. Useful for:
  • Sharing with remote judges
  • Quick demos to people not on your network
  • Testing mobile access

How to enable

# Step 3 with share link
python scripts/demo_step3_app.py --share

# Step 5 with share link
python scripts/demo_step5_byod_app.py --share
Output:
Running on local URL:  http://127.0.0.1:7860
Running on public URL: https://abc123xyz.gradio.live

This share link expires in 72 hours.
The share link works for 72 hours or until you stop the script, whichever comes first.

How it works

┌──────────────┐      Internet       ┌──────────────┐
│   Browser    │ ←──────────────────→ │    Gradio    │
│  (anywhere)  │   HTTPS tunnel       │   Servers    │
└──────────────┘                      └──────┬───────┘


                                    ┌─────────────────┐
                                    │  Your Machine   │
                                    │  localhost:7860 │
                                    └─────────────────┘
Gradio creates a secure tunnel from their servers to your local app.
Data passes through Gradio’s servers for routing, but the LLM inference still happens locally on your machine. Your civic data files never leave your machine.

Hugging Face Spaces (free cloud hosting)

Deploy the web app to Hugging Face Spaces for permanent, free hosting.
Important limitation: Hugging Face Spaces doesn’t support Ollama (which runs locally). You must swap to a cloud-based model API or use HF Inference API.

Prerequisites

  1. Create a free account at huggingface.co
  2. Create a new Space:
    • Click “New” → “Space”
    • Choose “Gradio” as the SDK
    • Select “Public” or “Private”

Option 1: Use Hugging Face Inference API

Free tier: 1,000 requests/day for most models. Update your script to use HF Inference API instead of Ollama:
from llama_index.llms.huggingface import HuggingFaceInferenceAPI
from llama_index.core import Settings
import os

# Use HF Inference API
Settings.llm = HuggingFaceInferenceAPI(
    model_name="meta-llama/Meta-Llama-3-8B-Instruct",
    token=os.getenv("HF_TOKEN"),  # Add this as a Space secret
)

# Rest of your code stays the same...
Add your HF token as a Space secret:
  1. Go to your Space settings
  2. Add a new secret: HF_TOKEN = your token from huggingface.co/settings/tokens

Option 2: Use OpenAI API

Cost: ~$0.002 per query with GPT-4o-mini.
from llama_index.llms.openai import OpenAI
from llama_index.core import Settings
import os

Settings.llm = OpenAI(
    model="gpt-4o-mini",
    api_key=os.getenv("OPENAI_API_KEY"),  # Add as Space secret
)

Deploy to Spaces

  1. Go to your Space page
  2. Click “Files” tab
  3. Upload:
    • demo_step3_app.py (rename to app.py)
    • requirements.txt (updated)
    • All files from data/ directory
  4. The Space will build automatically

Required file structure

Your-Space/
├── app.py                  # Renamed from demo_step3_app.py
├── requirements.txt        # Updated dependencies
├── README.md              # Space description
└── data/                  # Your civic datasets
    ├── ecohack_boston_environment.txt
    ├── cityhack_boston_311.txt
    ├── eduhack_boston_schools.txt
    └── justicehack_ma_justice.txt

Update requirements.txt for Spaces

Remove Ollama-specific dependencies:
llama-index>=0.12.0
llama-index-embeddings-huggingface>=0.5.0
llama-index-readers-file>=0.4.0
gradio>=5.0.0

# Choose ONE:
llama-index-llms-huggingface>=0.5.0  # For HF Inference API
# OR
llama-index-llms-openai>=0.3.0       # For OpenAI
Hugging Face Spaces has generous free tier limits. For a hackathon demo, HF Inference API is usually sufficient.

Streamlit Cloud (alternative)

Streamlit Cloud is another free hosting option. You’ll need to convert the Gradio app to Streamlit.

Conversion example

Gradio (current):
import gradio as gr

def query_fn(question, track):
    # ...
    return response

with gr.Blocks() as app:
    track = gr.Dropdown(["eco", "city", "edu", "justice"])
    question = gr.Textbox()
    output = gr.Textbox()
    question.submit(query_fn, [question, track], output)

app.launch()
Streamlit (converted):
import streamlit as st

st.title("CivicHacks AI Assistant")

track = st.selectbox("Select track", ["eco", "city", "edu", "justice"])
question = st.text_input("Ask a question")

if question:
    response = query_fn(question, track)
    st.write(response)

Deploy to Streamlit Cloud

  1. Push code to GitHub
  2. Go to share.streamlit.io
  3. Connect your GitHub repo
  4. Select the branch and main file (app.py)
  5. Deploy
Streamlit Cloud also requires cloud-based LLM APIs (no Ollama support).

Docker deployment (advanced)

For self-hosted deployment on a server, use Docker.

Dockerfile example

FROM python:3.12-slim

# Install Ollama
RUN curl -fsSL https://ollama.com/install.sh | sh

# Install Python dependencies
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy application files
COPY scripts/ ./scripts/
COPY data/ ./data/

# Download model
RUN ollama pull llama3.1

# Expose ports
EXPOSE 7860 11434

# Start Ollama and the app
CMD ["sh", "-c", "ollama serve & python scripts/demo_step3_app.py"]

Build and run

# Build image
docker build -t civichacks-demo .

# Run container
docker run -p 7860:7860 -p 11434:11434 civichacks-demo
Docker deployment is complex and requires managing Ollama inside the container. Only recommended for experienced users.

Performance comparison

DeploymentSpeedPrivacyCostSetup
LocalFast (local hardware)100% privateFree (electricity)Easy
Gradio shareFast (local hardware)Data routed via GradioFree (electricity)Easy
HF SpacesSlow (shared CPU)Data sent to HF/OpenAIFree tier or API costsMedium
Streamlit CloudSlow (shared CPU)Data sent to cloudFree tier or API costsMedium
DockerDepends on serverDepends on hostingServer costsHard
For hackathons and live demos, stick with local deployment. It’s faster, more private, and doesn’t require API keys or internet.

Network security considerations

Local network access

When running on 0.0.0.0, your app is accessible to anyone on your network. Restrict to localhost only:
app.launch(
    server_name="127.0.0.1",  # Only accessible on same machine
    server_port=7860,
)

Firewall rules

If you want network access but with restrictions, configure your firewall: macOS:
# Allow connections from specific IP range
sudo pfctl -e
sudo pfctl -f /etc/pf.conf
Linux (ufw):
# Allow from local network only
sudo ufw allow from 192.168.1.0/24 to any port 7860

Authentication

Gradio supports basic authentication:
app.launch(
    auth=("username", "password"),  # Simple auth
    # or
    auth=lambda u, p: u == "admin" and p == "secret",  # Custom logic
)
Basic auth is not secure over HTTP. Use HTTPS if deploying on public networks.

Build docs developers (and LLMs) love