django-cfg 1.3.13__py3-none-any.whl → 1.4.3__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 (446) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/accounts/admin/user_admin.py +39 -16
  3. django_cfg/apps/accounts/serializers/profile.py +1 -1
  4. django_cfg/apps/accounts/services/otp_service.py +18 -11
  5. django_cfg/apps/accounts/signals.py +15 -24
  6. django_cfg/apps/accounts/utils/notifications.py +217 -358
  7. django_cfg/apps/accounts/views/otp.py +2 -2
  8. django_cfg/apps/accounts/views/webhook.py +1 -1
  9. django_cfg/apps/agents/core/django_agent.py +1 -1
  10. django_cfg/apps/agents/examples/__init__.py +3 -0
  11. django_cfg/apps/agents/examples/simple_example.py +161 -0
  12. django_cfg/apps/api/commands/views.py +66 -83
  13. django_cfg/apps/api/health/drf_views.py +269 -0
  14. django_cfg/apps/api/health/serializers.py +45 -0
  15. django_cfg/apps/api/health/urls.py +6 -1
  16. django_cfg/apps/knowbase/admin/actions/__init__.py +13 -0
  17. django_cfg/apps/knowbase/admin/actions/visibility_actions.py +56 -0
  18. django_cfg/apps/knowbase/admin/document_admin.py +136 -270
  19. django_cfg/apps/knowbase/admin/helpers/__init__.py +17 -0
  20. django_cfg/apps/knowbase/admin/helpers/configs.py +72 -0
  21. django_cfg/apps/knowbase/admin/helpers/display_helpers.py +156 -0
  22. django_cfg/apps/knowbase/admin/helpers/statistics.py +108 -0
  23. django_cfg/apps/knowbase/config/constance_fields.py +1 -1
  24. django_cfg/apps/knowbase/config/settings.py +2 -2
  25. django_cfg/apps/knowbase/examples/__init__.py +3 -0
  26. django_cfg/apps/knowbase/examples/external_data_usage.py +191 -0
  27. django_cfg/apps/knowbase/mixins/__init__.py +19 -2
  28. django_cfg/apps/knowbase/mixins/config/__init__.py +14 -0
  29. django_cfg/apps/knowbase/mixins/config/defaults.py +75 -0
  30. django_cfg/apps/knowbase/mixins/config/meta_config.py +120 -0
  31. django_cfg/apps/knowbase/mixins/creator.py +10 -10
  32. django_cfg/apps/knowbase/mixins/examples/vehicle_model_example.py +199 -0
  33. django_cfg/apps/knowbase/mixins/external_data_mixin.py +105 -403
  34. django_cfg/apps/knowbase/mixins/generators/__init__.py +16 -0
  35. django_cfg/apps/knowbase/mixins/generators/content_generator.py +218 -0
  36. django_cfg/apps/knowbase/mixins/generators/field_analyzer.py +76 -0
  37. django_cfg/apps/knowbase/mixins/generators/metadata_generator.py +124 -0
  38. django_cfg/apps/knowbase/mixins/service.py +2 -2
  39. django_cfg/apps/knowbase/services/archive/__init__.py +1 -0
  40. django_cfg/apps/knowbase/services/archive/analyzers/__init__.py +17 -0
  41. django_cfg/apps/knowbase/services/archive/analyzers/complexity_analyzer.py +33 -0
  42. django_cfg/apps/knowbase/services/archive/analyzers/purpose_detector.py +36 -0
  43. django_cfg/apps/knowbase/services/archive/analyzers/quality_analyzer.py +39 -0
  44. django_cfg/apps/knowbase/services/archive/analyzers/tag_generator.py +103 -0
  45. django_cfg/apps/knowbase/services/archive/chunking/__init__.py +19 -0
  46. django_cfg/apps/knowbase/services/archive/chunking/base.py +81 -0
  47. django_cfg/apps/knowbase/services/archive/chunking/json_chunker.py +62 -0
  48. django_cfg/apps/knowbase/services/archive/chunking/markdown_chunker.py +107 -0
  49. django_cfg/apps/knowbase/services/archive/chunking/python_chunker.py +248 -0
  50. django_cfg/apps/knowbase/services/archive/chunking/text_chunker.py +70 -0
  51. django_cfg/apps/knowbase/services/archive/chunking_service.py +110 -729
  52. django_cfg/apps/knowbase/services/archive/context/__init__.py +14 -0
  53. django_cfg/apps/knowbase/services/archive/context/builders.py +220 -0
  54. django_cfg/apps/knowbase/services/archive/context/models.py +38 -0
  55. django_cfg/apps/knowbase/services/embedding/models.py +18 -14
  56. django_cfg/apps/knowbase/services/embedding/processors.py +6 -3
  57. django_cfg/apps/knowbase/tasks/document_processing.py +11 -3
  58. django_cfg/apps/leads/tests.py +1 -1
  59. django_cfg/apps/payments/admin/api_keys_admin.py +1 -1
  60. django_cfg/apps/payments/admin/balance_admin.py +1 -1
  61. django_cfg/apps/payments/admin/currencies_admin.py +1 -1
  62. django_cfg/apps/payments/admin/payments_admin.py +1 -1
  63. django_cfg/apps/payments/admin/subscriptions_admin.py +1 -1
  64. django_cfg/apps/payments/admin_interface/templates/payments/base.html +59 -126
  65. django_cfg/apps/payments/admin_interface/views/api/payments.py +1 -1
  66. django_cfg/apps/payments/admin_interface/views/api/stats.py +1 -1
  67. django_cfg/apps/payments/admin_interface/views/api/users.py +1 -1
  68. django_cfg/apps/payments/admin_interface/views/api/webhook_admin.py +1 -1
  69. django_cfg/apps/payments/admin_interface/views/api/webhook_public.py +1 -1
  70. django_cfg/apps/payments/admin_interface/views/base.py +29 -2
  71. django_cfg/apps/payments/apps.py +1 -1
  72. django_cfg/apps/payments/config/django_cfg_integration.py +2 -2
  73. django_cfg/apps/payments/config/helpers.py +3 -2
  74. django_cfg/apps/payments/management/commands/cleanup_expired_data.py +1 -1
  75. django_cfg/apps/payments/management/commands/currency_stats.py +1 -1
  76. django_cfg/apps/payments/management/commands/manage_currencies.py +1 -1
  77. django_cfg/apps/payments/management/commands/manage_providers.py +1 -1
  78. django_cfg/apps/payments/management/commands/process_pending_payments.py +1 -1
  79. django_cfg/apps/payments/management/commands/test_providers.py +1 -1
  80. django_cfg/apps/payments/middleware/api_access.py +1 -1
  81. django_cfg/apps/payments/middleware/rate_limiting.py +1 -1
  82. django_cfg/apps/payments/middleware/usage_tracking.py +1 -1
  83. django_cfg/apps/payments/models/balance.py +2 -2
  84. django_cfg/apps/payments/models/managers/api_key_managers.py +1 -1
  85. django_cfg/apps/payments/models/managers/balance_managers.py +1 -1
  86. django_cfg/apps/payments/models/managers/currency_managers.py +1 -1
  87. django_cfg/apps/payments/models/managers/payment_managers.py +1 -1
  88. django_cfg/apps/payments/models/managers/subscription_managers.py +1 -1
  89. django_cfg/apps/payments/models/payments.py +2 -2
  90. django_cfg/apps/payments/services/cache_service/__init__.py +1 -1
  91. django_cfg/apps/payments/services/cache_service/simple_cache.py +10 -5
  92. django_cfg/apps/payments/services/core/base.py +1 -1
  93. django_cfg/apps/payments/services/core/currency/__init__.py +13 -0
  94. django_cfg/apps/payments/services/core/currency/currency_converter.py +57 -0
  95. django_cfg/apps/payments/services/core/currency/currency_validator.py +61 -0
  96. django_cfg/apps/payments/services/core/operations/__init__.py +15 -0
  97. django_cfg/apps/payments/services/core/operations/payment_canceller.py +100 -0
  98. django_cfg/apps/payments/services/core/operations/payment_creator.py +196 -0
  99. django_cfg/apps/payments/services/core/operations/status_checker.py +100 -0
  100. django_cfg/apps/payments/services/core/payment_service.py +124 -612
  101. django_cfg/apps/payments/services/core/providers/__init__.py +13 -0
  102. django_cfg/apps/payments/services/core/providers/provider_client.py +132 -0
  103. django_cfg/apps/payments/services/core/providers/status_mapper.py +89 -0
  104. django_cfg/apps/payments/services/core/utils/__init__.py +13 -0
  105. django_cfg/apps/payments/services/core/utils/data_converter.py +48 -0
  106. django_cfg/apps/payments/services/core/utils/statistics_calculator.py +69 -0
  107. django_cfg/apps/payments/services/providers/base.py +1 -1
  108. django_cfg/apps/payments/services/providers/nowpayments/__init__.py +3 -3
  109. django_cfg/apps/payments/services/providers/nowpayments/parsers/__init__.py +9 -0
  110. django_cfg/apps/payments/services/providers/nowpayments/parsers/data/__init__.py +23 -0
  111. django_cfg/apps/payments/services/providers/nowpayments/parsers/data/constants.py +23 -0
  112. django_cfg/apps/payments/services/providers/nowpayments/parsers/data/currency_names.py +244 -0
  113. django_cfg/apps/payments/services/providers/nowpayments/parsers/data/patterns.py +511 -0
  114. django_cfg/apps/payments/services/providers/nowpayments/parsers/parser.py +168 -0
  115. django_cfg/apps/payments/services/providers/nowpayments/provider.py +1 -1
  116. django_cfg/apps/payments/services/providers/nowpayments/sync.py +1 -1
  117. django_cfg/apps/payments/services/providers/registry.py +1 -1
  118. django_cfg/apps/payments/services/providers/sync_service.py +1 -1
  119. django_cfg/apps/payments/signals/__init__.py +1 -1
  120. django_cfg/apps/payments/signals/api_key_signals.py +1 -1
  121. django_cfg/apps/payments/signals/balance_signals.py +1 -1
  122. django_cfg/apps/payments/signals/payment_signals.py +1 -1
  123. django_cfg/apps/payments/signals/subscription_signals.py +1 -1
  124. django_cfg/apps/payments/views/api/api_keys.py +1 -1
  125. django_cfg/apps/payments/views/api/balances.py +1 -1
  126. django_cfg/apps/payments/views/api/base.py +1 -1
  127. django_cfg/apps/payments/views/api/currencies.py +1 -1
  128. django_cfg/apps/payments/views/api/payments.py +1 -1
  129. django_cfg/apps/payments/views/api/subscriptions.py +1 -1
  130. django_cfg/apps/payments/views/api/webhooks.py +1 -1
  131. django_cfg/apps/payments/views/serializers/api_keys.py +1 -1
  132. django_cfg/apps/payments/views/serializers/balances.py +1 -1
  133. django_cfg/apps/payments/views/serializers/currencies.py +1 -1
  134. django_cfg/apps/payments/views/serializers/payments.py +1 -1
  135. django_cfg/apps/payments/views/serializers/subscriptions.py +1 -1
  136. django_cfg/apps/payments/views/serializers/webhooks.py +1 -1
  137. django_cfg/apps/support/admin/support_admin.py +21 -13
  138. django_cfg/apps/support/templates/support/chat/access_denied.html +21 -27
  139. django_cfg/apps/support/templates/support/chat/ticket_chat.html +183 -254
  140. django_cfg/apps/support/utils/support_email_service.py +1 -1
  141. django_cfg/apps/tasks/templates/tasks/layout/base.html +20 -115
  142. django_cfg/apps/tasks/utils/simulator.py +1 -1
  143. django_cfg/apps/tasks/views/dashboard.py +33 -3
  144. django_cfg/apps/urls.py +5 -1
  145. django_cfg/cli/README.md +57 -471
  146. django_cfg/cli/commands/create_project.py +140 -529
  147. django_cfg/cli/main.py +13 -10
  148. django_cfg/core/__init__.py +63 -6
  149. django_cfg/core/base/__init__.py +5 -0
  150. django_cfg/core/base/config_model.py +652 -0
  151. django_cfg/core/builders/__init__.py +11 -0
  152. django_cfg/core/builders/apps_builder.py +258 -0
  153. django_cfg/core/builders/middleware_builder.py +115 -0
  154. django_cfg/core/builders/security_builder.py +96 -0
  155. django_cfg/core/config.py +20 -892
  156. django_cfg/core/constants.py +69 -0
  157. django_cfg/core/environment/__init__.py +9 -0
  158. django_cfg/core/exceptions.py +45 -298
  159. django_cfg/core/generation/__init__.py +51 -0
  160. django_cfg/core/generation/core_generators/__init__.py +0 -0
  161. django_cfg/core/generation/core_generators/settings.py +90 -0
  162. django_cfg/core/generation/core_generators/static.py +82 -0
  163. django_cfg/core/generation/core_generators/templates.py +141 -0
  164. django_cfg/core/generation/data_generators/__init__.py +15 -0
  165. django_cfg/core/generation/data_generators/cache.py +132 -0
  166. django_cfg/core/generation/data_generators/database.py +117 -0
  167. django_cfg/core/generation/generation.py +92 -0
  168. django_cfg/core/generation/integration_generators/__init__.py +21 -0
  169. django_cfg/core/generation/integration_generators/api.py +237 -0
  170. django_cfg/core/generation/integration_generators/sessions.py +65 -0
  171. django_cfg/core/generation/integration_generators/tailwind.py +54 -0
  172. django_cfg/core/generation/integration_generators/tasks.py +92 -0
  173. django_cfg/core/generation/integration_generators/third_party.py +144 -0
  174. django_cfg/core/generation/orchestrator.py +285 -0
  175. django_cfg/core/generation/protocols.py +30 -0
  176. django_cfg/core/generation/security_generators/__init__.py +0 -0
  177. django_cfg/core/generation/utility_generators/__init__.py +24 -0
  178. django_cfg/core/generation/utility_generators/email.py +58 -0
  179. django_cfg/core/generation/utility_generators/i18n.py +66 -0
  180. django_cfg/core/generation/utility_generators/limits.py +58 -0
  181. django_cfg/core/generation/utility_generators/logging.py +66 -0
  182. django_cfg/core/generation/utility_generators/security.py +101 -0
  183. django_cfg/core/generation/utils/__init__.py +0 -0
  184. django_cfg/core/generation/utils/helpers.py +32 -0
  185. django_cfg/core/integration/__init__.py +18 -25
  186. django_cfg/core/integration/display/startup.py +146 -133
  187. django_cfg/core/integration/url_integration.py +13 -2
  188. django_cfg/core/services/__init__.py +5 -0
  189. django_cfg/core/services/config_service.py +121 -0
  190. django_cfg/core/state/__init__.py +9 -0
  191. django_cfg/core/state/registry.py +84 -0
  192. django_cfg/core/types/__init__.py +15 -0
  193. django_cfg/core/types/aliases.py +15 -0
  194. django_cfg/core/types/enums.py +49 -0
  195. django_cfg/dashboard/DEBUG_README.md +105 -0
  196. django_cfg/dashboard/REFACTORING_SUMMARY.md +237 -0
  197. django_cfg/dashboard/__init__.py +24 -0
  198. django_cfg/dashboard/components.py +308 -0
  199. django_cfg/dashboard/debug.py +176 -0
  200. django_cfg/dashboard/management/__init__.py +0 -0
  201. django_cfg/dashboard/management/commands/__init__.py +0 -0
  202. django_cfg/dashboard/management/commands/debug_dashboard.py +109 -0
  203. django_cfg/dashboard/sections/__init__.py +1 -0
  204. django_cfg/dashboard/sections/base.py +128 -0
  205. django_cfg/dashboard/sections/commands.py +32 -0
  206. django_cfg/dashboard/sections/overview.py +394 -0
  207. django_cfg/dashboard/sections/stats.py +48 -0
  208. django_cfg/dashboard/sections/system.py +73 -0
  209. django_cfg/management/commands/check_settings.py +6 -2
  210. django_cfg/management/commands/clear_constance.py +6 -1
  211. django_cfg/management/commands/create_token.py +5 -4
  212. django_cfg/management/commands/generate.py +5 -0
  213. django_cfg/management/commands/list_urls.py +7 -2
  214. django_cfg/management/commands/migrate_all.py +6 -2
  215. django_cfg/management/commands/migrator.py +6 -1
  216. django_cfg/management/commands/rundramatiq.py +6 -1
  217. django_cfg/management/commands/rundramatiq_simulator.py +11 -4
  218. django_cfg/management/commands/runserver_ngrok.py +9 -7
  219. django_cfg/management/commands/script.py +25 -21
  220. django_cfg/management/commands/show_config.py +6 -1
  221. django_cfg/management/commands/show_urls.py +8 -3
  222. django_cfg/management/commands/superuser.py +5 -4
  223. django_cfg/management/commands/task_clear.py +8 -3
  224. django_cfg/management/commands/task_status.py +8 -3
  225. django_cfg/management/commands/test_email.py +6 -1
  226. django_cfg/management/commands/test_telegram.py +6 -1
  227. django_cfg/management/commands/test_twilio.py +6 -1
  228. django_cfg/management/commands/tree.py +7 -4
  229. django_cfg/models/__init__.py +88 -3
  230. django_cfg/models/api/__init__.py +27 -0
  231. django_cfg/models/{api.py → api/config.py} +1 -1
  232. django_cfg/models/api/drf/__init__.py +21 -0
  233. django_cfg/models/api/drf/config.py +101 -0
  234. django_cfg/models/api/drf/redoc.py +31 -0
  235. django_cfg/models/api/drf/spectacular.py +129 -0
  236. django_cfg/models/api/drf/swagger.py +59 -0
  237. django_cfg/models/{api_keys.py → api/keys.py} +16 -6
  238. django_cfg/models/{limits.py → api/limits.py} +0 -1
  239. django_cfg/models/base/__init__.py +14 -0
  240. django_cfg/models/django/__init__.py +16 -0
  241. django_cfg/models/{constance.py → django/constance.py} +1 -1
  242. django_cfg/models/{environment.py → django/environment.py} +1 -1
  243. django_cfg/models/infrastructure/__init__.py +17 -0
  244. django_cfg/models/{cache.py → infrastructure/cache.py} +3 -2
  245. django_cfg/models/infrastructure/database/__init__.py +22 -0
  246. django_cfg/models/infrastructure/database/config.py +265 -0
  247. django_cfg/models/infrastructure/database/converters.py +91 -0
  248. django_cfg/models/infrastructure/database/parsers.py +96 -0
  249. django_cfg/models/infrastructure/database/routing.py +85 -0
  250. django_cfg/models/infrastructure/database/validators.py +170 -0
  251. django_cfg/models/{logging.py → infrastructure/logging.py} +1 -1
  252. django_cfg/models/{security.py → infrastructure/security.py} +2 -2
  253. django_cfg/models/ngrok/__init__.py +11 -0
  254. django_cfg/models/ngrok/auth.py +37 -0
  255. django_cfg/models/ngrok/config.py +77 -0
  256. django_cfg/models/ngrok/tunnel.py +35 -0
  257. django_cfg/models/payments/__init__.py +20 -0
  258. django_cfg/models/payments/api_keys.py +57 -0
  259. django_cfg/models/{payments.py → payments/config.py} +56 -154
  260. django_cfg/models/payments/providers/__init__.py +15 -0
  261. django_cfg/models/payments/providers/base.py +25 -0
  262. django_cfg/models/payments/providers/nowpayments.py +48 -0
  263. django_cfg/models/services/__init__.py +18 -0
  264. django_cfg/models/services/base.py +65 -0
  265. django_cfg/models/{email.py → services/email.py} +1 -1
  266. django_cfg/models/services/telegram.py +172 -0
  267. django_cfg/models/tasks/__init__.py +51 -0
  268. django_cfg/models/tasks/backends.py +250 -0
  269. django_cfg/models/tasks/config.py +314 -0
  270. django_cfg/models/tasks/utils.py +174 -0
  271. django_cfg/modules/base.py +18 -3
  272. django_cfg/modules/django_admin/decorators/actions.py +1 -1
  273. django_cfg/modules/django_admin/decorators/display.py +1 -1
  274. django_cfg/modules/django_admin/mixins/standalone_actions_mixin.py +1 -1
  275. django_cfg/modules/django_currency/examples/__init__.py +3 -0
  276. django_cfg/modules/django_currency/examples/example_database_usage.py +144 -0
  277. django_cfg/modules/django_drf_theme/CHANGELOG.md +210 -0
  278. django_cfg/modules/django_drf_theme/EXAMPLE.md +465 -0
  279. django_cfg/modules/django_drf_theme/IMPLEMENTATION.md +232 -0
  280. django_cfg/modules/django_drf_theme/README.md +207 -0
  281. django_cfg/modules/django_drf_theme/TAILWIND_CDN_GUIDE.md +274 -0
  282. django_cfg/modules/django_drf_theme/__init__.py +23 -0
  283. django_cfg/modules/django_drf_theme/apps.py +15 -0
  284. django_cfg/modules/django_drf_theme/renderers.py +58 -0
  285. django_cfg/modules/django_drf_theme/templates/rest_framework/tailwind/api.html +375 -0
  286. django_cfg/modules/django_drf_theme/templates/rest_framework/tailwind/base.html +938 -0
  287. django_cfg/modules/django_drf_theme/templates/rest_framework/tailwind/forms/filter_form.html +132 -0
  288. django_cfg/modules/django_drf_theme/templates/rest_framework/tailwind/forms/raw_data_form.html +123 -0
  289. django_cfg/modules/django_drf_theme/templatetags/__init__.py +1 -0
  290. django_cfg/modules/django_drf_theme/templatetags/tailwind_tags.py +57 -0
  291. django_cfg/modules/django_email/__init__.py +14 -0
  292. django_cfg/modules/{django_email.py → django_email/service.py} +78 -113
  293. django_cfg/modules/django_email/utils.py +40 -0
  294. django_cfg/modules/django_health/__init__.py +9 -0
  295. django_cfg/modules/{django_health.py → django_health/service.py} +23 -21
  296. django_cfg/modules/django_ipc_client/README.md +346 -0
  297. django_cfg/modules/django_ipc_client/__init__.py +51 -0
  298. django_cfg/modules/django_ipc_client/client.py +540 -0
  299. django_cfg/modules/django_ipc_client/config.py +207 -0
  300. django_cfg/modules/django_ipc_client/dashboard/README.md +517 -0
  301. django_cfg/modules/django_ipc_client/dashboard/UNFOLD_INTEGRATION.md +439 -0
  302. django_cfg/modules/django_ipc_client/dashboard/__init__.py +11 -0
  303. django_cfg/modules/django_ipc_client/dashboard/apps.py +22 -0
  304. django_cfg/modules/django_ipc_client/dashboard/monitor.py +435 -0
  305. django_cfg/modules/django_ipc_client/dashboard/static/django_ipc_dashboard/js/dashboard.js +373 -0
  306. django_cfg/modules/django_ipc_client/dashboard/templates/django_ipc_dashboard/base.html +76 -0
  307. django_cfg/modules/django_ipc_client/dashboard/templates/django_ipc_dashboard/dashboard.html +200 -0
  308. django_cfg/modules/django_ipc_client/dashboard/urls.py +22 -0
  309. django_cfg/modules/django_ipc_client/dashboard/urls_admin.py +9 -0
  310. django_cfg/modules/django_ipc_client/dashboard/views.py +251 -0
  311. django_cfg/modules/django_ipc_client/exceptions.py +201 -0
  312. django_cfg/modules/django_llm/llm/client.py +155 -550
  313. django_cfg/modules/django_llm/llm/embeddings/__init__.py +13 -0
  314. django_cfg/modules/django_llm/llm/embeddings/mock_embedder.py +106 -0
  315. django_cfg/modules/django_llm/llm/embeddings/openai_embedder.py +79 -0
  316. django_cfg/modules/django_llm/llm/models_api/__init__.py +9 -0
  317. django_cfg/modules/django_llm/llm/models_api/models_query.py +163 -0
  318. django_cfg/modules/django_llm/llm/providers/__init__.py +15 -0
  319. django_cfg/modules/django_llm/llm/providers/config_builder.py +103 -0
  320. django_cfg/modules/django_llm/llm/providers/provider_manager.py +148 -0
  321. django_cfg/modules/django_llm/llm/providers/provider_selector.py +60 -0
  322. django_cfg/modules/django_llm/llm/requests/__init__.py +15 -0
  323. django_cfg/modules/django_llm/llm/requests/cache_manager.py +170 -0
  324. django_cfg/modules/django_llm/llm/requests/chat_handler.py +199 -0
  325. django_cfg/modules/django_llm/llm/requests/embedding_handler.py +113 -0
  326. django_cfg/modules/django_llm/llm/responses/__init__.py +9 -0
  327. django_cfg/modules/django_llm/llm/responses/response_builder.py +131 -0
  328. django_cfg/modules/django_llm/llm/stats/__init__.py +9 -0
  329. django_cfg/modules/django_llm/llm/stats/stats_manager.py +107 -0
  330. django_cfg/modules/django_llm/translator/detectors/__init__.py +13 -0
  331. django_cfg/modules/django_llm/translator/detectors/language_detector.py +90 -0
  332. django_cfg/modules/django_llm/translator/detectors/script_detector.py +153 -0
  333. django_cfg/modules/django_llm/translator/stats/__init__.py +11 -0
  334. django_cfg/modules/django_llm/translator/stats/stats_tracker.py +85 -0
  335. django_cfg/modules/django_llm/translator/translator.py +150 -603
  336. django_cfg/modules/django_llm/translator/translators/__init__.py +15 -0
  337. django_cfg/modules/django_llm/translator/translators/json_translator.py +316 -0
  338. django_cfg/modules/django_llm/translator/translators/text_translator.py +139 -0
  339. django_cfg/modules/django_llm/translator/utils/__init__.py +13 -0
  340. django_cfg/modules/django_llm/translator/utils/prompt_builder.py +110 -0
  341. django_cfg/modules/django_llm/translator/utils/text_utils.py +114 -0
  342. django_cfg/modules/django_logging/FIXES_SUMMARY.md +276 -0
  343. django_cfg/modules/django_logging/LOGGING_GUIDE.md +504 -0
  344. django_cfg/modules/django_logging/__init__.py +14 -0
  345. django_cfg/modules/{django_logger.py → django_logging/django_logger.py} +13 -13
  346. django_cfg/modules/{logger.py → django_logging/logger.py} +14 -4
  347. django_cfg/modules/django_ngrok/__init__.py +39 -0
  348. django_cfg/modules/{django_ngrok.py → django_ngrok/service.py} +14 -42
  349. django_cfg/modules/django_rpc_old/POETRY.md +344 -0
  350. django_cfg/modules/django_rpc_old/README.md +397 -0
  351. django_cfg/modules/django_rpc_old/TESTING.md +358 -0
  352. django_cfg/modules/django_rpc_old/__init__.py +39 -0
  353. django_cfg/modules/django_rpc_old/client.py +531 -0
  354. django_cfg/modules/django_rpc_old/config.py +279 -0
  355. django_cfg/modules/django_rpc_old/exceptions.py +172 -0
  356. django_cfg/modules/django_tailwind/README.md +478 -0
  357. django_cfg/modules/django_tailwind/__init__.py +7 -0
  358. django_cfg/modules/django_tailwind/apps.py +10 -0
  359. django_cfg/modules/django_tailwind/templates/django_tailwind/app.html +5 -0
  360. django_cfg/modules/django_tailwind/templates/django_tailwind/base.html +117 -0
  361. django_cfg/modules/django_tailwind/templates/django_tailwind/components/navbar.html +124 -0
  362. django_cfg/modules/django_tailwind/templates/django_tailwind/components/theme_toggle.html +54 -0
  363. django_cfg/modules/django_tailwind/templates/django_tailwind/components/user_menu.html +116 -0
  364. django_cfg/modules/django_tailwind/templates/django_tailwind/simple.html +46 -0
  365. django_cfg/modules/django_tailwind/templatetags/__init__.py +1 -0
  366. django_cfg/modules/django_tailwind/templatetags/tailwind_info.py +185 -0
  367. django_cfg/modules/django_tasks/__init__.py +29 -0
  368. django_cfg/modules/django_tasks/factory.py +127 -0
  369. django_cfg/modules/{django_tasks.py → django_tasks/service.py} +45 -274
  370. django_cfg/modules/django_tasks/settings.py +107 -0
  371. django_cfg/modules/django_telegram/__init__.py +29 -0
  372. django_cfg/modules/{django_telegram.py → django_telegram/service.py} +45 -113
  373. django_cfg/modules/django_telegram/utils.py +62 -0
  374. django_cfg/modules/django_twilio/__init__.py +54 -107
  375. django_cfg/modules/django_twilio/_imports.py +30 -0
  376. django_cfg/modules/django_twilio/base.py +192 -0
  377. django_cfg/modules/django_twilio/email_otp.py +227 -0
  378. django_cfg/modules/django_twilio/sendgrid_service.py +1 -1
  379. django_cfg/modules/django_twilio/simple_service.py +1 -2
  380. django_cfg/modules/django_twilio/sms.py +94 -0
  381. django_cfg/modules/django_twilio/twilio_service.py +2 -3
  382. django_cfg/modules/django_twilio/unified.py +310 -0
  383. django_cfg/modules/django_twilio/utils.py +190 -0
  384. django_cfg/modules/django_twilio/whatsapp.py +137 -0
  385. django_cfg/modules/django_unfold/callbacks/base.py +198 -7
  386. django_cfg/modules/django_unfold/callbacks/main.py +102 -10
  387. django_cfg/modules/django_unfold/dashboard.py +65 -43
  388. django_cfg/modules/django_unfold/models/config.py +13 -12
  389. django_cfg/modules/django_unfold/models/navigation.py +8 -3
  390. django_cfg/modules/django_unfold/models/tabs.py +2 -2
  391. django_cfg/modules/django_unfold/templates/unfold/helpers/app_list.html +102 -0
  392. django_cfg/registry/core.py +24 -26
  393. django_cfg/registry/modules.py +5 -2
  394. django_cfg/registry/services.py +20 -3
  395. django_cfg/registry/third_party.py +8 -8
  396. django_cfg/static/admin/css/dashboard.css +260 -0
  397. django_cfg/static/admin/js/commands.js +171 -0
  398. django_cfg/static/admin/js/dashboard.js +126 -0
  399. django_cfg/templates/admin/components/management_commands.js +375 -0
  400. django_cfg/templates/admin/components/progress_bar.html +18 -23
  401. django_cfg/templates/admin/examples/component_class_example.html +156 -0
  402. django_cfg/templates/admin/index.html +48 -20
  403. django_cfg/templates/admin/index_new.html +106 -0
  404. django_cfg/templates/admin/layouts/base_dashboard.html +60 -0
  405. django_cfg/templates/admin/layouts/dashboard_with_tabs.html +1 -20
  406. django_cfg/templates/admin/sections/commands_section.html +626 -0
  407. django_cfg/templates/admin/sections/overview_section.html +112 -0
  408. django_cfg/templates/admin/sections/stats_section.html +35 -0
  409. django_cfg/templates/admin/sections/system_section.html +99 -0
  410. django_cfg/templates/admin/snippets/components/CHARTS_GUIDE.md +322 -0
  411. django_cfg/templates/admin/snippets/components/activity_tracker.html +85 -47
  412. django_cfg/templates/admin/snippets/components/charts_section.html +154 -64
  413. django_cfg/templates/admin/snippets/components/django_commands.html +3 -3
  414. django_cfg/templates/admin/snippets/components/recent_activity_improved.html +25 -0
  415. django_cfg/templates/admin/snippets/components/recent_users_table.html +1 -1
  416. django_cfg/templates/admin/snippets/components/system_metrics.html +179 -93
  417. django_cfg/templates/admin/snippets/zones/zones_table.html +2 -2
  418. django_cfg/templatetags/django_cfg.py +7 -1
  419. django_cfg/utils/smart_defaults.py +4 -4
  420. django_cfg-1.4.3.dist-info/METADATA +533 -0
  421. {django_cfg-1.3.13.dist-info → django_cfg-1.4.3.dist-info}/RECORD +432 -195
  422. django_cfg/apps/accounts/utils/auth_email_service.py +0 -84
  423. django_cfg/apps/payments/services/providers/nowpayments/parsers.py +0 -879
  424. django_cfg/core/generation.py +0 -621
  425. django_cfg/management/commands/validate_config.py +0 -189
  426. django_cfg/models/database.py +0 -480
  427. django_cfg/models/drf.py +0 -272
  428. django_cfg/models/ngrok.py +0 -122
  429. django_cfg/models/services.py +0 -440
  430. django_cfg/models/tasks.py +0 -550
  431. django_cfg/modules/django_twilio/service.py +0 -942
  432. django_cfg/template_archive/django_sample.zip +0 -0
  433. django_cfg/templates/rest_framework/api.html +0 -12
  434. django_cfg/utils/toolkit.py +0 -703
  435. django_cfg-1.3.13.dist-info/METADATA +0 -1029
  436. /django_cfg/apps/accounts/management/commands/{test_otp.py → otp_test.py} +0 -0
  437. /django_cfg/core/{environment.py → environment/detector.py} +0 -0
  438. /django_cfg/models/{cors.py → api/cors.py} +0 -0
  439. /django_cfg/models/{jwt.py → api/jwt.py} +0 -0
  440. /django_cfg/models/{base.py → base/config.py} +0 -0
  441. /django_cfg/models/{cfg.py → base/module.py} +0 -0
  442. /django_cfg/models/{revolution.py → django/revolution.py} +0 -0
  443. /django_cfg/modules/{dramatiq_setup.py → django_tasks/dramatiq_setup.py} +0 -0
  444. {django_cfg-1.3.13.dist-info → django_cfg-1.4.3.dist-info}/WHEEL +0 -0
  445. {django_cfg-1.3.13.dist-info → django_cfg-1.4.3.dist-info}/entry_points.txt +0 -0
  446. {django_cfg-1.3.13.dist-info → django_cfg-1.4.3.dist-info}/licenses/LICENSE +0 -0
@@ -1,108 +1,113 @@
1
1
  """
2
- Contextual chunking service.
2
+ Contextual chunking service orchestrator.
3
3
 
4
4
  Creates context-aware chunks with rich metadata for AI understanding.
5
+ Uses specialized chunkers for different content types.
5
6
  """
6
7
 
7
- import re
8
- import ast
9
8
  import logging
10
- from typing import List, Dict, Any, Optional, Tuple
9
+ from typing import List, Optional
11
10
  from django.contrib.auth import get_user_model
12
- from pydantic import BaseModel
13
11
 
14
- from ...models.archive import ArchiveItem, ArchiveItemChunk, ContentType, ChunkType
12
+ from ...models.archive import ArchiveItem, ArchiveItemChunk
15
13
  from ...utils.chunk_settings import get_chunking_params_for_type
16
14
  from ..base import BaseService
17
15
  from .exceptions import ChunkingError
18
16
 
19
- User = get_user_model()
17
+ # Import chunkers
18
+ from .chunking import (
19
+ PythonChunker,
20
+ MarkdownChunker,
21
+ JsonChunker,
22
+ TextChunker
23
+ )
20
24
 
25
+ User = get_user_model()
21
26
  logger = logging.getLogger(__name__)
22
27
 
23
28
 
24
- class ChunkContextMetadata(BaseModel):
25
- """Rich context metadata for chunks."""
26
-
27
- # Parent hierarchy
28
- archive_info: Dict[str, Any]
29
- item_info: Dict[str, Any]
30
-
31
- # Position and structure
32
- position_info: Dict[str, Any]
33
- structure_info: Dict[str, Any]
34
-
35
- # Semantic context
36
- semantic_info: Dict[str, Any]
37
-
38
- # Relational context
39
- relationship_info: Dict[str, Any]
40
-
41
- # Processing provenance
42
- processing_info: Dict[str, Any]
43
-
44
-
45
- class ChunkData(BaseModel):
46
- """Data structure for created chunk."""
47
-
48
- content: str
49
- chunk_index: int
50
- chunk_type: str
51
- context_metadata: Dict[str, Any]
29
+ class ContextualChunkingService(BaseService):
30
+ """
31
+ Service for creating context-aware chunks.
52
32
 
33
+ Orchestrates specialized chunkers using chain of responsibility pattern.
34
+ """
53
35
 
54
- class ContextualChunkingService(BaseService):
55
- """Service for creating context-aware chunks."""
56
-
57
36
  def __init__(self, user: User):
58
37
  super().__init__(user)
38
+
59
39
  # Get dynamic settings from Constance
60
40
  chunking_params = get_chunking_params_for_type('archive')
61
41
  self.chunk_size = chunking_params['chunk_size']
62
42
  self.overlap = chunking_params['overlap']
63
-
64
- logger.info(f"📦 Archive chunking initialized: chunk_size={self.chunk_size}, overlap={self.overlap}")
65
-
43
+
44
+ # Initialize chunkers in priority order
45
+ self.chunkers = [
46
+ PythonChunker(self.chunk_size, self.overlap),
47
+ MarkdownChunker(self.chunk_size, self.overlap),
48
+ JsonChunker(self.chunk_size, self.overlap),
49
+ TextChunker(self.chunk_size, self.overlap), # Fallback - handles anything
50
+ ]
51
+
52
+ logger.info(
53
+ f"📦 Archive chunking initialized: "
54
+ f"chunk_size={self.chunk_size}, overlap={self.overlap}"
55
+ )
56
+
66
57
  def create_chunks_with_context(
67
- self,
58
+ self,
68
59
  item: ArchiveItem,
69
60
  chunk_size: Optional[int] = None,
70
61
  overlap: Optional[int] = None
71
62
  ) -> List[ArchiveItemChunk]:
72
- """Create chunks with rich context metadata."""
73
-
63
+ """
64
+ Create chunks with rich context metadata.
65
+
66
+ Uses specialized chunkers based on content type.
67
+
68
+ Args:
69
+ item: Archive item to chunk
70
+ chunk_size: Optional custom chunk size
71
+ overlap: Optional custom overlap size
72
+
73
+ Returns:
74
+ List of created chunk objects
75
+ """
74
76
  if not item.raw_content or not item.is_processable:
75
77
  return []
76
-
78
+
77
79
  # Use instance settings if parameters not provided
78
80
  final_chunk_size = chunk_size or self.chunk_size
79
81
  final_overlap = overlap or self.overlap
80
-
81
- logger.debug(f"📦 Chunking {item.relative_path}: size={final_chunk_size}, overlap={final_overlap}")
82
-
82
+
83
+ # Update chunkers if custom sizes provided
84
+ if chunk_size or overlap:
85
+ self._update_chunker_settings(final_chunk_size, final_overlap)
86
+
87
+ logger.debug(
88
+ f"📦 Chunking {item.relative_path}: "
89
+ f"size={final_chunk_size}, overlap={final_overlap}"
90
+ )
91
+
83
92
  try:
84
- # Debug logging
85
- logger.info(f"Creating chunks for item: {item.relative_path}, content_type: {item.content_type}")
86
-
87
- # Choose chunking strategy based on content type
88
- if item.content_type == ContentType.CODE:
89
- logger.debug(f"Using code chunking for {item.relative_path}")
90
- chunks_data = self._chunk_code_content(item, final_chunk_size, final_overlap)
91
- elif item.content_type == ContentType.DOCUMENT:
92
- logger.debug(f"Using document chunking for {item.relative_path}")
93
- chunks_data = self._chunk_document_content(item, final_chunk_size, final_overlap)
94
- elif item.content_type == ContentType.DATA:
95
- logger.debug(f"Using data chunking for {item.relative_path}")
96
- chunks_data = self._chunk_data_content(item, final_chunk_size, final_overlap)
97
- else:
98
- logger.debug(f"Using generic chunking for {item.relative_path}")
99
- chunks_data = self._chunk_generic_content(item, final_chunk_size, final_overlap)
100
-
93
+ logger.info(
94
+ f"Creating chunks for item: {item.relative_path}, "
95
+ f"content_type: {item.content_type}"
96
+ )
97
+
98
+ # Find appropriate chunker using chain of responsibility
99
+ chunker = self._select_chunker(item)
100
+ logger.debug(
101
+ f"Using {chunker.__class__.__name__} for {item.relative_path}"
102
+ )
103
+
104
+ # Create chunks using selected chunker
105
+ chunks_data = chunker.chunk(item)
101
106
  logger.info(f"Generated {len(chunks_data)} chunks for {item.relative_path}")
102
-
103
- # Create chunk records
107
+
108
+ # Create chunk records in database
104
109
  chunk_objects = []
105
-
110
+
106
111
  for chunk_data in chunks_data:
107
112
  # Use objects to avoid custom manager issues
108
113
  chunk = ArchiveItemChunk.objects.create(
@@ -115,11 +120,14 @@ class ContextualChunkingService(BaseService):
115
120
  context_metadata=chunk_data.context_metadata
116
121
  )
117
122
  chunk_objects.append(chunk)
118
-
123
+
119
124
  return chunk_objects
120
-
125
+
121
126
  except Exception as e:
122
- logger.error(f"Chunking failed for {item.relative_path}: {str(e)}", exc_info=True)
127
+ logger.error(
128
+ f"Chunking failed for {item.relative_path}: {str(e)}",
129
+ exc_info=True
130
+ )
123
131
  raise ChunkingError(
124
132
  message=f"Failed to create chunks for item {item.relative_path}",
125
133
  code="CHUNKING_FAILED",
@@ -131,661 +139,34 @@ class ContextualChunkingService(BaseService):
131
139
  "content_length": len(item.raw_content) if item.raw_content else 0
132
140
  }
133
141
  ) from e
134
-
135
- def _chunk_code_content(
136
- self,
137
- item: ArchiveItem,
138
- chunk_size: int,
139
- overlap: int
140
- ) -> List[ChunkData]:
141
- """Chunk code files by logical boundaries."""
142
-
143
- if item.language == 'python':
144
- return self._chunk_python_code(item)
145
- elif item.language in ['javascript', 'typescript']:
146
- return self._chunk_js_code(item)
147
- else:
148
- return self._chunk_generic_code(item, chunk_size, overlap)
149
-
150
- def _chunk_python_code(self, item: ArchiveItem) -> List[ChunkData]:
151
- """Chunk Python code by classes and functions."""
152
-
153
- content = item.raw_content
154
- lines = content.split('\n')
155
- chunks = []
156
-
157
- try:
158
- tree = ast.parse(content)
159
-
160
- # Extract imports first
161
- imports_chunk = self._extract_python_imports(tree, lines, item, 0)
162
- if imports_chunk:
163
- chunks.append(imports_chunk)
164
-
165
- # Extract classes and functions
166
- for node in ast.walk(tree):
167
- if isinstance(node, (ast.ClassDef, ast.FunctionDef, ast.AsyncFunctionDef)):
168
- chunk = self._create_python_element_chunk(
169
- node, lines, item, len(chunks)
170
- )
171
- chunks.append(chunk)
172
-
173
- # Handle module-level code
174
- remaining_chunk = self._extract_python_remaining_code(
175
- tree, lines, item, len(chunks)
176
- )
177
- if remaining_chunk:
178
- chunks.append(remaining_chunk)
179
-
180
- except SyntaxError:
181
- # Fallback to line-based chunking
182
- return self._chunk_generic_code(item, self.chunk_size, self.overlap)
183
-
184
- return chunks
185
-
186
- def _create_python_element_chunk(
187
- self,
188
- node: ast.AST,
189
- lines: List[str],
190
- item: ArchiveItem,
191
- chunk_index: int
192
- ) -> ChunkData:
193
- """Create chunk for Python code element."""
194
-
195
- start_line = node.lineno - 1
196
- end_line = self._find_python_block_end(node, lines)
197
-
198
- content = '\n'.join(lines[start_line:end_line])
199
-
200
- # Analyze code structure
201
- code_info = self._analyze_python_structure(node, content)
202
-
203
- # Build context metadata
204
- context = self._build_code_chunk_context(
205
- item, chunk_index, content, start_line, end_line, code_info
206
- )
207
-
208
- return ChunkData(
209
- content=content,
210
- chunk_index=chunk_index,
211
- chunk_type=ChunkType.CODE,
212
- context_metadata=context
213
- )
214
-
215
- def _analyze_python_structure(self, node: ast.AST, content: str) -> Dict[str, Any]:
216
- """Analyze Python code structure for context."""
217
-
218
- info = {
219
- 'element_name': node.name,
220
- 'element_type': 'class' if isinstance(node, ast.ClassDef) else 'function',
221
- 'is_async': isinstance(node, ast.AsyncFunctionDef),
222
- 'docstring': ast.get_docstring(node),
223
- 'decorators': [d.id for d in getattr(node, 'decorator_list', []) if hasattr(d, 'id')],
224
- 'complexity_score': self._calculate_code_complexity(content),
225
- 'purpose': self._detect_code_purpose(node.name, content),
226
- }
227
-
228
- # Extract function/method arguments
229
- if hasattr(node, 'args'):
230
- info['arguments'] = [arg.arg for arg in node.args.args]
231
-
232
- # Extract class bases
233
- if isinstance(node, ast.ClassDef):
234
- info['base_classes'] = [base.id for base in node.bases if hasattr(base, 'id')]
235
-
236
- return info
237
-
238
- def _chunk_document_content(
239
- self,
240
- item: ArchiveItem,
241
- chunk_size: int,
242
- overlap: int
243
- ) -> List[ChunkData]:
244
- """Chunk document files by structure."""
245
-
246
- if item.language == 'markdown':
247
- return self._chunk_markdown_content(item)
248
- else:
249
- return self._chunk_generic_content(item, chunk_size, overlap)
250
-
251
- def _chunk_markdown_content(self, item: ArchiveItem) -> List[ChunkData]:
252
- """Chunk markdown by headings and sections."""
253
-
254
- content = item.raw_content
255
- lines = content.split('\n')
256
- chunks = []
257
-
258
- current_section = {'title': '', 'level': 0, 'start_line': 0}
259
-
260
- for i, line in enumerate(lines):
261
- if line.startswith('#'):
262
- # New section found
263
- if current_section['start_line'] < i:
264
- # Create chunk for previous section
265
- chunk = self._create_markdown_section_chunk(
266
- lines[current_section['start_line']:i],
267
- current_section,
268
- item,
269
- len(chunks)
270
- )
271
- chunks.append(chunk)
272
-
273
- # Start new section
274
- level = len(line) - len(line.lstrip('#'))
275
- current_section = {
276
- 'title': line.lstrip('# ').strip(),
277
- 'level': level,
278
- 'start_line': i
279
- }
280
-
281
- # Handle last section
282
- if current_section['start_line'] < len(lines):
283
- chunk = self._create_markdown_section_chunk(
284
- lines[current_section['start_line']:],
285
- current_section,
286
- item,
287
- len(chunks)
288
- )
289
- chunks.append(chunk)
290
-
291
- return chunks
292
-
293
- def _create_markdown_section_chunk(
294
- self,
295
- section_lines: List[str],
296
- section_info: Dict[str, Any],
297
- item: ArchiveItem,
298
- chunk_index: int
299
- ) -> ChunkData:
300
- """Create chunk for markdown section."""
301
-
302
- content = '\n'.join(section_lines)
303
-
304
- # Build context metadata
305
- context = self._build_document_chunk_context(
306
- item, chunk_index, content, section_info
307
- )
308
-
309
- chunk_type = ChunkType.HEADING if section_info['title'] else ChunkType.TEXT
310
-
311
- return ChunkData(
312
- content=content,
313
- chunk_index=chunk_index,
314
- chunk_type=chunk_type,
315
- context_metadata=context
316
- )
317
-
318
- def _chunk_data_content(
319
- self,
320
- item: ArchiveItem,
321
- chunk_size: int,
322
- overlap: int
323
- ) -> List[ChunkData]:
324
- """Chunk data files by logical structure."""
325
-
326
- if item.language == 'json':
327
- return self._chunk_json_content(item)
328
- elif item.language in ['yaml', 'yml']:
329
- return self._chunk_yaml_content(item)
330
- else:
331
- return self._chunk_generic_content(item, chunk_size, overlap)
332
-
333
- def _chunk_json_content(self, item: ArchiveItem) -> List[ChunkData]:
334
- """Chunk JSON by object structure."""
335
-
336
- import json
337
-
338
- try:
339
- data = json.loads(item.raw_content)
340
- chunks = []
341
-
342
- if isinstance(data, dict):
343
- # Chunk by top-level keys
344
- for key, value in data.items():
345
- chunk_content = json.dumps({key: value}, indent=2)
346
-
347
- context = self._build_data_chunk_context(
348
- item, len(chunks), chunk_content, 'json_object', key
349
- )
350
-
351
- chunks.append(ChunkData(
352
- content=chunk_content,
353
- chunk_index=len(chunks),
354
- chunk_type=ChunkType.METADATA,
355
- context_metadata=context
356
- ))
357
-
358
- return chunks
359
-
360
- except json.JSONDecodeError:
361
- # Fallback to text chunking
362
- return self._chunk_generic_content(item, self.chunk_size, self.overlap)
363
-
364
- def _chunk_generic_content(
365
- self,
366
- item: ArchiveItem,
367
- chunk_size: int,
368
- overlap: int
369
- ) -> List[ChunkData]:
370
- """Generic text chunking with overlap."""
371
-
372
- content = item.raw_content
373
- chunks = []
374
-
375
- # Simple text splitting with overlap
376
- start = 0
377
- chunk_index = 0
378
-
379
- while start < len(content):
380
- end = start + chunk_size
381
-
382
- # Try to break at word boundary
383
- if end < len(content):
384
- # Look for good break points
385
- break_point = self._find_good_break_point(content, start, end)
386
- if break_point > start:
387
- end = break_point
388
-
389
- chunk_content = content[start:end].strip()
390
-
391
- if chunk_content:
392
- context = self._build_generic_chunk_context(
393
- item, chunk_index, chunk_content, start, end
394
- )
395
-
396
- chunks.append(ChunkData(
397
- content=chunk_content,
398
- chunk_index=chunk_index,
399
- chunk_type=ChunkType.TEXT,
400
- context_metadata=context
401
- ))
402
-
403
- chunk_index += 1
404
-
405
- # Move start position with overlap
406
- start = max(start + chunk_size - overlap, end)
407
-
408
- return chunks
409
-
410
- def _find_good_break_point(self, content: str, start: int, end: int) -> int:
411
- """Find good break point for text chunking."""
412
-
413
- # Look for sentence endings
414
- for i in range(end - 1, start, -1):
415
- if content[i] in '.!?\n':
416
- return i + 1
417
-
418
- # Look for word boundaries
419
- for i in range(end - 1, start, -1):
420
- if content[i].isspace():
421
- return i
422
-
423
- return end
424
-
425
- def _build_code_chunk_context(
426
- self,
427
- item: ArchiveItem,
428
- chunk_index: int,
429
- content: str,
430
- start_line: int,
431
- end_line: int,
432
- code_info: Dict[str, Any]
433
- ) -> Dict[str, Any]:
434
- """Build context metadata for code chunk."""
435
-
436
- return {
437
- 'archive_info': {
438
- 'id': str(item.archive.id),
439
- 'title': item.archive.title,
440
- 'description': item.archive.description,
441
- },
442
- 'item_info': {
443
- 'id': str(item.id),
444
- 'relative_path': item.relative_path,
445
- 'item_name': item.item_name,
446
- 'content_type': item.content_type,
447
- 'language': item.language,
448
- },
449
- 'position_info': {
450
- 'chunk_index': chunk_index,
451
- 'start_line': start_line + 1,
452
- 'end_line': end_line,
453
- 'total_lines': len(item.raw_content.split('\n')),
454
- },
455
- 'structure_info': {
456
- 'element_name': code_info.get('element_name'),
457
- 'element_type': code_info.get('element_type'),
458
- 'is_async': code_info.get('is_async', False),
459
- 'has_docstring': bool(code_info.get('docstring')),
460
- },
461
- 'semantic_info': {
462
- 'chunk_type': 'code',
463
- 'content_purpose': code_info.get('purpose', 'implementation'),
464
- 'complexity_score': code_info.get('complexity_score', 0.0),
465
- 'technical_tags': self._generate_code_tags(content, code_info),
466
- },
467
- 'processing_info': {
468
- 'extraction_method': 'ast_parser',
469
- 'chunking_strategy': 'logical_units',
470
- 'quality_score': self._assess_code_quality(content),
471
- }
472
- }
473
-
474
- def _build_document_chunk_context(
475
- self,
476
- item: ArchiveItem,
477
- chunk_index: int,
478
- content: str,
479
- section_info: Dict[str, Any]
480
- ) -> Dict[str, Any]:
481
- """Build context metadata for document chunk."""
482
-
483
- return {
484
- 'archive_info': {
485
- 'id': str(item.archive.id),
486
- 'title': item.archive.title,
487
- },
488
- 'item_info': {
489
- 'id': str(item.id),
490
- 'relative_path': item.relative_path,
491
- 'content_type': item.content_type,
492
- 'language': item.language,
493
- },
494
- 'position_info': {
495
- 'chunk_index': chunk_index,
496
- },
497
- 'structure_info': {
498
- 'section_title': section_info.get('title'),
499
- 'section_level': section_info.get('level', 0),
500
- },
501
- 'semantic_info': {
502
- 'chunk_type': 'heading' if section_info.get('title') else 'text',
503
- 'content_purpose': 'documentation',
504
- 'topic_tags': self._generate_document_tags(content),
505
- },
506
- 'processing_info': {
507
- 'extraction_method': 'markdown_parser',
508
- 'chunking_strategy': 'heading_based',
509
- }
510
- }
511
-
512
- def _build_data_chunk_context(
513
- self,
514
- item: ArchiveItem,
515
- chunk_index: int,
516
- content: str,
517
- data_type: str,
518
- key_name: Optional[str] = None
519
- ) -> Dict[str, Any]:
520
- """Build context metadata for data chunk."""
521
-
522
- return {
523
- 'archive_info': {
524
- 'id': str(item.archive.id),
525
- 'title': item.archive.title,
526
- },
527
- 'item_info': {
528
- 'id': str(item.id),
529
- 'relative_path': item.relative_path,
530
- 'content_type': item.content_type,
531
- },
532
- 'position_info': {
533
- 'chunk_index': chunk_index,
534
- },
535
- 'structure_info': {
536
- 'data_key': key_name,
537
- 'data_type': data_type,
538
- },
539
- 'semantic_info': {
540
- 'chunk_type': 'metadata',
541
- 'content_purpose': 'data_definition',
542
- },
543
- 'processing_info': {
544
- 'extraction_method': 'json_parser',
545
- 'chunking_strategy': 'object_properties',
546
- }
547
- }
548
-
549
- def _build_generic_chunk_context(
550
- self,
551
- item: ArchiveItem,
552
- chunk_index: int,
553
- content: str,
554
- start_pos: int,
555
- end_pos: int
556
- ) -> Dict[str, Any]:
557
- """Build context metadata for generic text chunk."""
558
-
559
- return {
560
- 'archive_info': {
561
- 'id': str(item.archive.id),
562
- 'title': item.archive.title,
563
- },
564
- 'item_info': {
565
- 'id': str(item.id),
566
- 'relative_path': item.relative_path,
567
- 'content_type': item.content_type,
568
- },
569
- 'position_info': {
570
- 'chunk_index': chunk_index,
571
- 'start_char': start_pos,
572
- 'end_char': end_pos,
573
- 'relative_position': start_pos / len(item.raw_content),
574
- },
575
- 'semantic_info': {
576
- 'chunk_type': 'text',
577
- 'content_purpose': 'content',
578
- },
579
- 'processing_info': {
580
- 'extraction_method': 'text_splitting',
581
- 'chunking_strategy': 'fixed_size_overlap',
582
- }
583
- }
584
-
585
- def _generate_code_tags(self, content: str, code_info: Dict[str, Any]) -> List[str]:
586
- """Generate technical tags for code content."""
587
-
588
- tags = []
589
-
590
- # Element type tags
591
- if code_info.get('element_type'):
592
- tags.append(f"contains:{code_info['element_type']}")
593
-
594
- # Async tag
595
- if code_info.get('is_async'):
596
- tags.append('async')
597
-
598
- # Pattern detection
599
- if 'import ' in content or 'from ' in content:
600
- tags.append('contains:imports')
601
-
602
- if 'class ' in content:
603
- tags.append('contains:class_definition')
604
-
605
- if 'def ' in content:
606
- tags.append('contains:function_definition')
607
-
608
- if 'test' in code_info.get('element_name', '').lower():
609
- tags.append('purpose:testing')
610
-
611
- return tags
612
-
613
- def _generate_document_tags(self, content: str) -> List[str]:
614
- """Generate topic tags for document content."""
615
-
616
- tags = []
617
-
618
- # Detect headings
619
- if content.strip().startswith('#'):
620
- tags.append('contains:heading')
621
-
622
- # Detect lists
623
- if re.search(r'^\s*[-*+]\s', content, re.MULTILINE):
624
- tags.append('contains:list')
625
-
626
- # Detect code blocks
627
- if '```' in content or ' ' in content:
628
- tags.append('contains:code_block')
629
-
630
- return tags
631
-
632
- def _calculate_code_complexity(self, content: str) -> float:
633
- """Calculate code complexity score."""
634
-
635
- # Simple complexity based on lines and control structures
636
- lines = content.split('\n')
637
- complexity = len(lines) / 100.0 # Base complexity
638
-
639
- # Add complexity for control structures
640
- control_keywords = ['if', 'for', 'while', 'try', 'except', 'with']
641
- for keyword in control_keywords:
642
- complexity += content.count(keyword) * 0.1
643
-
644
- return min(1.0, complexity)
645
-
646
- def _assess_code_quality(self, content: str) -> float:
647
- """Assess code quality score."""
648
-
649
- # Simple quality assessment
650
- quality = 0.5 # Base quality
651
-
652
- # Boost for docstrings
653
- if '"""' in content or "'''" in content:
654
- quality += 0.2
655
-
656
- # Boost for comments
657
- comment_lines = len([line for line in content.split('\n') if line.strip().startswith('#')])
658
- quality += min(0.2, comment_lines / 10.0)
659
-
660
- # Penalty for very long lines
661
- long_lines = len([line for line in content.split('\n') if len(line) > 100])
662
- quality -= min(0.2, long_lines / 10.0)
663
-
664
- return max(0.0, min(1.0, quality))
665
-
666
- def _detect_code_purpose(self, element_name: str, content: str) -> str:
667
- """Detect purpose of code element."""
668
-
669
- name_lower = element_name.lower()
670
-
671
- if name_lower.startswith('test_'):
672
- return 'test'
673
- elif name_lower.startswith('_'):
674
- return 'private_method'
675
- elif 'config' in name_lower:
676
- return 'configuration'
677
- elif 'init' in name_lower:
678
- return 'initialization'
679
- elif 'main' in name_lower:
680
- return 'main_function'
681
- else:
682
- return 'implementation'
683
-
684
- def _find_python_block_end(self, node: ast.AST, lines: List[str]) -> int:
685
- """Find end line of Python code block."""
686
-
687
- # Start from the node's end line
688
- start_line = getattr(node, 'end_lineno', node.lineno) or node.lineno
689
-
690
- # Look for the actual end by checking indentation
691
- for i in range(start_line, len(lines)):
692
- line = lines[i]
693
- if line.strip() and not line.startswith(' ') and not line.startswith('\t'):
694
- return i
695
-
696
- return len(lines)
697
-
698
- def _extract_python_imports(
699
- self,
700
- tree: ast.AST,
701
- lines: List[str],
702
- item: ArchiveItem,
703
- chunk_index: int
704
- ) -> Optional[ChunkData]:
705
- """Extract imports as separate chunk."""
706
-
707
- import_lines = []
708
-
709
- for node in ast.walk(tree):
710
- if isinstance(node, (ast.Import, ast.ImportFrom)):
711
- import_lines.append(node.lineno - 1)
712
-
713
- if not import_lines:
714
- return None
715
-
716
- # Get all import lines
717
- import_content = '\n'.join(lines[min(import_lines):max(import_lines) + 1])
718
-
719
- context = self._build_code_chunk_context(
720
- item, chunk_index, import_content,
721
- min(import_lines), max(import_lines) + 1,
722
- {'element_name': 'imports', 'element_type': 'imports', 'purpose': 'imports'}
723
- )
724
-
725
- return ChunkData(
726
- content=import_content,
727
- chunk_index=chunk_index,
728
- chunk_type=ChunkType.METADATA,
729
- context_metadata=context
730
- )
731
-
732
- def _extract_python_remaining_code(
733
- self,
734
- tree: ast.AST,
735
- lines: List[str],
736
- item: ArchiveItem,
737
- chunk_index: int
738
- ) -> Optional[ChunkData]:
739
- """Extract remaining module-level code."""
740
-
741
- # This is a simplified implementation
742
- # In practice, you'd want to identify module-level statements
743
- # that aren't part of classes or functions
744
-
745
- return None # Skip for now
746
-
747
- def _chunk_generic_code(
748
- self,
749
- item: ArchiveItem,
750
- chunk_size: int,
751
- overlap: int
752
- ) -> List[ChunkData]:
753
- """Generic code chunking for unsupported languages."""
754
-
755
- return self._chunk_generic_content(item, chunk_size, overlap)
756
-
757
- def _chunk_js_code(self, item: ArchiveItem) -> List[ChunkData]:
758
- """Chunk JavaScript/TypeScript code."""
759
-
760
- # Simplified implementation - could be enhanced with proper JS parsing
761
- return self._chunk_generic_content(item, self.chunk_size, self.overlap)
762
-
763
- def _chunk_yaml_content(self, item: ArchiveItem) -> List[ChunkData]:
764
- """Chunk YAML content."""
765
-
766
- # Simplified implementation - could be enhanced with YAML parsing
767
- return self._chunk_generic_content(item, self.chunk_size, self.overlap)
768
-
769
-
770
- class ChunkContextBuilder:
771
- """Helper class for building chunk context metadata."""
772
-
773
- @staticmethod
774
- def build_context(
775
- archive_info: Dict[str, Any],
776
- item_info: Dict[str, Any],
777
- position_info: Dict[str, Any],
778
- structure_info: Dict[str, Any],
779
- semantic_info: Dict[str, Any],
780
- processing_info: Dict[str, Any]
781
- ) -> Dict[str, Any]:
782
- """Build complete context metadata."""
783
-
784
- return {
785
- 'archive_info': archive_info,
786
- 'item_info': item_info,
787
- 'position_info': position_info,
788
- 'structure_info': structure_info,
789
- 'semantic_info': semantic_info,
790
- 'processing_info': processing_info
791
- }
142
+
143
+ def _select_chunker(self, item: ArchiveItem):
144
+ """
145
+ Select appropriate chunker for item.
146
+
147
+ Uses chain of responsibility - first chunker that can handle wins.
148
+
149
+ Args:
150
+ item: Archive item to chunk
151
+
152
+ Returns:
153
+ Chunker instance
154
+ """
155
+ for chunker in self.chunkers:
156
+ if chunker.can_handle(item):
157
+ return chunker
158
+
159
+ # Should never happen since TextChunker handles everything
160
+ return self.chunkers[-1]
161
+
162
+ def _update_chunker_settings(self, chunk_size: int, overlap: int):
163
+ """
164
+ Update all chunkers with new settings.
165
+
166
+ Args:
167
+ chunk_size: New chunk size
168
+ overlap: New overlap size
169
+ """
170
+ for chunker in self.chunkers:
171
+ chunker.chunk_size = chunk_size
172
+ chunker.overlap = overlap