Small projects built while learning to build AI apps on top of a local LLM runtime — Ollama. Every model runs on the machine; there are no cloud API keys anywhere in this repo.
The repo has two tracks, built roughly in this order:
- Web apps (
ai_*/) — FastAPI backends serving a plain HTML/JS frontend - Agents (
AI Agents/) — LangChain + Streamlit, adding memory, voice, and retrieval
Each folder is a self-contained app: app.py (backend) + static/ (frontend).
| Project | What it is | Model | What it taught |
|---|---|---|---|
| intro_mistral.py | 10-line script hitting the Ollama API | mistral |
The raw /api/generate endpoint |
| ai_chatbot/ | Chat page | mistral |
Serving a frontend from FastAPI, POST endpoints |
| ai_text_summarizer/ | Paste text → summary | mistral |
Form(...) handling, prompt building |
| ai_code_assistant/ | Generate or debug code | codellama |
Branching prompts off a mode field |
| ai_workspace/ | Chat + summarize, properly structured | mistral |
Routers, Pydantic schemas, async httpx, .env config, SSE streaming |
| ai_legal_analyzer/ | Extract clauses, risks, obligations | phi |
Domain-specific prompting |
| ai_proofreader/ | Grammar & spelling fixes | deepseek-r1 |
Swapping models per task |
| ai_content_writer/ | Article from a topic + style | llama3 |
Multi-field prompts |
| customer_support_chatbot/ | Support Q&A page | qwq |
Persona prompting, surfacing Ollama errors properly |
| ecommerce_ai_recommender/ | Preferences → product picks | granite3.2 |
Grounding a prompt in a real catalog instead of letting the model invent one |
| medical_ai_symptom_checker/ | Symptoms → general info | medllama2 |
Where a safety disclaimer belongs: the page, not the prompt |
| ai_virtual_assistant/ | Chat + task scheduling | llama2 |
Model-driven intent extraction ("format": "json") over keyword matching |
ai_workspace/ is the one to read. It is the Milestone 1 rewrite of the
earlier apps and fixes what they got wrong — blocking requests calls, copy-pasted
Ollama code, hardcoded config, fake 200s on failure, innerHTML XSS. See
ai_workspace/README.md for the full before/after.
| Project | Endpoint | Body | Returns |
|---|---|---|---|
ai_chatbot |
POST /chat |
?prompt= (query param) |
{"response"} |
ai_text_summarizer |
POST /summarize |
form: text |
{"summary"} |
ai_code_assistant |
POST /generate_code |
form: prompt, mode (generate|debug) |
{"code"} |
ai_legal_analyzer |
POST /analyze_legal_text |
form: text |
{"insights"} |
ai_proofreader |
POST /proofread |
form: text |
{"corrected_text"} |
ai_content_writer |
POST /generate |
form: topic, style |
(see Known gaps) |
customer_support_chatbot |
POST /chat |
form: user_query |
{"response"} |
ecommerce_ai_recommender |
POST /recommend |
form: preferences |
{"recommendations"} |
medical_ai_symptom_checker |
POST /analyze_symptoms |
form: symptoms |
{"response"} |
ai_virtual_assistant |
POST /chat |
form: user_query |
{"response", "tasks"} |
ai_workspace has its own — streaming chat, model listing — documented in its README.
Streamlit UIs rather than hand-written HTML, and LangChain instead of raw HTTP.
| Day | Script | What it does | Concepts |
|---|---|---|---|
| 1 | basic_ai_agent.py | Chatbot that remembers the conversation | OllamaLLM, PromptTemplate, ChatMessageHistory, st.session_state |
| 2 | ai_voice_assistant.py | Same agent, spoken — CLI loop | speech_recognition (mic in), pyttsx3 (speech out) |
| 2 | ai_voice_assistant_ui.py | Voice assistant with a Streamlit UI | Push-to-talk button, persisted history |
| 3 | ai_web_scraper.py | URL → scrape <p> tags → summary |
requests + BeautifulSoup, truncating context |
| 3 | ai_web_scrapper_faiss.py | Scrape a site, then ask questions about it | Chunking, embeddings, FAISS vector search, RAG |
The day-1 file keeps its earlier CLI-only versions commented out at the bottom, so the progression (plain LLM → memory → web UI) is visible in one file.
The voice assistant's recognition step calls Google's speech API (
recognizer.recognize_google), so that part needs internet. The LLM itself stays local.
Install Ollama, then pull the models the projects use:
ollama pull mistral # chatbot, summarizer, workspace, agents
ollama pull llama3 # content writer, day-1 agent
ollama pull codellama # code assistant
ollama pull phi # legal analyzer
ollama pull deepseek-r1 # proofreader
ollama pull qwq # customer support chatbot
ollama pull granite3.2 # e-commerce recommender
ollama pull medllama2 # medical symptom checker
ollama pull llama2 # virtual assistantAny of the four newest apps will also run against a model you already have —
set OLLAMA_MODEL instead of pulling another few gigabytes:
OLLAMA_MODEL=mistral uvicorn app:app --reload # macOS / Linux
$env:OLLAMA_MODEL="mistral"; uvicorn app:app --reload # PowerShellOnly pull what you need — each is a multi-GB download. Ollama serves on
http://localhost:11434; check it with ollama list.
python -m venv ollama_env
ollama_env\Scripts\activate # Windows
source ollama_env/bin/activate # macOS / Linux
pip install -r requirements.txtrequirements.txt covers Track 1 only. The agents need more:
pip install streamlit langchain langchain-community langchain-ollama \
langchain-huggingface sentence-transformers faiss-cpu \
beautifulsoup4 numpy SpeechRecognition pyttsx3 pyaudiopyaudio (microphone access, day 2) needs a system build toolchain and is the
usual install failure — skip it unless you're running the voice assistant.
FastAPI apps — run from inside the project folder; static/ and .env
are resolved relative to the working directory:
cd ai_code_assistant
uvicorn app:app --reloadThen open http://127.0.0.1:8000 (API docs at /docs). ai_workspace uses a
package layout, so it's uvicorn app.main:app --reload instead.
The older apps all bind port 8000 — run one at a time, or pass --port 8001.
The four newest ones each have their own default port so they can run side by
side: customer_support_chatbot 8001, ecommerce_ai_recommender 8002,
medical_ai_symptom_checker 8003, ai_virtual_assistant 8004. That default
lives in each app's python app.py block, and uvicorn does not read it —
so pick one:
cd customer_support_chatbot
python app.py # uses the port baked into app.py
uvicorn app:app --reload --port 8001 # uvicorn needs the port spelled outStreamlit agents — run from the repo root:
streamlit run "AI Agents/day1/basic_ai_agent.py"Opens on http://localhost:8501.
intro_mistral.py first contact with the Ollama API
ai_chatbot/ ┐
ai_text_summarizer/ │
ai_code_assistant/ │
ai_legal_analyzer/ ├─ Track 1: FastAPI + static frontend
ai_proofreader/ │ (app.py + static/index.html each)
ai_content_writer/ │
customer_support_chatbot/ │
ecommerce_ai_recommender/ │
medical_ai_symptom_checker/ │
ai_virtual_assistant/ ┘
ai_workspace/ the structured rewrite — app/, routers/, config, .env
AI Agents/day1..day3/ Track 2: LangChain + Streamlit
requirements.txt Track 1 dependencies
ollama_env/ virtualenv (gitignored)
Kept honest rather than quietly patched — this is a learning repo, and these are the next things to fix.
ai_content_writeris broken.generate_content()builds the prompt and calls Ollama but never returns the result, so/generaterespondsnullwhile the page readsdata.content. Itsstatic/script.jsis empty too — the real logic is inlined inindex.html.- Empty placeholder
script.jsfiles inai_chatbot,ai_code_assistant, andai_content_writer; those pages use inline<script>blocks. (The four newest apps had the same gap and no longer do.) ai_text_summarizersends"Mistral"(capitalised) as the model name instead of theMODEL_NAMEconstant right above it.- Track 1 apps other than
ai_workspaceshare the same weaknesses: blockingrequestscalls, no timeouts, hardcoded model and URL, duplicated Ollama plumbing.ai_workspaceexists because of them. The four newest apps have since had the worst of that fixed — they check Ollama's status code, time out, and readOLLAMA_MODEL— but they are still blocking, and each still carries its own copy of the same Ollama code. Folding them onto theai_workspacestructure is the real fix and hasn't been done. ai_virtual_assistantforgets everything on restart.scheduled_tasksis a plain in-process list: it is wiped when the server restarts and is shared by every visitor, since there are no user accounts. It needs a database.- Scheduled due times are never parsed. The assistant stores the due time as
the free text the model extracted (
"tomorrow at 5"), not a real datetime, so nothing can sort, remind, or expire. - Agent dependencies aren't pinned anywhere — Track 2 has no
requirements.txtof its own.