Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
9c23c25
Add macOS Desktop Services Store file to gitignore
sahilds1 Feb 5, 2026
59b40f0
REFACTOR Pull apart get_closest_embeddings to make testing easier
sahilds1 Feb 13, 2026
3ffb74a
ADD Add infra required to run pytest
sahilds1 Feb 13, 2026
12b09a7
ADD Start adding tests for embedding_services"
sahilds1 Feb 13, 2026
2d2ccd1
Fix duplicate healthcheck key for db service build
amahuli03 Feb 16, 2026
01ccf9a
Enhance input sanitization and normalize pronouns
AkhilRB0204 Feb 17, 2026
aa3efcd
Merge remote-tracking branch 'upstream/develop' into bugfix-duplicate…
amahuli03 Feb 17, 2026
da9afaa
DOC Add a note about running pytest in the README
sahilds1 Feb 17, 2026
b08152f
fix: changed link to direct to balancer github page
amahuli03 Feb 18, 2026
b94e998
Fix error 1, added unit tests and more logging
amahuli03 Feb 20, 2026
530b90a
Changed button text from "donate" to "Support Developoment"
amahuli03 Feb 23, 2026
c409689
Merge pull request #462 from amahuli03/bugfix-duplicate-healthchecks-…
sahilds1 Feb 23, 2026
98599e5
Merge pull request #465 from amahuli03/445-update-donate-button
sahilds1 Feb 23, 2026
f96606d
Fix 401 by using adminApi instead of raw axios
amahuli03 Feb 23, 2026
662f29d
Merge pull request #468 from amahuli03/467/unauthorized-pdf-upload
sahilds1 Feb 26, 2026
bbf1034
Fixed wrong API url path in handleDownload
amahuli03 Feb 26, 2026
128418b
Fixed API URL in handleOpen as well
amahuli03 Feb 26, 2026
332af9f
drf-spectacular configuration
amahuli03 Feb 26, 2026
a34a9f8
Added URL routes for API docs generation
amahuli03 Feb 26, 2026
fe660d2
Added OpenAPI security scheme
amahuli03 Feb 26, 2026
3c83abd
Added extend_schema and serializer_class to endpoints that drf-specta…
amahuli03 Feb 26, 2026
5ce7782
Preload SentenceTransformer model at Django startup before traffic is…
sahilds1 Feb 27, 2026
7085aa0
Requested changes: fix patch decorators to point to where openAI is u…
amahuli03 Mar 2, 2026
669f939
Merge remote-tracking branch 'upstream/develop' into 390-bugfix-uploa…
amahuli03 Mar 2, 2026
e6754df
Requested changes: added comments explaining title truncation
amahuli03 Mar 2, 2026
4b4d727
Fix mock setups to match how generate_title accesses title
amahuli03 Mar 2, 2026
a8f5d90
Merge pull request #466 from amahuli03/390-bugfix-upload-file-endpoint
sahilds1 Mar 5, 2026
f2f4274
Merge pull request #471 from amahuli03/file-download-error
sahilds1 Mar 5, 2026
e8b0fc1
fix: treat openAIServices.openAI() return value as string
amahuli03 Mar 5, 2026
e0b7c23
fix mock test setup to return string instead of mocked response object
amahuli03 Mar 6, 2026
d68fa62
fix to make test_falls_back_to_chatgpt_if_no_title_found more robust
amahuli03 Mar 6, 2026
03b7639
Replace block-position title extraction with font-size-based approach
amahuli03 Mar 6, 2026
2a822f6
loosens the title regex to allow years, question
amahuli03 Mar 6, 2026
edf1eb6
Update tests for font-size-based title extraction
amahuli03 Mar 6, 2026
4bae746
update documentation to include instructions about how to use the API…
amahuli03 Mar 10, 2026
6f0deed
update site links on README
amahuli03 Mar 10, 2026
6ae14fe
Merge pull request #479 from amahuli03/update-readme-site-link
sahilds1 Mar 10, 2026
9fa287b
Merge pull request #472 from amahuli03/460/generate-api-documentation
sahilds1 Mar 11, 2026
50a8bd3
Merge branch 'develop' into 441-embedding-models
sahilds1 Mar 11, 2026
795f218
Run python-app workflow on pushes and PRs to develop branch
sahilds1 Mar 11, 2026
d0542df
Merge pull request #457 from sahilds1/456-update-gitignore
sahilds1 Mar 11, 2026
75c1a14
Merge pull request #474 from amahuli03/473/openai-title-generation-at…
sahilds1 Mar 11, 2026
d498a00
Pytest won’t automatically discover config files in subdirectories
sahilds1 Mar 19, 2026
6d3d8d1
Merge branch 'develop' into 441-embedding-models
sahilds1 Mar 19, 2026
3824d81
Suppress E402 import violations
sahilds1 Mar 19, 2026
46e9969
Add build_query tests and document coverage gaps in embedding_services
sahilds1 Mar 20, 2026
64a19ef
Fill test gaps in test_embedding_services
sahilds1 Mar 20, 2026
dec3c12
Fix incorrect build_query test assertions
sahilds1 Mar 20, 2026
f9e890a
Guard TransformerModel preload to runserver processes only
sahilds1 Mar 23, 2026
67176a8
Revert GitHub Workflow changes
sahilds1 Mar 25, 2026
d273921
Add section header comments to all four test groups in test_embedding…
sahilds1 Mar 26, 2026
8198574
Document why tests are split by responsibility
sahilds1 Mar 26, 2026
5d8c8b3
Improve logging and comments
sahilds1 Mar 31, 2026
31498dc
Fall back to lazy load using try except block
sahilds1 Mar 31, 2026
a39d33c
Revert settings.py to develop state
sahilds1 Mar 31, 2026
fe1eeca
Manually test fall back to lazy loading
sahilds1 Mar 31, 2026
13a0a21
Merge pull request #475 from amahuli03/title-generation-font-size
sahilds1 Mar 31, 2026
baa4438
Merge pull request #461 from sahilds1/441-embedding-models
sahilds1 Apr 14, 2026
88adfb1
Add issue template
sahilds1 Apr 14, 2026
55acb2e
Update README
sahilds1 Apr 14, 2026
fb3b272
Merge pull request #496 from sahilds1/187-add-docs
sahilds1 Apr 14, 2026
cedc58a
Add sandbox link to README usage section
sahilds1 Apr 14, 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
23 changes: 23 additions & 0 deletions .github/ISSUE_TEMPLATE/issue.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
## Title
<!-- Title: [Type]: Short description of the problem or goal -->

## Background
<!-- Why does this change need to happen? -->

## Existing Behavior
<!-- What code or docs are changing? Link or paste as needed -->

## Acceptance Criteria
- [] <!-- What does done look like? -->

## Approach
<!-- How are you tackling this? Update as you go -->

## References
<!-- Anything useful — docs, links, decisions -->

## Risks and Rollback
<!-- Anything that could go wrong, or leave blank if low risk -->

## Screenshots / Recordings
<!-- Before/after visuals or console output if helpful -->
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
config/env/*
!config/env/*.example
.idea/
.idea/
.DS_Store
10 changes: 10 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,16 @@ Each module contains:
- Auth endpoints via Djoser: `/auth/`
- JWT token lifetime: 60 minutes (access), 1 day (refresh)

#### API Documentation
- Auto-generated using **drf-spectacular** (OpenAPI 3.0)
- **Swagger UI**: `http://localhost:8000/api/docs/` — interactive API explorer
- **ReDoc**: `http://localhost:8000/api/redoc/` — readable reference docs
- **Raw schema**: `http://localhost:8000/api/schema/`
- Configuration in `SPECTACULAR_SETTINGS` in `settings.py`
- Views use `@extend_schema` decorators and `serializer_class` attributes for schema generation
- JWT auth is configured in the schema — use `JWT <token>` (not `Bearer`) in Swagger UI's Authorize dialog
- To document a new endpoint: add `serializer_class` to the view if it has one, or add `@extend_schema` with `inline_serializer` for views returning raw dicts

#### Key Data Models
- **Medication** (`api.views.listMeds.models`) - Medication catalog with benefits/risks
- **MedRule** (`api.models.model_medRule`) - Include/Exclude rules for medications based on patient history
Expand Down
38 changes: 34 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ for patients with bipolar disorder, helping them shorten their journey to stabil

## Usage

You can view the current build of the website here: [https://balancertestsite.com](https://balancertestsite.com/)
You can view the current build of the website here: [https://balancerproject.org/](https://balancerproject.org/)

You can view the website in a sandbox here: [https://sandbox.balancerproject.org/](https://sandbox.balancerproject.org/)

## Contributing

Expand All @@ -31,11 +33,9 @@ Get the code using git by either forking or cloning `CodeForPhilly/balancer-main
```
2. (Optional) Add your API keys to `config/env/dev.env`:
- `OpenAI API`
- `Anthropic API`

Tools used for development:
1. `Docker`: Install Docker Desktop
2. `Postman`: Ask to get invited to the Balancer Postman team `balancer_dev`
3. `npm`: In the terminal run 1) 'cd frontend' 2) 'npm install' 3) 'cd ..'

### Running Balancer for development
Expand All @@ -53,7 +53,7 @@ The application supports connecting to PostgreSQL databases via:
See [Database Connection Documentation](./docs/DATABASE_CONNECTION.md) for detailed configuration.

**Local Development:**
- Download a sample of papers to upload from [https://balancertestsite.com](https://balancertestsite.com/)
- Download a sample of papers to upload from [https://balancerproject.org/](https://balancerproject.org/)
- The email and password of `pgAdmin` are specified in `balancer-main/docker-compose.yml`
- The first time you use `pgAdmin` after building the Docker containers you will need to register the server.
- The `Host name/address` is the Postgres server service name in the Docker Compose file
Expand All @@ -73,6 +73,36 @@ df = pd.read_sql(query, engine)

#### Django REST
- The email and password are set in `server/api/management/commands/createsu.py`
- Backend tests can be run using `pytest` by running the below command inside the running backend container:

```
docker compose exec backend pytest api/ -v
```

## API Documentation

Interactive API docs are auto-generated using [drf-spectacular](https://drf-spectacular.readthedocs.io/) and available at:

- **Swagger UI**: [http://localhost:8000/api/docs/](http://localhost:8000/api/docs/) — interactive explorer with "Try it out" functionality
- **ReDoc**: [http://localhost:8000/api/redoc/](http://localhost:8000/api/redoc/) — clean, readable reference docs
- **Raw schema**: [http://localhost:8000/api/schema/](http://localhost:8000/api/schema/) — OpenAPI 3.0 JSON/YAML

### Testing authenticated endpoints

Most endpoints require JWT authentication. To test them in Swagger UI:

1. **Get a token**: Find the `POST /auth/jwt/create/` endpoint in Swagger UI, click **Try it out**, enter an authorized `email` and `password`, and click **Execute**. Copy the `access` token from the response.
2. **Authorize**: Click the **Authorize** button (lock icon) at the top of the page. Enter `JWT <your-access-token>` in the value field. The prefix must be `JWT`, not `Bearer`.
3. **Test endpoints**: All subsequent requests will include your token. Use **Try it out** on any protected endpoint.
4. **Token refresh**: Access tokens expire after 60 minutes. Use `POST /auth/jwt/refresh/` with your `refresh` token, or repeat step 1.

### Deployment

1. Merging your PR into develop automatically triggers a GitHub Release
2. The release triggers a container build workflow that builds and pushes the Docker image
3. [Go to GitHub Packages](https://github.com/CodeForPhilly/balancer-main/pkgs/container/balancer-main%2Fapp) to find the new image tag
4. Update newTag in kustomization.yaml [in the cluster repo](https://github.com/CodeForPhilly/cfp-live-cluster/blob/main/balancer/kustomization.yaml)
5. Open a PR to [cfp-sandbox-cluster](https://github.com/CodeForPhilly/cfp-sandbox-cluster) (or [cfp-live-cluster](https://github.com/CodeForPhilly/cfp-live-cluster))

## Architecture

Expand Down
5 changes: 0 additions & 5 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,6 @@ services:
networks:
app_net:
ipv4_address: 192.168.0.2
healthcheck:
test: ["CMD-SHELL", "pg_isready -U balancer -d balancer_dev"]
interval: 5s
timeout: 5s
retries: 5

pgadmin:
image: dpage/pgadmin4
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/components/Footer/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,11 @@ function Footer() {
>
Leave feedback
</Link>
<a href="https://www.flipcause.com/secure/cause_pdetails/MjMyMTIw"
<a href="https://github.com/CodeForPhilly/balancer-main"
target="_blank"
className="flex justify-center text-black hover:border-blue-600 hover:text-blue-600 hover:no-underline"
className="flex justify-center text-center text-black hover:border-blue-600 hover:text-blue-600 hover:no-underline"
>
Donate
Support Development
</a>
<Link
to="/help"
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -165,11 +165,11 @@ const Header: React.FC<LoginFormProps> = ({ isAuthenticated, isSuperuser }) => {
Leave Feedback
</Link>
<a
href="https://www.flipcause.com/secure/cause_pdetails/MjMyMTIw"
href="https://github.com/CodeForPhilly/balancer-main"
target="_blank"
className="header-nav-item"
>
Donate
Support Development
</a>
{isAuthenticated && isSuperuser && (
<div
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/Header/MdNavBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,11 @@ const MdNavBar = (props: LoginFormProps) => {
</Link>
</li>
<li className="border-b border-gray-300 p-4">
<a href="https://www.flipcause.com/secure/cause_pdetails/MjMyMTIw"
<a href="https://github.com/CodeForPhilly/balancer-main"
target="_blank"
className="mr-9 text-black hover:border-b-2 hover:border-blue-600 hover:text-black hover:no-underline"
>
Donate
Support Development
</a>
</li>
{isAuthenticated &&
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/pages/About/About.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,9 @@ function About() {
</div>
</div>
<div className="mb-20 mt-5 flex flex-row flex-wrap justify-center gap-4">
<a href="https://www.flipcause.com/secure/cause_pdetails/MjMyMTIw" target="_blank">
<a href="https://github.com/CodeForPhilly/balancer-main" target="_blank">
<button className="btnBlue transition-transform focus:outline-none focus:ring focus:ring-blue-200">
Donate
Support Development
</button>
</a>

Expand Down
9 changes: 2 additions & 7 deletions frontend/src/pages/DocumentManager/UploadFile.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useState, useRef } from "react";
import axios from "axios";
import { adminApi } from "../../api/apiClient";
import TypingAnimation from "../../components/Header/components/TypingAnimation.tsx";
import Layout from "../Layout/Layout.tsx";

Expand All @@ -22,14 +22,9 @@ const UploadFile: React.FC = () => {
formData.append("file", file);

try {
const response = await axios.post(
const response = await adminApi.post(
`/api/v1/api/uploadFile`,
formData,
{
headers: {
"Content-Type": "multipart/form-data"
},
}
);
console.log("File uploaded successfully", response.data);
} catch (error) {
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/pages/Files/ListOfFiles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ const ListOfFiles: React.FC<{ showTable?: boolean }> = ({
const handleDownload = async (guid: string, fileName: string) => {
try {
setDownloading(guid);
const { data } = await publicApi.get(`/v1/api/uploadFile/${guid}`, { responseType: 'blob' });
const { data } = await publicApi.get(`/api/v1/api/uploadFile/${guid}`, { responseType: 'blob' });

const url = window.URL.createObjectURL(new Blob([data]));
const link = document.createElement("a");
Expand All @@ -82,7 +82,7 @@ const ListOfFiles: React.FC<{ showTable?: boolean }> = ({
const handleOpen = async (guid: string) => {
try {
setOpening(guid);
const { data } = await publicApi.get(`/v1/api/uploadFile/${guid}`, { responseType: 'arraybuffer' });
const { data } = await publicApi.get(`/api/v1/api/uploadFile/${guid}`, { responseType: 'arraybuffer' });

const file = new Blob([data], { type: 'application/pdf' });
const fileURL = window.URL.createObjectURL(file);
Expand Down
35 changes: 35 additions & 0 deletions server/api/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,38 @@
class ApiConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'api'

def ready(self):

try:
import os
import sys

# ready() runs in every Django process: migrate, test, shell, runserver, etc.
# Only preload the model when we're actually going to serve requests.
# Dev (docker-compose.yml) runs `manage.py runserver 0.0.0.0:8000`.
# Prod (Dockerfile.prod CMD) runs `manage.py runserver 0.0.0.0:8000 --noreload`.
# entrypoint.prod.sh also runs migrate, createsu, and populatedb before exec'ing
# runserver — the guard below correctly skips model loading for those commands too.
if sys.argv[1:2] != ['runserver']:
return

# Dev's autoreloader spawns two processes: a parent file-watcher and a child
# server. ready() runs in both, but only the child (RUN_MAIN=true) serves
# requests. Skip the parent to avoid loading the model twice on each file change.
# Prod uses --noreload so RUN_MAIN is never set; 'noreload' in sys.argv handles that case.
if os.environ.get('RUN_MAIN') != 'true' and '--noreload' not in sys.argv:
return

# Note: paraphrase-MiniLM-L6-v2 (~80MB) is downloaded from HuggingFace on first
# use and cached to ~/.cache/torch/sentence_transformers/ inside the container.
# That cache is ephemeral — every container rebuild re-downloads the model unless
# a volume is mounted at that path.
from .services.sentencetTransformer_model import TransformerModel
TransformerModel.get_instance()
except Exception:
# TransformerModel._instance stays None on failure, so the first actual request
# that calls get_instance() will attempt to load the model again.
import logging
logger = logging.getLogger(__name__)
logger.exception("Failed to preload the embedding model at startup")
Loading
Loading