Skip to content
This repository was archived by the owner on Mar 5, 2026. It is now read-only.
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
109 changes: 87 additions & 22 deletions conf/config_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import os

import dotenv
import yaml


@dataclass
Expand Down Expand Up @@ -40,54 +41,118 @@ class UsageCollectionMongoConfig:
mongo_uri: str = "mongodb://admin:admin@localhost:27017"


@dataclass
class SmartyConfig:
base_url: str = "https://smarty.smartbank.uz"


@dataclass
class AppConfig:
logfire: LogfireConfig
sentry: SentryConfig
otel: OTELConfig
smarty: SmartyConfig
environment: str = "development"
mongo: UsageCollectionMongoConfig | None = None


def New() -> AppConfig:
dotenv.load_dotenv(".env")
# with open(".env", "r") as f:
# print("ENV FILE: ", f.read())

# for key, value in os.environ.items():
# print(f"{key}: {value}")

logfire_config = LogfireConfig(token=os.getenv("LOGFIRE_TOKEN", ""))
sentry_config = SentryConfig(dsn=os.getenv("SENTRY_DSN", ""))
environment = os.getenv("ENVIRONMENT", "development").lower()

# Load per-environment defaults from config.yaml
env_cfg: dict = {}
try:
with open("config.yaml", "r") as f:
all_configs = yaml.safe_load(f) or {}
env_cfg = all_configs.get(environment, {})
except FileNotFoundError:
pass

logfire_cfg = env_cfg.get("logfire", {})
sentry_cfg = env_cfg.get("sentry", {})
otel_cfg = env_cfg.get("otel", {})
mongo_cfg = env_cfg.get("mongo", {})
smarty_cfg = env_cfg.get("smarty", {})
# Resolve console_export: env var overrides yaml, yaml overrides False default
console_export_env = os.getenv("CONSOLE_EXPORT")
if console_export_env is not None:
console_export = console_export_env.lower() in ("true", "1", "yes")
else:
console_export = bool(otel_cfg.get("console_export", False))

logfire_config = LogfireConfig(
token=os.getenv("LOGFIRE_TOKEN", logfire_cfg.get("token", ""))
)
sentry_config = SentryConfig(dsn=os.getenv("SENTRY_DSN", sentry_cfg.get("dsn", "")))
otel_config = OTELConfig(
service_name=os.getenv("SERVICE_NAME", "ui_server"),
service_name=os.getenv(
"SERVICE_NAME", otel_cfg.get("service_name", "ui_server")
),
resource_attributes=os.getenv(
"RESOURCE_ATTRIBUTES",
"deployment.environment=PRODUCTION,service.namespace=ui-server",
otel_cfg.get(
"resource_attributes",
"deployment.environment=production,service.namespace=ui-server",
),
),
bsp_schedule_delay=int(
os.getenv("BSP_SCHEDULE_DELAY", otel_cfg.get("bsp_schedule_delay", 5000))
),
bsp_max_queue_size=int(
os.getenv("BSP_MAX_QUEUE_SIZE", otel_cfg.get("bsp_max_queue_size", 2048))
),
bsp_max_export_batch_size=int(
os.getenv(
"BSP_MAX_EXPORT_BATCH_SIZE",
otel_cfg.get("bsp_max_export_batch_size", 512),
)
),
bsp_export_timeout=int(
os.getenv("BSP_EXPORT_TIMEOUT", otel_cfg.get("bsp_export_timeout", 30000))
),
traces_sampler=os.getenv(
"TRACES_SAMPLER", otel_cfg.get("traces_sampler", "parentbased_traceidratio")
),
traces_sampler_arg=float(
os.getenv("TRACES_SAMPLER_ARG", otel_cfg.get("traces_sampler_arg", 1.0))
),
bsp_schedule_delay=int(os.getenv("BSP_SCHEDULE_DELAY", 5000)),
bsp_max_queue_size=int(os.getenv("BSP_MAX_QUEUE_SIZE", 2048)),
bsp_max_export_batch_size=int(os.getenv("BSP_MAX_EXPORT_BATCH_SIZE", 512)),
bsp_export_timeout=int(os.getenv("BSP_EXPORT_TIMEOUT", 30000)),
traces_sampler=os.getenv("TRACES_SAMPLER", "parentbased_traceidratio"),
traces_sampler_arg=float(os.getenv("TRACES_SAMPLER_ARG", 1.0)),
exporter_otlp_endpoint=os.getenv(
"OTEL_EXPORTER_OTLP_ENDPOINT", "http://localhost:4318/v1/traces"
"OTEL_EXPORTER_OTLP_ENDPOINT",
otel_cfg.get("exporter_otlp_endpoint", "http://localhost:4318/v1/traces"),
),
exporter_otlp_headers=os.getenv("EXPORTER_OTLP_HEADERS", None),
console_export=bool(os.getenv("CONSOLE_EXPORT", False)),
exporter_otlp_headers=os.getenv(
"EXPORTER_OTLP_HEADERS", otel_cfg.get("exporter_otlp_headers")
),
console_export=console_export,
)
return AppConfig(
environment=os.getenv("ENVIRONMENT", "development"),
environment=environment,
logfire=logfire_config,
sentry=sentry_config,
otel=otel_config,
mongo=UsageCollectionMongoConfig(
database_name=os.getenv("MONGO_DATABASE_NAME", "usage"),
collection_name=os.getenv("MONGO_COLLECTION_NAME", "ui_server"),
mongo_uri=os.getenv("MONGO_URI", "mongodb://admin:admin@localhost:27017"),
database_name=os.getenv(
"MONGO_DATABASE_NAME", mongo_cfg.get("database_name", "usage")
),
collection_name=os.getenv(
"MONGO_COLLECTION_NAME", mongo_cfg.get("collection_name", "ui_server")
),
mongo_uri=os.getenv(
"MONGO_URI",
mongo_cfg.get("mongo_uri", "mongodb://admin:admin@localhost:27017"),
),
),
smarty=SmartyConfig(
base_url=os.getenv(
"SMARTY_BASE_URL",
smarty_cfg.get("base_url", "https://smarty.smartbank.uz"),
),
),
)


config = New()

print("Config: ", config)
15 changes: 13 additions & 2 deletions conf/logger_conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,21 @@ def setup_logging(logfile: str) -> structlog.stdlib.BoundLogger:
# --- 1. Create handlers ---
console_handler = logging.StreamHandler(sys.stdout)
log_level = logging.DEBUG
if os.getenv("ENVIRONMENT", "development").lower() == "development":
if os.getenv("LOG_LEVEL", "DEBUG").upper() == "DEBUG":
log_level = logging.DEBUG
else:
elif os.getenv("LOG_LEVEL", "DEBUG").upper() == "INFO":
log_level = logging.INFO
elif os.getenv("LOG_LEVEL", "DEBUG").upper() == "WARNING":
log_level = logging.WARNING
elif os.getenv("LOG_LEVEL", "DEBUG").upper() == "ERROR":
log_level = logging.ERROR
elif os.getenv("LOG_LEVEL", "DEBUG").upper() == "CRITICAL":
log_level = logging.CRITICAL
elif os.getenv("LOG_LEVEL", "DEBUG").upper() == "FATAL":
log_level = logging.FATAL
else:
log_level = logging.DEBUG

console_handler.setLevel(log_level)
console_handler.setFormatter(logging.Formatter(fmt="%(message)s"))

Expand Down
47 changes: 47 additions & 0 deletions config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
development:
logfire:
token: ""
sentry:
dsn: ""
otel:
service_name: ui_server
resource_attributes: "deployment.environment=development,service.namespace=ui-server"
bsp_schedule_delay: 5000
bsp_max_queue_size: 2048
bsp_max_export_batch_size: 512
bsp_export_timeout: 30000
traces_sampler: parentbased_traceidratio
traces_sampler_arg: 1.0
exporter_otlp_endpoint: "http://localhost:4318/v1/traces"
exporter_otlp_headers: null
console_export: false
mongo:
database_name: usage
collection_name: ui_server
mongo_uri: "mongodb://admin:admin@localhost:27017"
smarty:
base_url: "https://smarty-test.smartbank.uz"

production:
logfire:
token: ""
sentry:
dsn: ""
otel:
service_name: ui_server
resource_attributes: "deployment.environment=production,service.namespace=ui-server"
bsp_schedule_delay: 5000
bsp_max_queue_size: 2048
bsp_max_export_batch_size: 512
bsp_export_timeout: 30000
traces_sampler: parentbased_traceidratio
traces_sampler_arg: 1.0
exporter_otlp_endpoint: "http://tempo:4318/v1/traces"
exporter_otlp_headers: null
console_export: false
mongo:
database_name: usage
collection_name: ui_server
mongo_uri: "mongodb://admin:admin@mongo:27017"
smarty:
base_url: "https://smarty.smartbank.uz"
3 changes: 2 additions & 1 deletion functions_to_format/functions/products.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import structlog
from models.context import Context
from .base_strategy import FunctionStrategy
from conf import config

# Import smarty_ui components
from smarty_ui import (
Expand Down Expand Up @@ -393,7 +394,7 @@ def make_product_state(
typed=dv.DivActionSubmit(
container_id=cart_container,
request=dv.DivActionSubmitRequest(
url=f"https://smarty.smartbank.uz/chat/v3/tools/call?function_name=add_product_to_cart&chat_id={chat_id}&arguments={json.dumps({'offer_id': p.offer_id, 'quantity': 1})}",
url=f"{config.smarty.base_url}/chat/v3/tools/call?function_name=add_product_to_cart&chat_id={chat_id}&arguments={json.dumps({'offer_id': p.offer_id, 'quantity': 1})}",
method=dv.RequestMethod.POST,
headers=[dv.RequestHeader(name="api-key", value=api_key)],
),
Expand Down
9 changes: 7 additions & 2 deletions src/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,12 @@
version = "0"
logger.info("Starting server", env=os.getenv("ENVIRONMENT"), version=version)

app = FastAPI()
app = FastAPI(
title="UI Server",
description="UI Server to generate UI json representations using Yandex Divkit",
version=version,
openapi_url="/ui_server/openapi.json",
)

# Setup telemetry
setup_telemetry(app, service_name="ui_server", version=version)
Expand Down Expand Up @@ -72,7 +77,7 @@
logger.info(f"Deleted file: {file}")

# Serve static files
app.mount("/ui_server/static", StaticFiles(directory="static"), name="static")
app.mount("/static", StaticFiles(directory="static"), name="static")


# https://www.youtbe.com/watch?v=NTP4XdTjRK0
Expand Down
3 changes: 2 additions & 1 deletion telemetry/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,9 @@ def setup_telemetry(
_prometheus_reader = PrometheusMetricReader()
metric_readers.append(_prometheus_reader)

if environment == "development" or config.otel.console_export:
if config.otel.console_export:
# Add console exporter for development
print("Adding console exporter for development")
console_metric_exporter = ConsoleMetricExporter()
metric_readers.append(
PeriodicExportingMetricReader(
Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading