UPDATE
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
|
||||
|
||||
def _isoformat(value: Any) -> Any:
|
||||
if isinstance(value, datetime):
|
||||
return value.isoformat()
|
||||
return value
|
||||
|
||||
|
||||
def build_integration_meta(
|
||||
*,
|
||||
flow_type: str,
|
||||
source_type: str,
|
||||
source_service: str,
|
||||
ownership: str,
|
||||
live: bool,
|
||||
cached: bool,
|
||||
generated_at: Any = None,
|
||||
snapshot_at: Any = None,
|
||||
notes: list[str] | None = None,
|
||||
) -> dict[str, Any]:
|
||||
meta = {
|
||||
"flow_type": flow_type,
|
||||
"source_type": source_type,
|
||||
"source_service": source_service,
|
||||
"ownership": ownership,
|
||||
"live": live,
|
||||
"cached": cached,
|
||||
}
|
||||
if generated_at is not None:
|
||||
meta["generated_at"] = _isoformat(generated_at)
|
||||
if snapshot_at is not None:
|
||||
meta["snapshot_at"] = _isoformat(snapshot_at)
|
||||
if notes:
|
||||
meta["notes"] = notes
|
||||
return meta
|
||||
@@ -226,7 +226,7 @@ services:
|
||||
use_user_embeddings: true
|
||||
description: "سرویس روایت داشبورد عملکرد و برداشت"
|
||||
fallback_behavior:
|
||||
on_invalid_json: "return_mocked_narrative"
|
||||
on_invalid_json: "raise_validation_error"
|
||||
on_missing_context: "use_only_deterministic_data"
|
||||
on_number_conflict: "prefer_deterministic_data"
|
||||
prompt_template: "config/tones/yield_harvest_tone.txt"
|
||||
|
||||
+34
-2
@@ -1,6 +1,7 @@
|
||||
import os
|
||||
import importlib.util
|
||||
from pathlib import Path
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
|
||||
try:
|
||||
from dotenv import load_dotenv
|
||||
@@ -30,6 +31,7 @@ FILE_LOGGING_ENABLED = _can_use_file_logging(LOG_DIR)
|
||||
|
||||
SECRET_KEY = os.environ.get("SECRET_KEY", "django-insecure-dev-only")
|
||||
DEBUG = os.environ.get("DEBUG", "0") == "1"
|
||||
DEVELOP = os.environ.get("DEVELOP", "false").strip().lower() in {"1", "true", "yes", "on"}
|
||||
ALLOWED_HOSTS = os.environ.get("ALLOWED_HOSTS", "localhost,127.0.0.1").split(",")
|
||||
|
||||
INSTALLED_APPS = [
|
||||
@@ -56,6 +58,8 @@ INSTALLED_APPS = [
|
||||
for optional_app in [
|
||||
"rest_framework",
|
||||
"corsheaders",
|
||||
"drf_spectacular",
|
||||
"drf_spectacular_sidecar",
|
||||
]:
|
||||
if importlib.util.find_spec(optional_app):
|
||||
INSTALLED_APPS.insert(6, optional_app)
|
||||
@@ -73,6 +77,9 @@ MIDDLEWARE = [
|
||||
if importlib.util.find_spec("corsheaders"):
|
||||
MIDDLEWARE.insert(1, "corsheaders.middleware.CorsMiddleware")
|
||||
|
||||
if importlib.util.find_spec("whitenoise"):
|
||||
MIDDLEWARE.insert(1, "whitenoise.middleware.WhiteNoiseMiddleware")
|
||||
|
||||
ROOT_URLCONF = "config.urls"
|
||||
WSGI_APPLICATION = "config.wsgi.application"
|
||||
|
||||
@@ -121,6 +128,9 @@ USE_TZ = True
|
||||
STATIC_URL = "static/"
|
||||
STATIC_ROOT = BASE_DIR / "staticfiles"
|
||||
|
||||
if importlib.util.find_spec("whitenoise"):
|
||||
STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"
|
||||
|
||||
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
||||
|
||||
CACHES = {
|
||||
@@ -134,6 +144,22 @@ REST_FRAMEWORK = {
|
||||
"DEFAULT_PERMISSION_CLASSES": [
|
||||
"rest_framework.permissions.AllowAny",
|
||||
],
|
||||
"DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
|
||||
}
|
||||
|
||||
SPECTACULAR_SETTINGS = {
|
||||
"TITLE": "CropLogic AI API",
|
||||
"DESCRIPTION": "Swagger/OpenAPI documentation for all CropLogic AI API endpoints.",
|
||||
"VERSION": "1.0.0",
|
||||
"SERVE_INCLUDE_SCHEMA": False,
|
||||
"SWAGGER_UI_DIST": "SIDECAR",
|
||||
"SWAGGER_UI_FAVICON_HREF": "SIDECAR",
|
||||
"REDOC_DIST": "SIDECAR",
|
||||
"SCHEMA_PATH_PREFIX": r"/api/",
|
||||
"SERVE_PERMISSIONS": ["rest_framework.permissions.AllowAny"],
|
||||
"SWAGGER_UI_SETTINGS": {
|
||||
"persistAuthorization": True,
|
||||
},
|
||||
}
|
||||
|
||||
CORS_ALLOW_ALL_ORIGINS = DEBUG
|
||||
@@ -161,16 +187,22 @@ WEATHER_API_BASE_URL = os.environ.get(
|
||||
"WEATHER_API_BASE_URL", "https://api.open-meteo.com/v1/forecast"
|
||||
)
|
||||
WEATHER_API_KEY = os.environ.get("WEATHER_API_KEY", "")
|
||||
WEATHER_DATA_PROVIDER = os.environ.get("WEATHER_DATA_PROVIDER", "mock").strip().lower()
|
||||
WEATHER_DATA_PROVIDER = os.environ.get("WEATHER_DATA_PROVIDER", "open-meteo").strip().lower()
|
||||
WEATHER_MOCK_DELAY_SECONDS = float(os.environ.get("WEATHER_MOCK_DELAY_SECONDS", "0.8"))
|
||||
WEATHER_TIMEOUT_SECONDS = float(os.environ.get("WEATHER_TIMEOUT_SECONDS", "60"))
|
||||
SOIL_DATA_PROVIDER = os.environ.get("SOIL_DATA_PROVIDER", "mock").strip().lower()
|
||||
SOIL_DATA_PROVIDER = os.environ.get("SOIL_DATA_PROVIDER", "soilgrids").strip().lower()
|
||||
SOIL_MOCK_DELAY_SECONDS = float(os.environ.get("SOIL_MOCK_DELAY_SECONDS", "0.8"))
|
||||
SOILGRIDS_TIMEOUT_SECONDS = float(os.environ.get("SOILGRIDS_TIMEOUT_SECONDS", "60"))
|
||||
BACKEND_PLANT_SYNC_BASE_URL = os.environ.get("BACKEND_PLANT_SYNC_BASE_URL", "")
|
||||
BACKEND_PLANT_SYNC_API_KEY = os.environ.get("BACKEND_PLANT_SYNC_API_KEY", "")
|
||||
BACKEND_PLANT_SYNC_TIMEOUT = int(os.environ.get("BACKEND_PLANT_SYNC_TIMEOUT", "20"))
|
||||
|
||||
if not (DEBUG or DEVELOP):
|
||||
if WEATHER_DATA_PROVIDER == "mock":
|
||||
raise ImproperlyConfigured("WEATHER_DATA_PROVIDER=mock is allowed only in dev/test environments.")
|
||||
if SOIL_DATA_PROVIDER == "mock":
|
||||
raise ImproperlyConfigured("SOIL_DATA_PROVIDER=mock is allowed only in dev/test environments.")
|
||||
|
||||
LOGGING = {
|
||||
"version": 1,
|
||||
"disable_existing_loggers": False,
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
from django.contrib import admin
|
||||
from django.urls import include, path
|
||||
from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView, SpectacularRedocView
|
||||
|
||||
urlpatterns = [
|
||||
path("admin/", admin.site.urls),
|
||||
path("api/schema/", SpectacularAPIView.as_view(), name="schema"),
|
||||
path("api/docs/swagger/", SpectacularSwaggerView.as_view(url_name="schema"), name="swagger-ui"),
|
||||
path("api/docs/redoc/", SpectacularRedocView.as_view(url_name="schema"), name="redoc"),
|
||||
# --- App APIs ---
|
||||
path("api/rag/", include("rag.urls")),
|
||||
path("api/farm-alerts/", include("farm_alerts.urls")),
|
||||
|
||||
Reference in New Issue
Block a user