diff --git a/README.md b/README.md index f52575f..a117961 100644 --- a/README.md +++ b/README.md @@ -1,65 +1,119 @@ -## ![Python](/app/static/repoicon.png) Python +## Python FastAPI/Postgres App -> With FastAPI using Postgres & tsvector. +**Production-ready, open-source FastAPI application with PostgreSQL and blazing-fast full-text search.** -Open Source, production ready Python FastAPI/Postgres app. +--- -[GitHub](https://github.com/goldlabelapps/python) | -[onr]Render](https://nx-ai.onrender.com) | -[by Goldlabel](https://goldlabel.pro) +### 🚀 Features - **Python 3.11+** -- **Postgres** -- **tsvector** - Superfast full-text search (with GIN index) +- **FastAPI** — Modern, high-performance REST API +- **PostgreSQL** — Robust relational database +- **tsvector + GIN** — Superfast full-text search +- **Uvicorn** — Lightning-fast ASGI server +- **Pytest** — Comprehensive testing -```sh -uvicorn app.main:app --reload -``` +--- + +## Project Overview + +This project provides a scalable API backend using FastAPI and PostgreSQL, featuring: -#### Install +- Automatic full-text search on all text fields (via tsvector) +- Endpoints for health checks, product management, prompt handling, and prospect management +- Efficient ingestion and processing of large CSV files -Create an environment file and add Postgres credentials etc +--- -`cp .env.sample .env` +## Getting Started + +### 1. Clone & Setup Environment ```bash +git clone +cd python +cp .env.sample .env # Add your Postgres credentials and settings python -m venv venv source venv/bin/activate pip install -r requirements.txt +``` + +### 2. Run the App + +```bash uvicorn app.main:app --reload ``` -[localhost](http://localhost:8000) | [onrender](https://nx-ai.onrender.com) +Visit [localhost:8000](http://localhost:8000) or [onrender](https://nx-ai.onrender.com) +--- -### Full-Text Search (tsvector) +## API Documentation -The prospects table includes a `search_vector` column (type: tsvector) that is automatically computed from all text fields on insert. A GIN index is created for this column, enabling fast and scalable full-text search queries. +FastAPI auto-generates interactive docs: -**How it works:** +- [Swagger UI](http://localhost:8000/docs) +- [ReDoc](http://localhost:8000/redoc) -- On every insert or update, the `search_vector` is computed from all text columns using PostgreSQL's `to_tsvector('english', ...)`. -- The GIN index (`idx_prospects_search_vector`) allows efficient search queries like: +--- + +## Full-Text Search (tsvector) + +The `prospects` table includes a `search_vector` column (type: tsvector) computed from all text fields on insert/update. A GIN index enables fast, scalable full-text search: ```sql SELECT * FROM prospects WHERE search_vector @@ plainto_tsquery('english', 'search terms'); ``` -This makes searching across all text fields in the prospects table extremely fast, even for large datasets. -- **FastAPI** — RESTful API framework -- **Uvicorn** — ASGI server -- **Pytest** — testing framework -- **HTTPX / TestClient** +**How it works:** +- On every insert/update, `search_vector` is computed using PostgreSQL's `to_tsvector('english', ...)`. +- The GIN index (`idx_prospects_search_vector`) enables efficient search across large datasets. + +--- + +## Processing Large CSV Files + +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. + +--- + +## Directory Structure + +``` +app/ + main.py # FastAPI entrypoint + api/ # API endpoints & schemas + health.py + root.py + routes.py + products/ + prompts/ + prospects/ + resend/ + utils/ + static/ # Static assets (e.g., repoicon.png) + utils/ # Utility scripts +tests/ # Pytest test suite +requirements.txt # Python dependencies +render.yaml # Deployment config (Render.com) +``` + +--- + +## Contributing + +Contributions are welcome! Please open issues or submit pull requests. + +--- -#### Docs +## License -FastAPI automatically generates interactive documentation: +This project is licensed under the MIT License. See [LICENSE](LICENSE) for details. -- Swagger UI: -- ReDoc: +--- -### Processing Large CSV Files +## Contact -The `/prospects/process` endpoint is designed for robust, scalable ingestion of large CSV files (e.g., 1300+ rows, 300KB+). It follows the same normalization and insertion pattern as `/prospects/seed`, but is optimized for large files: +For questions or support, open an issue or contact the maintainer. diff --git a/app/__init__.py b/app/__init__.py index c83cfb8..aa0c61d 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,4 +1,4 @@ """Python - FastAPI, Postgres, tsvector""" # Current Version -__version__ = "2.0.8" +__version__ = "2.1.1" diff --git a/app/api/prospects/database/reset_flag_and_hide.py b/app/api/prospects/database/reset_flag_and_hide.py new file mode 100644 index 0000000..e048fdc --- /dev/null +++ b/app/api/prospects/database/reset_flag_and_hide.py @@ -0,0 +1,20 @@ +# Script to reset all 'flag' and 'hide' values to false in the prospects table +from app.utils.db import get_db_connection + +def reset_flag_and_hide(): + conn_gen = get_db_connection() + conn = next(conn_gen) + cur = conn.cursor() + try: + cur.execute("UPDATE prospects SET flag = FALSE, hide = FALSE;") + conn.commit() + print("All 'flag' and 'hide' values reset to FALSE.") + except Exception as e: + print(f"Error: {e}") + conn.rollback() + finally: + cur.close() + conn.close() + +if __name__ == "__main__": + reset_flag_and_hide() diff --git a/app/utils/make_meta.py b/app/utils/make_meta.py index ac2684b..0a5e3bd 100644 --- a/app/utils/make_meta.py +++ b/app/utils/make_meta.py @@ -10,6 +10,6 @@ def make_meta(severity: str, title: str) -> dict: "version": __version__, "time": epoch, "severity": severity, - "message": title, - "base_url": base_url, + "title": title, + "base": base_url, } diff --git a/tests/prospects/test_prospects.py b/tests/prospects/test_prospects.py deleted file mode 100644 index 751a2a5..0000000 --- a/tests/prospects/test_prospects.py +++ /dev/null @@ -1,31 +0,0 @@ -import sys -import os -sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../../"))) -import pytest -from fastapi.testclient import TestClient -from app.main import app - -client = TestClient(app) - -def test_prospects_init_returns_placeholder(): - response = client.get("/prospects/init") - assert response.status_code == 200 - data = response.json() - assert "meta" in data - assert "data" in data - assert data["data"]["message"] == "This is a placeholder for prospects/init." - -def test_prospects_returns_list(): - response = client.get("/prospects") - assert response.status_code == 200 - data = response.json() - assert "meta" in data - assert "data" in data - assert isinstance(data["data"], list) or isinstance(data["data"], dict) - - -def test_prospects_init_meta_keys(): - response = client.get("/prospects/init") - meta = response.json()["meta"] - for key in ["severity", "title", "version", "base_url", "time"]: - assert key in meta diff --git a/tests/test_prospects.py b/tests/test_prospects.py new file mode 100644 index 0000000..3c16884 --- /dev/null +++ b/tests/test_prospects.py @@ -0,0 +1,28 @@ +import pytest +from fastapi.testclient import TestClient +from app.main import app + +client = TestClient(app) + +def test_get_prospects_root(): + response = client.get("/prospects") + assert response.status_code == 200 + data = response.json() + assert "meta" in data + assert "data" in data + assert isinstance(data["data"], list) + # Check that the expected keys are present in the data list + assert any("init" in item for item in data["data"]) + assert any("search" in item for item in data["data"]) + # Meta checks + meta = data["meta"] + assert meta["severity"] == "success" + assert meta["title"] == "Prospects endpoint" + +def test_prospects_returns_list(): + response = client.get("/prospects") + assert response.status_code == 200 + data = response.json() + assert "meta" in data + assert "data" in data + assert isinstance(data["data"], list) or isinstance(data["data"], dict)