Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

issue #221: .env.secrets & .env.config #222

Merged
merged 4 commits into from
Jan 20, 2025
Merged
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
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.env.secrets
28 changes: 28 additions & 0 deletions .env.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Document Intelligence
AZURE_API_ENDPOINT=https://fertiscan-computer-vision-service.cognitiveservices.azure.com/

# OpenAI
AZURE_OPENAI_ENDPOINT=https://fertiscan-openai.openai.azure.com/
AZURE_OPENAI_DEPLOYMENT=gpt-4o

# For CORS purposes
ALLOWED_ORIGINS=["*"]

# API base path for deployment
API_BASE_PATH=
SWAGGER_PATH=/docs

# DB
FERTISCAN_SCHEMA=fertiscan_0.0.15

# Phoenix API configuration
PHOENIX_ENDPOINT=
OTEL_EXPORTER_OTLP_ENDPOINT=

# Other
UPLOAD_PATH=./uploads
# LOG_FILENAME=fertiscan.log

# Azure Storage Configuration
AZURE_STORAGE_DEFAULT_ENDPOINT_PROTOCOL=https
AZURE_STORAGE_ENDPOINT_SUFFIX=core.windows.net
16 changes: 16 additions & 0 deletions .env.secrets.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Document Intelligence
AZURE_API_KEY=

# OpenAI
AZURE_OPENAI_KEY=

# DB
DB_USER=
DB_PASSWORD=
DB_HOST=
DB_PORT=
DB_NAME=

# Azure Storage Configuration
AZURE_STORAGE_ACCOUNT_NAME=
AZURE_STORAGE_ACCOUNT_KEY=
26 changes: 0 additions & 26 deletions .env.template

This file was deleted.

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ celerybeat.pid

# Environments
.env
.env.secrets
.venv
env/
venv/
Expand Down
24 changes: 0 additions & 24 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,6 @@ COPY . .
RUN pip install --no-cache-dir -r requirements.txt
RUN opentelemetry-bootstrap --action=install

ARG ARG_AZURE_API_ENDPOINT
ARG ARG_AZURE_API_KEY
ARG ARG_AZURE_OPENAI_DEPLOYMENT
ARG ARG_AZURE_OPENAI_ENDPOINT
ARG ARG_AZURE_OPENAI_KEY
ARG ARG_FERTISCAN_STORAGE_URL
ARG ARG_FERTISCAN_DB_URL
ARG ARG_FERTISCAN_SCHEMA
ARG ARG_ALLOWED_ORIGINS
ARG ARG_PROMPT_PATH
ARG ARG_UPLOAD_PATH

ENV AZURE_API_ENDPOINT=${ARG_AZURE_API_ENDPOINT:-your_azure_form_recognizer_endpoint}
ENV AZURE_API_KEY=${ARG_AZURE_API_KEY:-your_azure_form_recognizer_key}
ENV AZURE_OPENAI_DEPLOYMENT=${ARG_AZURE_OPENAI_DEPLOYMENT:-your_azure_openai_deployment}
ENV AZURE_OPENAI_ENDPOINT=${ARG_AZURE_OPENAI_ENDPOINT:-your_azure_openai_endpoint}
ENV AZURE_OPENAI_KEY=${ARG_AZURE_OPENAI_KEY:-your_azure_openai_key}
ENV FERTISCAN_STORAGE_URL=${ARG_FERTISCAN_STORAGE_URL:-your_fertiscan_storage_url}
ENV FERTISCAN_DB_URL=${ARG_FERTISCAN_DB_URL:-your_fertiscan_db_url}
ENV FERTISCAN_SCHEMA=${ARG_FERTISCAN_SCHEMA:-your_fertiscan_schema}
ENV ALLOWED_ORIGINS=${ARG_ALLOWED_ORIGINS:-["http://url.to_frontend/"]}
ENV PROMPT_PATH=${ARG_PROMPT_PATH:-path/to/file}
ENV UPLOAD_PATH=${ARG_UPLOAD_PATH:-path/to/file}

EXPOSE 5000

RUN chown -R 1000:1000 /app
Expand Down
36 changes: 16 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,35 +49,27 @@ generation using an [LLM](https://en.wikipedia.org/wiki/Large_language_model).
1. Build the Docker image:

```sh
docker build -t fertiscan-backend \
--build-arg ARG_AZURE_API_ENDPOINT=your_azure_form_recognizer_endpoint \
--build-arg ARG_AZURE_API_KEY=your_azure_form_recognizer_key \
--build-arg ARG_AZURE_OPENAI_DEPLOYMENT=your_azure_openai_deployment \
--build-arg ARG_AZURE_OPENAI_ENDPOINT=your_azure_openai_endpoint \
--build-arg ARG_AZURE_OPENAI_KEY=your_azure_openai_key \
--build-arg ARG_FERTISCAN_STORAGE_URL=your_fertiscan_storage_url \
--build-arg ARG_FERTISCAN_DB_URL=your_fertiscan_db_url \
--build-arg ARG_FERTISCAN_SCHEMA=your_fertiscan_schema \
--build-arg ARG_ALLOWED_ORIGINS=["http://url.to_frontend/"] \
--build-arg OTEL_EXPORTER_OTLP_ENDPOINT=your_phoenix_endpoint \
--build-arg ARG_PROMPT_PATH=path/to/file \
--build-arg ARG_UPLOAD_PATH=path/to/file \
.
docker build -t fertiscan-backend .
```

2. Run the Docker container:

```sh
docker run -p 5000:5000 fertiscan-backend
docker run -p 5000:5000 --env-file .env.secrets fertiscan-backend
```

#### Docker Compose

1. Create a `.env` file from [.env.template](./.env.template). Include the
following environment variables:
1. Create a `.env.secrets` file from
[.env.secrets.template](./.env.secrets.template). Include the following
environment variables:

```ini
FERTISCAN_DB_URL=postgresql://postgres:postgres@postgres:5432/fertiscan
DB_USER=postgres
DB_PASSWORD=postgres
DB_HOST=postgres
DB_PORT=5432
DB_NAME=fertiscan
BB_URL=bytebase_url
[email protected]
BB_SERVICE_KEY=your-bytebase-sa-key
Expand Down Expand Up @@ -111,7 +103,7 @@ following details:

### Environment Variables

Create a `.env` file from [.env.template](./.env.template).
Create a `.env.secrets` file from [.env.secrets.template](./.env.secrets.template).

```ini
AZURE_API_ENDPOINT=your_azure_form_recognizer_endpoint
Expand All @@ -120,7 +112,11 @@ AZURE_OPENAI_API_ENDPOINT=your_azure_openai_endpoint
AZURE_OPENAI_API_KEY=your_azure_openai_key
AZURE_OPENAI_DEPLOYMENT=your_azure_openai_deployment

FERTISCAN_DB_URL=your_fertiscan_db_url
DB_USER=your_db_user
DB_PASSWORD=your_db_password
DB_HOST=your_db_host
DB_PORT=your_db_port
DB_NAME=your_db_name
FERTISCAN_SCHEMA=your_fertiscan_schema

UPLOAD_PATH=path/to/file
Expand Down
83 changes: 67 additions & 16 deletions app/config.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
from contextlib import asynccontextmanager
from http import HTTPStatus

from dotenv import load_dotenv
from fastapi import FastAPI
from fastapi import APIRouter, FastAPI, Request
from fastapi.logger import logger
from fastapi.middleware.cors import CORSMiddleware
from pipeline import GPT, OCR
from psycopg_pool import ConnectionPool
from pydantic import Field, PostgresDsn
from pydantic_settings import BaseSettings

from fastapi.responses import JSONResponse
from opentelemetry import trace
from opentelemetry._logs import set_logger_provider
from opentelemetry.exporter.otlp.proto.grpc._log_exporter import OTLPLogExporter
Expand All @@ -17,18 +15,32 @@
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from pipeline import GPT, OCR
from psycopg.conninfo import make_conninfo
from psycopg_pool import ConnectionPool
from pydantic import Field, computed_field
from pydantic_settings import BaseSettings

from fastapi.logger import logger
from app.exceptions import log_error

load_dotenv(".env.secrets")
load_dotenv(".env.config")

load_dotenv()

class Settings(BaseSettings):
api_endpoint: str = Field(alias="azure_api_endpoint")
api_key: str = Field(alias="azure_api_key")
base_path: str = Field("", alias="api_base_path")
fertiscan_db_url: PostgresDsn
db_user: str
db_password: str
db_host: str
db_port: int
db_name: str
fertiscan_schema: str
fertiscan_storage_url: str
azure_storage_account_name: str
azure_storage_account_key: str
azure_storage_default_endpoint_protocol: str
azure_storage_endpoint_suffix: str
openai_api_deployment: str = Field(alias="azure_openai_deployment")
openai_api_endpoint: str = Field(alias="azure_openai_endpoint")
openai_api_key: str = Field(alias="azure_openai_key")
Expand All @@ -38,9 +50,31 @@ class Settings(BaseSettings):
allowed_origins: list[str]
otel_exporter_otlp_endpoint: str = Field(alias="otel_exporter_otlp_endpoint")

@computed_field
@property
def azure_storage_connection_string(self) -> str:
return (
f"DefaultEndpointsProtocol={self.azure_storage_default_endpoint_protocol};"
f"AccountName={self.azure_storage_account_name};"
f"AccountKey={self.azure_storage_account_key};"
f"EndpointSuffix={self.azure_storage_endpoint_suffix}"
)

@computed_field
@property
def db_conn_info(self) -> str:
return make_conninfo(
user=self.db_user,
password=self.db_password,
host=self.db_host,
port=self.db_port,
dbname=self.db_name,
)


@asynccontextmanager
async def lifespan(app: FastAPI):
settings = app.state.settings
settings: Settings = app.settings
app.pool.open()
resource = Resource.create(
{
Expand All @@ -52,13 +86,21 @@ async def lifespan(app: FastAPI):
tracer_provider = TracerProvider(resource=resource)
trace.set_tracer_provider(tracer_provider)
tracer_provider.add_span_processor(
BatchSpanProcessor(OTLPSpanExporter(endpoint=settings.otel_exporter_otlp_endpoint, insecure=True))
BatchSpanProcessor(
OTLPSpanExporter(
endpoint=settings.otel_exporter_otlp_endpoint, insecure=True
)
)
)
# Logging setup
logger_provider = LoggerProvider(resource=resource)
set_logger_provider(logger_provider)
logger_provider.add_log_record_processor(
BatchLogRecordProcessor(OTLPLogExporter(endpoint=settings.otel_exporter_otlp_endpoint, insecure=True))
BatchLogRecordProcessor(
OTLPLogExporter(
endpoint=settings.otel_exporter_otlp_endpoint, insecure=True
)
)
)
handler = LoggingHandler(logger_provider=logger_provider)
logger.addHandler(handler)
Expand All @@ -68,11 +110,11 @@ async def lifespan(app: FastAPI):
tracer_provider.shutdown()


def create_app(settings: Settings):
def create_app(settings: Settings, router: APIRouter, lifespan=None):
app = FastAPI(
lifespan=lifespan, docs_url=settings.swagger_path, root_path=settings.base_path
)
app.state.settings = settings
app.settings = settings

app.add_middleware(
CORSMiddleware,
Expand All @@ -84,7 +126,7 @@ def create_app(settings: Settings):

pool = ConnectionPool(
open=False,
conninfo=settings.fertiscan_db_url.unicode_string(),
conninfo=settings.db_conn_info,
kwargs={"options": f"-c search_path={settings.fertiscan_schema},public"},
)
app.pool = pool
Expand All @@ -100,4 +142,13 @@ def create_app(settings: Settings):
)
app.gpt = gpt

app.include_router(router)

@app.exception_handler(Exception)
async def global_exception_handler(_: Request, e: Exception):
log_error(e)
return JSONResponse(
status_code=HTTPStatus.INTERNAL_SERVER_ERROR, content=str(e)
)

return app
Loading
Loading