config_service.py 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. from sqlalchemy.orm import Session
  2. from sqlalchemy import select, update
  3. from typing import Dict, List, Optional, Any
  4. import json
  5. from app.models.config import SystemConfig, ConfigHistory
  6. from app.schemas.config_schema import ConfigItem, ConfigUpdate
  7. from app.services.system_config_manager import clear_config_cache
  8. class ConfigService:
  9. def __init__(self, db: Session):
  10. self.db = db
  11. def get_all_configs(self) -> Dict[str, List[ConfigItem]]:
  12. """获取所有配置项,按分类分组"""
  13. configs = self.db.query(SystemConfig).all()
  14. grouped = {}
  15. for config in configs:
  16. category = config.category
  17. if category not in grouped:
  18. grouped[category] = []
  19. value = self._parse_value(config.config_value, config.config_type)
  20. grouped[category].append(ConfigItem(
  21. key=config.config_key,
  22. value=value,
  23. type=config.config_type,
  24. category=config.category,
  25. description=config.description,
  26. updated_at=config.updated_at
  27. ))
  28. return grouped
  29. def get_config(self, key: str) -> Optional[ConfigItem]:
  30. """获取单个配置项"""
  31. config = self.db.query(SystemConfig).filter(
  32. SystemConfig.config_key == key
  33. ).first()
  34. if not config:
  35. return None
  36. value = self._parse_value(config.config_value, config.config_type)
  37. return ConfigItem(
  38. key=config.config_key,
  39. value=value,
  40. type=config.config_type,
  41. category=config.category,
  42. description=config.description,
  43. updated_at=config.updated_at
  44. )
  45. def update_configs(self, configs: List[ConfigUpdate], admin_id: int):
  46. """批量更新配置项"""
  47. for config_update in configs:
  48. self._update_single_config(
  49. config_update.key,
  50. config_update.value,
  51. admin_id
  52. )
  53. self.db.commit()
  54. # 清除所有配置缓存
  55. clear_config_cache()
  56. def _update_single_config(self, key: str, value: Any, admin_id: int):
  57. """更新单个配置项"""
  58. config = self.db.query(SystemConfig).filter(
  59. SystemConfig.config_key == key
  60. ).first()
  61. if not config:
  62. # 自动创建配置项
  63. from app.services.system_config_manager import SystemConfigManager
  64. config_manager = SystemConfigManager()
  65. default_value = config_manager.DEFAULT_VALUES.get(key)
  66. if default_value is None:
  67. raise ValueError(f"配置项 {key} 不存在且没有默认值")
  68. # 确定配置类型
  69. if isinstance(default_value, bool):
  70. config_type = "boolean"
  71. elif isinstance(default_value, (int, float)):
  72. config_type = "number"
  73. elif isinstance(default_value, str):
  74. config_type = "string"
  75. else:
  76. config_type = "json"
  77. # 创建配置项
  78. config = SystemConfig(
  79. config_key=key,
  80. config_value=self._serialize_value(default_value, config_type),
  81. config_type=config_type,
  82. category="系统设置",
  83. description="",
  84. updated_by=admin_id
  85. )
  86. self.db.add(config)
  87. old_value = ""
  88. else:
  89. self._validate_value(value, config.config_type)
  90. old_value = config.config_value
  91. new_value = self._serialize_value(value, config.config_type)
  92. history = ConfigHistory(
  93. config_key=key,
  94. old_value=old_value,
  95. new_value=new_value,
  96. updated_by=admin_id
  97. )
  98. self.db.add(history)
  99. config.config_value = new_value
  100. config.updated_by = admin_id
  101. def get_config_history(self, key: str, page: int = 1, size: int = 20):
  102. """获取配置修改历史"""
  103. offset = (page - 1) * size
  104. history_list = self.db.query(ConfigHistory).filter(
  105. ConfigHistory.config_key == key
  106. ).order_by(ConfigHistory.updated_at.desc()).offset(offset).limit(size).all()
  107. total = self.db.query(ConfigHistory).filter(
  108. ConfigHistory.config_key == key
  109. ).count()
  110. return {
  111. "items": history_list,
  112. "total": total,
  113. "page": page,
  114. "size": size
  115. }
  116. def reset_config(self, key: str, admin_id: int):
  117. """重置配置为默认值"""
  118. default_values = {
  119. "system_name": "智创空间",
  120. "enable_registration": True,
  121. "enable_search": True,
  122. "enable_local_models": True,
  123. "max_tokens_per_request": 4000,
  124. "max_images_per_request": 4,
  125. "max_audio_chars": 5000,
  126. "max_video_duration": 10
  127. }
  128. if key not in default_values:
  129. raise ValueError(f"配置项 {key} 没有默认值")
  130. self._update_single_config(key, default_values[key], admin_id)
  131. self.db.commit()
  132. def _parse_value(self, value_str: str, value_type: str) -> Any:
  133. """解析配置值,对空值容错"""
  134. if not value_str or value_str.strip() == "":
  135. if value_type == "string":
  136. return ""
  137. elif value_type == "number":
  138. return 0
  139. elif value_type == "boolean":
  140. return False
  141. return ""
  142. if value_type == "string":
  143. # 字符串类型:如果是 JSON 格式的字符串(带引号),解析它;否则直接返回原值
  144. try:
  145. return json.loads(value_str)
  146. except (json.JSONDecodeError, ValueError):
  147. return value_str
  148. elif value_type == "number":
  149. try:
  150. return json.loads(value_str)
  151. except (json.JSONDecodeError, ValueError):
  152. return 0
  153. elif value_type == "boolean":
  154. if value_str.lower() in ("true", "1", "yes"):
  155. return True
  156. elif value_str.lower() in ("false", "0", "no"):
  157. return False
  158. try:
  159. return json.loads(value_str)
  160. except (json.JSONDecodeError, ValueError):
  161. return False
  162. elif value_type == "json":
  163. try:
  164. return json.loads(value_str)
  165. except (json.JSONDecodeError, ValueError):
  166. return {}
  167. return value_str
  168. def _serialize_value(self, value: Any, value_type: str) -> str:
  169. """序列化配置值"""
  170. if value_type == "boolean" and isinstance(value, str):
  171. value = value.lower() in ("true", "1")
  172. elif value_type == "number" and isinstance(value, str):
  173. value = float(value) if '.' in value else int(value)
  174. return json.dumps(value, ensure_ascii=False)
  175. def _validate_value(self, value: Any, value_type: str):
  176. """验证配置值类型"""
  177. if value_type == "string" and not isinstance(value, str):
  178. raise ValueError("配置值必须是字符串类型")
  179. elif value_type == "number":
  180. if isinstance(value, str):
  181. try:
  182. float(value)
  183. except ValueError:
  184. raise ValueError("配置值必须是数字类型")
  185. elif not isinstance(value, (int, float)):
  186. raise ValueError("配置值必须是数字类型")
  187. elif value_type == "boolean":
  188. if isinstance(value, str):
  189. if value.lower() not in ("true", "false", "1", "0"):
  190. raise ValueError("配置值必须是布尔类型")
  191. elif not isinstance(value, bool):
  192. raise ValueError("配置值必须是布尔类型")