Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 0 additions & 5 deletions .env.local

This file was deleted.

6 changes: 3 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -135,11 +135,11 @@ celerybeat.pid
*.sage.py

# Environments
.env
.env**
.envrc
.venv
.venv**
env/
venv/
venv**/
ENV/
env.bak/
venv.bak/
Expand Down
16 changes: 13 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,8 @@ poetry config virtualenvs.path /your/desired/path

Ensure below files are configured (create if not exist) properly to run the project;

- `.env.local`,
- `.env`, and
- `.streamlit/secrets.toml`
- `.env.development`
- `.env.production`

## Install Dependencies

Expand All @@ -51,6 +50,17 @@ poetry install

## How to Run

## Configure ENVIRONMENT

setup `.env.development` and `.env.production` in project root

```bash
# for local configuration(linux)
export ENV=development
# for production(linux)
export ENV=production
```

## Run Streamlit App

```bash
Expand Down
310 changes: 201 additions & 109 deletions poetry.lock

Large diffs are not rendered by default.

13 changes: 9 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,23 @@ dependencies = [
"python-box (>=7.3.2,<8.0.0)",
"uvicorn (>=0.40.0,<0.41.0)",
"pymongo (>=4.15.5,<5.0.0)",
"bs4 (>=0.0.2,<0.0.3)",
"dotenv (>=0.9.9,<0.10.0)",
"pydantic (>=2.12.5,<3.0.0)",
"click (>=8.3.1,<9.0.0)",
]


[tool.poetry]
packages = [
{ include = "sample", from = "src" },
{ include = "features", from = "src" },
{ include = "utils", from = "src" },
{ include = "api", from = "src" },
{ include = "assets/images/logo.png", from = "src" },
]


[project.scripts]
sample = "sample.cli:cli"
lint = "utils.lint:main"
lint = "sample.utils.lint:main"


[tool.poetry.group.dev.dependencies]
Expand All @@ -44,6 +45,7 @@ pipreqs = "0.5.0"
ruff = "0.5.3"
twine = "^6.2.0"
vulture = "^2.3"
deptry = "^0.24.0"

[tool.flake8]
max_line_length = 190
Expand All @@ -62,3 +64,6 @@ ignore = []
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

[tool.deptry]
known_first_party = ["sample"]
2 changes: 1 addition & 1 deletion src/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from utils._version import get_version
from sample.utils._version import get_version

__version__ = get_version()
3 changes: 0 additions & 3 deletions src/api/__init__.py

This file was deleted.

46 changes: 0 additions & 46 deletions src/db/connection.py

This file was deleted.

2 changes: 1 addition & 1 deletion src/sample/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from utils._version import get_version
from sample.utils._version import get_version

__version__ = get_version()
32 changes: 3 additions & 29 deletions src/sample/__main__.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,11 @@
# sample/__main__.py

from . import __version__
import sys
import logging
import subprocess
import sys
from pathlib import Path
import click

logging.basicConfig(level=logging.INFO)


@click.group(invoke_without_command=True)
@click.option("--version", is_flag=True, help="Show the Sample version and exit.")
@click.pass_context
def cli(ctx, version):
"""Sample command-line tools."""
if version:
click.echo(__version__)
ctx.exit()


@cli.command()
def dev():
"""Run the Sample Streamlit app."""
main()


@cli.command()
def api():
"""Run the Sample FastAPI backend."""
from api.fast_api import start

start()
from . import __version__


def main():
Expand Down Expand Up @@ -83,4 +57,4 @@ def main():


if __name__ == "__main__":
cli()
main()
3 changes: 3 additions & 0 deletions src/sample/api/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from sample.utils._version import get_version

__version__ = get_version()
29 changes: 21 additions & 8 deletions src/api/fast_api.py → src/sample/api/fast_api.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
from fastapi import FastAPI, HTTPException, Request
import sys
from pathlib import Path

from fastapi import APIRouter, FastAPI, HTTPException, Request
from fastapi.responses import HTMLResponse
from pydantic import BaseModel
from sample.db.connection import connect_db
from sample.utils.constants import DEFAULT_GREETING
from sample.utils.helper import normalize_name

sys.path.append(str(Path(__file__).resolve().parent.parent))

from . import __version__
from utils.constants import DEFAULT_GREETING
from utils.helper import normalize_name

app = FastAPI(
title="sample API",
Expand All @@ -19,6 +26,8 @@
},
)

greet_router = APIRouter(prefix="/api/v1", tags=["V1"])


class GreetRequest(BaseModel):
name: str
Expand All @@ -28,12 +37,12 @@ class GreetResponse(BaseModel):
message: str


@app.get("/version")
@app.get("/version",tags=["Meta"])
def version():
return {"version": app.version}


@app.get("/", response_class=HTMLResponse)
@app.get("/", response_class=HTMLResponse,tags=["Meta"])
async def read_root(request: Request):
return """
<html>
Expand Down Expand Up @@ -75,12 +84,12 @@ async def read_root(request: Request):
"""


@app.get("/health")
@app.get("/health",tags=["Meta"])
def health_check():
return {"status": "ok"}


@app.post("/greet", response_model=GreetResponse)
@greet_router.post("/greet", response_model=GreetResponse)
def greet_user(payload: GreetRequest):
clean_name = normalize_name(payload.name)

Expand All @@ -90,11 +99,15 @@ def greet_user(payload: GreetRequest):
return {"message": f"{DEFAULT_GREETING}, {clean_name} 👋"}


app.include_router(greet_router)


def start():
import uvicorn

print(f"🧵 {__version__}\n")
uvicorn.run("api.fast_api:app", host="127.0.0.1", port=5000, reload=True)
connect_db()
uvicorn.run("sample.api.fast_api:app", host="127.0.0.1", port=5000, reload=True)


if __name__ == "__main__":
Expand Down
2 changes: 1 addition & 1 deletion src/sample/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ def dev():
@cli.command()
def api():
"""Run the Sample FastAPI backend."""
from api.fast_api import start
from sample.api.fast_api import start

start()
File renamed without changes.
60 changes: 60 additions & 0 deletions src/sample/db/connection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import io
from datetime import datetime

from sample.utils.constants import MONGO_CONFIG

_mongo_client = None
_db = None


def connect_db():
"""
Connect to MongoDB and return the Database object.
Requires pymongo to be installed via the 'mongo' extra.
"""
global _mongo_client, _db

if _db is not None:
return _db

try:
from pymongo import MongoClient
except ImportError as e:
raise RuntimeError(
"Mongo support not installed. "
"Install with: pip install sample[mongo] or poetry install --extras 'mongo'"
) from e

try:
uri = MONGO_CONFIG["MONGODB_URI"]
name = MONGO_CONFIG["DATABASE_NAME"]

_mongo_client = MongoClient(uri, serverSelectionTimeoutMS=3000)
# Force an actual connection attempt
_mongo_client.admin.command("ping")
_db = _mongo_client[name]
print("MongoDB connected successfully.")
return _db

except KeyError as e:
raise RuntimeError(f"MongoDB Configuration Error: Missing key {e}")

except Exception as e:
raise RuntimeError(f"MongoDB Connection Error: {e}")


def save_to_mongodb(data, collection):
try:
data["created_at"] = datetime.now()
result = collection.insert_one(data)
return result.inserted_id
except Exception as e:
print("MongoDB Insert Error:", e)
return False


def pil_to_bytes(pil_image):
buf = io.BytesIO()
pil_image.save(buf, format="PNG")
buf.seek(0)
return buf
File renamed without changes.
10 changes: 4 additions & 6 deletions src/features/greeting.py → src/sample/features/greeting.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import streamlit as st

from utils.constants import (
APP_TITLE,
DEFAULT_GREETING
)
from utils.helper import normalize_name
from sample.db.connection import connect_db
from sample.utils.constants import APP_TITLE, DEFAULT_GREETING
from sample.utils.helper import normalize_name


def greet():
st.header(APP_TITLE)

name = st.text_input("Enter your name")
connect_db()

clean_name = normalize_name(name)

Expand Down
12 changes: 7 additions & 5 deletions src/sample/streamlit_app.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import sys
from pathlib import Path

import streamlit as st
from sample.features.greeting import greet

# --- Imports ---
from sample.utils.constants import COMPANY_LOGO, FAQ_TITLE
from sample.utils.faq import faq_page
from sample.utils.load_messages import get_msg

# --- Path setup ---
package_root = str(Path(__file__).parent)
if package_root not in sys.path:
sys.path.append(package_root)

# --- Imports ---
from utils.constants import COMPANY_LOGO, FAQ_TITLE
from utils.faq import faq_page
from utils.load_messages import get_msg
from features.greeting import greet

MSG = get_msg("MAIN_APP")

Expand Down
Empty file added src/sample/utils/__init__.py
Empty file.
Loading