django-cfg 1.1.82__py3-none-any.whl → 1.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (244) hide show
  1. django_cfg/__init__.py +20 -448
  2. django_cfg/apps/accounts/README.md +3 -3
  3. django_cfg/apps/accounts/admin/__init__.py +0 -2
  4. django_cfg/apps/accounts/admin/activity.py +2 -9
  5. django_cfg/apps/accounts/admin/filters.py +0 -42
  6. django_cfg/apps/accounts/admin/inlines.py +8 -8
  7. django_cfg/apps/accounts/admin/otp.py +5 -5
  8. django_cfg/apps/accounts/admin/registration_source.py +1 -8
  9. django_cfg/apps/accounts/admin/user.py +12 -20
  10. django_cfg/apps/accounts/managers/user_manager.py +2 -129
  11. django_cfg/apps/accounts/migrations/0006_remove_twilioresponse_otp_secret_and_more.py +46 -0
  12. django_cfg/apps/accounts/models.py +3 -123
  13. django_cfg/apps/accounts/serializers/otp.py +40 -44
  14. django_cfg/apps/accounts/serializers/profile.py +0 -2
  15. django_cfg/apps/accounts/services/otp_service.py +98 -186
  16. django_cfg/apps/accounts/signals.py +25 -15
  17. django_cfg/apps/accounts/utils/auth_email_service.py +84 -0
  18. django_cfg/apps/accounts/views/otp.py +35 -36
  19. django_cfg/apps/agents/README.md +129 -0
  20. django_cfg/apps/agents/__init__.py +68 -0
  21. django_cfg/apps/agents/admin/__init__.py +17 -0
  22. django_cfg/apps/agents/admin/execution_admin.py +460 -0
  23. django_cfg/apps/agents/admin/registry_admin.py +360 -0
  24. django_cfg/apps/agents/admin/toolsets_admin.py +482 -0
  25. django_cfg/apps/agents/apps.py +29 -0
  26. django_cfg/apps/agents/core/__init__.py +20 -0
  27. django_cfg/apps/agents/core/agent.py +281 -0
  28. django_cfg/apps/agents/core/dependencies.py +154 -0
  29. django_cfg/apps/agents/core/exceptions.py +66 -0
  30. django_cfg/apps/agents/core/models.py +106 -0
  31. django_cfg/apps/agents/core/orchestrator.py +391 -0
  32. django_cfg/apps/agents/examples/__init__.py +3 -0
  33. django_cfg/apps/agents/examples/simple_example.py +161 -0
  34. django_cfg/apps/agents/integration/__init__.py +14 -0
  35. django_cfg/apps/agents/integration/middleware.py +80 -0
  36. django_cfg/apps/agents/integration/registry.py +345 -0
  37. django_cfg/apps/agents/integration/signals.py +50 -0
  38. django_cfg/apps/agents/management/__init__.py +3 -0
  39. django_cfg/apps/agents/management/commands/__init__.py +3 -0
  40. django_cfg/apps/agents/management/commands/create_agent.py +365 -0
  41. django_cfg/apps/agents/management/commands/orchestrator_status.py +191 -0
  42. django_cfg/apps/agents/managers/__init__.py +23 -0
  43. django_cfg/apps/agents/managers/execution.py +236 -0
  44. django_cfg/apps/agents/managers/registry.py +254 -0
  45. django_cfg/apps/agents/managers/toolsets.py +496 -0
  46. django_cfg/apps/agents/migrations/0001_initial.py +286 -0
  47. django_cfg/apps/agents/migrations/__init__.py +5 -0
  48. django_cfg/apps/agents/models/__init__.py +15 -0
  49. django_cfg/apps/agents/models/execution.py +215 -0
  50. django_cfg/apps/agents/models/registry.py +220 -0
  51. django_cfg/apps/agents/models/toolsets.py +305 -0
  52. django_cfg/apps/agents/patterns/__init__.py +24 -0
  53. django_cfg/apps/agents/patterns/content_agents.py +234 -0
  54. django_cfg/apps/agents/toolsets/__init__.py +15 -0
  55. django_cfg/apps/agents/toolsets/cache_toolset.py +285 -0
  56. django_cfg/apps/agents/toolsets/django_toolset.py +220 -0
  57. django_cfg/apps/agents/toolsets/file_toolset.py +324 -0
  58. django_cfg/apps/agents/toolsets/orm_toolset.py +319 -0
  59. django_cfg/apps/agents/urls.py +46 -0
  60. django_cfg/apps/knowbase/README.md +150 -0
  61. django_cfg/apps/knowbase/__init__.py +27 -0
  62. django_cfg/apps/knowbase/admin/__init__.py +23 -0
  63. django_cfg/apps/knowbase/admin/archive_admin.py +857 -0
  64. django_cfg/apps/knowbase/admin/chat_admin.py +386 -0
  65. django_cfg/apps/knowbase/admin/document_admin.py +650 -0
  66. django_cfg/apps/knowbase/admin/external_data_admin.py +685 -0
  67. django_cfg/apps/knowbase/apps.py +81 -0
  68. django_cfg/apps/knowbase/config/README.md +176 -0
  69. django_cfg/apps/knowbase/config/__init__.py +51 -0
  70. django_cfg/apps/knowbase/config/constance_fields.py +186 -0
  71. django_cfg/apps/knowbase/config/constance_settings.py +200 -0
  72. django_cfg/apps/knowbase/config/settings.py +444 -0
  73. django_cfg/apps/knowbase/examples/__init__.py +3 -0
  74. django_cfg/apps/knowbase/examples/external_data_usage.py +191 -0
  75. django_cfg/apps/knowbase/management/__init__.py +0 -0
  76. django_cfg/apps/knowbase/management/commands/__init__.py +0 -0
  77. django_cfg/apps/knowbase/management/commands/knowbase_stats.py +158 -0
  78. django_cfg/apps/knowbase/management/commands/setup_knowbase.py +59 -0
  79. django_cfg/apps/knowbase/managers/__init__.py +22 -0
  80. django_cfg/apps/knowbase/managers/archive.py +426 -0
  81. django_cfg/apps/knowbase/managers/base.py +32 -0
  82. django_cfg/apps/knowbase/managers/chat.py +141 -0
  83. django_cfg/apps/knowbase/managers/document.py +203 -0
  84. django_cfg/apps/knowbase/managers/external_data.py +471 -0
  85. django_cfg/apps/knowbase/migrations/0001_initial.py +427 -0
  86. django_cfg/apps/knowbase/migrations/0002_archiveitem_archiveitemchunk_documentarchive_and_more.py +434 -0
  87. django_cfg/apps/knowbase/migrations/__init__.py +5 -0
  88. django_cfg/apps/knowbase/mixins/__init__.py +15 -0
  89. django_cfg/apps/knowbase/mixins/config.py +108 -0
  90. django_cfg/apps/knowbase/mixins/creator.py +81 -0
  91. django_cfg/apps/knowbase/mixins/examples/vehicle_model_example.py +199 -0
  92. django_cfg/apps/knowbase/mixins/external_data_mixin.py +813 -0
  93. django_cfg/apps/knowbase/mixins/service.py +362 -0
  94. django_cfg/apps/knowbase/models/__init__.py +41 -0
  95. django_cfg/apps/knowbase/models/archive.py +599 -0
  96. django_cfg/apps/knowbase/models/base.py +58 -0
  97. django_cfg/apps/knowbase/models/chat.py +157 -0
  98. django_cfg/apps/knowbase/models/document.py +267 -0
  99. django_cfg/apps/knowbase/models/external_data.py +376 -0
  100. django_cfg/apps/knowbase/serializers/__init__.py +68 -0
  101. django_cfg/apps/knowbase/serializers/archive_serializers.py +386 -0
  102. django_cfg/apps/knowbase/serializers/chat_serializers.py +137 -0
  103. django_cfg/apps/knowbase/serializers/document_serializers.py +94 -0
  104. django_cfg/apps/knowbase/serializers/external_data_serializers.py +256 -0
  105. django_cfg/apps/knowbase/serializers/public_serializers.py +74 -0
  106. django_cfg/apps/knowbase/services/__init__.py +40 -0
  107. django_cfg/apps/knowbase/services/archive/__init__.py +42 -0
  108. django_cfg/apps/knowbase/services/archive/archive_service.py +541 -0
  109. django_cfg/apps/knowbase/services/archive/chunking_service.py +791 -0
  110. django_cfg/apps/knowbase/services/archive/exceptions.py +52 -0
  111. django_cfg/apps/knowbase/services/archive/extraction_service.py +508 -0
  112. django_cfg/apps/knowbase/services/archive/vectorization_service.py +362 -0
  113. django_cfg/apps/knowbase/services/base.py +53 -0
  114. django_cfg/apps/knowbase/services/chat_service.py +239 -0
  115. django_cfg/apps/knowbase/services/document_service.py +144 -0
  116. django_cfg/apps/knowbase/services/embedding/__init__.py +43 -0
  117. django_cfg/apps/knowbase/services/embedding/async_processor.py +244 -0
  118. django_cfg/apps/knowbase/services/embedding/batch_processor.py +250 -0
  119. django_cfg/apps/knowbase/services/embedding/batch_result.py +61 -0
  120. django_cfg/apps/knowbase/services/embedding/models.py +229 -0
  121. django_cfg/apps/knowbase/services/embedding/processors.py +148 -0
  122. django_cfg/apps/knowbase/services/embedding/utils.py +176 -0
  123. django_cfg/apps/knowbase/services/prompt_builder.py +191 -0
  124. django_cfg/apps/knowbase/services/search_service.py +293 -0
  125. django_cfg/apps/knowbase/signals/__init__.py +21 -0
  126. django_cfg/apps/knowbase/signals/archive_signals.py +211 -0
  127. django_cfg/apps/knowbase/signals/chat_signals.py +37 -0
  128. django_cfg/apps/knowbase/signals/document_signals.py +143 -0
  129. django_cfg/apps/knowbase/signals/external_data_signals.py +157 -0
  130. django_cfg/apps/knowbase/tasks/__init__.py +39 -0
  131. django_cfg/apps/knowbase/tasks/archive_tasks.py +316 -0
  132. django_cfg/apps/knowbase/tasks/document_processing.py +341 -0
  133. django_cfg/apps/knowbase/tasks/external_data_tasks.py +341 -0
  134. django_cfg/apps/knowbase/tasks/maintenance.py +195 -0
  135. django_cfg/apps/knowbase/urls.py +43 -0
  136. django_cfg/apps/knowbase/utils/__init__.py +12 -0
  137. django_cfg/apps/knowbase/utils/chunk_settings.py +261 -0
  138. django_cfg/apps/knowbase/utils/text_processing.py +375 -0
  139. django_cfg/apps/knowbase/utils/validation.py +99 -0
  140. django_cfg/apps/knowbase/views/__init__.py +28 -0
  141. django_cfg/apps/knowbase/views/archive_views.py +469 -0
  142. django_cfg/apps/knowbase/views/base.py +49 -0
  143. django_cfg/apps/knowbase/views/chat_views.py +181 -0
  144. django_cfg/apps/knowbase/views/document_views.py +183 -0
  145. django_cfg/apps/knowbase/views/public_views.py +129 -0
  146. django_cfg/apps/leads/admin.py +70 -0
  147. django_cfg/apps/newsletter/admin.py +234 -0
  148. django_cfg/apps/newsletter/admin_filters.py +124 -0
  149. django_cfg/apps/support/admin.py +196 -0
  150. django_cfg/apps/support/admin_filters.py +71 -0
  151. django_cfg/apps/support/templates/support/chat/ticket_chat.html +1 -1
  152. django_cfg/apps/urls.py +5 -4
  153. django_cfg/cli/README.md +1 -1
  154. django_cfg/cli/commands/create_project.py +2 -2
  155. django_cfg/cli/commands/info.py +1 -1
  156. django_cfg/config.py +44 -0
  157. django_cfg/core/config.py +29 -82
  158. django_cfg/core/environment.py +1 -1
  159. django_cfg/core/generation.py +19 -107
  160. django_cfg/{integration.py → core/integration.py} +18 -16
  161. django_cfg/core/validation.py +1 -1
  162. django_cfg/management/__init__.py +1 -1
  163. django_cfg/management/commands/__init__.py +1 -1
  164. django_cfg/management/commands/auto_generate.py +482 -0
  165. django_cfg/management/commands/migrator.py +19 -101
  166. django_cfg/management/commands/test_email.py +1 -1
  167. django_cfg/middleware/README.md +0 -158
  168. django_cfg/middleware/__init__.py +0 -2
  169. django_cfg/middleware/user_activity.py +3 -3
  170. django_cfg/models/api.py +145 -0
  171. django_cfg/models/base.py +287 -0
  172. django_cfg/models/cache.py +4 -4
  173. django_cfg/models/constance.py +25 -88
  174. django_cfg/models/database.py +9 -9
  175. django_cfg/models/drf.py +3 -36
  176. django_cfg/models/email.py +163 -0
  177. django_cfg/models/environment.py +276 -0
  178. django_cfg/models/limits.py +1 -1
  179. django_cfg/models/logging.py +366 -0
  180. django_cfg/models/revolution.py +41 -2
  181. django_cfg/models/security.py +125 -0
  182. django_cfg/models/services.py +1 -1
  183. django_cfg/modules/__init__.py +2 -56
  184. django_cfg/modules/base.py +78 -52
  185. django_cfg/modules/django_currency/service.py +2 -2
  186. django_cfg/modules/django_email.py +2 -2
  187. django_cfg/modules/django_health.py +267 -0
  188. django_cfg/modules/django_llm/llm/client.py +79 -17
  189. django_cfg/modules/django_llm/translator/translator.py +2 -2
  190. django_cfg/modules/django_logger.py +2 -2
  191. django_cfg/modules/django_ngrok.py +2 -2
  192. django_cfg/modules/django_tasks.py +68 -3
  193. django_cfg/modules/django_telegram.py +3 -3
  194. django_cfg/modules/django_twilio/sendgrid_service.py +2 -2
  195. django_cfg/modules/django_twilio/service.py +2 -2
  196. django_cfg/modules/django_twilio/simple_service.py +2 -2
  197. django_cfg/modules/django_twilio/twilio_service.py +2 -2
  198. django_cfg/modules/django_unfold/__init__.py +69 -0
  199. django_cfg/modules/{unfold → django_unfold}/callbacks.py +23 -22
  200. django_cfg/modules/django_unfold/dashboard.py +278 -0
  201. django_cfg/modules/django_unfold/icons/README.md +145 -0
  202. django_cfg/modules/django_unfold/icons/__init__.py +12 -0
  203. django_cfg/modules/django_unfold/icons/constants.py +2851 -0
  204. django_cfg/modules/django_unfold/icons/generate_icons.py +486 -0
  205. django_cfg/modules/django_unfold/models/__init__.py +42 -0
  206. django_cfg/modules/django_unfold/models/config.py +601 -0
  207. django_cfg/modules/django_unfold/models/dashboard.py +206 -0
  208. django_cfg/modules/django_unfold/models/dropdown.py +40 -0
  209. django_cfg/modules/django_unfold/models/navigation.py +73 -0
  210. django_cfg/modules/django_unfold/models/tabs.py +25 -0
  211. django_cfg/modules/{unfold → django_unfold}/system_monitor.py +2 -2
  212. django_cfg/modules/django_unfold/utils.py +140 -0
  213. django_cfg/registry/__init__.py +23 -0
  214. django_cfg/registry/core.py +61 -0
  215. django_cfg/registry/exceptions.py +11 -0
  216. django_cfg/registry/modules.py +12 -0
  217. django_cfg/registry/services.py +26 -0
  218. django_cfg/registry/third_party.py +52 -0
  219. django_cfg/routing/__init__.py +19 -0
  220. django_cfg/routing/callbacks.py +198 -0
  221. django_cfg/routing/routers.py +48 -0
  222. django_cfg/templates/admin/layouts/dashboard_with_tabs.html +8 -9
  223. django_cfg/templatetags/__init__.py +0 -0
  224. django_cfg/templatetags/django_cfg.py +33 -0
  225. django_cfg/urls.py +33 -0
  226. django_cfg/utils/path_resolution.py +1 -1
  227. django_cfg/utils/smart_defaults.py +7 -61
  228. django_cfg/utils/toolkit.py +663 -0
  229. {django_cfg-1.1.82.dist-info → django_cfg-1.2.0.dist-info}/METADATA +83 -86
  230. django_cfg-1.2.0.dist-info/RECORD +441 -0
  231. django_cfg/archive/django_sample.zip +0 -0
  232. django_cfg/models/unfold.py +0 -271
  233. django_cfg/modules/unfold/__init__.py +0 -29
  234. django_cfg/modules/unfold/dashboard.py +0 -318
  235. django_cfg/pyproject.toml +0 -370
  236. django_cfg/routers.py +0 -83
  237. django_cfg-1.1.82.dist-info/RECORD +0 -278
  238. /django_cfg/{exceptions.py → core/exceptions.py} +0 -0
  239. /django_cfg/modules/{unfold → django_unfold}/models.py +0 -0
  240. /django_cfg/modules/{unfold → django_unfold}/tailwind.py +0 -0
  241. /django_cfg/{version_check.py → utils/version_check.py} +0 -0
  242. {django_cfg-1.1.82.dist-info → django_cfg-1.2.0.dist-info}/WHEEL +0 -0
  243. {django_cfg-1.1.82.dist-info → django_cfg-1.2.0.dist-info}/entry_points.txt +0 -0
  244. {django_cfg-1.1.82.dist-info → django_cfg-1.2.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,444 @@
1
+ """
2
+ Pydantic-based configuration for Knowledge Base app.
3
+
4
+ This module provides a clean, type-safe configuration system that replaces
5
+ the removed Constance settings with sensible defaults and validation.
6
+ """
7
+
8
+ from typing import Dict, Any, Optional
9
+ from pydantic import BaseModel, Field, field_validator
10
+ from pathlib import Path
11
+ import os
12
+
13
+ # Import environment configuration for API keys
14
+ try:
15
+ from django.conf import settings
16
+ except ImportError:
17
+ # Fallback for tests or when environment is not available
18
+ env = None
19
+
20
+
21
+ class CacheSettings(BaseModel):
22
+ """Cache settings for LLMClient."""
23
+
24
+ cache_dir: Path = Field(..., description="Cache directory path")
25
+ cache_ttl: int = Field(..., description="Cache TTL in seconds")
26
+ max_cache_size: int = Field(..., description="Maximum cache size")
27
+
28
+ class Config:
29
+ arbitrary_types_allowed = True # Allow Path type
30
+
31
+
32
+ class EmbeddingConfig(BaseModel):
33
+ """Configuration for embedding processing."""
34
+
35
+ model: str = Field(
36
+ default="text-embedding-ada-002",
37
+ description="OpenAI embedding model to use"
38
+ )
39
+ batch_size: int = Field(
40
+ default=50,
41
+ ge=1,
42
+ le=100,
43
+ description="Number of chunks to process in one batch"
44
+ )
45
+ max_retries: int = Field(
46
+ default=3,
47
+ ge=0,
48
+ le=10,
49
+ description="Maximum number of retries for failed embeddings"
50
+ )
51
+ timeout_seconds: int = Field(
52
+ default=30,
53
+ ge=5,
54
+ le=300,
55
+ description="Timeout for embedding API calls"
56
+ )
57
+ cache_dir: str = Field(
58
+ default=".cache/django_cfg_knowbase_llm",
59
+ description="Directory for LLM cache files (relative to project root)"
60
+ )
61
+ cache_ttl: int = Field(
62
+ default=3600,
63
+ ge=60,
64
+ le=86400,
65
+ description="Cache TTL in seconds (1 hour to 24 hours)"
66
+ )
67
+ cache_max_size: int = Field(
68
+ default=1000,
69
+ ge=10,
70
+ le=10000,
71
+ description="Maximum number of items in memory cache"
72
+ )
73
+
74
+ # API Keys from environment
75
+ @property
76
+ def openai_api_key(self) -> Optional[str]:
77
+ """Get OpenAI API key from environment configuration."""
78
+ return settings.api_keys.openai if env else os.getenv("OPENAI_API_KEY")
79
+
80
+ @property
81
+ def openrouter_api_key(self) -> Optional[str]:
82
+ """Get OpenRouter API key from environment configuration."""
83
+ return settings.api_keys.openrouter if env else os.getenv("OPENROUTER_API_KEY")
84
+
85
+
86
+ class ChunkingConfig(BaseModel):
87
+ """Configuration for text chunking."""
88
+
89
+ document_chunk_size: int = Field(
90
+ default=1000,
91
+ ge=100,
92
+ le=8000,
93
+ description="Chunk size for document processing (characters)"
94
+ )
95
+ document_chunk_overlap: int = Field(
96
+ default=200,
97
+ ge=0,
98
+ le=1000,
99
+ description="Overlap between document chunks (characters)"
100
+ )
101
+ archive_chunk_size: int = Field(
102
+ default=800,
103
+ ge=100,
104
+ le=8000,
105
+ description="Chunk size for archive processing (characters)"
106
+ )
107
+ archive_chunk_overlap: int = Field(
108
+ default=160,
109
+ ge=0,
110
+ le=1000,
111
+ description="Overlap between archive chunks (characters)"
112
+ )
113
+
114
+ @field_validator('document_chunk_overlap')
115
+ @classmethod
116
+ def validate_document_overlap(cls, v, info):
117
+ if info.data and 'document_chunk_size' in info.data and v >= info.data['document_chunk_size']:
118
+ raise ValueError('Document chunk overlap must be less than chunk size')
119
+ return v
120
+
121
+ @field_validator('archive_chunk_overlap')
122
+ @classmethod
123
+ def validate_archive_overlap(cls, v, info):
124
+ if info.data and 'archive_chunk_size' in info.data and v >= info.data['archive_chunk_size']:
125
+ raise ValueError('Archive chunk overlap must be less than chunk size')
126
+ return v
127
+
128
+
129
+ class SearchConfig(BaseModel):
130
+ """Configuration for search functionality."""
131
+
132
+ results_limit: int = Field(
133
+ default=10,
134
+ ge=1,
135
+ le=100,
136
+ description="Maximum number of search results to return"
137
+ )
138
+
139
+ # Type-specific similarity thresholds for better multilingual and content-type support
140
+ document_threshold: float = Field(
141
+ default=0.7,
142
+ ge=0.0,
143
+ le=1.0,
144
+ description="Similarity threshold for document chunks (high precision)"
145
+ )
146
+ archive_threshold: float = Field(
147
+ default=0.6,
148
+ ge=0.0,
149
+ le=1.0,
150
+ description="Similarity threshold for archive chunks (medium precision for code)"
151
+ )
152
+ # Note: external_data_threshold removed - now configured per-object in ExternalData.similarity_threshold
153
+
154
+ # Legacy field for backward compatibility
155
+ similarity_threshold: float = Field(
156
+ default=0.7,
157
+ ge=0.0,
158
+ le=1.0,
159
+ description="Default similarity threshold (legacy, use type-specific thresholds)"
160
+ )
161
+
162
+
163
+ class ChatConfig(BaseModel):
164
+ """Configuration for chat functionality."""
165
+
166
+ context_chunks: int = Field(
167
+ default=5,
168
+ ge=1,
169
+ le=20,
170
+ description="Number of chunks to include in chat context"
171
+ )
172
+ max_tokens: int = Field(
173
+ default=4000,
174
+ ge=100,
175
+ le=32000,
176
+ description="Maximum tokens for chat completion"
177
+ )
178
+ temperature: float = Field(
179
+ default=0.7,
180
+ ge=0.0,
181
+ le=2.0,
182
+ description="Temperature for chat completion (creativity level)"
183
+ )
184
+
185
+
186
+ class ProcessingConfig(BaseModel):
187
+ """Configuration for processing limits and timeouts."""
188
+
189
+ max_document_size_mb: int = Field(
190
+ default=10,
191
+ ge=1,
192
+ le=100,
193
+ description="Maximum document size in MB"
194
+ )
195
+ max_archive_size_mb: int = Field(
196
+ default=50,
197
+ ge=1,
198
+ le=500,
199
+ description="Maximum archive size in MB"
200
+ )
201
+ timeout_minutes: int = Field(
202
+ default=30,
203
+ ge=1,
204
+ le=180,
205
+ description="Processing timeout in minutes"
206
+ )
207
+
208
+
209
+ class KnowledgeBaseConfig(BaseModel):
210
+ """Main configuration for the Knowledge Base app."""
211
+
212
+ embedding: EmbeddingConfig = Field(default_factory=EmbeddingConfig)
213
+ chunking: ChunkingConfig = Field(default_factory=ChunkingConfig)
214
+ search: SearchConfig = Field(default_factory=SearchConfig)
215
+ chat: ChatConfig = Field(default_factory=ChatConfig)
216
+ processing: ProcessingConfig = Field(default_factory=ProcessingConfig)
217
+
218
+ class Config:
219
+ env_prefix = "KNOWBASE_"
220
+ case_sensitive = False
221
+
222
+ def get_chunking_params_for_type(self, content_type: str) -> Dict[str, Any]:
223
+ """
224
+ Get chunking parameters for SemanticChunker.
225
+
226
+ Args:
227
+ content_type: Either 'document' or 'archive'
228
+
229
+ Returns:
230
+ Dictionary with chunk_size and overlap parameters
231
+ """
232
+ if content_type == 'archive':
233
+ return {
234
+ 'chunk_size': self.chunking.archive_chunk_size,
235
+ 'overlap': self.chunking.archive_chunk_overlap
236
+ }
237
+ else: # default to document
238
+ return {
239
+ 'chunk_size': self.chunking.document_chunk_size,
240
+ 'overlap': self.chunking.document_chunk_overlap
241
+ }
242
+
243
+ def get_embedding_model(self) -> str:
244
+ """Get the configured embedding model."""
245
+ return self.embedding.model
246
+
247
+ def get_embedding_batch_size(self) -> int:
248
+ """Get the configured embedding batch size."""
249
+ return self.embedding.batch_size
250
+
251
+ def get_openai_api_key(self) -> Optional[str]:
252
+ """Get OpenAI API key from environment."""
253
+ return self.embedding.openai_api_key
254
+
255
+ def get_openrouter_api_key(self) -> Optional[str]:
256
+ """Get OpenRouter API key from environment."""
257
+ return self.embedding.openrouter_api_key
258
+
259
+ def get_cache_dir(self) -> Path:
260
+ """Get cache directory path and ensure it exists."""
261
+ from pathlib import Path
262
+ cache_path = Path(self.embedding.cache_dir)
263
+ if not cache_path.is_absolute():
264
+ cache_path = Path.cwd() / cache_path
265
+
266
+ # Ensure cache directory exists
267
+ cache_path.mkdir(parents=True, exist_ok=True)
268
+ return cache_path
269
+
270
+ def get_cache_settings(self) -> CacheSettings:
271
+ """Get cache settings for LLMClient."""
272
+ return CacheSettings(
273
+ cache_dir=self.get_cache_dir(),
274
+ cache_ttl=self.embedding.cache_ttl,
275
+ max_cache_size=self.embedding.cache_max_size
276
+ )
277
+
278
+ def to_dict(self) -> Dict[str, Any]:
279
+ """Convert config to dictionary for easy access."""
280
+ return self.dict()
281
+
282
+
283
+ # Global configuration instance
284
+ _config: Optional[KnowledgeBaseConfig] = None
285
+
286
+
287
+ def get_config() -> KnowledgeBaseConfig:
288
+ """
289
+ Get the global configuration instance.
290
+
291
+ This function implements a singleton pattern to ensure we only
292
+ create one configuration instance per application run.
293
+ """
294
+ global _config
295
+ if _config is None:
296
+ _config = KnowledgeBaseConfig()
297
+ return _config
298
+
299
+
300
+ def reload_config() -> KnowledgeBaseConfig:
301
+ """
302
+ Reload configuration from environment variables.
303
+
304
+ Useful for testing or when configuration needs to be updated.
305
+ """
306
+ global _config
307
+ _config = KnowledgeBaseConfig()
308
+ return _config
309
+
310
+
311
+ # Convenience functions for easy access (backward compatibility)
312
+ def get_document_chunk_size() -> int:
313
+ """Get document chunk size."""
314
+ return get_config().chunking.document_chunk_size
315
+
316
+
317
+ def get_document_chunk_overlap() -> int:
318
+ """Get document chunk overlap."""
319
+ return get_config().chunking.document_chunk_overlap
320
+
321
+
322
+ def get_archive_chunk_size() -> int:
323
+ """Get archive chunk size."""
324
+ return get_config().chunking.archive_chunk_size
325
+
326
+
327
+ def get_archive_chunk_overlap() -> int:
328
+ """Get archive chunk overlap."""
329
+ return get_config().chunking.archive_chunk_overlap
330
+
331
+
332
+ def get_embedding_batch_size() -> int:
333
+ """Get embedding batch size."""
334
+ return get_config().embedding.batch_size
335
+
336
+
337
+ def get_embedding_model() -> str:
338
+ """Get embedding model."""
339
+ return get_config().embedding.model
340
+
341
+
342
+ def get_search_results_limit() -> int:
343
+ """Get search results limit."""
344
+ return get_config().search.results_limit
345
+
346
+
347
+ def get_search_similarity_threshold() -> float:
348
+ """Get search similarity threshold (legacy)."""
349
+ return get_config().search.similarity_threshold
350
+
351
+
352
+ def get_document_threshold() -> float:
353
+ """Get similarity threshold for document chunks."""
354
+ return get_config().search.document_threshold
355
+
356
+
357
+ def get_archive_threshold() -> float:
358
+ """Get similarity threshold for archive chunks."""
359
+ return get_config().search.archive_threshold
360
+
361
+
362
+ # Note: get_external_data_threshold removed - now configured per-object in ExternalData.similarity_threshold
363
+
364
+
365
+ def get_threshold_for_type(content_type: str) -> float:
366
+ """
367
+ Get appropriate similarity threshold for content type.
368
+
369
+ Args:
370
+ content_type: 'document', 'archive', or 'external_data'
371
+
372
+ Returns:
373
+ Appropriate similarity threshold for the content type
374
+ """
375
+ config = get_config()
376
+ thresholds = {
377
+ 'document': config.search.document_threshold,
378
+ 'archive': config.search.archive_threshold,
379
+ # Note: external_data now uses per-object thresholds from ExternalData.similarity_threshold
380
+ }
381
+ return thresholds.get(content_type, config.search.similarity_threshold)
382
+
383
+
384
+ def get_chat_context_chunks() -> int:
385
+ """Get number of chunks for chat context."""
386
+ return get_config().chat.context_chunks
387
+
388
+
389
+ def get_chat_max_tokens() -> int:
390
+ """Get maximum tokens for chat completion."""
391
+ return get_config().chat.max_tokens
392
+
393
+
394
+ def get_chat_temperature() -> float:
395
+ """Get chat completion temperature."""
396
+ return get_config().chat.temperature
397
+
398
+
399
+ def get_max_archive_size_mb() -> int:
400
+ """Get maximum archive size in MB."""
401
+ return get_config().processing.max_archive_size_mb
402
+
403
+
404
+ def get_max_document_size_mb() -> int:
405
+ """Get maximum document size in MB."""
406
+ return get_config().processing.max_document_size_mb
407
+
408
+
409
+ def get_processing_timeout_minutes() -> int:
410
+ """Get processing timeout in minutes."""
411
+ return get_config().processing.timeout_minutes
412
+
413
+
414
+ def get_chunking_params_for_type(content_type: str) -> Dict[str, Any]:
415
+ """
416
+ Get chunking parameters for SemanticChunker.
417
+
418
+ Args:
419
+ content_type: Either 'document' or 'archive'
420
+
421
+ Returns:
422
+ Dictionary with chunk_size and overlap parameters
423
+ """
424
+ return get_config().get_chunking_params_for_type(content_type)
425
+
426
+
427
+ def get_openai_api_key() -> Optional[str]:
428
+ """Get OpenAI API key from environment."""
429
+ return get_config().get_openai_api_key()
430
+
431
+
432
+ def get_openrouter_api_key() -> Optional[str]:
433
+ """Get OpenRouter API key from environment."""
434
+ return get_config().get_openrouter_api_key()
435
+
436
+
437
+ def get_cache_dir():
438
+ """Get cache directory path."""
439
+ return get_config().get_cache_dir()
440
+
441
+
442
+ def get_cache_settings() -> CacheSettings:
443
+ """Get cache settings for LLMClient."""
444
+ return get_config().get_cache_settings()
@@ -0,0 +1,3 @@
1
+ """
2
+ Examples for using the External Data system in django_cfg.apps.knowbase.
3
+ """
@@ -0,0 +1,191 @@
1
+ """
2
+ Примеры использования нового ExternalDataManager.
3
+
4
+ Этот файл показывает, как легко интегрировать внешние данные в knowbase
5
+ после рефакторинга.
6
+ """
7
+
8
+ from django.contrib.auth import get_user_model
9
+ from django_cfg.apps.knowbase.utils.external_data_manager import ExternalDataManager, quick_add_model, quick_search
10
+ from django_cfg.apps.knowbase.models.external_data import ExternalDataType
11
+
12
+ User = get_user_model()
13
+
14
+
15
+ def example_add_django_model():
16
+ """Пример добавления Django модели как внешнего источника данных."""
17
+
18
+ # Получаем пользователя
19
+ user = User.objects.first()
20
+ if not user:
21
+ print("❌ No users found")
22
+ return
23
+
24
+ # Создаем менеджер
25
+ manager = ExternalDataManager(user)
26
+
27
+ # Добавляем модель Vehicle (если она существует)
28
+ try:
29
+ from apps.vehicles_data.models import Vehicle
30
+
31
+ external_data = manager.add_django_model(
32
+ model_class=Vehicle,
33
+ title="Vehicle Database",
34
+ fields=['brand__name', 'model', 'year', 'description'],
35
+ description="All vehicles from the database",
36
+ search_fields=['brand__name', 'model'],
37
+ chunk_size=800,
38
+ overlap_size=150,
39
+ auto_vectorize=True
40
+ )
41
+
42
+ print(f"✅ Added Vehicle model as external data: {external_data.id}")
43
+ print(f" Status: {external_data.status}")
44
+ print(f" Total chunks: {external_data.total_chunks}")
45
+
46
+ except ImportError:
47
+ print("⚠️ Vehicle model not found, using example data instead")
48
+
49
+ # Добавляем произвольные данные
50
+ external_data = manager.add_custom_data(
51
+ title="Sample Car Data",
52
+ identifier="sample_cars",
53
+ content="""
54
+ Toyota Camry 2023: Reliable sedan with excellent fuel economy
55
+ Honda Civic 2023: Compact car perfect for city driving
56
+ BMW X5 2023: Luxury SUV with advanced features
57
+ Tesla Model 3 2023: Electric vehicle with autopilot
58
+ """,
59
+ description="Sample car data for testing",
60
+ tags=['cars', 'vehicles', 'sample']
61
+ )
62
+
63
+ print(f"✅ Added sample car data: {external_data.id}")
64
+
65
+
66
+ def example_search_external_data():
67
+ """Пример поиска по внешним данным."""
68
+
69
+ user = User.objects.first()
70
+ if not user:
71
+ print("❌ No users found")
72
+ return
73
+
74
+ manager = ExternalDataManager(user)
75
+
76
+ # Поиск по запросу
77
+ results = manager.search(
78
+ query="reliable car with good fuel economy",
79
+ limit=3,
80
+ threshold=0.6
81
+ )
82
+
83
+ print(f"🔍 Search results ({len(results)} found):")
84
+ for i, result in enumerate(results, 1):
85
+ print(f" {i}. {result['source_title']} (similarity: {result['similarity']:.3f})")
86
+ print(f" Content: {result['content'][:100]}...")
87
+ print()
88
+
89
+
90
+ def example_get_statistics():
91
+ """Пример получения статистики."""
92
+
93
+ user = User.objects.first()
94
+ if not user:
95
+ print("❌ No users found")
96
+ return
97
+
98
+ manager = ExternalDataManager(user)
99
+ stats = manager.get_statistics()
100
+
101
+ print("📊 External Data Statistics:")
102
+ print(f" Total sources: {stats.total_sources}")
103
+ print(f" Active sources: {stats.active_sources}")
104
+ print(f" Processed sources: {stats.processed_sources}")
105
+ print(f" Failed sources: {stats.failed_sources}")
106
+ print(f" Total chunks: {stats.total_chunks}")
107
+ print(f" Total tokens: {stats.total_tokens}")
108
+ print(f" Total cost: ${stats.total_cost:.4f}")
109
+ print(f" Source types: {stats.source_type_counts}")
110
+
111
+
112
+ def example_health_check():
113
+ """Пример проверки здоровья системы."""
114
+
115
+ user = User.objects.first()
116
+ if not user:
117
+ print("❌ No users found")
118
+ return
119
+
120
+ manager = ExternalDataManager(user)
121
+ health = manager.health_check()
122
+
123
+ print("🏥 System Health Check:")
124
+ print(f" Status: {health.status}")
125
+ print(f" Healthy: {'✅' if health.healthy else '❌'}")
126
+ print(f" Database: {'✅' if health.database_healthy else '❌'}")
127
+ print(f" Embedding Service: {'✅' if health.embedding_service_healthy else '❌'}")
128
+ print(f" Processing: {'✅' if health.processing_healthy else '❌'}")
129
+ print(f" Response time: {health.response_time_ms:.2f}ms")
130
+ print(f" Active sources: {health.active_sources}")
131
+ print(f" Pending processing: {health.pending_processing}")
132
+ print(f" Failed processing: {health.failed_processing}")
133
+
134
+ if health.issues:
135
+ print(f" Issues: {health.issues}")
136
+ if health.warnings:
137
+ print(f" Warnings: {health.warnings}")
138
+
139
+
140
+ def example_quick_functions():
141
+ """Пример использования быстрых функций."""
142
+
143
+ user = User.objects.first()
144
+ if not user:
145
+ print("❌ No users found")
146
+ return
147
+
148
+ # Быстрый поиск
149
+ results = quick_search(
150
+ user=user,
151
+ query="electric vehicle",
152
+ limit=2
153
+ )
154
+
155
+ print(f"⚡ Quick search results: {len(results)} found")
156
+ for result in results:
157
+ print(f" - {result['source_title']}: {result['similarity']:.3f}")
158
+
159
+
160
+ def run_all_examples():
161
+ """Запустить все примеры."""
162
+
163
+ print("🚀 Running External Data Manager Examples")
164
+ print("=" * 50)
165
+
166
+ try:
167
+ print("\n1. Adding Django Model:")
168
+ example_add_django_model()
169
+
170
+ print("\n2. Searching External Data:")
171
+ example_search_external_data()
172
+
173
+ print("\n3. Getting Statistics:")
174
+ example_get_statistics()
175
+
176
+ print("\n4. Health Check:")
177
+ example_health_check()
178
+
179
+ print("\n5. Quick Functions:")
180
+ example_quick_functions()
181
+
182
+ print("\n✅ All examples completed successfully!")
183
+
184
+ except Exception as e:
185
+ print(f"\n❌ Error running examples: {e}")
186
+ import traceback
187
+ traceback.print_exc()
188
+
189
+
190
+ if __name__ == "__main__":
191
+ run_all_examples()
File without changes