django-cfg 1.3.11__py3-none-any.whl → 1.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- django_cfg/__init__.py +1 -1
- django_cfg/apps/accounts/admin/inlines.py +11 -5
- 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/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/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/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_cfg_rpc_client/README.md +346 -0
- django_cfg/modules/django_cfg_rpc_client/__init__.py +51 -0
- django_cfg/modules/django_cfg_rpc_client/client.py +540 -0
- django_cfg/modules/django_cfg_rpc_client/config.py +207 -0
- django_cfg/modules/django_cfg_rpc_client/dashboard/README.md +517 -0
- django_cfg/modules/django_cfg_rpc_client/dashboard/UNFOLD_INTEGRATION.md +439 -0
- django_cfg/modules/django_cfg_rpc_client/dashboard/__init__.py +11 -0
- django_cfg/modules/django_cfg_rpc_client/dashboard/apps.py +22 -0
- django_cfg/modules/django_cfg_rpc_client/dashboard/monitor.py +435 -0
- django_cfg/modules/django_cfg_rpc_client/dashboard/static/django_cfg_rpc_dashboard/js/dashboard.js +373 -0
- django_cfg/modules/django_cfg_rpc_client/dashboard/templates/django_cfg_rpc_dashboard/base.html +76 -0
- django_cfg/modules/django_cfg_rpc_client/dashboard/templates/django_cfg_rpc_dashboard/dashboard.html +200 -0
- django_cfg/modules/django_cfg_rpc_client/dashboard/urls.py +22 -0
- django_cfg/modules/django_cfg_rpc_client/dashboard/urls_admin.py +9 -0
- django_cfg/modules/django_cfg_rpc_client/dashboard/views.py +251 -0
- django_cfg/modules/django_cfg_rpc_client/exceptions.py +201 -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_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/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.0.dist-info/METADATA +920 -0
- {django_cfg-1.3.11.dist-info → django_cfg-1.4.0.dist-info}/RECORD +425 -196
- 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.11.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.11.dist-info → django_cfg-1.4.0.dist-info}/WHEEL +0 -0
- {django_cfg-1.3.11.dist-info → django_cfg-1.4.0.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.3.11.dist-info → django_cfg-1.4.0.dist-info}/licenses/LICENSE +0 -0
@@ -5,23 +5,17 @@ Enhanced document management with Material Icons and optimized queries.
|
|
5
5
|
"""
|
6
6
|
|
7
7
|
from django.contrib import admin, messages
|
8
|
-
from django.urls import reverse
|
9
|
-
from django.utils.safestring import mark_safe
|
10
8
|
from django.db import models, IntegrityError
|
11
|
-
from django.db.models import Count, Sum, Avg, Q
|
12
9
|
from django.db.models.fields.json import JSONField
|
13
10
|
from django_json_widget.widgets import JSONEditorWidget
|
14
11
|
from unfold.admin import ModelAdmin, TabularInline
|
15
12
|
from unfold.contrib.filters.admin import AutocompleteSelectFilter, AutocompleteSelectMultipleFilter
|
16
13
|
from unfold.contrib.forms.widgets import WysiwygWidget
|
17
|
-
from django_cfg import ImportExportModelAdmin,
|
14
|
+
from django_cfg import ImportExportModelAdmin, ImportForm, ExportForm
|
18
15
|
|
19
16
|
from django_cfg.modules.django_admin import (
|
20
17
|
OptimizedModelAdmin,
|
21
18
|
DisplayMixin,
|
22
|
-
MoneyDisplayConfig,
|
23
|
-
StatusBadgeConfig,
|
24
|
-
DateTimeDisplayConfig,
|
25
19
|
Icons,
|
26
20
|
ActionVariant,
|
27
21
|
display,
|
@@ -30,11 +24,19 @@ from django_cfg.modules.django_admin import (
|
|
30
24
|
from django_cfg.modules.django_admin.utils.badges import StatusBadge
|
31
25
|
|
32
26
|
from ..models import Document, DocumentChunk, DocumentCategory
|
27
|
+
from .helpers import (
|
28
|
+
DocumentDisplayHelpers,
|
29
|
+
DocumentStatistics,
|
30
|
+
ChunkStatistics,
|
31
|
+
CategoryStatistics,
|
32
|
+
DocumentAdminConfigs
|
33
|
+
)
|
34
|
+
from .actions import VisibilityActions
|
33
35
|
|
34
36
|
|
35
37
|
class DocumentChunkInline(TabularInline):
|
36
38
|
"""Inline for document chunks with Unfold styling."""
|
37
|
-
|
39
|
+
|
38
40
|
model = DocumentChunk
|
39
41
|
verbose_name = "Document Chunk"
|
40
42
|
verbose_name_plural = "📄 Document Chunks (Read-only)"
|
@@ -42,40 +44,38 @@ class DocumentChunkInline(TabularInline):
|
|
42
44
|
max_num = 0
|
43
45
|
can_delete = False
|
44
46
|
show_change_link = True
|
45
|
-
|
47
|
+
|
46
48
|
def has_add_permission(self, request, obj=None):
|
47
49
|
return False
|
48
|
-
|
50
|
+
|
49
51
|
def has_change_permission(self, request, obj=None):
|
50
52
|
return False
|
51
|
-
|
53
|
+
|
52
54
|
def has_delete_permission(self, request, obj=None):
|
53
55
|
return False
|
54
|
-
|
56
|
+
|
55
57
|
fields = [
|
56
|
-
'short_uuid', 'chunk_index', 'content_preview_inline', 'token_count',
|
58
|
+
'short_uuid', 'chunk_index', 'content_preview_inline', 'token_count',
|
57
59
|
'has_embedding_inline', 'embedding_cost'
|
58
60
|
]
|
59
61
|
readonly_fields = [
|
60
62
|
'short_uuid', 'chunk_index', 'content_preview_inline', 'token_count', 'character_count',
|
61
63
|
'has_embedding_inline', 'embedding_cost', 'created_at'
|
62
64
|
]
|
63
|
-
|
65
|
+
|
64
66
|
hide_title = False
|
65
67
|
classes = ['collapse']
|
66
|
-
|
68
|
+
|
67
69
|
@display(description="Content Preview")
|
68
70
|
def content_preview_inline(self, obj):
|
69
71
|
"""Shortened content preview for inline display."""
|
70
|
-
|
71
|
-
|
72
|
-
return obj.content[:100] + "..." if len(obj.content) > 100 else obj.content
|
73
|
-
|
72
|
+
return DocumentDisplayHelpers.display_content_preview(obj, max_length=100)
|
73
|
+
|
74
74
|
@display(description="Has Embedding", boolean=True)
|
75
75
|
def has_embedding_inline(self, obj):
|
76
76
|
"""Check if chunk has embedding vector for inline."""
|
77
77
|
return obj.embedding is not None and len(obj.embedding) > 0
|
78
|
-
|
78
|
+
|
79
79
|
def get_queryset(self, request):
|
80
80
|
"""Optimize queryset for inline display."""
|
81
81
|
return super().get_queryset(request).select_related('document', 'user')
|
@@ -84,17 +84,17 @@ class DocumentChunkInline(TabularInline):
|
|
84
84
|
@admin.register(Document)
|
85
85
|
class DocumentAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, ImportExportModelAdmin):
|
86
86
|
"""Admin interface for Document model using Django Admin Utilities."""
|
87
|
-
|
87
|
+
|
88
88
|
# Performance optimization
|
89
89
|
select_related_fields = ['user']
|
90
|
-
|
90
|
+
|
91
91
|
# Import/Export configuration
|
92
92
|
import_form_class = ImportForm
|
93
93
|
export_form_class = ExportForm
|
94
|
-
|
94
|
+
|
95
95
|
list_display = [
|
96
|
-
'title_display', 'categories_display', 'user_display',
|
97
|
-
'visibility_display', 'status_display', 'chunks_count_display',
|
96
|
+
'title_display', 'categories_display', 'user_display',
|
97
|
+
'visibility_display', 'status_display', 'chunks_count_display',
|
98
98
|
'vectorization_progress', 'tokens_display', 'cost_display', 'created_at_display'
|
99
99
|
]
|
100
100
|
list_display_links = ['title_display']
|
@@ -113,7 +113,7 @@ class DocumentAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, ImportExportM
|
|
113
113
|
'processing_error', 'processing_duration', 'processing_status',
|
114
114
|
'total_cost_usd', 'created_at', 'updated_at', 'duplicate_check'
|
115
115
|
]
|
116
|
-
|
116
|
+
|
117
117
|
fieldsets = (
|
118
118
|
('📄 Basic Information', {
|
119
119
|
'fields': ('id', 'title', 'user', 'categories', 'is_public', 'file_type', 'file_size'),
|
@@ -125,7 +125,7 @@ class DocumentAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, ImportExportM
|
|
125
125
|
}),
|
126
126
|
('⚙️ Processing Status', {
|
127
127
|
'fields': (
|
128
|
-
'processing_status', 'processing_started_at',
|
128
|
+
'processing_status', 'processing_started_at',
|
129
129
|
'processing_completed_at', 'processing_error'
|
130
130
|
),
|
131
131
|
'classes': ('tab',)
|
@@ -145,38 +145,39 @@ class DocumentAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, ImportExportM
|
|
145
145
|
})
|
146
146
|
)
|
147
147
|
filter_horizontal = ['categories']
|
148
|
-
|
148
|
+
|
149
149
|
# Unfold configuration
|
150
150
|
compressed_fields = True
|
151
151
|
warn_unsaved_form = True
|
152
|
-
|
152
|
+
|
153
153
|
# Form field overrides
|
154
154
|
formfield_overrides = {
|
155
155
|
models.TextField: {"widget": WysiwygWidget},
|
156
156
|
JSONField: {"widget": JSONEditorWidget}
|
157
157
|
}
|
158
|
-
|
158
|
+
|
159
159
|
actions = ['reprocess_documents', 'mark_as_public', 'mark_as_private']
|
160
|
-
|
160
|
+
|
161
161
|
def get_queryset(self, request):
|
162
162
|
"""Optimize queryset with select_related and prefetch_related."""
|
163
163
|
queryset = Document.objects.all_users().select_related('user').prefetch_related('categories')
|
164
|
-
|
165
|
-
|
164
|
+
|
165
|
+
# Staff users see all documents, regular users see only their own
|
166
|
+
if not request.user.is_staff:
|
166
167
|
queryset = queryset.filter(user=request.user)
|
167
|
-
|
168
|
+
|
168
169
|
return queryset
|
169
|
-
|
170
|
+
|
170
171
|
def save_model(self, request, obj, form, change):
|
171
172
|
"""Automatically set user to current user when creating new documents."""
|
172
173
|
if not change:
|
173
174
|
obj.user = request.user
|
174
|
-
|
175
|
+
|
175
176
|
is_duplicate, existing_doc = Document.objects.check_duplicate_before_save(
|
176
|
-
user=obj.user,
|
177
|
+
user=obj.user,
|
177
178
|
content=obj.content
|
178
179
|
)
|
179
|
-
|
180
|
+
|
180
181
|
if is_duplicate and existing_doc:
|
181
182
|
messages.error(
|
182
183
|
request,
|
@@ -185,7 +186,7 @@ class DocumentAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, ImportExportM
|
|
185
186
|
f'Please modify the content or update the existing document.'
|
186
187
|
)
|
187
188
|
return
|
188
|
-
|
189
|
+
|
189
190
|
try:
|
190
191
|
super().save_model(request, obj, form, change)
|
191
192
|
except IntegrityError as e:
|
@@ -198,72 +199,54 @@ class DocumentAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, ImportExportM
|
|
198
199
|
else:
|
199
200
|
messages.error(request, f'Database error: {str(e)}')
|
200
201
|
raise
|
201
|
-
|
202
|
+
|
202
203
|
@display(description="Document Title", ordering="title")
|
203
204
|
def title_display(self, obj):
|
204
205
|
"""Display document title with truncation."""
|
205
206
|
title = obj.title or "Untitled Document"
|
206
207
|
if len(title) > 50:
|
207
208
|
title = title[:47] + "..."
|
208
|
-
|
209
|
-
config = StatusBadgeConfig(show_icons=True, icon=Icons.DESCRIPTION)
|
209
|
+
|
210
210
|
return StatusBadge.create(
|
211
211
|
text=title,
|
212
212
|
variant="primary",
|
213
|
-
config=
|
213
|
+
config=DocumentAdminConfigs.DOCUMENT_TITLE
|
214
214
|
)
|
215
|
-
|
216
|
-
@display(description="User")
|
215
|
+
|
217
216
|
def user_display(self, obj):
|
218
|
-
"""User display."""
|
219
|
-
|
220
|
-
|
221
|
-
return self.display_user_simple(obj.user)
|
222
|
-
|
223
|
-
@display(description="Visibility")
|
217
|
+
"""User display (delegates to helper)."""
|
218
|
+
return DocumentDisplayHelpers.display_user(obj, self)
|
219
|
+
|
224
220
|
def visibility_display(self, obj):
|
225
|
-
"""
|
226
|
-
|
227
|
-
|
228
|
-
return StatusBadge.create(text="Public", variant="success", config=config)
|
229
|
-
else:
|
230
|
-
config = StatusBadgeConfig(show_icons=True, icon=Icons.LOCK)
|
231
|
-
return StatusBadge.create(text="Private", variant="danger", config=config)
|
232
|
-
|
221
|
+
"""Visibility display (delegates to helper)."""
|
222
|
+
return DocumentDisplayHelpers.display_visibility(obj)
|
223
|
+
|
233
224
|
@display(description="Status")
|
234
225
|
def status_display(self, obj):
|
235
226
|
"""Display processing status."""
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
'processing': 'info',
|
240
|
-
'completed': 'success',
|
241
|
-
'failed': 'danger',
|
242
|
-
'cancelled': 'secondary'
|
243
|
-
},
|
244
|
-
show_icons=True,
|
245
|
-
icon=Icons.CHECK_CIRCLE if obj.processing_status == 'completed' else Icons.ERROR if obj.processing_status == 'failed' else Icons.SCHEDULE
|
246
|
-
)
|
227
|
+
icon = DocumentAdminConfigs.get_processing_status_icon(obj.processing_status)
|
228
|
+
status_config = DocumentAdminConfigs.PROCESSING_STATUS
|
229
|
+
status_config.icon = icon
|
247
230
|
return self.display_status_auto(obj, 'processing_status', status_config)
|
248
|
-
|
231
|
+
|
249
232
|
@display(description="Categories")
|
250
233
|
def categories_display(self, obj):
|
251
234
|
"""Display categories count."""
|
252
235
|
categories = obj.categories.all()
|
253
|
-
|
236
|
+
|
254
237
|
if not categories:
|
255
238
|
return "No categories"
|
256
|
-
|
239
|
+
|
257
240
|
public_count = sum(1 for cat in categories if cat.is_public)
|
258
241
|
private_count = len(categories) - public_count
|
259
|
-
|
242
|
+
|
260
243
|
if private_count == 0:
|
261
244
|
return f"{len(categories)} public"
|
262
245
|
elif public_count == 0:
|
263
246
|
return f"{len(categories)} private"
|
264
247
|
else:
|
265
248
|
return f"{public_count} public, {private_count} private"
|
266
|
-
|
249
|
+
|
267
250
|
@display(description="Chunks", ordering="chunks_count")
|
268
251
|
def chunks_count_display(self, obj):
|
269
252
|
"""Display chunks count."""
|
@@ -271,43 +254,31 @@ class DocumentAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, ImportExportM
|
|
271
254
|
if count > 0:
|
272
255
|
return f"{count} chunks"
|
273
256
|
return "0 chunks"
|
274
|
-
|
275
|
-
@display(description="Tokens", ordering="total_tokens")
|
257
|
+
|
276
258
|
def tokens_display(self, obj):
|
277
|
-
"""
|
278
|
-
|
279
|
-
if tokens > 1000:
|
280
|
-
return f"{tokens/1000:.1f}K"
|
281
|
-
return str(tokens)
|
259
|
+
"""Token count display (delegates to helper)."""
|
260
|
+
return DocumentDisplayHelpers.display_token_count(obj, 'total_tokens')
|
282
261
|
|
283
|
-
@display(description="Cost (USD)", ordering="total_cost_usd")
|
284
262
|
def cost_display(self, obj):
|
285
|
-
"""
|
286
|
-
|
287
|
-
|
288
|
-
decimal_places=6,
|
289
|
-
show_sign=False
|
290
|
-
)
|
291
|
-
return self.display_money_amount(obj, 'total_cost_usd', config)
|
292
|
-
|
263
|
+
"""Cost display (delegates to helper)."""
|
264
|
+
return DocumentDisplayHelpers.display_cost_usd(obj, self, 'total_cost_usd')
|
265
|
+
|
293
266
|
@display(description="Vectorization")
|
294
267
|
def vectorization_progress(self, obj):
|
295
268
|
"""Display vectorization progress."""
|
296
269
|
return Document.objects.get_vectorization_status_display(obj)
|
297
|
-
|
298
|
-
@display(description="Created")
|
270
|
+
|
299
271
|
def created_at_display(self, obj):
|
300
|
-
"""Created time
|
301
|
-
|
302
|
-
|
303
|
-
|
272
|
+
"""Created time display (delegates to helper)."""
|
273
|
+
return DocumentDisplayHelpers.display_created_at(obj, self)
|
274
|
+
|
304
275
|
@display(description="Processing Duration")
|
305
276
|
def processing_duration_display(self, obj):
|
306
277
|
"""Display processing duration in readable format."""
|
307
278
|
duration = obj.processing_duration
|
308
279
|
if duration is None:
|
309
280
|
return "N/A"
|
310
|
-
|
281
|
+
|
311
282
|
if duration < 60:
|
312
283
|
return f"{duration:.1f}s"
|
313
284
|
elif duration < 3600:
|
@@ -316,83 +287,54 @@ class DocumentAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, ImportExportM
|
|
316
287
|
else:
|
317
288
|
hours = duration / 3600
|
318
289
|
return f"{hours:.1f}h"
|
319
|
-
|
290
|
+
|
320
291
|
@display(description="Duplicate Check")
|
321
292
|
def duplicate_check(self, obj):
|
322
293
|
"""Check for duplicate documents with same content."""
|
323
294
|
duplicate_info = Document.objects.get_duplicate_info(obj)
|
324
|
-
|
295
|
+
|
325
296
|
if isinstance(duplicate_info, str):
|
326
297
|
if "No duplicates found" in duplicate_info:
|
327
298
|
return "✓ No duplicates found"
|
328
299
|
return duplicate_info
|
329
|
-
|
300
|
+
|
330
301
|
duplicates_data = duplicate_info['duplicates']
|
331
302
|
count = duplicate_info['count']
|
332
|
-
|
303
|
+
|
333
304
|
duplicate_names = [dup.title for dup in duplicates_data[:3]]
|
334
305
|
result = f"⚠️ Found {count} duplicate(s): " + ", ".join(duplicate_names)
|
335
306
|
if count > 3:
|
336
307
|
result += f" and {count - 3} more"
|
337
|
-
|
308
|
+
|
338
309
|
return result
|
339
|
-
|
310
|
+
|
340
311
|
@action(description="Reprocess documents", variant=ActionVariant.INFO)
|
341
312
|
def reprocess_documents(self, request, queryset):
|
342
313
|
"""Reprocess selected documents."""
|
343
314
|
count = queryset.count()
|
344
315
|
messages.info(request, f"Reprocessing functionality not implemented yet. {count} documents selected.")
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
messages.success(request, f"Marked {updated} documents as public.")
|
351
|
-
|
352
|
-
@action(description="Mark as private", variant=ActionVariant.WARNING)
|
353
|
-
def mark_as_private(self, request, queryset):
|
354
|
-
"""Mark selected documents as private."""
|
355
|
-
updated = queryset.update(is_public=False)
|
356
|
-
messages.warning(request, f"Marked {updated} documents as private.")
|
357
|
-
|
316
|
+
|
317
|
+
# Visibility actions (delegate to shared actions)
|
318
|
+
mark_as_public = VisibilityActions.mark_as_public
|
319
|
+
mark_as_private = VisibilityActions.mark_as_private
|
320
|
+
|
358
321
|
def changelist_view(self, request, extra_context=None):
|
359
322
|
"""Add summary statistics to changelist."""
|
360
323
|
extra_context = extra_context or {}
|
361
|
-
|
362
324
|
queryset = self.get_queryset(request)
|
363
|
-
|
364
|
-
total_documents=Count('id'),
|
365
|
-
total_chunks=Sum('chunks_count'),
|
366
|
-
total_tokens=Sum('total_tokens'),
|
367
|
-
total_cost=Sum('total_cost_usd')
|
368
|
-
)
|
369
|
-
|
370
|
-
status_counts = dict(
|
371
|
-
queryset.values_list('processing_status').annotate(
|
372
|
-
count=Count('id')
|
373
|
-
)
|
374
|
-
)
|
375
|
-
|
376
|
-
extra_context['summary_stats'] = {
|
377
|
-
'total_documents': stats['total_documents'] or 0,
|
378
|
-
'total_chunks': stats['total_chunks'] or 0,
|
379
|
-
'total_tokens': stats['total_tokens'] or 0,
|
380
|
-
'total_cost': f"${(stats['total_cost'] or 0):.6f}",
|
381
|
-
'status_counts': status_counts
|
382
|
-
}
|
383
|
-
|
325
|
+
extra_context['summary_stats'] = DocumentStatistics.get_document_stats(queryset)
|
384
326
|
return super().changelist_view(request, extra_context)
|
385
327
|
|
386
328
|
|
387
329
|
@admin.register(DocumentChunk)
|
388
330
|
class DocumentChunkAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin):
|
389
331
|
"""Admin interface for DocumentChunk model using Django Admin Utilities."""
|
390
|
-
|
332
|
+
|
391
333
|
# Performance optimization
|
392
334
|
select_related_fields = ['document', 'user']
|
393
|
-
|
335
|
+
|
394
336
|
list_display = [
|
395
|
-
'chunk_display', 'document_display', 'user_display', 'token_count_display',
|
337
|
+
'chunk_display', 'document_display', 'user_display', 'token_count_display',
|
396
338
|
'embedding_status', 'embedding_cost_display', 'created_at_display'
|
397
339
|
]
|
398
340
|
list_display_links = ['chunk_display']
|
@@ -407,7 +349,7 @@ class DocumentChunkAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin):
|
|
407
349
|
'id', 'embedding_info', 'token_count', 'character_count',
|
408
350
|
'embedding_cost', 'created_at', 'updated_at', 'content_preview'
|
409
351
|
]
|
410
|
-
|
352
|
+
|
411
353
|
fieldsets = (
|
412
354
|
('📄 Basic Information', {
|
413
355
|
'fields': ('id', 'document', 'user', 'chunk_index'),
|
@@ -435,138 +377,91 @@ class DocumentChunkAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin):
|
|
435
377
|
'classes': ('tab', 'collapse')
|
436
378
|
})
|
437
379
|
)
|
438
|
-
|
380
|
+
|
439
381
|
# Unfold configuration
|
440
382
|
compressed_fields = True
|
441
383
|
warn_unsaved_form = True
|
442
|
-
|
384
|
+
|
443
385
|
# Form field overrides
|
444
386
|
formfield_overrides = {
|
445
387
|
JSONField: {"widget": JSONEditorWidget}
|
446
388
|
}
|
447
|
-
|
389
|
+
|
448
390
|
actions = ['regenerate_embeddings', 'clear_embeddings']
|
449
|
-
|
391
|
+
|
450
392
|
@display(description="Chunk", ordering="chunk_index")
|
451
393
|
def chunk_display(self, obj):
|
452
394
|
"""Display chunk identifier."""
|
453
|
-
config = StatusBadgeConfig(show_icons=True, icon=Icons.ARTICLE)
|
454
395
|
return StatusBadge.create(
|
455
396
|
text=f"Chunk {obj.chunk_index + 1}",
|
456
397
|
variant="info",
|
457
|
-
config=
|
398
|
+
config=DocumentAdminConfigs.CHUNK
|
458
399
|
)
|
459
|
-
|
400
|
+
|
460
401
|
@display(description="Document", ordering="document__title")
|
461
402
|
def document_display(self, obj):
|
462
403
|
"""Display document title."""
|
463
404
|
return obj.document.title
|
464
|
-
|
465
|
-
@display(description="User")
|
405
|
+
|
466
406
|
def user_display(self, obj):
|
467
|
-
"""User display."""
|
468
|
-
|
469
|
-
|
470
|
-
return self.display_user_simple(obj.user)
|
471
|
-
|
472
|
-
@display(description="Tokens", ordering="token_count")
|
407
|
+
"""User display (delegates to helper)."""
|
408
|
+
return DocumentDisplayHelpers.display_user(obj, self)
|
409
|
+
|
473
410
|
def token_count_display(self, obj):
|
474
|
-
"""
|
475
|
-
|
476
|
-
|
477
|
-
return f"{tokens/1000:.1f}K"
|
478
|
-
return str(tokens)
|
479
|
-
|
480
|
-
@display(description="Embedding")
|
411
|
+
"""Token count display (delegates to helper)."""
|
412
|
+
return DocumentDisplayHelpers.display_token_count(obj, 'token_count')
|
413
|
+
|
481
414
|
def embedding_status(self, obj):
|
482
|
-
"""
|
483
|
-
|
484
|
-
|
485
|
-
config = StatusBadgeConfig(show_icons=True, icon=Icons.CHECK_CIRCLE)
|
486
|
-
return StatusBadge.create(text="✓ Vectorized", variant="success", config=config)
|
487
|
-
else:
|
488
|
-
config = StatusBadgeConfig(show_icons=True, icon=Icons.ERROR)
|
489
|
-
return StatusBadge.create(text="✗ Not vectorized", variant="danger", config=config)
|
490
|
-
|
491
|
-
@display(description="Cost (USD)", ordering="embedding_cost")
|
415
|
+
"""Embedding status display (delegates to helper)."""
|
416
|
+
return DocumentDisplayHelpers.display_embedding_status(obj)
|
417
|
+
|
492
418
|
def embedding_cost_display(self, obj):
|
493
|
-
"""
|
494
|
-
|
495
|
-
|
496
|
-
decimal_places=6,
|
497
|
-
show_sign=False
|
498
|
-
)
|
499
|
-
return self.display_money_amount(obj, 'embedding_cost', config)
|
500
|
-
|
501
|
-
@display(description="Created")
|
419
|
+
"""Embedding cost display (delegates to helper)."""
|
420
|
+
return DocumentDisplayHelpers.display_cost_usd(obj, self, 'embedding_cost')
|
421
|
+
|
502
422
|
def created_at_display(self, obj):
|
503
|
-
"""Created time
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
@display(description="Content Preview")
|
423
|
+
"""Created time display (delegates to helper)."""
|
424
|
+
return DocumentDisplayHelpers.display_created_at(obj, self)
|
425
|
+
|
508
426
|
def content_preview(self, obj):
|
509
|
-
"""
|
510
|
-
return
|
511
|
-
|
427
|
+
"""Content preview display (delegates to helper)."""
|
428
|
+
return DocumentDisplayHelpers.display_content_preview(obj, max_length=200)
|
429
|
+
|
512
430
|
@display(description="Embedding Info")
|
513
431
|
def embedding_info(self, obj):
|
514
432
|
"""Display embedding information safely."""
|
515
433
|
if obj.embedding is not None and len(obj.embedding) > 0:
|
516
434
|
return f"✓ Vector ({len(obj.embedding)} dimensions)"
|
517
435
|
return "✗ No embedding"
|
518
|
-
|
436
|
+
|
519
437
|
@action(description="Regenerate embeddings", variant=ActionVariant.INFO)
|
520
438
|
def regenerate_embeddings(self, request, queryset):
|
521
439
|
"""Regenerate embeddings for selected chunks."""
|
522
440
|
count = queryset.count()
|
523
441
|
messages.info(request, f"Regenerate embeddings functionality not implemented yet. {count} chunks selected.")
|
524
|
-
|
442
|
+
|
525
443
|
@action(description="Clear embeddings", variant=ActionVariant.WARNING)
|
526
444
|
def clear_embeddings(self, request, queryset):
|
527
445
|
"""Clear embeddings for selected chunks."""
|
528
446
|
updated = queryset.update(embedding=None)
|
529
447
|
messages.warning(request, f"Cleared embeddings for {updated} chunks.")
|
530
|
-
|
448
|
+
|
531
449
|
def changelist_view(self, request, extra_context=None):
|
532
450
|
"""Add chunk statistics to changelist."""
|
533
451
|
extra_context = extra_context or {}
|
534
|
-
|
535
452
|
queryset = self.get_queryset(request)
|
536
|
-
|
537
|
-
total_chunks=Count('id'),
|
538
|
-
total_tokens=Sum('token_count'),
|
539
|
-
total_characters=Sum('character_count'),
|
540
|
-
total_embedding_cost=Sum('embedding_cost'),
|
541
|
-
avg_tokens_per_chunk=Avg('token_count')
|
542
|
-
)
|
543
|
-
|
544
|
-
model_counts = dict(
|
545
|
-
queryset.values_list('embedding_model').annotate(
|
546
|
-
count=Count('id')
|
547
|
-
)
|
548
|
-
)
|
549
|
-
|
550
|
-
extra_context['chunk_stats'] = {
|
551
|
-
'total_chunks': stats['total_chunks'] or 0,
|
552
|
-
'total_tokens': stats['total_tokens'] or 0,
|
553
|
-
'total_characters': stats['total_characters'] or 0,
|
554
|
-
'total_embedding_cost': f"${(stats['total_embedding_cost'] or 0):.6f}",
|
555
|
-
'avg_tokens_per_chunk': f"{(stats['avg_tokens_per_chunk'] or 0):.0f}",
|
556
|
-
'model_counts': model_counts
|
557
|
-
}
|
558
|
-
|
453
|
+
extra_context['chunk_stats'] = ChunkStatistics.get_chunk_stats(queryset)
|
559
454
|
return super().changelist_view(request, extra_context)
|
560
455
|
|
561
456
|
|
562
457
|
@admin.register(DocumentCategory)
|
563
458
|
class DocumentCategoryAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, ImportExportModelAdmin):
|
564
459
|
"""Admin interface for DocumentCategory model using Django Admin Utilities."""
|
565
|
-
|
460
|
+
|
566
461
|
# Import/Export configuration
|
567
462
|
import_form_class = ImportForm
|
568
463
|
export_form_class = ExportForm
|
569
|
-
|
464
|
+
|
570
465
|
list_display = [
|
571
466
|
'short_uuid', 'name_display', 'visibility_display', 'document_count', 'created_at_display'
|
572
467
|
]
|
@@ -575,7 +470,7 @@ class DocumentCategoryAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, Impor
|
|
575
470
|
list_filter = ['is_public', 'created_at']
|
576
471
|
search_fields = ['name', 'description']
|
577
472
|
readonly_fields = ['id', 'created_at', 'updated_at']
|
578
|
-
|
473
|
+
|
579
474
|
fieldsets = (
|
580
475
|
('📁 Basic Information', {
|
581
476
|
'fields': ('id', 'name', 'description', 'is_public'),
|
@@ -586,81 +481,52 @@ class DocumentCategoryAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, Impor
|
|
586
481
|
'classes': ('tab', 'collapse')
|
587
482
|
})
|
588
483
|
)
|
589
|
-
|
484
|
+
|
590
485
|
# Unfold configuration
|
591
486
|
compressed_fields = True
|
592
487
|
warn_unsaved_form = True
|
593
|
-
|
488
|
+
|
594
489
|
# Form field overrides
|
595
490
|
formfield_overrides = {
|
596
491
|
models.TextField: {"widget": WysiwygWidget}
|
597
492
|
}
|
598
|
-
|
493
|
+
|
599
494
|
actions = ['make_public', 'make_private']
|
600
|
-
|
495
|
+
|
601
496
|
@display(description="Category Name")
|
602
497
|
def name_display(self, obj):
|
603
498
|
"""Display category name."""
|
604
|
-
config = StatusBadgeConfig(show_icons=True, icon=Icons.FOLDER)
|
605
499
|
return StatusBadge.create(
|
606
500
|
text=obj.name,
|
607
501
|
variant="primary",
|
608
|
-
config=
|
502
|
+
config=DocumentAdminConfigs.CATEGORY
|
609
503
|
)
|
610
|
-
|
611
|
-
@display(description="Visibility")
|
504
|
+
|
612
505
|
def visibility_display(self, obj):
|
613
|
-
"""
|
614
|
-
|
615
|
-
|
616
|
-
return StatusBadge.create(text="Public", variant="success", config=config)
|
617
|
-
else:
|
618
|
-
config = StatusBadgeConfig(show_icons=True, icon=Icons.LOCK)
|
619
|
-
return StatusBadge.create(text="Private", variant="danger", config=config)
|
620
|
-
|
506
|
+
"""Visibility display (delegates to helper)."""
|
507
|
+
return DocumentDisplayHelpers.display_visibility(obj)
|
508
|
+
|
621
509
|
@display(description="Documents", ordering="document_count")
|
622
510
|
def document_count(self, obj):
|
623
511
|
"""Display count of documents in this category."""
|
624
512
|
count = obj.documents.count()
|
625
513
|
return f"{count} documents"
|
626
|
-
|
627
|
-
@display(description="Created")
|
514
|
+
|
628
515
|
def created_at_display(self, obj):
|
629
|
-
"""Created time
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
updated = queryset.update(is_public=True)
|
637
|
-
messages.success(request, f"Made {updated} categories public.")
|
638
|
-
|
639
|
-
@action(description="Make private", variant=ActionVariant.WARNING)
|
640
|
-
def make_private(self, request, queryset):
|
641
|
-
"""Make selected categories private."""
|
642
|
-
updated = queryset.update(is_public=False)
|
643
|
-
messages.warning(request, f"Made {updated} categories private.")
|
644
|
-
|
516
|
+
"""Created time display (delegates to helper)."""
|
517
|
+
return DocumentDisplayHelpers.display_created_at(obj, self)
|
518
|
+
|
519
|
+
# Visibility actions (delegate to shared actions, using make_* aliases)
|
520
|
+
make_public = VisibilityActions.mark_as_public
|
521
|
+
make_private = VisibilityActions.mark_as_private
|
522
|
+
|
645
523
|
def get_queryset(self, request):
|
646
524
|
"""Optimize queryset with prefetch_related."""
|
647
525
|
return super().get_queryset(request).prefetch_related('documents')
|
648
|
-
|
526
|
+
|
649
527
|
def changelist_view(self, request, extra_context=None):
|
650
528
|
"""Add category statistics to changelist."""
|
651
529
|
extra_context = extra_context or {}
|
652
|
-
|
653
530
|
queryset = self.get_queryset(request)
|
654
|
-
|
655
|
-
total_categories=Count('id'),
|
656
|
-
public_categories=Count('id', filter=models.Q(is_public=True)),
|
657
|
-
private_categories=Count('id', filter=models.Q(is_public=False))
|
658
|
-
)
|
659
|
-
|
660
|
-
extra_context['category_stats'] = {
|
661
|
-
'total_categories': stats['total_categories'] or 0,
|
662
|
-
'public_categories': stats['public_categories'] or 0,
|
663
|
-
'private_categories': stats['private_categories'] or 0
|
664
|
-
}
|
665
|
-
|
531
|
+
extra_context['category_stats'] = CategoryStatistics.get_category_stats(queryset)
|
666
532
|
return super().changelist_view(request, extra_context)
|