Merge pull request #168 from MuhamadAjiW/feat/uvicorn-config

Feature: Uvicorn Config on .env
This commit is contained in:
Rohan Verma 2025-06-10 20:27:39 -07:00 committed by GitHub
commit 08646d1efe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 212 additions and 21 deletions

View file

@ -3,45 +3,78 @@ DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/surfsense
SECRET_KEY=SECRET
NEXT_FRONTEND_URL=http://localhost:3000
#Auth
# Auth
AUTH_TYPE=GOOGLE or LOCAL
# For Google Auth Only
GOOGLE_OAUTH_CLIENT_ID=924507538m
GOOGLE_OAUTH_CLIENT_SECRET=GOCSV
#Embedding Model
# Embedding Model
EMBEDDING_MODEL=mixedbread-ai/mxbai-embed-large-v1
RERANKERS_MODEL_NAME=ms-marco-MiniLM-L-12-v2
RERANKERS_MODEL_TYPE=flashrank
#LiteLLM TTS Provider: https://docs.litellm.ai/docs/text_to_speech#supported-providers
# LiteLLM TTS Provider: https://docs.litellm.ai/docs/text_to_speech#supported-providers
TTS_SERVICE=openai/tts-1
#Respective TTS Service API
# Respective TTS Service API
TTS_SERVICE_API_KEY=
#OPTIONAL: TTS Provider API Base
# OPTIONAL: TTS Provider API Base
TTS_SERVICE_API_BASE=
#LiteLLM STT Provider: https://docs.litellm.ai/docs/audio_transcription#supported-providers
# LiteLLM STT Provider: https://docs.litellm.ai/docs/audio_transcription#supported-providers
STT_SERVICE=openai/whisper-1
#Respective STT Service API
# Respective STT Service API
STT_SERVICE_API_KEY=""
#OPTIONAL: STT Provider API Base
# OPTIONAL: STT Provider API Base
STT_SERVICE_API_BASE=
FIRECRAWL_API_KEY=fcr-01J0000000000000000000000
#File Parser Service
# File Parser Service
ETL_SERVICE=UNSTRUCTURED or LLAMACLOUD
UNSTRUCTURED_API_KEY=Tpu3P0U8iy
LLAMA_CLOUD_API_KEY=llx-nnn
#OPTIONAL: Add these for LangSmith Observability
# OPTIONAL: Add these for LangSmith Observability
LANGSMITH_TRACING=true
LANGSMITH_ENDPOINT=https://api.smith.langchain.com
LANGSMITH_API_KEY=lsv2_pt_.....
LANGSMITH_PROJECT=surfsense
# Uvicorn Server Configuration
# Full documentation for Uvicorn options can be found at: https://www.uvicorn.org/#command-line-options
UVICORN_HOST="0.0.0.0"
UVICORN_PORT=8000
UVICORN_LOG_LEVEL=info
# OPTIONAL: Advanced Uvicorn Options (uncomment to use)
# UVICORN_PROXY_HEADERS=false
# UVICORN_FORWARDED_ALLOW_IPS="127.0.0.1"
# UVICORN_WORKERS=1
# UVICORN_ACCESS_LOG=true
# UVICORN_LOOP="auto"
# UVICORN_HTTP="auto"
# UVICORN_WS="auto"
# UVICORN_LIFESPAN="auto"
# UVICORN_LOG_CONFIG=""
# UVICORN_SERVER_HEADER=true
# UVICORN_DATE_HEADER=true
# UVICORN_LIMIT_CONCURRENCY=
# UVICORN_LIMIT_MAX_REQUESTS=
# UVICORN_TIMEOUT_KEEP_ALIVE=5
# UVICORN_TIMEOUT_NOTIFY=30
# UVICORN_SSL_KEYFILE=""
# UVICORN_SSL_CERTFILE=""
# UVICORN_SSL_KEYFILE_PASSWORD=""
# UVICORN_SSL_VERSION=""
# UVICORN_SSL_CERT_REQS=""
# UVICORN_SSL_CA_CERTS=""
# UVICORN_SSL_CIPHERS=""
# UVICORN_HEADERS=""
# UVICORN_USE_COLORS=true
# UVICORN_UDS=""
# UVICORN_FD=""
# UVICORN_ROOT_PATH=""

View file

@ -0,0 +1,82 @@
import os
def _parse_bool(value):
"""Parse boolean value from string."""
return value.lower() == "true" if value else False
def _parse_int(value, var_name):
"""Parse integer value with error handling."""
try:
return int(value)
except ValueError:
raise ValueError(f"Invalid integer value for {var_name}: {value}")
def _parse_headers(value):
"""Parse headers from comma-separated string."""
try:
return [
tuple(h.split(":", 1))
for h in value.split(",")
if ":" in h
]
except Exception:
raise ValueError(f"Invalid headers format: {value}")
def load_uvicorn_config(args=None):
"""
Load Uvicorn configuration from environment variables and CLI args.
Returns a dict suitable for passing to uvicorn.Config.
"""
config_kwargs = dict(
app="app.app:app",
host=os.getenv("UVICORN_HOST", "0.0.0.0"),
port=int(os.getenv("UVICORN_PORT", 8000)),
log_level=os.getenv("UVICORN_LOG_LEVEL", "info"),
reload=args.reload if args else False,
reload_dirs=["app"] if (args and args.reload) else None,
)
# Configuration mapping for advanced options
config_mapping = {
"UVICORN_PROXY_HEADERS": ("proxy_headers", _parse_bool),
"UVICORN_FORWARDED_ALLOW_IPS": ("forwarded_allow_ips", str),
"UVICORN_WORKERS": ("workers", lambda x: _parse_int(x, "UVICORN_WORKERS")),
"UVICORN_ACCESS_LOG": ("access_log", _parse_bool),
"UVICORN_LOOP": ("loop", str),
"UVICORN_HTTP": ("http", str),
"UVICORN_WS": ("ws", str),
"UVICORN_LIFESPAN": ("lifespan", str),
"UVICORN_ENV_FILE": ("env_file", str),
"UVICORN_LOG_CONFIG": ("log_config", str),
"UVICORN_SERVER_HEADER": ("server_header", _parse_bool),
"UVICORN_DATE_HEADER": ("date_header", _parse_bool),
"UVICORN_LIMIT_CONCURRENCY": ("limit_concurrency", lambda x: _parse_int(x, "UVICORN_LIMIT_CONCURRENCY")),
"UVICORN_LIMIT_MAX_REQUESTS": ("limit_max_requests", lambda x: _parse_int(x, "UVICORN_LIMIT_MAX_REQUESTS")),
"UVICORN_TIMEOUT_KEEP_ALIVE": ("timeout_keep_alive", lambda x: _parse_int(x, "UVICORN_TIMEOUT_KEEP_ALIVE")),
"UVICORN_TIMEOUT_NOTIFY": ("timeout_notify", lambda x: _parse_int(x, "UVICORN_TIMEOUT_NOTIFY")),
"UVICORN_SSL_KEYFILE": ("ssl_keyfile", str),
"UVICORN_SSL_CERTFILE": ("ssl_certfile", str),
"UVICORN_SSL_KEYFILE_PASSWORD": ("ssl_keyfile_password", str),
"UVICORN_SSL_VERSION": ("ssl_version", lambda x: _parse_int(x, "UVICORN_SSL_VERSION")),
"UVICORN_SSL_CERT_REQS": ("ssl_cert_reqs", lambda x: _parse_int(x, "UVICORN_SSL_CERT_REQS")),
"UVICORN_SSL_CA_CERTS": ("ssl_ca_certs", str),
"UVICORN_SSL_CIPHERS": ("ssl_ciphers", str),
"UVICORN_HEADERS": ("headers", _parse_headers),
"UVICORN_USE_COLORS": ("use_colors", _parse_bool),
"UVICORN_UDS": ("uds", str),
"UVICORN_FD": ("fd", lambda x: _parse_int(x, "UVICORN_FD")),
"UVICORN_ROOT_PATH": ("root_path", str),
}
# Process advanced configuration options
for env_var, (config_key, parser) in config_mapping.items():
value = os.getenv(env_var)
if value:
try:
config_kwargs[config_key] = parser(value)
except ValueError as e:
raise ValueError(f"Configuration error for {env_var}: {e}")
return config_kwargs

View file

@ -1,22 +1,24 @@
import uvicorn
import argparse
import logging
from dotenv import load_dotenv
from app.config.uvicorn import load_uvicorn_config
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
)
load_dotenv()
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Run the SurfSense application')
parser.add_argument('--reload', action='store_true', help='Enable hot reloading')
parser = argparse.ArgumentParser(description="Run the SurfSense application")
parser.add_argument("--reload", action="store_true", help="Enable hot reloading")
args = parser.parse_args()
uvicorn.run(
"app.app:app",
host="0.0.0.0",
log_level="info",
reload=args.reload,
reload_dirs=["app"]
)
config_kwargs = load_uvicorn_config(args)
config = uvicorn.Config(**config_kwargs)
server = uvicorn.Server(config)
server.run()

View file

@ -110,6 +110,42 @@ Before you begin, ensure you have:
| LANGSMITH_API_KEY | Your LangSmith API key |
| LANGSMITH_PROJECT | LangSmith project name (e.g., `surfsense`) |
**Backend Uvicorn Server Configuration:**
| ENV VARIABLE | DESCRIPTION | DEFAULT VALUE |
|------------------------------|---------------------------------------------|---------------|
| UVICORN_HOST | Host address to bind the server | 0.0.0.0 |
| UVICORN_PORT | Port to run the backend API | 8000 |
| UVICORN_LOG_LEVEL | Logging level (e.g., info, debug, warning) | info |
| UVICORN_PROXY_HEADERS | Enable/disable proxy headers | false |
| UVICORN_FORWARDED_ALLOW_IPS | Comma-separated list of allowed IPs | 127.0.0.1 |
| UVICORN_WORKERS | Number of worker processes | 1 |
| UVICORN_ACCESS_LOG | Enable/disable access log (true/false) | true |
| UVICORN_LOOP | Event loop implementation | auto |
| UVICORN_HTTP | HTTP protocol implementation | auto |
| UVICORN_WS | WebSocket protocol implementation | auto |
| UVICORN_LIFESPAN | Lifespan implementation | auto |
| UVICORN_LOG_CONFIG | Path to logging config file or empty string | |
| UVICORN_SERVER_HEADER | Enable/disable Server header | true |
| UVICORN_DATE_HEADER | Enable/disable Date header | true |
| UVICORN_LIMIT_CONCURRENCY | Max concurrent connections | |
| UVICORN_LIMIT_MAX_REQUESTS | Max requests before worker restart | |
| UVICORN_TIMEOUT_KEEP_ALIVE | Keep-alive timeout (seconds) | 5 |
| UVICORN_TIMEOUT_NOTIFY | Worker shutdown notification timeout (sec) | 30 |
| UVICORN_SSL_KEYFILE | Path to SSL key file | |
| UVICORN_SSL_CERTFILE | Path to SSL certificate file | |
| UVICORN_SSL_KEYFILE_PASSWORD | Password for SSL key file | |
| UVICORN_SSL_VERSION | SSL version | |
| UVICORN_SSL_CERT_REQS | SSL certificate requirements | |
| UVICORN_SSL_CA_CERTS | Path to CA certificates file | |
| UVICORN_SSL_CIPHERS | SSL ciphers | |
| UVICORN_HEADERS | Comma-separated list of headers | |
| UVICORN_USE_COLORS | Enable/disable colored logs | true |
| UVICORN_UDS | Unix domain socket path | |
| UVICORN_FD | File descriptor to bind to | |
| UVICORN_ROOT_PATH | Root path for the application | |
For more details, see the [Uvicorn documentation](https://www.uvicorn.org/#command-line-options).
### Frontend Environment Variables
| ENV VARIABLE | DESCRIPTION |

View file

@ -80,6 +80,44 @@ Edit the `.env` file and set the following variables:
| LANGSMITH_API_KEY | Your LangSmith API key |
| LANGSMITH_PROJECT | LangSmith project name (e.g., `surfsense`) |
**Uvicorn Server Configuration**
| ENV VARIABLE | DESCRIPTION | DEFAULT VALUE |
|------------------------------|---------------------------------------------|---------------|
| UVICORN_HOST | Host address to bind the server | 0.0.0.0 |
| UVICORN_PORT | Port to run the backend API | 8000 |
| UVICORN_LOG_LEVEL | Logging level (e.g., info, debug, warning) | info |
| UVICORN_PROXY_HEADERS | Enable/disable proxy headers | false |
| UVICORN_FORWARDED_ALLOW_IPS | Comma-separated list of allowed IPs | 127.0.0.1 |
| UVICORN_WORKERS | Number of worker processes | 1 |
| UVICORN_ACCESS_LOG | Enable/disable access log (true/false) | true |
| UVICORN_LOOP | Event loop implementation | auto |
| UVICORN_HTTP | HTTP protocol implementation | auto |
| UVICORN_WS | WebSocket protocol implementation | auto |
| UVICORN_LIFESPAN | Lifespan implementation | auto |
| UVICORN_LOG_CONFIG | Path to logging config file or empty string | |
| UVICORN_SERVER_HEADER | Enable/disable Server header | true |
| UVICORN_DATE_HEADER | Enable/disable Date header | true |
| UVICORN_LIMIT_CONCURRENCY | Max concurrent connections | |
| UVICORN_LIMIT_MAX_REQUESTS | Max requests before worker restart | |
| UVICORN_TIMEOUT_KEEP_ALIVE | Keep-alive timeout (seconds) | 5 |
| UVICORN_TIMEOUT_NOTIFY | Worker shutdown notification timeout (sec) | 30 |
| UVICORN_SSL_KEYFILE | Path to SSL key file | |
| UVICORN_SSL_CERTFILE | Path to SSL certificate file | |
| UVICORN_SSL_KEYFILE_PASSWORD | Password for SSL key file | |
| UVICORN_SSL_VERSION | SSL version | |
| UVICORN_SSL_CERT_REQS | SSL certificate requirements | |
| UVICORN_SSL_CA_CERTS | Path to CA certificates file | |
| UVICORN_SSL_CIPHERS | SSL ciphers | |
| UVICORN_HEADERS | Comma-separated list of headers | |
| UVICORN_USE_COLORS | Enable/disable colored logs | true |
| UVICORN_UDS | Unix domain socket path | |
| UVICORN_FD | File descriptor to bind to | |
| UVICORN_ROOT_PATH | Root path for the application | |
Refer to the `.env.example` file for all available Uvicorn options and their usage. Uncomment and set in your `.env` file as needed.
For more details, see the [Uvicorn documentation](https://www.uvicorn.org/#command-line-options).
### 2. Install Dependencies
Install the backend dependencies using `uv`: