Initialize WhatsApp Medical Chatbot API project structure

This commit is contained in:
Automated Action 2025-06-16 17:01:52 +00:00
parent b4298ad662
commit 313d8f3b49
35 changed files with 763 additions and 151 deletions

22
.env.example Normal file
View File

@ -0,0 +1,22 @@
# Application
APP_NAME="WhatsApp Medical Chatbot API"
API_V1_PREFIX="/api/v1"
DEBUG=True
ENVIRONMENT="development"
# Security
SECRET_KEY="" # Generate using: openssl rand -hex 32
ACCESS_TOKEN_EXPIRE_MINUTES=30
ALGORITHM="HS256"
# WhatsApp API
WHATSAPP_API_URL=""
WHATSAPP_API_TOKEN=""
WHATSAPP_API_PHONE_NUMBER=""
WHATSAPP_VERIFY_TOKEN=""
# OpenAI API for NLP tasks
OPENAI_API_KEY=""
# Speech-to-Text Service
SPEECH_TO_TEXT_API_KEY=""

159
.gitignore vendored
View File

@ -1,17 +1,11 @@
repos*
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
media/
*.db
whitelist.txt
ai_docs/
specs/
# C extensions
*.so
test_cases.py
# Distribution / packaging
.Python
build/
@ -26,170 +20,37 @@ parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
test_case1.py
api/core/dependencies/mailjet.py
tests/v1/waitlist/waitlist_test.py
result.json
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
test_case1.py
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
case_test.py
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
*.sqlite3
*.sqlite
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
.pdm.toml
.pdm-python
.pdm-build/
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env*
!.env.sample
.env
.venv
.blog_env/
env/
venv*
*venv/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
.vscode/
jeff.py
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
**/.DS_Store
.aider*
# IDE specific files
.idea/
.dump.rdb
.celery.log
docker-compose.yaml
# project analysis result
analysis_results.json
.vscode/
*.swp
*.swo
**/.claude/settings.local.json
*.aider
.claude/
# Project specific
/storage/
.DS_Store

29
Dockerfile Normal file
View File

@ -0,0 +1,29 @@
FROM python:3.11-slim
WORKDIR /app
# Install system dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
libcairo2-dev \
libpango1.0-dev \
libffi-dev \
shared-mime-info \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Copy requirements first for better caching
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application code
COPY . .
# Create necessary directories
RUN mkdir -p /app/storage/db /app/storage/voice_notes /app/storage/reports
# Expose port
EXPOSE 8000
# Run the application
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

120
README.md
View File

@ -1,3 +1,119 @@
# FastAPI Application
# WhatsApp Medical Chatbot API
This is a FastAPI application bootstrapped by BackendIM, the AI-powered backend generation platform.
This is a FastAPI-based API for a WhatsApp medical chatbot that provides various healthcare services.
## Features
- WhatsApp integration for chat-based interactions
- Consultation booking with healthcare professionals
- OTC drug purchase capabilities
- Symptom checking and clinical triage
- Doctor report generation
- Voice note processing for audio input
- Monitoring with Grafana, Prometheus, Loki, and Promtail
## Tech Stack
- **Backend**: Python 3.11+ with FastAPI
- **Database**: SQLite with SQLAlchemy ORM
- **Authentication**: JWT-based authentication
- **Documentation**: OpenAPI (Swagger UI and ReDoc)
- **Monitoring**: Prometheus, Grafana, Loki, and Promtail
- **Deployment**: Docker, Docker Compose, and Kubernetes
## Getting Started
### Prerequisites
- Python 3.11+
- Docker and Docker Compose (for containerized deployment)
### Installation
1. Clone the repository:
```bash
git clone <repository-url>
cd whatsapp-medical-chatbot-api
```
2. Create a virtual environment:
```bash
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
```
3. Install dependencies:
```bash
pip install -r requirements.txt
```
4. Create a `.env` file based on `.env.example`:
```bash
cp .env.example .env
```
Then edit the `.env` file to set the required environment variables.
### Running the Application
#### Using Python
```bash
uvicorn main:app --reload
```
#### Using Docker
```bash
docker-compose up -d
```
### Environment Variables
The application requires the following environment variables:
- `APP_NAME`: Name of the application
- `API_V1_PREFIX`: Prefix for API v1 endpoints
- `SECRET_KEY`: Secret key for JWT token generation
- `ACCESS_TOKEN_EXPIRE_MINUTES`: JWT token expiration time in minutes
- `WHATSAPP_API_URL`: WhatsApp API URL
- `WHATSAPP_API_TOKEN`: WhatsApp API authentication token
- `WHATSAPP_API_PHONE_NUMBER`: WhatsApp phone number for the chatbot
- `WHATSAPP_VERIFY_TOKEN`: WhatsApp webhook verification token
- `OPENAI_API_KEY`: OpenAI API key for NLP tasks
- `SPEECH_TO_TEXT_API_KEY`: API key for speech-to-text service
## API Documentation
The API documentation is available at:
- Swagger UI: `http://localhost:8000/docs`
- ReDoc: `http://localhost:8000/redoc`
- OpenAPI JSON: `http://localhost:8000/openapi.json`
## Monitoring
The application is set up with monitoring using Prometheus, Grafana, Loki, and Promtail:
- Prometheus: `http://localhost:9090`
- Grafana: `http://localhost:3000`
- Loki: `http://localhost:3100`
## Deployment
### Docker Compose
```bash
docker-compose up -d
```
### Kubernetes
Kubernetes manifests are provided in the `k8s` directory.
```bash
kubectl apply -f k8s/
```
## License
This project is licensed under the MIT License - see the LICENSE file for details.

1
app/__init__.py Normal file
View File

@ -0,0 +1 @@
# This file is intentionally left empty to make the directory a Python package

1
app/api/__init__.py Normal file
View File

@ -0,0 +1 @@
# This file is intentionally left empty to make the directory a Python package

51
app/api/deps.py Normal file
View File

@ -0,0 +1,51 @@
from typing import Optional
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
from jose import jwt, JWTError
from pydantic import ValidationError
from sqlalchemy.orm import Session
from app.core.config import settings
from app.core.security import verify_password
from app.db.session import get_db
from app.models.user import User
from app.schemas.token import TokenPayload
oauth2_scheme = OAuth2PasswordBearer(tokenUrl=f"{settings.API_V1_PREFIX}/auth/login")
def get_current_user(
db: Session = Depends(get_db), token: str = Depends(oauth2_scheme)
) -> User:
try:
payload = jwt.decode(
token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM]
)
token_data = TokenPayload(**payload)
except (JWTError, ValidationError):
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Could not validate credentials",
)
user = db.query(User).filter(User.id == token_data.sub).first()
if not user:
raise HTTPException(status_code=404, detail="User not found")
return user
def get_current_active_user(
current_user: User = Depends(get_current_user),
) -> User:
if not current_user.is_active:
raise HTTPException(status_code=400, detail="Inactive user")
return current_user
def authenticate_user(db: Session, email: str, password: str) -> Optional[User]:
user = db.query(User).filter(User.email == email).first()
if not user:
return None
if not verify_password(password, user.password):
return None
return user

1
app/api/v1/__init__.py Normal file
View File

@ -0,0 +1 @@
# This file is intentionally left empty to make the directory a Python package

6
app/api/v1/api.py Normal file
View File

@ -0,0 +1,6 @@
from fastapi import APIRouter
from app.api.v1.endpoints import health
api_router = APIRouter()
api_router.include_router(health.router, tags=["health"])

View File

@ -0,0 +1 @@
# This file is intentionally left empty to make the directory a Python package

View File

@ -0,0 +1,23 @@
from fastapi import APIRouter, Depends
from sqlalchemy.orm import Session
from app.db.session import get_db
router = APIRouter()
@router.get("/health", summary="Health check")
def health_check(db: Session = Depends(get_db)):
try:
# Check database connection
db.execute("SELECT 1")
db_status = "ok"
except Exception as e:
db_status = f"error: {str(e)}"
health_status = {
"status": "ok",
"database": db_status,
}
return health_status

1
app/core/__init__.py Normal file
View File

@ -0,0 +1 @@
# This file is intentionally left empty to make the directory a Python package

51
app/core/config.py Normal file
View File

@ -0,0 +1,51 @@
import os
from typing import List, Optional, Union
from pathlib import Path
from pydantic import AnyHttpUrl, validator
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
APP_NAME: str = "WhatsApp Medical Chatbot API"
API_V1_PREFIX: str = "/api/v1"
SECRET_KEY: str = os.getenv("SECRET_KEY", "")
ACCESS_TOKEN_EXPIRE_MINUTES: int = 30
ALGORITHM: str = "HS256"
# CORS
BACKEND_CORS_ORIGINS: List[AnyHttpUrl] = []
@validator("BACKEND_CORS_ORIGINS", pre=True)
def assemble_cors_origins(cls, v: Union[str, List[str]]) -> Union[List[str], str]:
if isinstance(v, str) and not v.startswith("["):
return [i.strip() for i in v.split(",")]
elif isinstance(v, (list, str)):
return v
raise ValueError(v)
# Database
DB_DIR: Path = Path("/app") / "storage" / "db"
# WhatsApp API
WHATSAPP_API_URL: Optional[str] = None
WHATSAPP_API_TOKEN: Optional[str] = None
WHATSAPP_API_PHONE_NUMBER: Optional[str] = None
WHATSAPP_VERIFY_TOKEN: Optional[str] = None
# OpenAI API for NLP tasks
OPENAI_API_KEY: Optional[str] = None
# Speech-to-Text Service
SPEECH_TO_TEXT_API_KEY: Optional[str] = None
ENVIRONMENT: str = "development"
DEBUG: bool = True
class Config:
case_sensitive = True
env_file = ".env"
env_file_encoding = "utf-8"
settings = Settings()

29
app/core/security.py Normal file
View File

@ -0,0 +1,29 @@
from datetime import datetime, timedelta
from typing import Optional
from jose import jwt
from passlib.context import CryptContext
from app.core.config import settings
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
def create_access_token(subject: str, expires_delta: Optional[timedelta] = None) -> str:
if expires_delta:
expire = datetime.utcnow() + expires_delta
else:
expire = datetime.utcnow() + timedelta(
minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES
)
to_encode = {"exp": expire, "sub": str(subject)}
encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM)
return encoded_jwt
def verify_password(plain_password: str, hashed_password: str) -> bool:
return pwd_context.verify(plain_password, hashed_password)
def get_password_hash(password: str) -> str:
return pwd_context.hash(password)

1
app/db/__init__.py Normal file
View File

@ -0,0 +1 @@
# This file is intentionally left empty to make the directory a Python package

3
app/db/base.py Normal file
View File

@ -0,0 +1,3 @@
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()

23
app/db/session.py Normal file
View File

@ -0,0 +1,23 @@
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from app.core.config import settings
# Ensure DB directory exists
settings.DB_DIR.mkdir(parents=True, exist_ok=True)
SQLALCHEMY_DATABASE_URL = f"sqlite:///{settings.DB_DIR}/db.sqlite"
engine = create_engine(
SQLALCHEMY_DATABASE_URL,
connect_args={"check_same_thread": False}
)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()

1
app/models/__init__.py Normal file
View File

@ -0,0 +1 @@
# This file is intentionally left empty to make the directory a Python package

15
app/models/base_model.py Normal file
View File

@ -0,0 +1,15 @@
import uuid
from datetime import datetime
from sqlalchemy import Column, DateTime, String
from sqlalchemy.ext.declarative import declared_attr
class BaseModel:
id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
@declared_attr
def __tablename__(cls) -> str:
return cls.__name__.lower()

1
app/schemas/__init__.py Normal file
View File

@ -0,0 +1 @@
# This file is intentionally left empty to make the directory a Python package

16
app/schemas/token.py Normal file
View File

@ -0,0 +1,16 @@
from typing import Optional
from pydantic import BaseModel
class Token(BaseModel):
access_token: str
token_type: str
class TokenPayload(BaseModel):
sub: Optional[str] = None
class TokenData(BaseModel):
username: Optional[str] = None

1
app/services/__init__.py Normal file
View File

@ -0,0 +1 @@
# This file is intentionally left empty to make the directory a Python package

1
app/utils/__init__.py Normal file
View File

@ -0,0 +1 @@
# This file is intentionally left empty to make the directory a Python package

78
docker-compose.yml Normal file
View File

@ -0,0 +1,78 @@
version: '3.8'
services:
api:
build: .
container_name: whatsapp-medical-chatbot-api
restart: always
ports:
- "8000:8000"
volumes:
- ./app:/app/app
- ./storage:/app/storage
env_file:
- .env
networks:
- app-network
prometheus:
image: prom/prometheus:latest
container_name: prometheus
restart: always
ports:
- "9090:9090"
volumes:
- ./monitoring/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus_data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--web.console.libraries=/usr/share/prometheus/console_libraries'
- '--web.console.templates=/usr/share/prometheus/consoles'
networks:
- app-network
grafana:
image: grafana/grafana:latest
container_name: grafana
restart: always
ports:
- "3000:3000"
volumes:
- grafana_data:/var/lib/grafana
- ./monitoring/grafana/provisioning:/etc/grafana/provisioning
depends_on:
- prometheus
networks:
- app-network
loki:
image: grafana/loki:latest
container_name: loki
restart: always
ports:
- "3100:3100"
command: -config.file=/etc/loki/local-config.yaml
networks:
- app-network
promtail:
image: grafana/promtail:latest
container_name: promtail
restart: always
volumes:
- ./storage/logs:/var/log
- ./monitoring/promtail/config.yml:/etc/promtail/config.yml
command: -config.file=/etc/promtail/config.yml
depends_on:
- loki
networks:
- app-network
networks:
app-network:
driver: bridge
volumes:
prometheus_data:
grafana_data:

9
k8s/configmap.yaml Normal file
View File

@ -0,0 +1,9 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: whatsapp-medical-chatbot-api-config
data:
APP_NAME: "WhatsApp Medical Chatbot API"
API_V1_PREFIX: "/api/v1"
WHATSAPP_API_URL: "https://api.example.com/whatsapp"
WHATSAPP_API_PHONE_NUMBER: "+1234567890"

87
k8s/deployment.yaml Normal file
View File

@ -0,0 +1,87 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: whatsapp-medical-chatbot-api
labels:
app: whatsapp-medical-chatbot-api
spec:
replicas: 3
selector:
matchLabels:
app: whatsapp-medical-chatbot-api
template:
metadata:
labels:
app: whatsapp-medical-chatbot-api
spec:
containers:
- name: api
image: whatsapp-medical-chatbot-api:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8000
env:
- name: APP_NAME
valueFrom:
configMapKeyRef:
name: whatsapp-medical-chatbot-api-config
key: APP_NAME
- name: API_V1_PREFIX
valueFrom:
configMapKeyRef:
name: whatsapp-medical-chatbot-api-config
key: API_V1_PREFIX
- name: SECRET_KEY
valueFrom:
secretKeyRef:
name: whatsapp-medical-chatbot-api-secrets
key: SECRET_KEY
- name: WHATSAPP_API_URL
valueFrom:
configMapKeyRef:
name: whatsapp-medical-chatbot-api-config
key: WHATSAPP_API_URL
- name: WHATSAPP_API_TOKEN
valueFrom:
secretKeyRef:
name: whatsapp-medical-chatbot-api-secrets
key: WHATSAPP_API_TOKEN
- name: WHATSAPP_API_PHONE_NUMBER
valueFrom:
configMapKeyRef:
name: whatsapp-medical-chatbot-api-config
key: WHATSAPP_API_PHONE_NUMBER
- name: WHATSAPP_VERIFY_TOKEN
valueFrom:
secretKeyRef:
name: whatsapp-medical-chatbot-api-secrets
key: WHATSAPP_VERIFY_TOKEN
- name: OPENAI_API_KEY
valueFrom:
secretKeyRef:
name: whatsapp-medical-chatbot-api-secrets
key: OPENAI_API_KEY
- name: SPEECH_TO_TEXT_API_KEY
valueFrom:
secretKeyRef:
name: whatsapp-medical-chatbot-api-secrets
key: SPEECH_TO_TEXT_API_KEY
volumeMounts:
- name: storage
mountPath: /app/storage
livenessProbe:
httpGet:
path: /api/v1/health
port: 8000
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /api/v1/health
port: 8000
initialDelaySeconds: 5
periodSeconds: 5
volumes:
- name: storage
persistentVolumeClaim:
claimName: whatsapp-medical-chatbot-api-pvc

19
k8s/ingress.yaml Normal file
View File

@ -0,0 +1,19 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: whatsapp-medical-chatbot-api-ingress
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
rules:
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: whatsapp-medical-chatbot-api
port:
number: 80

10
k8s/pvc.yaml Normal file
View File

@ -0,0 +1,10 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: whatsapp-medical-chatbot-api-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi

11
k8s/secrets.yaml Normal file
View File

@ -0,0 +1,11 @@
apiVersion: v1
kind: Secret
metadata:
name: whatsapp-medical-chatbot-api-secrets
type: Opaque
data:
SECRET_KEY: YOUR_BASE64_ENCODED_SECRET_KEY
WHATSAPP_API_TOKEN: YOUR_BASE64_ENCODED_WHATSAPP_API_TOKEN
WHATSAPP_VERIFY_TOKEN: YOUR_BASE64_ENCODED_WHATSAPP_VERIFY_TOKEN
OPENAI_API_KEY: YOUR_BASE64_ENCODED_OPENAI_API_KEY
SPEECH_TO_TEXT_API_KEY: YOUR_BASE64_ENCODED_SPEECH_TO_TEXT_API_KEY

14
k8s/service.yaml Normal file
View File

@ -0,0 +1,14 @@
apiVersion: v1
kind: Service
metadata:
name: whatsapp-medical-chatbot-api
labels:
app: whatsapp-medical-chatbot-api
spec:
selector:
app: whatsapp-medical-chatbot-api
ports:
- port: 80
targetPort: 8000
protocol: TCP
type: ClusterIP

63
main.py Normal file
View File

@ -0,0 +1,63 @@
import logging
from pathlib import Path
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from prometheus_fastapi_instrumentator import Instrumentator
from app.api.v1.api import api_router
from app.core.config import settings
# Setup logging
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
)
logger = logging.getLogger(__name__)
app = FastAPI(
title=settings.APP_NAME,
openapi_url="/openapi.json",
docs_url="/docs",
redoc_url="/redoc",
)
# Set up CORS middleware
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # Allow all origins
allow_credentials=True,
allow_methods=["*"], # Allow all methods
allow_headers=["*"], # Allow all headers
)
# Add Prometheus metrics
Instrumentator().instrument(app).expose(app)
# Include API router
app.include_router(api_router, prefix=settings.API_V1_PREFIX)
@app.get("/", tags=["Root"])
async def root():
"""
Root endpoint that returns application information.
"""
return {
"name": settings.APP_NAME,
"docs": "/docs",
"health_check": f"{settings.API_V1_PREFIX}/health",
}
if __name__ == "__main__":
import uvicorn
# Ensure storage directories exist
storage_dir = Path("/app/storage")
storage_dir.mkdir(parents=True, exist_ok=True)
(storage_dir / "db").mkdir(exist_ok=True)
(storage_dir / "voice_notes").mkdir(exist_ok=True)
(storage_dir / "reports").mkdir(exist_ok=True)
uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)

View File

@ -0,0 +1,15 @@
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
access: proxy
url: http://prometheus:9090
isDefault: true
editable: false
- name: Loki
type: loki
access: proxy
url: http://loki:3100
editable: false

View File

@ -0,0 +1,12 @@
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'whatsapp-medical-chatbot-api'
static_configs:
- targets: ['api:8000']

View File

@ -0,0 +1,18 @@
server:
http_listen_port: 9080
grpc_listen_port: 0
positions:
filename: /tmp/positions.yaml
clients:
- url: http://loki:3100/loki/api/v1/push
scrape_configs:
- job_name: system
static_configs:
- targets:
- localhost
labels:
job: whatsapp-medical-chatbot-api
__path__: /var/log/*log

21
requirements.txt Normal file
View File

@ -0,0 +1,21 @@
fastapi==0.104.1
uvicorn==0.24.0
pydantic==2.4.2
pydantic-settings==2.0.3
sqlalchemy==2.0.23
alembic==1.12.1
python-jose[cryptography]==3.3.0
passlib[bcrypt]==1.7.4
python-multipart==0.0.6
requests==2.31.0
httpx==0.25.1
aiofiles==23.2.1
python-dotenv==1.0.0
tenacity==8.2.3
pytest==7.4.3
speechrecognition==3.10.0
jinja2==3.1.2
weasyprint==60.1
ruff==0.1.5
prometheus-client==0.17.1
prometheus-fastapi-instrumentator==6.1.0