Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
66ffeaa
docs: add feature specs for ask endpoint validation, response contrac…
CameronDetig Feb 7, 2026
3f6feba
docs: Adding streamlit specification document, and reformatting other…
CameronDetig Feb 7, 2026
3687986
test: Adding testing files to cover the specifications
CameronDetig Feb 8, 2026
de0ea84
docs: Update project brief and specifications, enhance test coverage,…
CameronDetig Feb 8, 2026
be41c47
data: Generated documents that will be used to fill the vector databa…
CameronDetig Feb 8, 2026
1249b06
data: updating location on data files, and adding two more
CameronDetig Feb 8, 2026
ce051a7
docs: Add optional Docker support spec and enhanced entrypoint CLI sp…
CameronDetig Feb 8, 2026
80060d5
feat: First pass on the implementation of the chatbot using the speci…
CameronDetig Feb 8, 2026
e745dff
feat: Enhance entrypoint CLI with Python interpreter selection and au…
CameronDetig Feb 8, 2026
34a12c2
feat: Integrate Langchain support for generation and retrieval
CameronDetig Feb 8, 2026
0135d5f
Merge pull request #1 from CameronDetig/langchain-integration
CameronDetig Feb 8, 2026
29141ec
feat: Update project specifications in the constitution.md file. Adde…
CameronDetig Feb 8, 2026
9e87493
feat: Enhance retrieval database setup with build status reporting an…
CameronDetig Feb 8, 2026
c7c404a
feat: Update CI workflow to include tox installation and modify test …
CameronDetig Feb 8, 2026
fc105a6
fix: correcting error in workflow file
CameronDetig Feb 8, 2026
77a3e9e
fix: correcting another error in workflow file
CameronDetig Feb 8, 2026
cf62bd5
fix: Added CPU torch index to unblock py310 installs in CI
CameronDetig Feb 8, 2026
5bdf3e3
feat: Add embedding model download and verification during setup; imp…
CameronDetig Feb 8, 2026
ed1afe0
Merge branch 'feature/customer-faq-assistant-cameron-d' of https://gi…
CameronDetig Feb 8, 2026
d0dc290
feat: migrating from distilgpt2 to flan-t5 which is instruction tuned…
CameronDetig Feb 8, 2026
7d2bf4d
refactor: Update docker-compose for UI build process and enhance READ…
CameronDetig Feb 8, 2026
3d25de0
docs: Adding image of the UI to the readme
CameronDetig Feb 8, 2026
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
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Optional configuration. Defaults are applied if unset.
RAG_MIN_SCORE=0.25
# API_URL=http://127.0.0.1:8000
50 changes: 50 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: CI

on:
push:
branches:
- main
- feature/customer-faq-assistant-cameron-d
pull_request:
branches:
- main
- feature/customer-faq-assistant-cameron-d
workflow_dispatch:

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

jobs:
test-matrix:
name: Tests (Python ${{ matrix.python-version }})
runs-on: ubuntu-latest
timeout-minutes: 25
env:
PIP_EXTRA_INDEX_URL: https://download.pytorch.org/whl/cpu
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12"]

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: pip
cache-dependency-path: requirements.txt

- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install -r requirements.txt
python -m pip install tox

- name: Run tests
env:
PY_VER: ${{ matrix.python-version }}
run: python -m tox -e py${PY_VER//./}
57 changes: 57 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# Distribution / packaging
build/
dist/
*.egg-info/
.eggs/

# Virtual environments
.venv/
.venv*/
venv/
env/
ENV/

# Tool caches
.mypy_cache/
.pytest_cache/
.ruff_cache/
.coverage
.coverage.*
htmlcov/
.tox/
.nox/

# Logs
*.log

# Environment / secrets
.env
.env.*
!.env.example

# Jupyter
.ipynb_checkpoints/

# IDE/editor files
.vscode/
.idea/
*.swp
*.swo

# OS files
.DS_Store
Thumbs.db

# Streamlit local secrets/config overrides
.streamlit/secrets.toml

# Local vector DB / embeddings artifacts
chroma/
chroma_db/
.chroma/
*.sqlite3
16 changes: 16 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
FROM python:3.11-slim

WORKDIR /app

ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1

COPY requirements.txt /app/requirements.txt
RUN pip install --no-cache-dir -r /app/requirements.txt

COPY app /app/app
COPY data /app/data

EXPOSE 8000

CMD ["python", "-m", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
187 changes: 144 additions & 43 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,43 +1,144 @@
# Candidate Assessment: Spec-Driven Development With Codegen Tools

This assessment evaluates how you use modern code generation tools (for example `5.2-Codex`, `Claude`, `Copilot`, and similar) to design, build, and test a software application using a spec-driven development pattern. You may build a frontend, a backend, or both.

## Goals
- Build a working application with at least one meaningful feature.
- Create a testing framework to validate the application.
- Demonstrate effective use of code generation tools to accelerate delivery.
- Show clear, maintainable engineering practices.

## Deliverables
- Application source code in this repository.
- A test suite and test harness that can be run locally.
- Documentation that explains how to run the app and the tests.

## Scope Options
Pick one:
- Frontend-only application.
- Backend-only application.
- Full-stack application.

Your solution should include at least one real workflow, for example:
- Create and view a resource.
- Search or filter data.
- Persist data in memory or storage.

## Rules
- You must use a code generation tool (for example `5.2-Codex`, `Claude`, or similar). You can use multiple tools.
- You must build the application and a testing framework for it.
- The application and tests must run locally.
- Do not include secrets or credentials in this repository.

## Evaluation Criteria
- Working product: Does the app do what it claims?
- Test coverage: Do tests cover key workflows and edge cases?
- Engineering quality: Clarity, structure, and maintainability.
- Use of codegen: How effectively you used tools to accelerate work.
- Documentation: Clear setup and run instructions.

## What to Submit
- When you are complete, put up a Pull Request against this repository with your changes.
- A short summary of your approach and tools used in your PR submission
- Any additional information or approach that helped you.
# Customer FAQ Assistant (Mockridge Bank)

[![CI](https://github.com/CameronDetig/spec-driven-development/actions/workflows/ci.yml/badge.svg?branch=feature/customer-faq-assistant-cameron-d)](https://github.com/CameronDetig/spec-driven-development/actions/workflows/ci.yml)
![Python](https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12-blue)

Spec-driven local RAG assistant built with FastAPI + Streamlit.

## What It Does
- Answers customer questions relating to products and services for a fictional bank (Mockridge Bank)
- Available through API or Streamlit UI
- Retrieves relevant local FAQ documents from ChromaDB
- Generates answers with:
- `mock` deterministic mode (default, test-friendly)
- `flan-t5` optional mode (small locally running instruction-tuned LLM, no API key required)
- Returns answer + cited sources

## Tech Stack
- Python 3.10, 3.11, or 3.12
- FastAPI
- Streamlit
- ChromaDB
- LangChain (`langchain`, `langchain-huggingface`, `langchain-chroma`)
- pytest

## Preview

<img src="images/streamlit_ui.png" alt="Streamlit UI" width="600">

## Quick Start

### 1) Setup
```bash
python run.py setup
```

What setup does:
- creates/uses `.venv` (unless `--no-venv`)
- installs dependencies
- builds retrieval DB

If you want to be able to use the LLM option, run setup with this command. It will download the flan-t5 model (~300MB):
```bash
python run.py setup --with-llm
```

### 2) Run Full Stack
```bash
python run.py fullstack
```

Endpoints:
- API: `http://127.0.0.1:8000`
- UI: `http://127.0.0.1:8501`

### API Documentation
When the API is running, interactive documentation is available at:
- Swagger UI: http://localhost:8000/docs
- ReDoc: http://localhost:8000/redoc

## Run Commands

```bash
python run.py help
python run.py api
python run.py ui
python run.py fullstack
python run.py test
python run.py test-matrix
```

`test-matrix` runs tox environments for available interpreters (`py310`, `py311`, `py312`).

## Testing

Single environment:
```bash
python run.py test
```

Multi-python matrix:
```bash
python run.py test-matrix
```

Direct:
```bash
python -m pytest -q
tox
```

## CI (GitHub Actions)

Workflow: `.github/workflows/ci.yml`

Triggers:
- push to:
- `main`
- `feature/customer-faq-assistant-cameron-d`
- pull_request to:
- `main`
- `feature/customer-faq-assistant-cameron-d`
- manual (`workflow_dispatch`)

CI job:
- Python matrix: 3.10 / 3.11 / 3.12
- installs `requirements.txt`
- runs `pytest -q`

## API Overview

- `GET /health`
- `GET /db/status`
- `POST /db/build`
- `POST /ask`

Example request:
```json
{
"question": "What can I do with the mobile app?",
"top_k": 3,
"generator": "mock"
}
```

## Environment Variables

- `RAG_MIN_SCORE` (minimum similarity score for retrieved documents. default: `0.25`)
- `API_URL` (used by Streamlit UI; default `http://127.0.0.1:8000`)

## Project Structure

- `app/main.py` API routes
- `app/retrieval.py` RAG retrieval/indexing logic
- `app/generation.py` generator selection and LLM adapter
- `app/rag_chain.py` LangChain prompt/chain
- `ui/streamlit_app.py` UI
- `SPECS/` authoritative feature specs
- `tests/` test suite
- `run.py` project entrypoint

## Notes
- Default mode is deterministic and intended for local testing/CI.
- Optional `flan-t5` mode uses Google's Flan-T5-small (80M params) for local experimentation and requires model assets (~308MB download via `python run.py setup --with-llm`).
- Project uses CPU-only PyTorch for faster setup and smaller footprint (~200MB vs ~2.5GB). GPU acceleration is unnecessary for the small models used in this project.
44 changes: 44 additions & 0 deletions SPECS/ask-endpoint-validation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Feature Spec: Ask Endpoint Validation

## Goal
- Enforce strict, predictable request validation for `POST /ask` so API behavior is safe and testable.

## Scope
- In:
- Validate request body fields `question` and `top_k`.
- Return consistent 400 errors for invalid input.
- Out:
- Retrieval ranking behavior.
- Answer generation quality.

## Requirements
- Endpoint:
- `POST /ask`
- Request schema:
- `question` is required string with length `5..300`.
- `top_k` is optional integer with default `3` and valid range `1..5`.
- `generator` is optional string with allowed values `mock` or `flan-t5`.
- Validation failures MUST return HTTP 400.
- Validation failures include:
- Missing `question`.
- `question` length below 5.
- `question` length above 300.
- `top_k` below 1.
- `top_k` above 5.
- `generator` not in allowed values.
- Error responses MUST be JSON and machine-parseable.
- Error responses MUST include a top-level `detail` field suitable for user-facing validation feedback.
- Validation MUST run before retrieval or generation logic executes.
- If DB is not built, endpoint MUST return `503` with actionable guidance to build DB first.

## Related Specifications
- `ask-response-contract.md` - Defines success response schema for valid requests
- `retrieval-pipeline.md` - Processes validated requests

## Acceptance Criteria
- [x] Missing `question` returns `400`. (test_validation.py::test_ask_missing_question_returns_400)
- [x] `question` shorter than 5 characters returns `400`. (test_validation.py::test_ask_question_too_short_returns_400)
- [x] `question` longer than 300 characters returns `400`. (test_validation.py::test_ask_question_too_long_returns_400)
- [x] `top_k = 0` returns `400`. (test_validation.py::test_ask_top_k_zero_returns_400)
- [x] `top_k > 5` returns `400`. (test_validation.py::test_ask_top_k_above_range_returns_400)
- [x] Omitted `top_k` is accepted and treated as `3`. (test_validation.py::test_ask_omitted_top_k_uses_default)
Loading