09 — Running the app step-by-step
Duration: 15 min (excluding the 4.9 GB model download) Prerequisites: chapters 03 and 08.
All commands, in order
Section titled “All commands, in order”# 1. Clone the two needed repos side-by-side (skip if already done)mkdir project-1cd project-1git clone https://github.com/inskillflow/csv-llm-shared.gitgit clone https://github.com/inskillflow/csv-llm-ollama.git
# 2. Install dependencies (still from project-1/)pip install -r csv-llm-shared/requirements.txtpip install -r csv-llm-ollama/requirements.txt
# 3. Start Ollama in a separate window (keep it open)ollama serve
# 4. Pull the model (ONCE, ~4.9 GB)ollama pull llama3.1:8bollama list # verify
# 5. Launch the Streamlit app (port 8504)cd csv-llm-ollama.\start.ps1# orstreamlit run app.py --server.port 8504The app opens at http://127.0.0.1:8504.
First import
Section titled “First import”On first load, the app says:
No transactions for this profile. Load a CSV from the sidebar.
In the left sidebar:
- CSV path is pre-filled with
data/data1-anonymized.csv. - Profile name is
data1. - Click 📥 (Re)load this CSV.
You’ll see:
734 transactions loaded into
data1.
The Dashboards tab now shows 4 KPIs and 4 figures.
Dashboards tab
Section titled “Dashboards tab”Contains:
-
4 KPIs at the top:
- Total spending: $118,667.69
- Monthly average: $9,888.97
- Avg per transaction: $175.80
-
expense transactions: 675
Section titled “expense transactions: 675”
-
4 charts:
- Spending by month (bar) — clear November peak.
- Breakdown by category (doughnut) — Housing dominates.
- Top 10 merchants (horizontal bar) — Rent + StorageBox lead.
- Recurring merchants (≥ 3 active months) — Coastal Spoon Cafe, Harbor Noodle House, etc.
-
Filters above the charts:
- Multi-select on categories.
- Date range.
Transactions tab
Section titled “Transactions tab”An interactive st.dataframe with all 734 rows sorted by date desc. You can sort any column by clicking the header, and filter in the top-right (search icon).
Chat tab — first prompt
Section titled “Chat tab — first prompt”Click the 💬 Chat tab. You see:
Model: llama3.1:8b (read-only SQL tool calling on csv-llm-ollama.sqlite, profile data1)
💡 Sample questions:
- How much did I spend on groceries last month?
- What is my biggest spending category?
- How many times did I visit Coastal Spoon Cafe this year and how much did I spend?
- List my top 5 merchants.
Type Q2: What is my biggest spending category?
After ~5 to 15 seconds (latency depends on your CPU/GPU) you see:
⏳ The model is thinking…
Then:
Your biggest spending category is Housing with a total of $30,895.29.
⏱️ 6.2 s · 1 SQL call
And a 🔧 SQL #1 expander you can open to see:
SELECT category, SUM(amount) AS totalFROM transactionsWHERE profile = 'data1' AND amount > 0GROUP BY categoryORDER BY total DESCLIMIT 1With the tabular result:
| category | total |
|---|---|
| Housing | 30895.29 |
The 4 canonical questions
Section titled “The 4 canonical questions”Typical latency (CPU only) and expected SQL pattern:
| # | Question | Latency | Expected answer |
|---|---|---|---|
| Q1 | Groceries last month? | 7 s | Filter by category='Groceries' + last-month date range |
| Q2 | Biggest category? | 5 s | Housing with $30,895.29 |
| Q3 | Coastal Spoon Cafe this year? | 6 s | 19 times, total $1,221.34 |
| Q4 | Top 5 merchants? | 10 s | Rent Payment Willow Street, StorageBox Monthly, GardenCare Subscription, Postbox Rental, Queenstown Path Pass |
Two things to verify if you don’t get these results:
- You loaded
data/data1-anonymized.csv(734 rows), not something else. - Your model is
llama3.1:8b(and notllama3.2:3bwhich can’t tool-call reliably).
Security tips
Section titled “Security tips”Three lines of defense in this app:
1. SELECT-only at the Python layer
Section titled “1. SELECT-only at the Python layer”db.safe_query() (chapter 05) rejects anything that isn’t a SELECT, contains forbidden keywords, or chains statements with ;.
2. Tool description is read-only
Section titled “2. Tool description is read-only”The SQL_TOOL spec mentions “read-only” + “SELECT” explicitly. The model does not see an INSERT/UPDATE tool, so it has nothing to call.
3. SQLite file is local
Section titled “3. SQLite file is local”The database lives at csv-llm-ollama/.cache/csv-llm-ollama.sqlite. No network exposure. The Streamlit server binds to 127.0.0.1 only — your firewall doesn’t even need a rule.
Troubleshooting
Section titled “Troubleshooting”| Error | Likely cause | Fix |
|---|---|---|
ConnectionError: Failed to connect to Ollama | ollama serve not running | Open a window, run ollama serve |
model "llama3.1:8b" not found | Not pulled | ollama pull llama3.1:8b |
| Answer like “I cannot compute…” | Model doesn’t tool-call | Verify: must be llama3.1:8b, not llama3.2:3b |
SQL refused: only SELECT statements allowed | Model tried INSERT/UPDATE | Rephrase, or enrich the system prompt |
| Port 8504 already in use | Previous Streamlit crashed | .\stop.ps1 then relaunch |
Stop the app
Section titled “Stop the app”.\csv-llm-ollama\stop.ps1Frees port 8504 (handy if Streamlit died ungracefully).
What to build next
Section titled “What to build next”- Try the cloud variant: same UI, 5× faster — Project 2 — csv-llm-openai.
- Deep-dive the shared library: extend
ingest.pyfor your own bank — Project 3 — csv-llm-shared. - Add a forecasting tool: a second tool
forecast_month(category)that uses a simple moving average — the LLM picks when to call which. - Swap the model:
ollama pull qwen2.5:7bthen change the default in the sidebar. Compare answer quality and latency.
Takeaways
Section titled “Takeaways”- All commands fit in 6 lines (clone, install, serve, pull, run).
- The app loads
data1-anonymized.csvin one click and shows 4 dashboards + a chat. - Each question shows the generated SQL and tabular result in an expander.
- Latency: 5–15 s per question on CPU. Faster with a GPU.
- 100% local — your spending data never leaves your machine.