django-cfg 1.1.82__py3-none-any.whl → 1.2.1__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 +450 -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 +91 -19
  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.1.dist-info}/METADATA +83 -86
  230. django_cfg-1.2.1.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.1.dist-info}/WHEEL +0 -0
  243. {django_cfg-1.1.82.dist-info → django_cfg-1.2.1.dist-info}/entry_points.txt +0 -0
  244. {django_cfg-1.1.82.dist-info → django_cfg-1.2.1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,81 @@
1
+ """
2
+ Knowledge Base App Configuration
3
+ """
4
+
5
+ from django.apps import AppConfig
6
+ from django.db.models.signals import post_migrate
7
+
8
+
9
+ class KnowbaseConfig(AppConfig):
10
+ """Knowledge Base application configuration."""
11
+
12
+ default_auto_field = 'django.db.models.BigAutoField'
13
+ name = 'django_cfg.apps.knowbase'
14
+ label = 'django_cfg_knowbase'
15
+ verbose_name = 'Django CFG Knowledge Base'
16
+
17
+ def ready(self):
18
+ """Initialize app when Django starts."""
19
+ # Import signals to register them
20
+ from . import signals
21
+
22
+ # Connect post-migrate signal for database setup
23
+ post_migrate.connect(self.create_pgvector_extension, sender=self)
24
+
25
+ # Initialize task system and auto-start worker if configured
26
+ try:
27
+ from django_cfg.modules.django_tasks import initialize_task_system
28
+ initialize_task_system()
29
+ except Exception as e:
30
+ import logging
31
+ logger = logging.getLogger(__name__)
32
+ logger.warning(f"Failed to initialize task system: {e}")
33
+
34
+ def create_pgvector_extension(self, sender, **kwargs):
35
+ """Create pgvector extension and indexes if they don't exist."""
36
+ from django.db import connection
37
+ import logging
38
+ logger = logging.getLogger(__name__)
39
+
40
+ try:
41
+ with connection.cursor() as cursor:
42
+ # Create extensions
43
+ cursor.execute("CREATE EXTENSION IF NOT EXISTS vector;")
44
+ cursor.execute("CREATE EXTENSION IF NOT EXISTS pg_trgm;") # For text search
45
+ logger.info("✅ pgvector extensions created/verified")
46
+
47
+ # Create vector index for cosine similarity if table exists
48
+ cursor.execute("""
49
+ SELECT EXISTS (
50
+ SELECT FROM information_schema.tables
51
+ WHERE table_name = 'django_cfg_knowbase_document_chunks'
52
+ );
53
+ """)
54
+ table_exists = cursor.fetchone()[0]
55
+
56
+ if table_exists:
57
+ # Check if index already exists
58
+ cursor.execute("""
59
+ SELECT EXISTS (
60
+ SELECT FROM pg_indexes
61
+ WHERE indexname = 'embedding_cosine_idx'
62
+ );
63
+ """)
64
+ index_exists = cursor.fetchone()[0]
65
+
66
+ if not index_exists:
67
+ cursor.execute("""
68
+ CREATE INDEX CONCURRENTLY IF NOT EXISTS embedding_cosine_idx
69
+ ON django_cfg_knowbase_document_chunks
70
+ USING ivfflat (embedding vector_cosine_ops)
71
+ WITH (lists = 100);
72
+ """)
73
+ logger.info("✅ Created embedding_cosine_idx index")
74
+ else:
75
+ logger.debug("✅ embedding_cosine_idx index already exists")
76
+ else:
77
+ logger.debug("⏳ django_cfg_knowbase_document_chunks table not yet created, skipping index creation")
78
+
79
+ except Exception as e:
80
+ # Log warning but don't fail - extension/index might already exist
81
+ logger.warning(f"Could not create pgvector extension/indexes: {e}")
@@ -0,0 +1,176 @@
1
+ # Knowledge Base Configuration
2
+
3
+ This directory contains the new Pydantic-based configuration system that replaces the removed Constance settings.
4
+
5
+ ## Overview
6
+
7
+ The configuration system provides:
8
+ - **Type safety** with Pydantic models
9
+ - **Validation** of configuration values
10
+ - **Environment variable support** with `KNOWBASE_` prefix
11
+ - **Backward compatibility** with existing code
12
+
13
+ ## Files
14
+
15
+ - `settings.py` - **Main Pydantic configuration models** (single source of truth)
16
+ - `constance_fields.py` - **Constance configuration** (automatically synchronized with `settings.py`)
17
+ - `SYNCHRONIZATION.md` - **Detailed explanation** of how synchronization works
18
+ - `README.md` - This file
19
+
20
+ ## Usage
21
+
22
+ ### Basic Usage
23
+
24
+ ```python
25
+ from apps.knowbase.config.settings import get_config
26
+
27
+ # Get the global configuration
28
+ config = get_config()
29
+
30
+ # Access settings
31
+ chunk_size = config.chunking.document_chunk_size # 1000
32
+ embedding_model = config.embedding.model # "text-embedding-ada-002"
33
+ ```
34
+
35
+ ### Convenience Functions
36
+
37
+ ```python
38
+ from apps.knowbase.config.settings import (
39
+ get_document_chunk_size,
40
+ get_embedding_model,
41
+ get_chunking_params_for_type
42
+ )
43
+
44
+ # Direct access to common settings
45
+ chunk_size = get_document_chunk_size() # 1000
46
+ model = get_embedding_model() # "text-embedding-ada-002"
47
+
48
+ # Get chunking parameters for SemanticChunker
49
+ doc_params = get_chunking_params_for_type('document')
50
+ # Returns: {'chunk_size': 1000, 'overlap': 200}
51
+
52
+ archive_params = get_chunking_params_for_type('archive')
53
+ # Returns: {'chunk_size': 800, 'overlap': 160}
54
+ ```
55
+
56
+ ## Configuration Sections
57
+
58
+ ### EmbeddingConfig
59
+ - `model`: OpenAI embedding model (default: "text-embedding-ada-002")
60
+ - `batch_size`: Chunks per batch (default: 50, range: 1-100)
61
+ - `max_retries`: Max retries for failed embeddings (default: 3)
62
+ - `timeout_seconds`: API timeout (default: 30)
63
+
64
+ ### ChunkingConfig
65
+ - `document_chunk_size`: Document chunk size (default: 1000, range: 100-8000)
66
+ - `document_chunk_overlap`: Document overlap (default: 200)
67
+ - `archive_chunk_size`: Archive chunk size (default: 800, range: 100-8000)
68
+ - `archive_chunk_overlap`: Archive overlap (default: 160)
69
+
70
+ ### SearchConfig
71
+ - `results_limit`: Max search results (default: 10, range: 1-100)
72
+ - `similarity_threshold`: Min similarity score (default: 0.7, range: 0.0-1.0)
73
+
74
+ ### ChatConfig
75
+ - `context_chunks`: Chunks in chat context (default: 5, range: 1-20)
76
+ - `max_tokens`: Max tokens for completion (default: 4000, range: 100-32000)
77
+ - `temperature`: Creativity level (default: 0.7, range: 0.0-2.0)
78
+
79
+ ### ProcessingConfig
80
+ - `max_document_size_mb`: Max document size (default: 10MB, range: 1-100)
81
+ - `max_archive_size_mb`: Max archive size (default: 50MB, range: 1-500)
82
+ - `timeout_minutes`: Processing timeout (default: 30, range: 1-180)
83
+
84
+ ## Environment Variables
85
+
86
+ You can override any setting using environment variables with the `KNOWBASE_` prefix:
87
+
88
+ ```bash
89
+ # Override document chunk size
90
+ export KNOWBASE_CHUNKING__DOCUMENT_CHUNK_SIZE=1500
91
+
92
+ # Override embedding model
93
+ export KNOWBASE_EMBEDDING__MODEL=text-embedding-3-small
94
+
95
+ # Override search results limit
96
+ export KNOWBASE_SEARCH__RESULTS_LIMIT=20
97
+ ```
98
+
99
+ Note the double underscore `__` to separate nested configuration sections.
100
+
101
+ ## Validation
102
+
103
+ The configuration system automatically validates all values:
104
+
105
+ ```python
106
+ # This will raise a validation error
107
+ config = KnowledgeBaseConfig(
108
+ chunking={
109
+ "document_chunk_size": -100 # Must be >= 100
110
+ }
111
+ )
112
+
113
+ # This will also raise an error
114
+ config = KnowledgeBaseConfig(
115
+ chunking={
116
+ "document_chunk_size": 100,
117
+ "document_chunk_overlap": 200 # Must be < chunk_size
118
+ }
119
+ )
120
+ ```
121
+
122
+ ## Synchronization with Constance
123
+
124
+ **Important**: `settings.py` is the **single source of truth**. The `constance_fields.py` automatically pulls default values from the Pydantic configuration to ensure consistency.
125
+
126
+ ```python
127
+ # settings.py (MASTER)
128
+ class ChunkingConfig(BaseModel):
129
+ document_chunk_size: int = Field(default=1000, ge=100, le=8000)
130
+
131
+ # constance_fields.py (SYNCHRONIZED)
132
+ def get_knowbase_constance_fields():
133
+ default_config = KnowledgeBaseConfig() # ← Pulls from settings.py
134
+ return [
135
+ ConstanceField(
136
+ name="DOCUMENT_CHUNK_SIZE",
137
+ default=default_config.chunking.document_chunk_size, # ← Always in sync!
138
+ )
139
+ ]
140
+ ```
141
+
142
+ This eliminates duplicate default values and ensures consistency across the application.
143
+
144
+ ## Migration from Constance
145
+
146
+ The new system is backward compatible. Existing code using:
147
+
148
+ ```python
149
+ from apps.knowbase.utils.chunk_settings import get_document_chunk_size
150
+ ```
151
+
152
+ Will continue to work without changes. The `chunk_settings.py` module now internally uses the new Pydantic configuration.
153
+
154
+ ## Benefits
155
+
156
+ 1. **Type Safety**: All configuration values are properly typed
157
+ 2. **Validation**: Invalid values are caught at startup
158
+ 3. **Documentation**: Each setting has clear descriptions and ranges
159
+ 4. **Environment Support**: Easy deployment configuration
160
+ 5. **Performance**: No database queries for configuration access
161
+ 6. **Testing**: Easy to mock and test different configurations
162
+
163
+ ## Testing
164
+
165
+ ```python
166
+ from apps.knowbase.config.settings import KnowledgeBaseConfig
167
+
168
+ # Create test configuration
169
+ test_config = KnowledgeBaseConfig(
170
+ chunking={"document_chunk_size": 500},
171
+ embedding={"batch_size": 10}
172
+ )
173
+
174
+ # Use in tests
175
+ assert test_config.chunking.document_chunk_size == 500
176
+ ```
@@ -0,0 +1,51 @@
1
+ """
2
+ Knowledge Base configuration module.
3
+
4
+ This module provides configuration utilities for the knowledge base app,
5
+ including Pydantic-based settings and optional Constance field definitions.
6
+ """
7
+
8
+ # Import the main Pydantic configuration
9
+ from .settings import (
10
+ KnowledgeBaseConfig,
11
+ get_config,
12
+ reload_config,
13
+ get_document_chunk_size,
14
+ get_archive_chunk_size,
15
+ get_embedding_model,
16
+ get_embedding_batch_size,
17
+ get_chunking_params_for_type,
18
+ )
19
+
20
+ # Constance-related imports are optional and only loaded when needed
21
+ # to avoid django_cfg dependency issues
22
+ def get_django_cfg_knowbase_constance_fields():
23
+ """Lazy import of Constance fields to avoid dependency issues."""
24
+ from .constance_fields import get_django_cfg_knowbase_constance_fields as _get_fields
25
+ return _get_fields()
26
+
27
+ def get_django_cfg_knowbase_field_validation_rules():
28
+ """Lazy import of Constance validation rules to avoid dependency issues."""
29
+ from .constance_fields import get_django_cfg_knowbase_field_validation_rules as _get_rules
30
+ return _get_rules()
31
+
32
+ def get_all_django_cfg_knowbase_constance_config():
33
+ """Lazy import of complete Constance configuration to avoid dependency issues."""
34
+ from .constance_fields import get_all_django_cfg_knowbase_constance_config as _get_config
35
+ return _get_config()
36
+
37
+ __all__ = [
38
+ # Pydantic configuration
39
+ "KnowledgeBaseConfig",
40
+ "get_config",
41
+ "reload_config",
42
+ "get_document_chunk_size",
43
+ "get_archive_chunk_size",
44
+ "get_embedding_model",
45
+ "get_embedding_batch_size",
46
+ "get_chunking_params_for_type",
47
+ # Constance configuration (lazy loaded)
48
+ "get_django_cfg_knowbase_constance_fields",
49
+ "get_django_cfg_knowbase_field_validation_rules",
50
+ "get_all_django_cfg_knowbase_constance_config",
51
+ ]
@@ -0,0 +1,186 @@
1
+ """
2
+ Constance fields configuration for Knowledge Base app.
3
+
4
+ This module defines all dynamic settings for the knowledge base system
5
+ that can be configured through Django admin at runtime.
6
+
7
+ Note: Default values are now sourced from the Pydantic configuration
8
+ to ensure consistency across the application.
9
+ """
10
+
11
+ from typing import List
12
+ from django_cfg.models.constance import ConstanceField
13
+ from .settings import KnowledgeBaseConfig, get_openai_api_key, get_openrouter_api_key
14
+
15
+
16
+ def get_django_cfg_knowbase_constance_fields() -> List[ConstanceField]:
17
+ """
18
+ Get essential Constance fields for Knowledge Base app.
19
+
20
+ Default values are automatically pulled from the Pydantic configuration
21
+ to ensure consistency.
22
+
23
+ Returns:
24
+ List of ConstanceField objects for critical knowledge base settings
25
+ """
26
+ # Get default values from Pydantic config
27
+ default_config = KnowledgeBaseConfig()
28
+
29
+ return [
30
+ # === Core Processing Settings ===
31
+ ConstanceField(
32
+ name="DOCUMENT_CHUNK_SIZE",
33
+ default=default_config.chunking.document_chunk_size,
34
+ help_text=f"Chunk size for document processing (characters). Default: {default_config.chunking.document_chunk_size}. Affects context quality vs memory usage.",
35
+ field_type="int",
36
+ group="Knowledge Base",
37
+ ),
38
+ ConstanceField(
39
+ name="ARCHIVE_CHUNK_SIZE",
40
+ default=default_config.chunking.archive_chunk_size,
41
+ help_text=f"Chunk size for archive processing (characters). Default: {default_config.chunking.archive_chunk_size}. Smaller for code files.",
42
+ field_type="int",
43
+ group="Knowledge Base",
44
+ ),
45
+
46
+ # === Embedding Settings ===
47
+ ConstanceField(
48
+ name="EMBEDDING_MODEL",
49
+ default=default_config.embedding.model,
50
+ help_text=f"OpenAI embedding model. Default: {default_config.embedding.model}. Options: text-embedding-ada-002, text-embedding-3-small, text-embedding-3-large. API Key: {'✅ Available' if get_openai_api_key() else '❌ Missing'}",
51
+ field_type="str",
52
+ group="Knowledge Base",
53
+ ),
54
+ ConstanceField(
55
+ name="EMBEDDING_BATCH_SIZE",
56
+ default=default_config.embedding.batch_size,
57
+ help_text=f"Chunks per embedding batch (1-100). Default: {default_config.embedding.batch_size}. Higher = faster but more memory. OpenRouter Key: {'✅ Available' if get_openrouter_api_key() else '❌ Missing'}",
58
+ field_type="int",
59
+ group="Knowledge Base",
60
+ ),
61
+
62
+ # === Search Threshold Settings ===
63
+ ConstanceField(
64
+ name="DOCUMENT_THRESHOLD",
65
+ default=default_config.search.document_threshold,
66
+ help_text=f"Similarity threshold for document chunks (0.0-1.0). Default: {default_config.search.document_threshold}. Higher = more precise, lower = more results.",
67
+ field_type="float",
68
+ group="Knowledge Base",
69
+ ),
70
+ ConstanceField(
71
+ name="ARCHIVE_THRESHOLD",
72
+ default=default_config.search.archive_threshold,
73
+ help_text=f"Similarity threshold for archive/code chunks (0.0-1.0). Default: {default_config.search.archive_threshold}. Medium precision for code similarity.",
74
+ field_type="float",
75
+ group="Knowledge Base",
76
+ ),
77
+ # Note: EXTERNAL_DATA_THRESHOLD removed - now configured per-object in ExternalData.similarity_threshold
78
+
79
+ # === AI Assistant Settings ===
80
+ ConstanceField(
81
+ name="BOT_IDENTITY",
82
+ default="I am Reforms.ai, an AI assistant specialized in helping with knowledge base queries and technical documentation. I was developed by the Reforms.ai team to provide accurate information based on your uploaded documents and code archives.",
83
+ help_text="AI assistant identity and description. This text defines who the bot is and what it does. Used in system prompts for all conversations.",
84
+ field_type="longtext",
85
+ group="Knowledge Base",
86
+ ),
87
+ ConstanceField(
88
+ name="BOT_NO_CONTEXT_MESSAGE",
89
+ default="I can help you with questions about your knowledge base, technical documentation, and uploaded content. However, I don't currently have any specific context loaded for this conversation.",
90
+ help_text="Message shown when AI assistant has no specific context loaded. Explains what the bot can help with when no documents are found.",
91
+ field_type="longtext",
92
+ group="Knowledge Base",
93
+ ),
94
+ ]
95
+
96
+
97
+ def get_django_cfg_knowbase_field_validation_rules() -> dict:
98
+ """
99
+ Get validation rules for essential knowledge base Constance fields.
100
+
101
+ Validation rules are now consistent with Pydantic configuration constraints.
102
+
103
+ Returns:
104
+ Dictionary with field names as keys and validation functions as values
105
+ """
106
+ # Get constraints from Pydantic config
107
+ default_config = KnowledgeBaseConfig()
108
+
109
+ def validate_chunk_size(value):
110
+ """Validate chunk size values using Pydantic constraints."""
111
+ if not isinstance(value, int):
112
+ return False, "Chunk size must be an integer"
113
+ if value < 100:
114
+ return False, "Chunk size must be at least 100 characters"
115
+ if value > 8000:
116
+ return False, "Chunk size should not exceed 8000 characters"
117
+ return True, ""
118
+
119
+ def validate_batch_size(value):
120
+ """Validate embedding batch size using Pydantic constraints."""
121
+ if not isinstance(value, int):
122
+ return False, "Batch size must be an integer"
123
+ if value < 1:
124
+ return False, "Batch size must be at least 1"
125
+ if value > 100:
126
+ return False, "Batch size should not exceed 100 for stability"
127
+ return True, ""
128
+
129
+ def validate_embedding_model(value):
130
+ """Validate embedding model name."""
131
+ if not isinstance(value, str):
132
+ return False, "Embedding model must be a string"
133
+ if not value.strip():
134
+ return False, "Embedding model cannot be empty"
135
+ valid_models = [
136
+ "text-embedding-ada-002",
137
+ "text-embedding-3-small",
138
+ "text-embedding-3-large"
139
+ ]
140
+ if value not in valid_models:
141
+ return True, f"Warning: '{value}' is not a standard OpenAI model. Valid options: {', '.join(valid_models)}"
142
+ return True, ""
143
+
144
+ def validate_bot_identity(value):
145
+ """Validate bot identity text."""
146
+ if not isinstance(value, str):
147
+ return False, "Bot identity must be a string"
148
+ if not value.strip():
149
+ return False, "Bot identity cannot be empty"
150
+ if len(value) < 10:
151
+ return False, "Bot identity should be at least 10 characters"
152
+ if len(value) > 1000:
153
+ return False, "Bot identity should not exceed 1000 characters"
154
+ return True, ""
155
+
156
+ def validate_bot_message(value):
157
+ """Validate bot message text."""
158
+ if not isinstance(value, str):
159
+ return False, "Bot message must be a string"
160
+ if not value.strip():
161
+ return False, "Bot message cannot be empty"
162
+ if len(value) < 10:
163
+ return False, "Bot message should be at least 10 characters"
164
+ if len(value) > 500:
165
+ return False, "Bot message should not exceed 500 characters"
166
+ return True, ""
167
+
168
+ return {
169
+ "DOCUMENT_CHUNK_SIZE": validate_chunk_size,
170
+ "ARCHIVE_CHUNK_SIZE": validate_chunk_size,
171
+ "EMBEDDING_BATCH_SIZE": validate_batch_size,
172
+ "EMBEDDING_MODEL": validate_embedding_model,
173
+ "BOT_IDENTITY": validate_bot_identity,
174
+ "BOT_NO_CONTEXT_MESSAGE": validate_bot_message,
175
+ }
176
+
177
+
178
+ # Convenience function for easy import
179
+ def get_all_django_cfg_knowbase_constance_config():
180
+ """
181
+ Get complete Constance configuration for Knowledge Base.
182
+
183
+ Returns:
184
+ Tuple of (fields, validation_rules)
185
+ """
186
+ return get_django_cfg_knowbase_constance_fields(), get_django_cfg_knowbase_field_validation_rules()
@@ -0,0 +1,200 @@
1
+ """
2
+ Constance settings accessor for Knowledge Base app.
3
+
4
+ This module provides a centralized way to access all Constance settings
5
+ with proper fallbacks and type safety using Pydantic 2.
6
+ """
7
+
8
+ from typing import Optional, Dict, Any
9
+ from pydantic import BaseModel, Field, validator
10
+ from constance import config
11
+
12
+
13
+ class KnowledgeBaseConstanceSettings(BaseModel):
14
+ """Pydantic model for Knowledge Base Constance settings with validation."""
15
+
16
+ # === AI Assistant Settings ===
17
+ bot_identity: str = Field(
18
+ default="I am Reforms.ai, an AI assistant specialized in helping with knowledge base queries and technical documentation. I was developed by the Reforms.ai team to provide accurate information based on your uploaded documents and code archives.",
19
+ min_length=10,
20
+ max_length=1000,
21
+ description="AI assistant identity and description"
22
+ )
23
+
24
+ bot_no_context_message: str = Field(
25
+ default="I can help you with questions about your knowledge base, technical documentation, and uploaded content. However, I don't currently have any specific context loaded for this conversation.",
26
+ min_length=10,
27
+ max_length=500,
28
+ description="Message shown when AI has no specific context"
29
+ )
30
+
31
+ # === Processing Settings ===
32
+ document_chunk_size: int = Field(
33
+ default=1000,
34
+ ge=100,
35
+ le=8000,
36
+ description="Chunk size for document processing (characters)"
37
+ )
38
+
39
+ archive_chunk_size: int = Field(
40
+ default=800,
41
+ ge=100,
42
+ le=8000,
43
+ description="Chunk size for archive processing (characters)"
44
+ )
45
+
46
+ # === Embedding Settings ===
47
+ embedding_model: str = Field(
48
+ default="text-embedding-ada-002",
49
+ min_length=1,
50
+ description="OpenAI embedding model name"
51
+ )
52
+
53
+ embedding_batch_size: int = Field(
54
+ default=50,
55
+ ge=1,
56
+ le=100,
57
+ description="Chunks per embedding batch"
58
+ )
59
+
60
+ # === Search Threshold Settings ===
61
+ document_threshold: float = Field(
62
+ default=0.7,
63
+ ge=0.0,
64
+ le=1.0,
65
+ description="Similarity threshold for document chunks"
66
+ )
67
+
68
+ archive_threshold: float = Field(
69
+ default=0.6,
70
+ ge=0.0,
71
+ le=1.0,
72
+ description="Similarity threshold for archive chunks"
73
+ )
74
+
75
+ # Note: external_data_threshold removed - now configured per-object in ExternalData.similarity_threshold
76
+
77
+ @validator('embedding_model')
78
+ def validate_embedding_model(cls, v):
79
+ """Validate embedding model name."""
80
+ valid_models = [
81
+ "text-embedding-ada-002",
82
+ "text-embedding-3-small",
83
+ "text-embedding-3-large"
84
+ ]
85
+ if v not in valid_models:
86
+ # Warning, not error - allow custom models
87
+ pass
88
+ return v
89
+
90
+ class Config:
91
+ """Pydantic configuration."""
92
+ validate_assignment = True
93
+ extra = "forbid"
94
+ json_encoders = {
95
+ # Add custom encoders if needed
96
+ }
97
+
98
+ @classmethod
99
+ def from_constance(cls) -> 'KnowledgeBaseConstanceSettings':
100
+ """Create instance from Constance settings with fallbacks."""
101
+ try:
102
+ return cls(
103
+ bot_identity=getattr(config, 'BOT_IDENTITY', cls.model_fields['bot_identity'].default),
104
+ bot_no_context_message=getattr(config, 'BOT_NO_CONTEXT_MESSAGE', cls.model_fields['bot_no_context_message'].default),
105
+ document_chunk_size=getattr(config, 'DOCUMENT_CHUNK_SIZE', cls.model_fields['document_chunk_size'].default),
106
+ archive_chunk_size=getattr(config, 'ARCHIVE_CHUNK_SIZE', cls.model_fields['archive_chunk_size'].default),
107
+ embedding_model=getattr(config, 'EMBEDDING_MODEL', cls.model_fields['embedding_model'].default),
108
+ embedding_batch_size=getattr(config, 'EMBEDDING_BATCH_SIZE', cls.model_fields['embedding_batch_size'].default),
109
+ document_threshold=getattr(config, 'DOCUMENT_THRESHOLD', cls.model_fields['document_threshold'].default),
110
+ archive_threshold=getattr(config, 'ARCHIVE_THRESHOLD', cls.model_fields['archive_threshold'].default),
111
+ )
112
+ except Exception as e:
113
+ # If any validation fails, return defaults
114
+ return cls()
115
+
116
+ @classmethod
117
+ def get_current(cls) -> 'KnowledgeBaseConstanceSettings':
118
+ """Get current settings instance (cached for performance)."""
119
+ # Always refresh cache to avoid stale data issues
120
+ # TODO: Implement smarter cache invalidation based on Constance changes
121
+ return cls.from_constance()
122
+
123
+ @classmethod
124
+ def refresh_cache(cls):
125
+ """Refresh cached settings instance."""
126
+ if hasattr(cls, '_cached_instance'):
127
+ delattr(cls, '_cached_instance')
128
+
129
+ # === Convenience Methods for Backward Compatibility ===
130
+
131
+ @classmethod
132
+ def get_bot_identity(cls) -> str:
133
+ """Get bot identity from current settings."""
134
+ return cls.get_current().bot_identity
135
+
136
+ @classmethod
137
+ def get_bot_no_context_message(cls) -> str:
138
+ """Get bot no-context message from current settings."""
139
+ return cls.get_current().bot_no_context_message
140
+
141
+ @classmethod
142
+ def get_document_chunk_size(cls) -> int:
143
+ """Get document chunk size from current settings."""
144
+ return cls.get_current().document_chunk_size
145
+
146
+ @classmethod
147
+ def get_archive_chunk_size(cls) -> int:
148
+ """Get archive chunk size from current settings."""
149
+ return cls.get_current().archive_chunk_size
150
+
151
+ @classmethod
152
+ def get_embedding_model(cls) -> str:
153
+ """Get embedding model from current settings."""
154
+ return cls.get_current().embedding_model
155
+
156
+ @classmethod
157
+ def get_embedding_batch_size(cls) -> int:
158
+ """Get embedding batch size from current settings."""
159
+ return cls.get_current().embedding_batch_size
160
+
161
+ @classmethod
162
+ def get_document_threshold(cls) -> float:
163
+ """Get document similarity threshold from current settings."""
164
+ return cls.get_current().document_threshold
165
+
166
+ @classmethod
167
+ def get_archive_threshold(cls) -> float:
168
+ """Get archive similarity threshold from current settings."""
169
+ return cls.get_current().archive_threshold
170
+
171
+ # Note: get_external_data_threshold removed - now configured per-object in ExternalData.similarity_threshold
172
+
173
+ @classmethod
174
+ def get_threshold_for_type(cls, content_type: str) -> float:
175
+ """Get appropriate threshold for content type."""
176
+ current = cls.get_current()
177
+ thresholds = {
178
+ 'document': current.document_threshold,
179
+ 'archive': current.archive_threshold,
180
+ # Note: external_data now uses per-object thresholds from ExternalData.similarity_threshold
181
+ }
182
+ return thresholds.get(content_type, 0.7) # fallback
183
+
184
+ @classmethod
185
+ def get_all_settings(cls) -> Dict[str, Any]:
186
+ """Get all settings as a dictionary."""
187
+ return cls.get_current().model_dump()
188
+
189
+ @classmethod
190
+ def validate_settings(cls) -> Dict[str, str]:
191
+ """Validate current settings and return results."""
192
+ try:
193
+ settings = cls.from_constance()
194
+ return {field: 'OK' for field in settings.model_fields.keys()}
195
+ except Exception as e:
196
+ return {'validation_error': str(e)}
197
+
198
+
199
+ # Convenience alias for shorter imports
200
+ ConstanceSettings = KnowledgeBaseConstanceSettings