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
@@ -0,0 +1,15 @@
|
|
1
|
+
"""
|
2
|
+
Translation modules.
|
3
|
+
|
4
|
+
Text and JSON translation with caching and batch processing.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from .text_translator import TextTranslator, TranslationError, LanguageDetectionError
|
8
|
+
from .json_translator import JsonTranslator
|
9
|
+
|
10
|
+
__all__ = [
|
11
|
+
'TextTranslator',
|
12
|
+
'JsonTranslator',
|
13
|
+
'TranslationError',
|
14
|
+
'LanguageDetectionError',
|
15
|
+
]
|
@@ -0,0 +1,316 @@
|
|
1
|
+
"""
|
2
|
+
JSON object translation.
|
3
|
+
|
4
|
+
Handles translation of JSON objects with smart caching and batch processing.
|
5
|
+
"""
|
6
|
+
|
7
|
+
import json
|
8
|
+
import logging
|
9
|
+
from typing import Dict, Any, List, Set, Optional
|
10
|
+
|
11
|
+
logger = logging.getLogger(__name__)
|
12
|
+
|
13
|
+
|
14
|
+
class JsonTranslator:
|
15
|
+
"""Translate JSON objects with caching."""
|
16
|
+
|
17
|
+
def __init__(
|
18
|
+
self,
|
19
|
+
llm_client,
|
20
|
+
translation_cache,
|
21
|
+
language_detector,
|
22
|
+
text_utils,
|
23
|
+
prompt_builder
|
24
|
+
):
|
25
|
+
"""
|
26
|
+
Initialize JSON translator.
|
27
|
+
|
28
|
+
Args:
|
29
|
+
llm_client: LLM client for API calls
|
30
|
+
translation_cache: Cache manager
|
31
|
+
language_detector: Language detector
|
32
|
+
text_utils: Text utilities
|
33
|
+
prompt_builder: Prompt builder
|
34
|
+
"""
|
35
|
+
self.client = llm_client
|
36
|
+
self.cache = translation_cache
|
37
|
+
self.language_detector = language_detector
|
38
|
+
self.text_utils = text_utils
|
39
|
+
self.prompt_builder = prompt_builder
|
40
|
+
|
41
|
+
def translate_json(
|
42
|
+
self,
|
43
|
+
data: Dict[str, Any],
|
44
|
+
target_language: str = "en",
|
45
|
+
source_language: str = "auto",
|
46
|
+
fail_silently: bool = False,
|
47
|
+
model: Optional[str] = None,
|
48
|
+
temperature: Optional[float] = None,
|
49
|
+
) -> Dict[str, Any]:
|
50
|
+
"""
|
51
|
+
Translate JSON object with automatic language detection.
|
52
|
+
|
53
|
+
Args:
|
54
|
+
data: JSON object to translate
|
55
|
+
target_language: Target language for translation
|
56
|
+
source_language: Source language ('auto' for detection)
|
57
|
+
fail_silently: Don't raise exceptions on failure
|
58
|
+
model: Optional model override
|
59
|
+
temperature: Optional temperature override
|
60
|
+
|
61
|
+
Returns:
|
62
|
+
Translated JSON object
|
63
|
+
"""
|
64
|
+
try:
|
65
|
+
# Extract translatable texts
|
66
|
+
translatable_texts = self._extract_translatable_texts(
|
67
|
+
data, source_language, target_language
|
68
|
+
)
|
69
|
+
|
70
|
+
if not translatable_texts:
|
71
|
+
logger.info("No texts need translation in JSON object")
|
72
|
+
return data
|
73
|
+
|
74
|
+
logger.info(f"Found {len(translatable_texts)} texts to translate")
|
75
|
+
|
76
|
+
# Translate entire JSON in one request
|
77
|
+
return self._translate_json_batch(
|
78
|
+
data=data,
|
79
|
+
target_language=target_language,
|
80
|
+
source_language=source_language,
|
81
|
+
model=model,
|
82
|
+
temperature=temperature,
|
83
|
+
fail_silently=fail_silently
|
84
|
+
)
|
85
|
+
|
86
|
+
except Exception as e:
|
87
|
+
error_msg = f"Failed to translate JSON: {e}"
|
88
|
+
logger.error(error_msg)
|
89
|
+
if not fail_silently:
|
90
|
+
from .text_translator import TranslationError
|
91
|
+
raise TranslationError(error_msg) from e
|
92
|
+
return data
|
93
|
+
|
94
|
+
def _translate_json_batch(
|
95
|
+
self,
|
96
|
+
data: Any,
|
97
|
+
target_language: str,
|
98
|
+
source_language: str = 'auto',
|
99
|
+
model: Optional[str] = None,
|
100
|
+
temperature: Optional[float] = None,
|
101
|
+
fail_silently: bool = False
|
102
|
+
) -> Any:
|
103
|
+
"""Translate JSON object with smart text-level caching."""
|
104
|
+
try:
|
105
|
+
# Extract all translatable texts
|
106
|
+
translatable_texts = self._extract_translatable_texts(
|
107
|
+
data, source_language, target_language
|
108
|
+
)
|
109
|
+
|
110
|
+
if not translatable_texts:
|
111
|
+
return data
|
112
|
+
|
113
|
+
# Detect actual source language from first text if auto
|
114
|
+
actual_source_lang = source_language
|
115
|
+
if source_language == 'auto' and translatable_texts:
|
116
|
+
first_text = list(translatable_texts)[0]
|
117
|
+
detected_lang = self.language_detector.detect_language(first_text)
|
118
|
+
if detected_lang and detected_lang != 'unknown':
|
119
|
+
actual_source_lang = detected_lang
|
120
|
+
else:
|
121
|
+
actual_source_lang = 'en'
|
122
|
+
|
123
|
+
# Check cache for each text
|
124
|
+
cached_translations = {}
|
125
|
+
uncached_texts = []
|
126
|
+
|
127
|
+
for text in translatable_texts:
|
128
|
+
cached_translation = self.cache.get(text, actual_source_lang, target_language)
|
129
|
+
if cached_translation:
|
130
|
+
cached_translations[text] = cached_translation
|
131
|
+
else:
|
132
|
+
uncached_texts.append(text)
|
133
|
+
|
134
|
+
logger.info(f"Cache: {len(cached_translations)} hits, {len(uncached_texts)} misses")
|
135
|
+
|
136
|
+
# If everything is cached, just reconstruct
|
137
|
+
if not uncached_texts:
|
138
|
+
return self._apply_translations(data, cached_translations)
|
139
|
+
|
140
|
+
# Create JSON with only uncached texts
|
141
|
+
uncached_json = self._create_partial_json(data, uncached_texts)
|
142
|
+
json_str = json.dumps(uncached_json, ensure_ascii=False, indent=2)
|
143
|
+
|
144
|
+
# Create translation prompt
|
145
|
+
prompt = self.prompt_builder.build_json_translation_prompt(
|
146
|
+
json_str, actual_source_lang, target_language
|
147
|
+
)
|
148
|
+
|
149
|
+
# Make LLM request
|
150
|
+
response = self.client.chat_completion(
|
151
|
+
messages=[{"role": "user", "content": prompt}],
|
152
|
+
model=model,
|
153
|
+
temperature=temperature if temperature is not None else 0.1,
|
154
|
+
max_tokens=4000
|
155
|
+
)
|
156
|
+
|
157
|
+
translated_json_str = response.get("content", "").strip()
|
158
|
+
|
159
|
+
# Parse LLM response
|
160
|
+
try:
|
161
|
+
# Remove markdown formatting
|
162
|
+
if translated_json_str.startswith("```json"):
|
163
|
+
translated_json_str = translated_json_str.replace("```json", "").replace("```", "").strip()
|
164
|
+
elif translated_json_str.startswith("```"):
|
165
|
+
translated_json_str = translated_json_str.replace("```", "").strip()
|
166
|
+
|
167
|
+
translated_partial_data = json.loads(translated_json_str)
|
168
|
+
|
169
|
+
# Extract new translations
|
170
|
+
new_translations = self._extract_translations_by_comparison(
|
171
|
+
uncached_json, translated_partial_data, uncached_texts
|
172
|
+
)
|
173
|
+
|
174
|
+
# Cache new translations
|
175
|
+
for original_text, translated_text in new_translations.items():
|
176
|
+
self.cache.set(original_text, actual_source_lang, target_language, translated_text)
|
177
|
+
|
178
|
+
# Combine cached + new translations
|
179
|
+
all_translations = {**cached_translations, **new_translations}
|
180
|
+
|
181
|
+
# Reconstruct full JSON
|
182
|
+
result = self._apply_translations(data, all_translations)
|
183
|
+
|
184
|
+
logger.info(f"Translation complete: {len(cached_translations)} cached, {len(new_translations)} new")
|
185
|
+
return result
|
186
|
+
|
187
|
+
except json.JSONDecodeError as e:
|
188
|
+
logger.error(f"LLM returned invalid JSON: {e}")
|
189
|
+
if fail_silently:
|
190
|
+
return self._apply_translations(data, cached_translations)
|
191
|
+
else:
|
192
|
+
from .text_translator import TranslationError
|
193
|
+
raise TranslationError(f"LLM returned invalid JSON: {e}")
|
194
|
+
|
195
|
+
except Exception as e:
|
196
|
+
logger.error(f"Batch JSON translation failed: {e}")
|
197
|
+
if fail_silently:
|
198
|
+
return data
|
199
|
+
else:
|
200
|
+
from .text_translator import TranslationError
|
201
|
+
raise TranslationError(f"Batch JSON translation failed: {e}")
|
202
|
+
|
203
|
+
def _extract_translatable_texts(
|
204
|
+
self,
|
205
|
+
obj: Any,
|
206
|
+
source_language: str,
|
207
|
+
target_language: str
|
208
|
+
) -> Set[str]:
|
209
|
+
"""Extract texts that need translation from JSON object."""
|
210
|
+
translatable_texts = set()
|
211
|
+
|
212
|
+
def _extract_recursive(item):
|
213
|
+
if isinstance(item, str):
|
214
|
+
if self.text_utils.needs_translation(item, source_language, target_language):
|
215
|
+
translatable_texts.add(item)
|
216
|
+
elif isinstance(item, list):
|
217
|
+
for sub_item in item:
|
218
|
+
_extract_recursive(sub_item)
|
219
|
+
elif isinstance(item, dict):
|
220
|
+
for key, value in item.items():
|
221
|
+
if isinstance(key, str) and self.text_utils.needs_translation(key, source_language, target_language):
|
222
|
+
translatable_texts.add(key)
|
223
|
+
_extract_recursive(value)
|
224
|
+
|
225
|
+
_extract_recursive(obj)
|
226
|
+
return translatable_texts
|
227
|
+
|
228
|
+
def _apply_translations(self, obj: Any, translations: Dict[str, str]) -> Any:
|
229
|
+
"""Apply translations to JSON object."""
|
230
|
+
if isinstance(obj, str):
|
231
|
+
return translations.get(obj, obj)
|
232
|
+
elif isinstance(obj, list):
|
233
|
+
return [self._apply_translations(item, translations) for item in obj]
|
234
|
+
elif isinstance(obj, dict):
|
235
|
+
translated_dict = {}
|
236
|
+
for key, value in obj.items():
|
237
|
+
translated_key = translations.get(key, key)
|
238
|
+
translated_value = self._apply_translations(value, translations)
|
239
|
+
translated_dict[translated_key] = translated_value
|
240
|
+
return translated_dict
|
241
|
+
else:
|
242
|
+
return obj
|
243
|
+
|
244
|
+
def _create_partial_json(self, data: Any, texts_to_include: List[str]) -> Any:
|
245
|
+
"""Create JSON containing only specified texts for translation."""
|
246
|
+
texts_set = set(texts_to_include)
|
247
|
+
|
248
|
+
def filter_recursive(obj):
|
249
|
+
if isinstance(obj, str):
|
250
|
+
return obj if obj in texts_set else "SKIP_TRANSLATION"
|
251
|
+
elif isinstance(obj, dict):
|
252
|
+
result = {}
|
253
|
+
for key, value in obj.items():
|
254
|
+
filtered_value = filter_recursive(value)
|
255
|
+
if self._contains_translatable_content(filtered_value, texts_set):
|
256
|
+
result[key] = filtered_value
|
257
|
+
return result
|
258
|
+
elif isinstance(obj, list):
|
259
|
+
result = []
|
260
|
+
for item in obj:
|
261
|
+
filtered_item = filter_recursive(item)
|
262
|
+
if self._contains_translatable_content(filtered_item, texts_set):
|
263
|
+
result.append(filtered_item)
|
264
|
+
return result
|
265
|
+
else:
|
266
|
+
return obj
|
267
|
+
|
268
|
+
return filter_recursive(data)
|
269
|
+
|
270
|
+
def _contains_translatable_content(self, obj: Any, texts_set: set) -> bool:
|
271
|
+
"""Check if object contains any translatable text."""
|
272
|
+
if isinstance(obj, str):
|
273
|
+
return obj in texts_set
|
274
|
+
elif isinstance(obj, dict):
|
275
|
+
return any(self._contains_translatable_content(value, texts_set) for value in obj.values())
|
276
|
+
elif isinstance(obj, list):
|
277
|
+
return any(self._contains_translatable_content(item, texts_set) for item in obj)
|
278
|
+
else:
|
279
|
+
return False
|
280
|
+
|
281
|
+
def _extract_translations_by_comparison(
|
282
|
+
self,
|
283
|
+
original_data: Any,
|
284
|
+
translated_data: Any,
|
285
|
+
uncached_texts: List[str]
|
286
|
+
) -> Dict[str, str]:
|
287
|
+
"""Extract translations by comparing original and translated data."""
|
288
|
+
translations = {}
|
289
|
+
uncached_set = set(uncached_texts)
|
290
|
+
|
291
|
+
def _compare_recursive(original_item, translated_item):
|
292
|
+
if isinstance(original_item, str) and isinstance(translated_item, str):
|
293
|
+
if original_item in uncached_set and original_item != translated_item:
|
294
|
+
translations[original_item] = translated_item
|
295
|
+
elif isinstance(original_item, list) and isinstance(translated_item, list):
|
296
|
+
for orig, trans in zip(original_item, translated_item):
|
297
|
+
_compare_recursive(orig, trans)
|
298
|
+
elif isinstance(original_item, dict) and isinstance(translated_item, dict):
|
299
|
+
# Compare keys
|
300
|
+
orig_keys = list(original_item.keys())
|
301
|
+
trans_keys = list(translated_item.keys())
|
302
|
+
|
303
|
+
for orig_key, trans_key in zip(orig_keys, trans_keys):
|
304
|
+
if orig_key in uncached_set and orig_key != trans_key:
|
305
|
+
translations[orig_key] = trans_key
|
306
|
+
|
307
|
+
# Compare values
|
308
|
+
for orig_key, orig_value in original_item.items():
|
309
|
+
trans_key = translations.get(orig_key, orig_key)
|
310
|
+
if trans_key in translated_item:
|
311
|
+
_compare_recursive(orig_value, translated_item[trans_key])
|
312
|
+
|
313
|
+
_compare_recursive(original_data, translated_data)
|
314
|
+
|
315
|
+
logger.info(f"Extracted {len(translations)} translations from LLM response")
|
316
|
+
return translations
|
@@ -0,0 +1,139 @@
|
|
1
|
+
"""
|
2
|
+
Single text translation.
|
3
|
+
|
4
|
+
Handles translation of single text strings with caching.
|
5
|
+
"""
|
6
|
+
|
7
|
+
import logging
|
8
|
+
from typing import Optional
|
9
|
+
|
10
|
+
logger = logging.getLogger(__name__)
|
11
|
+
|
12
|
+
|
13
|
+
class TranslationError(Exception):
|
14
|
+
"""Base exception for translation-related errors."""
|
15
|
+
pass
|
16
|
+
|
17
|
+
|
18
|
+
class LanguageDetectionError(TranslationError):
|
19
|
+
"""Raised when language detection fails."""
|
20
|
+
pass
|
21
|
+
|
22
|
+
|
23
|
+
class TextTranslator:
|
24
|
+
"""Translate single text strings."""
|
25
|
+
|
26
|
+
def __init__(
|
27
|
+
self,
|
28
|
+
llm_client,
|
29
|
+
translation_cache,
|
30
|
+
stats_tracker,
|
31
|
+
script_detector,
|
32
|
+
text_utils,
|
33
|
+
prompt_builder
|
34
|
+
):
|
35
|
+
"""
|
36
|
+
Initialize text translator.
|
37
|
+
|
38
|
+
Args:
|
39
|
+
llm_client: LLM client for API calls
|
40
|
+
translation_cache: Cache manager
|
41
|
+
stats_tracker: Statistics tracker
|
42
|
+
script_detector: Script detector for language detection
|
43
|
+
text_utils: Text utilities
|
44
|
+
prompt_builder: Prompt builder
|
45
|
+
"""
|
46
|
+
self.client = llm_client
|
47
|
+
self.cache = translation_cache
|
48
|
+
self.stats = stats_tracker
|
49
|
+
self.script_detector = script_detector
|
50
|
+
self.text_utils = text_utils
|
51
|
+
self.prompt_builder = prompt_builder
|
52
|
+
|
53
|
+
def translate(
|
54
|
+
self,
|
55
|
+
text: str,
|
56
|
+
target_language: str = "en",
|
57
|
+
source_language: str = "auto",
|
58
|
+
fail_silently: bool = False,
|
59
|
+
model: Optional[str] = None,
|
60
|
+
temperature: Optional[float] = None,
|
61
|
+
) -> str:
|
62
|
+
"""
|
63
|
+
Translate single text.
|
64
|
+
|
65
|
+
Args:
|
66
|
+
text: Text to translate
|
67
|
+
target_language: Target language code
|
68
|
+
source_language: Source language code ('auto' for detection)
|
69
|
+
fail_silently: Don't raise exceptions on failure
|
70
|
+
model: Optional model override
|
71
|
+
temperature: Optional temperature override
|
72
|
+
|
73
|
+
Returns:
|
74
|
+
Translated text
|
75
|
+
|
76
|
+
Raises:
|
77
|
+
TranslationError: If translation fails and fail_silently is False
|
78
|
+
"""
|
79
|
+
try:
|
80
|
+
# Auto-detect source language if needed
|
81
|
+
if source_language == 'auto':
|
82
|
+
source_language = self.script_detector.detect_language(text)
|
83
|
+
if source_language == 'unknown':
|
84
|
+
logger.warning(f"Could not detect language for: {text[:50]}...")
|
85
|
+
if not fail_silently:
|
86
|
+
raise LanguageDetectionError("Could not detect source language")
|
87
|
+
return text
|
88
|
+
|
89
|
+
# Check if translation is needed
|
90
|
+
if not self.text_utils.needs_translation(
|
91
|
+
text, source_language, target_language, self.script_detector
|
92
|
+
):
|
93
|
+
return text
|
94
|
+
|
95
|
+
# Check translation cache
|
96
|
+
cached_translation = self.cache.get(text, source_language, target_language)
|
97
|
+
if cached_translation:
|
98
|
+
self.stats.record_cache_hit()
|
99
|
+
return cached_translation
|
100
|
+
|
101
|
+
self.stats.record_cache_miss()
|
102
|
+
|
103
|
+
# Generate prompt
|
104
|
+
prompt = self.prompt_builder.build_text_translation_prompt(
|
105
|
+
text, source_language, target_language
|
106
|
+
)
|
107
|
+
|
108
|
+
# Use LLM client for translation
|
109
|
+
messages = [{"role": "user", "content": prompt}]
|
110
|
+
response = self.client.chat_completion(
|
111
|
+
messages=messages,
|
112
|
+
model=model,
|
113
|
+
temperature=temperature if temperature is not None else 0.1,
|
114
|
+
max_tokens=1000
|
115
|
+
)
|
116
|
+
|
117
|
+
# Extract translation
|
118
|
+
translated_text = response.get('content', '').strip()
|
119
|
+
|
120
|
+
if not translated_text:
|
121
|
+
if not fail_silently:
|
122
|
+
raise TranslationError("Empty translation response")
|
123
|
+
return text
|
124
|
+
|
125
|
+
# Cache the result
|
126
|
+
self.cache.set(text, source_language, target_language, translated_text)
|
127
|
+
|
128
|
+
# Update stats
|
129
|
+
self.stats.record_translation(source_language, target_language, response)
|
130
|
+
|
131
|
+
return translated_text
|
132
|
+
|
133
|
+
except Exception as e:
|
134
|
+
self.stats.record_failure()
|
135
|
+
error_msg = f"Failed to translate text: {e}"
|
136
|
+
logger.error(error_msg)
|
137
|
+
if not fail_silently:
|
138
|
+
raise TranslationError(error_msg) from e
|
139
|
+
return text
|
@@ -0,0 +1,110 @@
|
|
1
|
+
"""
|
2
|
+
Prompt generation for translation.
|
3
|
+
|
4
|
+
Builds prompts for text and JSON translation.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from typing import Dict
|
8
|
+
|
9
|
+
|
10
|
+
class PromptBuilder:
|
11
|
+
"""Build prompts for translation."""
|
12
|
+
|
13
|
+
def __init__(self):
|
14
|
+
self.language_names = {
|
15
|
+
"en": "English",
|
16
|
+
"ru": "Russian",
|
17
|
+
"ko": "Korean",
|
18
|
+
"zh": "Chinese",
|
19
|
+
"ja": "Japanese",
|
20
|
+
"es": "Spanish",
|
21
|
+
"fr": "French",
|
22
|
+
"de": "German",
|
23
|
+
"it": "Italian",
|
24
|
+
"pt": "Portuguese",
|
25
|
+
"ar": "Arabic",
|
26
|
+
"hi": "Hindi",
|
27
|
+
"tr": "Turkish",
|
28
|
+
"pl": "Polish",
|
29
|
+
"uk": "Ukrainian",
|
30
|
+
"be": "Belarusian",
|
31
|
+
"kk": "Kazakh"
|
32
|
+
}
|
33
|
+
|
34
|
+
def build_text_translation_prompt(
|
35
|
+
self,
|
36
|
+
text: str,
|
37
|
+
source_language: str,
|
38
|
+
target_language: str
|
39
|
+
) -> str:
|
40
|
+
"""
|
41
|
+
Build prompt for text translation.
|
42
|
+
|
43
|
+
Args:
|
44
|
+
text: Text to translate
|
45
|
+
source_language: Source language code
|
46
|
+
target_language: Target language code
|
47
|
+
|
48
|
+
Returns:
|
49
|
+
Translation prompt
|
50
|
+
"""
|
51
|
+
source_name = self.language_names.get(source_language, source_language)
|
52
|
+
target_name = self.language_names.get(target_language, target_language)
|
53
|
+
|
54
|
+
prompt = f"""You are a professional translator. Translate the following text from {source_name} to {target_name}.
|
55
|
+
|
56
|
+
IMPORTANT INSTRUCTIONS:
|
57
|
+
1. Translate ONLY the text provided
|
58
|
+
2. Preserve original formatting, numbers, URLs, and technical values
|
59
|
+
3. Keep the translation accurate and natural
|
60
|
+
4. Return ONLY the translation, no explanations or comments
|
61
|
+
5. If the text contains mixed languages, translate only the parts in {source_name}
|
62
|
+
|
63
|
+
Text to translate:
|
64
|
+
{text}
|
65
|
+
|
66
|
+
Translation:"""
|
67
|
+
|
68
|
+
return prompt
|
69
|
+
|
70
|
+
def build_json_translation_prompt(
|
71
|
+
self,
|
72
|
+
json_str: str,
|
73
|
+
source_language: str,
|
74
|
+
target_language: str
|
75
|
+
) -> str:
|
76
|
+
"""
|
77
|
+
Build prompt for JSON translation.
|
78
|
+
|
79
|
+
Args:
|
80
|
+
json_str: JSON string to translate
|
81
|
+
source_language: Source language code
|
82
|
+
target_language: Target language code
|
83
|
+
|
84
|
+
Returns:
|
85
|
+
JSON translation prompt
|
86
|
+
"""
|
87
|
+
prompt = f"""You are a professional translator. Your task is to translate ONLY the VALUES in this JSON, NEVER the keys.
|
88
|
+
|
89
|
+
🚨 CRITICAL RULES - VIOLATION WILL RESULT IN FAILURE:
|
90
|
+
1. ❌ NEVER TRANSLATE JSON KEYS: "title" stays "title", NOT "título" or "заголовок"
|
91
|
+
2. ❌ NEVER TRANSLATE JSON KEYS: "description" stays "description", NOT "descripción" or "описание"
|
92
|
+
3. ❌ NEVER TRANSLATE JSON KEYS: "navigation" stays "navigation", NOT "navegación" or "навигация"
|
93
|
+
4. ✅ ONLY translate the VALUES: "Hello" → "Hola", "World" → "Mundo"
|
94
|
+
5. ❌ DO NOT translate: URLs, emails, numbers, booleans, null, empty strings, "SKIP_TRANSLATION"
|
95
|
+
6. ✅ Keep exact JSON structure and key names in English
|
96
|
+
|
97
|
+
WRONG EXAMPLE (DO NOT DO THIS):
|
98
|
+
{{"título": "Hola", "descripción": "Mundo"}}
|
99
|
+
|
100
|
+
CORRECT EXAMPLE (DO THIS):
|
101
|
+
{{"title": "Hola", "description": "Mundo"}}
|
102
|
+
|
103
|
+
If you translate ANY JSON key, you have FAILED the task completely.
|
104
|
+
|
105
|
+
JSON to translate from {source_language} to {target_language}:
|
106
|
+
{json_str}
|
107
|
+
|
108
|
+
Return ONLY the JSON with translated VALUES and original English keys:"""
|
109
|
+
|
110
|
+
return prompt
|