config.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. """DMS环境配置。"""
  2. from __future__ import annotations
  3. import os
  4. from pathlib import Path
  5. from typing import Any
  6. from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
  7. import shutil
  8. BACKEND_ROOT = Path(__file__).resolve().parents[1]
  9. DEFAULT_STORAGE_ROOT = BACKEND_ROOT / "dms-storage"
  10. DEFAULT_UI_DICTIONARY_CONFIG_PATH = (
  11. BACKEND_ROOT / "dms" / "resources" / "ui-dictionaries.zh-CN.json"
  12. )
  13. DEFAULT_DOCUMENT_RELATION_PRESET_CONFIG_PATH = (
  14. BACKEND_ROOT / "dms" / "resources" / "document-relation-presets.zh-CN.json"
  15. )
  16. DEFAULT_DATABASE_URL = (
  17. "mysql+pymysql://dms_app:change-me@127.0.0.1:3306/dms?charset=utf8mb4"
  18. )
  19. def _positive_int(name: str, default: int) -> int:
  20. raw_value = os.environ.get(name)
  21. if raw_value is None or not raw_value.strip():
  22. return default
  23. try:
  24. value = int(raw_value)
  25. except ValueError as exc:
  26. raise ValueError(f"{name}必须是正整数") from exc
  27. if value <= 0:
  28. raise ValueError(f"{name}必须是正整数")
  29. return value
  30. def load_dms_config() -> dict[str, Any]:
  31. """从环境变量加载DMS配置,不读取或覆盖现有AI配置。"""
  32. storage_value = os.environ.get("DMS_STORAGE_ROOT", "").strip()
  33. storage_root = Path(storage_value or DEFAULT_STORAGE_ROOT).expanduser()
  34. max_upload_size = _positive_int(
  35. "DMS_MAX_UPLOAD_SIZE", 100 * 1024 * 1024
  36. )
  37. max_file_size = _positive_int(
  38. "DMS_MAX_FILE_SIZE", min(50 * 1024 * 1024, max_upload_size)
  39. )
  40. if max_file_size > max_upload_size:
  41. raise ValueError("DMS_MAX_FILE_SIZE不得超过DMS_MAX_UPLOAD_SIZE")
  42. database_url = os.environ.get("DMS_DATABASE_URL", "").strip()
  43. ui_dictionary_config_value = os.environ.get(
  44. "DMS_UI_DICTIONARY_CONFIG_PATH", ""
  45. ).strip()
  46. ui_dictionary_config_path = Path(
  47. ui_dictionary_config_value or DEFAULT_UI_DICTIONARY_CONFIG_PATH
  48. ).expanduser()
  49. relation_preset_config_value = os.environ.get(
  50. "DMS_DOCUMENT_RELATION_PRESET_CONFIG_PATH", ""
  51. ).strip()
  52. relation_preset_config_path = Path(
  53. relation_preset_config_value
  54. or DEFAULT_DOCUMENT_RELATION_PRESET_CONFIG_PATH
  55. ).expanduser()
  56. business_timezone = (
  57. os.environ.get("DMS_BUSINESS_TIMEZONE", "").strip()
  58. or "Asia/Shanghai"
  59. )
  60. try:
  61. ZoneInfo(business_timezone)
  62. except (ZoneInfoNotFoundError, ValueError) as exc:
  63. raise ValueError("DMS_BUSINESS_TIMEZONE必须是有效的IANA时区") from exc
  64. office_preview_enabled = (
  65. os.environ.get("DMS_OFFICE_PREVIEW_ENABLED", "true").strip().lower()
  66. in {"1", "true", "yes", "on"}
  67. )
  68. libreoffice_executable = (
  69. os.environ.get("DMS_LIBREOFFICE_EXECUTABLE", "").strip()
  70. or shutil.which("soffice")
  71. or shutil.which("libreoffice")
  72. or ""
  73. )
  74. libreoffice_timeout_seconds = _positive_int(
  75. "DMS_LIBREOFFICE_TIMEOUT_SECONDS", 60
  76. )
  77. libreoffice_max_concurrency = _positive_int(
  78. "DMS_LIBREOFFICE_MAX_CONCURRENCY", 2
  79. )
  80. pdf_viewer_engine_raw = (
  81. os.environ.get("DMS_PDF_VIEWER_ENGINE", "iframe").strip().lower()
  82. )
  83. pdf_viewer_engine = (
  84. pdf_viewer_engine_raw if pdf_viewer_engine_raw in {"iframe", "pdfjs"} else "iframe"
  85. )
  86. return {
  87. "SQLALCHEMY_DATABASE_URI": database_url or DEFAULT_DATABASE_URL,
  88. "SQLALCHEMY_TRACK_MODIFICATIONS": False,
  89. "SQLALCHEMY_ENGINE_OPTIONS": {
  90. "isolation_level": "READ COMMITTED",
  91. "pool_pre_ping": True,
  92. "pool_recycle": 1800,
  93. "connect_args": {
  94. "init_command": "SET time_zone = '+00:00'",
  95. },
  96. },
  97. "DMS_STORAGE_ROOT": str(storage_root.resolve()),
  98. "DMS_MAX_UPLOAD_SIZE": max_upload_size,
  99. "DMS_MAX_FILE_SIZE": max_file_size,
  100. "MAX_CONTENT_LENGTH": max_upload_size,
  101. "DMS_BATCH_MAX_FILES": _positive_int("DMS_BATCH_MAX_FILES", 50),
  102. "DMS_BUSINESS_TIMEZONE": business_timezone,
  103. "DMS_JWT_SECRET": os.environ.get("DMS_JWT_SECRET", ""),
  104. "DMS_JWT_ISSUER": "dms",
  105. "DMS_JWT_EXPIRES_SECONDS": 7200,
  106. "DMS_JWT_KEEP_SIGNED_IN_EXPIRES_SECONDS": 604800,
  107. "DMS_UI_DICTIONARY_CONFIG_PATH": str(
  108. ui_dictionary_config_path.resolve()
  109. ),
  110. "DMS_DOCUMENT_RELATION_PRESET_CONFIG_PATH": str(
  111. relation_preset_config_path.resolve()
  112. ),
  113. "DMS_OFFICE_PREVIEW_ENABLED": office_preview_enabled,
  114. "DMS_LIBREOFFICE_EXECUTABLE": libreoffice_executable,
  115. "DMS_LIBREOFFICE_TIMEOUT_SECONDS": libreoffice_timeout_seconds,
  116. "DMS_LIBREOFFICE_MAX_CONCURRENCY": libreoffice_max_concurrency,
  117. "DMS_PDF_VIEWER_ENGINE": pdf_viewer_engine,
  118. }