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.
- django_cfg/__init__.py +1 -1
- django_cfg/apps/accounts/admin/user_admin.py +39 -16
- django_cfg/apps/accounts/serializers/profile.py +1 -1
- django_cfg/apps/accounts/services/otp_service.py +18 -11
- django_cfg/apps/accounts/signals.py +15 -24
- django_cfg/apps/accounts/utils/notifications.py +217 -358
- django_cfg/apps/accounts/views/otp.py +2 -2
- django_cfg/apps/accounts/views/webhook.py +1 -1
- django_cfg/apps/agents/core/django_agent.py +1 -1
- django_cfg/apps/agents/examples/__init__.py +3 -0
- django_cfg/apps/agents/examples/simple_example.py +161 -0
- django_cfg/apps/api/commands/views.py +66 -83
- django_cfg/apps/api/health/drf_views.py +269 -0
- django_cfg/apps/api/health/serializers.py +45 -0
- django_cfg/apps/api/health/urls.py +6 -1
- django_cfg/apps/knowbase/admin/actions/__init__.py +13 -0
- django_cfg/apps/knowbase/admin/actions/visibility_actions.py +56 -0
- django_cfg/apps/knowbase/admin/document_admin.py +136 -270
- django_cfg/apps/knowbase/admin/helpers/__init__.py +17 -0
- django_cfg/apps/knowbase/admin/helpers/configs.py +72 -0
- django_cfg/apps/knowbase/admin/helpers/display_helpers.py +156 -0
- django_cfg/apps/knowbase/admin/helpers/statistics.py +108 -0
- django_cfg/apps/knowbase/config/constance_fields.py +1 -1
- django_cfg/apps/knowbase/config/settings.py +2 -2
- django_cfg/apps/knowbase/examples/__init__.py +3 -0
- django_cfg/apps/knowbase/examples/external_data_usage.py +191 -0
- django_cfg/apps/knowbase/mixins/__init__.py +19 -2
- django_cfg/apps/knowbase/mixins/config/__init__.py +14 -0
- django_cfg/apps/knowbase/mixins/config/defaults.py +75 -0
- django_cfg/apps/knowbase/mixins/config/meta_config.py +120 -0
- django_cfg/apps/knowbase/mixins/creator.py +10 -10
- django_cfg/apps/knowbase/mixins/examples/vehicle_model_example.py +199 -0
- django_cfg/apps/knowbase/mixins/external_data_mixin.py +105 -403
- django_cfg/apps/knowbase/mixins/generators/__init__.py +16 -0
- django_cfg/apps/knowbase/mixins/generators/content_generator.py +218 -0
- django_cfg/apps/knowbase/mixins/generators/field_analyzer.py +76 -0
- django_cfg/apps/knowbase/mixins/generators/metadata_generator.py +124 -0
- django_cfg/apps/knowbase/mixins/service.py +2 -2
- django_cfg/apps/knowbase/services/archive/__init__.py +1 -0
- django_cfg/apps/knowbase/services/archive/analyzers/__init__.py +17 -0
- django_cfg/apps/knowbase/services/archive/analyzers/complexity_analyzer.py +33 -0
- django_cfg/apps/knowbase/services/archive/analyzers/purpose_detector.py +36 -0
- django_cfg/apps/knowbase/services/archive/analyzers/quality_analyzer.py +39 -0
- django_cfg/apps/knowbase/services/archive/analyzers/tag_generator.py +103 -0
- django_cfg/apps/knowbase/services/archive/chunking/__init__.py +19 -0
- django_cfg/apps/knowbase/services/archive/chunking/base.py +81 -0
- django_cfg/apps/knowbase/services/archive/chunking/json_chunker.py +62 -0
- django_cfg/apps/knowbase/services/archive/chunking/markdown_chunker.py +107 -0
- django_cfg/apps/knowbase/services/archive/chunking/python_chunker.py +248 -0
- django_cfg/apps/knowbase/services/archive/chunking/text_chunker.py +70 -0
- django_cfg/apps/knowbase/services/archive/chunking_service.py +110 -729
- django_cfg/apps/knowbase/services/archive/context/__init__.py +14 -0
- django_cfg/apps/knowbase/services/archive/context/builders.py +220 -0
- django_cfg/apps/knowbase/services/archive/context/models.py +38 -0
- django_cfg/apps/knowbase/services/embedding/models.py +18 -14
- django_cfg/apps/knowbase/services/embedding/processors.py +6 -3
- django_cfg/apps/knowbase/tasks/document_processing.py +11 -3
- django_cfg/apps/leads/tests.py +1 -1
- django_cfg/apps/payments/admin/api_keys_admin.py +1 -1
- django_cfg/apps/payments/admin/balance_admin.py +1 -1
- django_cfg/apps/payments/admin/currencies_admin.py +1 -1
- django_cfg/apps/payments/admin/payments_admin.py +1 -1
- django_cfg/apps/payments/admin/subscriptions_admin.py +1 -1
- django_cfg/apps/payments/admin_interface/templates/payments/base.html +59 -126
- django_cfg/apps/payments/admin_interface/views/api/payments.py +1 -1
- django_cfg/apps/payments/admin_interface/views/api/stats.py +1 -1
- django_cfg/apps/payments/admin_interface/views/api/users.py +1 -1
- django_cfg/apps/payments/admin_interface/views/api/webhook_admin.py +1 -1
- django_cfg/apps/payments/admin_interface/views/api/webhook_public.py +1 -1
- django_cfg/apps/payments/admin_interface/views/base.py +29 -2
- django_cfg/apps/payments/apps.py +1 -1
- django_cfg/apps/payments/config/django_cfg_integration.py +2 -2
- django_cfg/apps/payments/config/helpers.py +3 -2
- django_cfg/apps/payments/management/commands/cleanup_expired_data.py +1 -1
- django_cfg/apps/payments/management/commands/currency_stats.py +1 -1
- django_cfg/apps/payments/management/commands/manage_currencies.py +1 -1
- django_cfg/apps/payments/management/commands/manage_providers.py +1 -1
- django_cfg/apps/payments/management/commands/process_pending_payments.py +1 -1
- django_cfg/apps/payments/management/commands/test_providers.py +1 -1
- django_cfg/apps/payments/middleware/api_access.py +1 -1
- django_cfg/apps/payments/middleware/rate_limiting.py +1 -1
- django_cfg/apps/payments/middleware/usage_tracking.py +1 -1
- django_cfg/apps/payments/models/balance.py +2 -2
- django_cfg/apps/payments/models/managers/api_key_managers.py +1 -1
- django_cfg/apps/payments/models/managers/balance_managers.py +1 -1
- django_cfg/apps/payments/models/managers/currency_managers.py +1 -1
- django_cfg/apps/payments/models/managers/payment_managers.py +1 -1
- django_cfg/apps/payments/models/managers/subscription_managers.py +1 -1
- django_cfg/apps/payments/models/payments.py +2 -2
- django_cfg/apps/payments/services/cache_service/__init__.py +1 -1
- django_cfg/apps/payments/services/cache_service/simple_cache.py +10 -5
- django_cfg/apps/payments/services/core/base.py +1 -1
- django_cfg/apps/payments/services/core/currency/__init__.py +13 -0
- django_cfg/apps/payments/services/core/currency/currency_converter.py +57 -0
- django_cfg/apps/payments/services/core/currency/currency_validator.py +61 -0
- django_cfg/apps/payments/services/core/operations/__init__.py +15 -0
- django_cfg/apps/payments/services/core/operations/payment_canceller.py +100 -0
- django_cfg/apps/payments/services/core/operations/payment_creator.py +196 -0
- django_cfg/apps/payments/services/core/operations/status_checker.py +100 -0
- django_cfg/apps/payments/services/core/payment_service.py +124 -612
- django_cfg/apps/payments/services/core/providers/__init__.py +13 -0
- django_cfg/apps/payments/services/core/providers/provider_client.py +132 -0
- django_cfg/apps/payments/services/core/providers/status_mapper.py +89 -0
- django_cfg/apps/payments/services/core/utils/__init__.py +13 -0
- django_cfg/apps/payments/services/core/utils/data_converter.py +48 -0
- django_cfg/apps/payments/services/core/utils/statistics_calculator.py +69 -0
- django_cfg/apps/payments/services/providers/base.py +1 -1
- django_cfg/apps/payments/services/providers/nowpayments/__init__.py +3 -3
- django_cfg/apps/payments/services/providers/nowpayments/parsers/__init__.py +9 -0
- django_cfg/apps/payments/services/providers/nowpayments/parsers/data/__init__.py +23 -0
- django_cfg/apps/payments/services/providers/nowpayments/parsers/data/constants.py +23 -0
- django_cfg/apps/payments/services/providers/nowpayments/parsers/data/currency_names.py +244 -0
- django_cfg/apps/payments/services/providers/nowpayments/parsers/data/patterns.py +511 -0
- django_cfg/apps/payments/services/providers/nowpayments/parsers/parser.py +168 -0
- django_cfg/apps/payments/services/providers/nowpayments/provider.py +1 -1
- django_cfg/apps/payments/services/providers/nowpayments/sync.py +1 -1
- django_cfg/apps/payments/services/providers/registry.py +1 -1
- django_cfg/apps/payments/services/providers/sync_service.py +1 -1
- django_cfg/apps/payments/signals/__init__.py +1 -1
- django_cfg/apps/payments/signals/api_key_signals.py +1 -1
- django_cfg/apps/payments/signals/balance_signals.py +1 -1
- django_cfg/apps/payments/signals/payment_signals.py +1 -1
- django_cfg/apps/payments/signals/subscription_signals.py +1 -1
- django_cfg/apps/payments/views/api/api_keys.py +1 -1
- django_cfg/apps/payments/views/api/balances.py +1 -1
- django_cfg/apps/payments/views/api/base.py +1 -1
- django_cfg/apps/payments/views/api/currencies.py +1 -1
- django_cfg/apps/payments/views/api/payments.py +1 -1
- django_cfg/apps/payments/views/api/subscriptions.py +1 -1
- django_cfg/apps/payments/views/api/webhooks.py +1 -1
- django_cfg/apps/payments/views/serializers/api_keys.py +1 -1
- django_cfg/apps/payments/views/serializers/balances.py +1 -1
- django_cfg/apps/payments/views/serializers/currencies.py +1 -1
- django_cfg/apps/payments/views/serializers/payments.py +1 -1
- django_cfg/apps/payments/views/serializers/subscriptions.py +1 -1
- django_cfg/apps/payments/views/serializers/webhooks.py +1 -1
- django_cfg/apps/support/admin/support_admin.py +21 -13
- django_cfg/apps/support/templates/support/chat/access_denied.html +21 -27
- django_cfg/apps/support/templates/support/chat/ticket_chat.html +183 -254
- django_cfg/apps/support/utils/support_email_service.py +1 -1
- django_cfg/apps/tasks/templates/tasks/layout/base.html +20 -115
- django_cfg/apps/tasks/utils/simulator.py +1 -1
- django_cfg/apps/tasks/views/dashboard.py +33 -3
- django_cfg/apps/urls.py +5 -1
- django_cfg/cli/README.md +57 -471
- django_cfg/cli/commands/create_project.py +140 -529
- django_cfg/cli/main.py +13 -10
- django_cfg/core/__init__.py +63 -6
- django_cfg/core/base/__init__.py +5 -0
- django_cfg/core/base/config_model.py +652 -0
- django_cfg/core/builders/__init__.py +11 -0
- django_cfg/core/builders/apps_builder.py +258 -0
- django_cfg/core/builders/middleware_builder.py +115 -0
- django_cfg/core/builders/security_builder.py +96 -0
- django_cfg/core/config.py +20 -892
- django_cfg/core/constants.py +69 -0
- django_cfg/core/environment/__init__.py +9 -0
- django_cfg/core/exceptions.py +45 -298
- django_cfg/core/generation/__init__.py +51 -0
- django_cfg/core/generation/core_generators/__init__.py +0 -0
- django_cfg/core/generation/core_generators/settings.py +90 -0
- django_cfg/core/generation/core_generators/static.py +82 -0
- django_cfg/core/generation/core_generators/templates.py +141 -0
- django_cfg/core/generation/data_generators/__init__.py +15 -0
- django_cfg/core/generation/data_generators/cache.py +132 -0
- django_cfg/core/generation/data_generators/database.py +117 -0
- django_cfg/core/generation/generation.py +92 -0
- django_cfg/core/generation/integration_generators/__init__.py +21 -0
- django_cfg/core/generation/integration_generators/api.py +237 -0
- django_cfg/core/generation/integration_generators/sessions.py +65 -0
- django_cfg/core/generation/integration_generators/tailwind.py +54 -0
- django_cfg/core/generation/integration_generators/tasks.py +92 -0
- django_cfg/core/generation/integration_generators/third_party.py +144 -0
- django_cfg/core/generation/orchestrator.py +285 -0
- django_cfg/core/generation/protocols.py +30 -0
- django_cfg/core/generation/security_generators/__init__.py +0 -0
- django_cfg/core/generation/utility_generators/__init__.py +24 -0
- django_cfg/core/generation/utility_generators/email.py +58 -0
- django_cfg/core/generation/utility_generators/i18n.py +66 -0
- django_cfg/core/generation/utility_generators/limits.py +58 -0
- django_cfg/core/generation/utility_generators/logging.py +66 -0
- django_cfg/core/generation/utility_generators/security.py +101 -0
- django_cfg/core/generation/utils/__init__.py +0 -0
- django_cfg/core/generation/utils/helpers.py +32 -0
- django_cfg/core/integration/__init__.py +18 -25
- django_cfg/core/integration/display/startup.py +146 -133
- django_cfg/core/integration/url_integration.py +13 -2
- django_cfg/core/services/__init__.py +5 -0
- django_cfg/core/services/config_service.py +121 -0
- django_cfg/core/state/__init__.py +9 -0
- django_cfg/core/state/registry.py +84 -0
- django_cfg/core/types/__init__.py +15 -0
- django_cfg/core/types/aliases.py +15 -0
- django_cfg/core/types/enums.py +49 -0
- django_cfg/dashboard/DEBUG_README.md +105 -0
- django_cfg/dashboard/REFACTORING_SUMMARY.md +237 -0
- django_cfg/dashboard/__init__.py +24 -0
- django_cfg/dashboard/components.py +308 -0
- django_cfg/dashboard/debug.py +176 -0
- django_cfg/dashboard/management/__init__.py +0 -0
- django_cfg/dashboard/management/commands/__init__.py +0 -0
- django_cfg/dashboard/management/commands/debug_dashboard.py +109 -0
- django_cfg/dashboard/sections/__init__.py +1 -0
- django_cfg/dashboard/sections/base.py +128 -0
- django_cfg/dashboard/sections/commands.py +32 -0
- django_cfg/dashboard/sections/overview.py +394 -0
- django_cfg/dashboard/sections/stats.py +48 -0
- django_cfg/dashboard/sections/system.py +73 -0
- django_cfg/management/commands/check_settings.py +6 -2
- django_cfg/management/commands/clear_constance.py +6 -1
- django_cfg/management/commands/create_token.py +5 -4
- django_cfg/management/commands/generate.py +5 -0
- django_cfg/management/commands/list_urls.py +7 -2
- django_cfg/management/commands/migrate_all.py +6 -2
- django_cfg/management/commands/migrator.py +6 -1
- django_cfg/management/commands/rundramatiq.py +6 -1
- django_cfg/management/commands/rundramatiq_simulator.py +11 -4
- django_cfg/management/commands/runserver_ngrok.py +9 -7
- django_cfg/management/commands/script.py +25 -21
- django_cfg/management/commands/show_config.py +6 -1
- django_cfg/management/commands/show_urls.py +8 -3
- django_cfg/management/commands/superuser.py +5 -4
- django_cfg/management/commands/task_clear.py +8 -3
- django_cfg/management/commands/task_status.py +8 -3
- django_cfg/management/commands/test_email.py +6 -1
- django_cfg/management/commands/test_telegram.py +6 -1
- django_cfg/management/commands/test_twilio.py +6 -1
- django_cfg/management/commands/tree.py +7 -4
- django_cfg/models/__init__.py +88 -3
- django_cfg/models/api/__init__.py +27 -0
- django_cfg/models/{api.py → api/config.py} +1 -1
- django_cfg/models/api/drf/__init__.py +21 -0
- django_cfg/models/api/drf/config.py +101 -0
- django_cfg/models/api/drf/redoc.py +31 -0
- django_cfg/models/api/drf/spectacular.py +129 -0
- django_cfg/models/api/drf/swagger.py +59 -0
- django_cfg/models/{api_keys.py → api/keys.py} +16 -6
- django_cfg/models/{limits.py → api/limits.py} +0 -1
- django_cfg/models/base/__init__.py +14 -0
- django_cfg/models/django/__init__.py +16 -0
- django_cfg/models/{constance.py → django/constance.py} +1 -1
- django_cfg/models/{environment.py → django/environment.py} +1 -1
- django_cfg/models/infrastructure/__init__.py +17 -0
- django_cfg/models/{cache.py → infrastructure/cache.py} +3 -2
- django_cfg/models/infrastructure/database/__init__.py +22 -0
- django_cfg/models/infrastructure/database/config.py +265 -0
- django_cfg/models/infrastructure/database/converters.py +91 -0
- django_cfg/models/infrastructure/database/parsers.py +96 -0
- django_cfg/models/infrastructure/database/routing.py +85 -0
- django_cfg/models/infrastructure/database/validators.py +170 -0
- django_cfg/models/{logging.py → infrastructure/logging.py} +1 -1
- django_cfg/models/{security.py → infrastructure/security.py} +2 -2
- django_cfg/models/ngrok/__init__.py +11 -0
- django_cfg/models/ngrok/auth.py +37 -0
- django_cfg/models/ngrok/config.py +77 -0
- django_cfg/models/ngrok/tunnel.py +35 -0
- django_cfg/models/payments/__init__.py +20 -0
- django_cfg/models/payments/api_keys.py +57 -0
- django_cfg/models/{payments.py → payments/config.py} +56 -154
- django_cfg/models/payments/providers/__init__.py +15 -0
- django_cfg/models/payments/providers/base.py +25 -0
- django_cfg/models/payments/providers/nowpayments.py +48 -0
- django_cfg/models/services/__init__.py +18 -0
- django_cfg/models/services/base.py +65 -0
- django_cfg/models/{email.py → services/email.py} +1 -1
- django_cfg/models/services/telegram.py +172 -0
- django_cfg/models/tasks/__init__.py +51 -0
- django_cfg/models/tasks/backends.py +250 -0
- django_cfg/models/tasks/config.py +314 -0
- django_cfg/models/tasks/utils.py +174 -0
- django_cfg/modules/base.py +18 -3
- django_cfg/modules/django_admin/decorators/actions.py +1 -1
- django_cfg/modules/django_admin/decorators/display.py +1 -1
- django_cfg/modules/django_admin/mixins/standalone_actions_mixin.py +1 -1
- django_cfg/modules/django_currency/examples/__init__.py +3 -0
- django_cfg/modules/django_currency/examples/example_database_usage.py +144 -0
- django_cfg/modules/django_drf_theme/CHANGELOG.md +210 -0
- django_cfg/modules/django_drf_theme/EXAMPLE.md +465 -0
- django_cfg/modules/django_drf_theme/IMPLEMENTATION.md +232 -0
- django_cfg/modules/django_drf_theme/README.md +207 -0
- django_cfg/modules/django_drf_theme/TAILWIND_CDN_GUIDE.md +274 -0
- django_cfg/modules/django_drf_theme/__init__.py +23 -0
- django_cfg/modules/django_drf_theme/apps.py +15 -0
- django_cfg/modules/django_drf_theme/renderers.py +58 -0
- django_cfg/modules/django_drf_theme/templates/rest_framework/tailwind/api.html +375 -0
- django_cfg/modules/django_drf_theme/templates/rest_framework/tailwind/base.html +938 -0
- django_cfg/modules/django_drf_theme/templates/rest_framework/tailwind/forms/filter_form.html +132 -0
- django_cfg/modules/django_drf_theme/templates/rest_framework/tailwind/forms/raw_data_form.html +123 -0
- django_cfg/modules/django_drf_theme/templatetags/__init__.py +1 -0
- django_cfg/modules/django_drf_theme/templatetags/tailwind_tags.py +57 -0
- django_cfg/modules/django_email/__init__.py +14 -0
- django_cfg/modules/{django_email.py → django_email/service.py} +78 -113
- django_cfg/modules/django_email/utils.py +40 -0
- django_cfg/modules/django_health/__init__.py +9 -0
- django_cfg/modules/{django_health.py → django_health/service.py} +23 -21
- django_cfg/modules/django_ipc_client/README.md +346 -0
- django_cfg/modules/django_ipc_client/__init__.py +51 -0
- django_cfg/modules/django_ipc_client/client.py +540 -0
- django_cfg/modules/django_ipc_client/config.py +207 -0
- django_cfg/modules/django_ipc_client/dashboard/README.md +517 -0
- django_cfg/modules/django_ipc_client/dashboard/UNFOLD_INTEGRATION.md +439 -0
- django_cfg/modules/django_ipc_client/dashboard/__init__.py +11 -0
- django_cfg/modules/django_ipc_client/dashboard/apps.py +22 -0
- django_cfg/modules/django_ipc_client/dashboard/monitor.py +435 -0
- django_cfg/modules/django_ipc_client/dashboard/static/django_ipc_dashboard/js/dashboard.js +373 -0
- django_cfg/modules/django_ipc_client/dashboard/templates/django_ipc_dashboard/base.html +76 -0
- django_cfg/modules/django_ipc_client/dashboard/templates/django_ipc_dashboard/dashboard.html +200 -0
- django_cfg/modules/django_ipc_client/dashboard/urls.py +22 -0
- django_cfg/modules/django_ipc_client/dashboard/urls_admin.py +9 -0
- django_cfg/modules/django_ipc_client/dashboard/views.py +251 -0
- django_cfg/modules/django_ipc_client/exceptions.py +201 -0
- django_cfg/modules/django_llm/llm/client.py +155 -550
- django_cfg/modules/django_llm/llm/embeddings/__init__.py +13 -0
- django_cfg/modules/django_llm/llm/embeddings/mock_embedder.py +106 -0
- django_cfg/modules/django_llm/llm/embeddings/openai_embedder.py +79 -0
- django_cfg/modules/django_llm/llm/models_api/__init__.py +9 -0
- django_cfg/modules/django_llm/llm/models_api/models_query.py +163 -0
- django_cfg/modules/django_llm/llm/providers/__init__.py +15 -0
- django_cfg/modules/django_llm/llm/providers/config_builder.py +103 -0
- django_cfg/modules/django_llm/llm/providers/provider_manager.py +148 -0
- django_cfg/modules/django_llm/llm/providers/provider_selector.py +60 -0
- django_cfg/modules/django_llm/llm/requests/__init__.py +15 -0
- django_cfg/modules/django_llm/llm/requests/cache_manager.py +170 -0
- django_cfg/modules/django_llm/llm/requests/chat_handler.py +199 -0
- django_cfg/modules/django_llm/llm/requests/embedding_handler.py +113 -0
- django_cfg/modules/django_llm/llm/responses/__init__.py +9 -0
- django_cfg/modules/django_llm/llm/responses/response_builder.py +131 -0
- django_cfg/modules/django_llm/llm/stats/__init__.py +9 -0
- django_cfg/modules/django_llm/llm/stats/stats_manager.py +107 -0
- django_cfg/modules/django_llm/translator/detectors/__init__.py +13 -0
- django_cfg/modules/django_llm/translator/detectors/language_detector.py +90 -0
- django_cfg/modules/django_llm/translator/detectors/script_detector.py +153 -0
- django_cfg/modules/django_llm/translator/stats/__init__.py +11 -0
- django_cfg/modules/django_llm/translator/stats/stats_tracker.py +85 -0
- django_cfg/modules/django_llm/translator/translator.py +150 -603
- django_cfg/modules/django_llm/translator/translators/__init__.py +15 -0
- django_cfg/modules/django_llm/translator/translators/json_translator.py +316 -0
- django_cfg/modules/django_llm/translator/translators/text_translator.py +139 -0
- django_cfg/modules/django_llm/translator/utils/__init__.py +13 -0
- django_cfg/modules/django_llm/translator/utils/prompt_builder.py +110 -0
- django_cfg/modules/django_llm/translator/utils/text_utils.py +114 -0
- django_cfg/modules/django_logging/FIXES_SUMMARY.md +276 -0
- django_cfg/modules/django_logging/LOGGING_GUIDE.md +504 -0
- django_cfg/modules/django_logging/__init__.py +14 -0
- django_cfg/modules/{django_logger.py → django_logging/django_logger.py} +13 -13
- django_cfg/modules/{logger.py → django_logging/logger.py} +14 -4
- django_cfg/modules/django_ngrok/__init__.py +39 -0
- django_cfg/modules/{django_ngrok.py → django_ngrok/service.py} +14 -42
- django_cfg/modules/django_rpc_old/POETRY.md +344 -0
- django_cfg/modules/django_rpc_old/README.md +397 -0
- django_cfg/modules/django_rpc_old/TESTING.md +358 -0
- django_cfg/modules/django_rpc_old/__init__.py +39 -0
- django_cfg/modules/django_rpc_old/client.py +531 -0
- django_cfg/modules/django_rpc_old/config.py +279 -0
- django_cfg/modules/django_rpc_old/exceptions.py +172 -0
- django_cfg/modules/django_tailwind/README.md +478 -0
- django_cfg/modules/django_tailwind/__init__.py +7 -0
- django_cfg/modules/django_tailwind/apps.py +10 -0
- django_cfg/modules/django_tailwind/templates/django_tailwind/app.html +5 -0
- django_cfg/modules/django_tailwind/templates/django_tailwind/base.html +117 -0
- django_cfg/modules/django_tailwind/templates/django_tailwind/components/navbar.html +124 -0
- django_cfg/modules/django_tailwind/templates/django_tailwind/components/theme_toggle.html +54 -0
- django_cfg/modules/django_tailwind/templates/django_tailwind/components/user_menu.html +116 -0
- django_cfg/modules/django_tailwind/templates/django_tailwind/simple.html +46 -0
- django_cfg/modules/django_tailwind/templatetags/__init__.py +1 -0
- django_cfg/modules/django_tailwind/templatetags/tailwind_info.py +185 -0
- django_cfg/modules/django_tasks/__init__.py +29 -0
- django_cfg/modules/django_tasks/factory.py +127 -0
- django_cfg/modules/{django_tasks.py → django_tasks/service.py} +45 -274
- django_cfg/modules/django_tasks/settings.py +107 -0
- django_cfg/modules/django_telegram/__init__.py +29 -0
- django_cfg/modules/{django_telegram.py → django_telegram/service.py} +45 -113
- django_cfg/modules/django_telegram/utils.py +62 -0
- django_cfg/modules/django_twilio/__init__.py +54 -107
- django_cfg/modules/django_twilio/_imports.py +30 -0
- django_cfg/modules/django_twilio/base.py +192 -0
- django_cfg/modules/django_twilio/email_otp.py +227 -0
- django_cfg/modules/django_twilio/sendgrid_service.py +1 -1
- django_cfg/modules/django_twilio/simple_service.py +1 -2
- django_cfg/modules/django_twilio/sms.py +94 -0
- django_cfg/modules/django_twilio/twilio_service.py +2 -3
- django_cfg/modules/django_twilio/unified.py +310 -0
- django_cfg/modules/django_twilio/utils.py +190 -0
- django_cfg/modules/django_twilio/whatsapp.py +137 -0
- django_cfg/modules/django_unfold/callbacks/base.py +198 -7
- django_cfg/modules/django_unfold/callbacks/main.py +102 -10
- django_cfg/modules/django_unfold/dashboard.py +65 -43
- django_cfg/modules/django_unfold/models/config.py +13 -12
- django_cfg/modules/django_unfold/models/navigation.py +8 -3
- django_cfg/modules/django_unfold/models/tabs.py +2 -2
- django_cfg/modules/django_unfold/templates/unfold/helpers/app_list.html +102 -0
- django_cfg/registry/core.py +24 -26
- django_cfg/registry/modules.py +5 -2
- django_cfg/registry/services.py +20 -3
- django_cfg/registry/third_party.py +8 -8
- django_cfg/static/admin/css/dashboard.css +260 -0
- django_cfg/static/admin/js/commands.js +171 -0
- django_cfg/static/admin/js/dashboard.js +126 -0
- django_cfg/templates/admin/components/management_commands.js +375 -0
- django_cfg/templates/admin/components/progress_bar.html +18 -23
- django_cfg/templates/admin/examples/component_class_example.html +156 -0
- django_cfg/templates/admin/index.html +48 -20
- django_cfg/templates/admin/index_new.html +106 -0
- django_cfg/templates/admin/layouts/base_dashboard.html +60 -0
- django_cfg/templates/admin/layouts/dashboard_with_tabs.html +1 -20
- django_cfg/templates/admin/sections/commands_section.html +626 -0
- django_cfg/templates/admin/sections/overview_section.html +112 -0
- django_cfg/templates/admin/sections/stats_section.html +35 -0
- django_cfg/templates/admin/sections/system_section.html +99 -0
- django_cfg/templates/admin/snippets/components/CHARTS_GUIDE.md +322 -0
- django_cfg/templates/admin/snippets/components/activity_tracker.html +85 -47
- django_cfg/templates/admin/snippets/components/charts_section.html +154 -64
- django_cfg/templates/admin/snippets/components/django_commands.html +3 -3
- django_cfg/templates/admin/snippets/components/recent_activity_improved.html +25 -0
- django_cfg/templates/admin/snippets/components/recent_users_table.html +1 -1
- django_cfg/templates/admin/snippets/components/system_metrics.html +179 -93
- django_cfg/templates/admin/snippets/zones/zones_table.html +2 -2
- django_cfg/templatetags/django_cfg.py +7 -1
- django_cfg/utils/smart_defaults.py +4 -4
- django_cfg-1.4.3.dist-info/METADATA +533 -0
- {django_cfg-1.3.13.dist-info → django_cfg-1.4.3.dist-info}/RECORD +432 -195
- django_cfg/apps/accounts/utils/auth_email_service.py +0 -84
- django_cfg/apps/payments/services/providers/nowpayments/parsers.py +0 -879
- django_cfg/core/generation.py +0 -621
- django_cfg/management/commands/validate_config.py +0 -189
- django_cfg/models/database.py +0 -480
- django_cfg/models/drf.py +0 -272
- django_cfg/models/ngrok.py +0 -122
- django_cfg/models/services.py +0 -440
- django_cfg/models/tasks.py +0 -550
- django_cfg/modules/django_twilio/service.py +0 -942
- django_cfg/template_archive/django_sample.zip +0 -0
- django_cfg/templates/rest_framework/api.html +0 -12
- django_cfg/utils/toolkit.py +0 -703
- django_cfg-1.3.13.dist-info/METADATA +0 -1029
- /django_cfg/apps/accounts/management/commands/{test_otp.py → otp_test.py} +0 -0
- /django_cfg/core/{environment.py → environment/detector.py} +0 -0
- /django_cfg/models/{cors.py → api/cors.py} +0 -0
- /django_cfg/models/{jwt.py → api/jwt.py} +0 -0
- /django_cfg/models/{base.py → base/config.py} +0 -0
- /django_cfg/models/{cfg.py → base/module.py} +0 -0
- /django_cfg/models/{revolution.py → django/revolution.py} +0 -0
- /django_cfg/modules/{dramatiq_setup.py → django_tasks/dramatiq_setup.py} +0 -0
- {django_cfg-1.3.13.dist-info → django_cfg-1.4.3.dist-info}/WHEEL +0 -0
- {django_cfg-1.3.13.dist-info → django_cfg-1.4.3.dist-info}/entry_points.txt +0 -0
- {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,
|
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
|
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
|
-
|
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
|
25
|
-
"""
|
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
|
-
|
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
|
-
"""
|
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
|
-
|
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
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
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(
|
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
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
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
|