Skip to content

Commit 9bdc9c8

Browse files
Merge pull request #55 from goldlabelapps/staging
Add Gemini API and tests; update routes & docs
2 parents b89a450 + 88ccd1d commit 9bdc9c8

8 files changed

Lines changed: 52 additions & 43 deletions

File tree

README.md

Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
## Python FastAPI/Postgres App
22

3-
**Production-ready, open-source FastAPI application with PostgreSQL and blazing-fast full-text search.**
3+
> Production-ready, open-source FastAPI application with PostgreSQL and blazing-fast full-text search.
44
5-
---
5+
#### Project Overview
66

7-
### 🚀 Features
7+
This project provides a scalable API backend using FastAPI and PostgreSQL, featuring:
8+
9+
- Automatic full-text search on all text fields (via tsvector)
10+
- Endpoints for health checks, product management, prompt handling, and prospect management
11+
- Efficient ingestion and processing of large CSV files
12+
13+
#### 🚀 Features
814

915
- **Python 3.11+**
1016
- **FastAPI** — Modern, high-performance REST API
@@ -13,19 +19,7 @@
1319
- **Uvicorn** — Lightning-fast ASGI server
1420
- **Pytest** — Comprehensive testing
1521

16-
---
17-
18-
## Project Overview
19-
20-
This project provides a scalable API backend using FastAPI and PostgreSQL, featuring:
21-
22-
- Automatic full-text search on all text fields (via tsvector)
23-
- Endpoints for health checks, product management, prompt handling, and prospect management
24-
- Efficient ingestion and processing of large CSV files
25-
26-
---
27-
28-
## Getting Started
22+
#### Getting Started
2923

3024
### 1. Clone & Setup Environment
3125

@@ -38,24 +32,21 @@ source venv/bin/activate
3832
pip install -r requirements.txt
3933
```
4034

41-
### 2. Run the App
35+
#### 2. Run the App
4236

4337
```bash
4438
uvicorn app.main:app --reload
4539
```
4640

4741
Visit [localhost:8000](http://localhost:8000) or [onrender](https://nx-ai.onrender.com)
4842

49-
---
50-
51-
## API Documentation
43+
#### API Documentation
5244

5345
FastAPI auto-generates interactive docs:
5446

5547
- [Swagger UI](https://nx-ai.onrender.com/docs)
5648
- [ReDoc](https://nx-ai.onrender.com/redoc)
5749

58-
---
5950

6051
## Full-Text Search (tsvector)
6152

@@ -69,13 +60,11 @@ SELECT * FROM prospects WHERE search_vector @@ plainto_tsquery('english', 'searc
6960
- On every insert/update, `search_vector` is computed using PostgreSQL's `to_tsvector('english', ...)`.
7061
- The GIN index (`idx_prospects_search_vector`) enables efficient search across large datasets.
7162

72-
---
7363

7464
## Processing Large CSV Files
7565

7666
The `/prospects/process` endpoint supports robust ingestion of large CSVs (e.g., 1300+ rows, 300KB+), following the same normalization and insertion pattern as `/prospects/seed` but optimized for scale.
7767

78-
---
7968

8069
## Directory Structure
8170

@@ -98,13 +87,11 @@ requirements.txt # Python dependencies
9887
render.yaml # Deployment config (Render.com)
9988
```
10089

101-
---
10290

10391
## Contributing
10492

10593
Contributions welcome. Please open issues or submit pull requests.
10694

107-
---
10895

10996
## License
11097

app/api/gemini/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
"""Gemini Routes"""
2+
3+
from .gemini import router as gemini_router

app/api/gemini/gemini.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from fastapi import APIRouter
2+
3+
router = APIRouter()
4+
5+
@router.get("/gemini")
6+
def root() -> dict:
7+
"""GET /gemini endpoint."""
8+
return {"message": "Welcome to the Gemini API!"}
9+

app/api/root.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,14 @@ def root() -> dict:
1313
base_url = os.getenv("BASE_URL", "http://localhost:8000")
1414
epoch = int(time.time() * 1000)
1515
meta = {
16-
"title": "NX-AI",
16+
"title": "Python",
1717
"severity": "success",
1818
"version": __version__,
1919
"base_url": base_url,
2020
"time": epoch,
2121
}
2222
endpoints = [
23+
{"name": "gemini", "url": f"{base_url}/gemini"},
2324
{"name": "docs", "url": f"{base_url}/docs"},
2425
{"name": "resend", "url": f"{base_url}/resend"},
2526
{"name": "health", "url": f"{base_url}/health"},

app/api/routes.py

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
1-
from app import __version__
21
"""API routes"""
3-
2+
from app import __version__
43
from dotenv import load_dotenv
5-
64
from fastapi import APIRouter, Depends
7-
85
from app.utils.db import get_db_connection
96
from app.api.schemas import EchoRequest, EchoResponse
107

@@ -16,18 +13,13 @@
1613
from app.api.prompts.prompts import router as prompts_router
1714
from app.api.prospects.prospects import router as prospects_router
1815
from app.api.prospects.search import router as prospects_search_router
19-
from app.utils.prospects.database.alter import router as prospects_alter_router
20-
from app.utils.prospects.database.seed import router as prospects_seed_router
21-
from app.utils.prospects.database.empty import router as prospects_empty_router
22-
from app.utils.prospects.database.process import router as prospects_process_router
16+
from app.api.gemini.gemini import router as gemini_router
2317

2418
router.include_router(root_router)
2519
router.include_router(resend_router)
2620
router.include_router(health_router)
2721
router.include_router(prompts_router)
2822
router.include_router(prospects_search_router)
2923
router.include_router(prospects_router)
30-
router.include_router(prospects_alter_router)
31-
router.include_router(prospects_seed_router)
32-
router.include_router(prospects_empty_router)
33-
router.include_router(prospects_process_router)
24+
router.include_router(gemini_router)
25+

render.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ projects:
88
- type: web
99
name: nx-ai
1010
runtime: python
11-
repo: https://github.com/goldlabelapps/nx-ai
11+
repo: https://github.com/goldlabelapps/python
1212
plan: free
1313
region: oregon
1414
buildCommand: pip install -r requirements.txt

tests/test_gemini.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import sys
2+
import os
3+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../")))
4+
import pytest
5+
from fastapi.testclient import TestClient
6+
from app.main import app
7+
8+
client = TestClient(app)
9+
10+
11+
def test_gemini_endpoint():
12+
response = client.get("/gemini")
13+
assert response.status_code == 200
14+
assert response.json() == {"message": "Welcome to the Gemini API!"}

tests/test_prospects.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,16 @@ def test_get_prospects_root():
1111
assert "meta" in data
1212
assert "data" in data
1313
assert isinstance(data["data"], list)
14-
# Check that the expected keys are present in the data list
15-
assert any("init" in item for item in data["data"])
16-
assert any("search" in item for item in data["data"])
14+
# Check that the expected keys are present in the data list (if not empty)
15+
if data["data"]:
16+
first_item = data["data"][0]
17+
# Adjust these keys to match your actual prospect schema
18+
assert "id" in first_item
19+
assert "first_name" in first_item or "last_name" in first_item
1720
# Meta checks
1821
meta = data["meta"]
1922
assert meta["severity"] == "success"
20-
assert meta["title"] == "Prospects endpoint"
23+
assert meta["title"] == "Read paginated prospects"
2124

2225
def test_prospects_returns_list():
2326
response = client.get("/prospects")

0 commit comments

Comments
 (0)