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,13 @@
|
|
1
|
+
"""
|
2
|
+
Embedding generation strategies for LLM client.
|
3
|
+
|
4
|
+
Provides real and mock embedding implementations.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from .openai_embedder import OpenAIEmbedder
|
8
|
+
from .mock_embedder import MockEmbedder
|
9
|
+
|
10
|
+
__all__ = [
|
11
|
+
'OpenAIEmbedder',
|
12
|
+
'MockEmbedder',
|
13
|
+
]
|
@@ -0,0 +1,106 @@
|
|
1
|
+
"""
|
2
|
+
Mock embedder for providers without embedding support.
|
3
|
+
|
4
|
+
Generates mock embeddings using MD5 hash for OpenRouter and similar providers.
|
5
|
+
"""
|
6
|
+
|
7
|
+
import time
|
8
|
+
import hashlib
|
9
|
+
import logging
|
10
|
+
from typing import Optional
|
11
|
+
|
12
|
+
from ..costs import calculate_embedding_cost
|
13
|
+
from ..models import EmbeddingResponse
|
14
|
+
|
15
|
+
logger = logging.getLogger(__name__)
|
16
|
+
|
17
|
+
|
18
|
+
class MockEmbedder:
|
19
|
+
"""Generates mock embeddings for providers without embedding support."""
|
20
|
+
|
21
|
+
# Standard embedding dimension for ada-002 compatibility
|
22
|
+
EMBEDDING_DIMENSION = 1536
|
23
|
+
|
24
|
+
def __init__(self, models_cache=None):
|
25
|
+
"""
|
26
|
+
Initialize mock embedder.
|
27
|
+
|
28
|
+
Args:
|
29
|
+
models_cache: Optional models cache for cost calculation
|
30
|
+
"""
|
31
|
+
self.models_cache = models_cache
|
32
|
+
|
33
|
+
def generate(self, text: str, model: str) -> EmbeddingResponse:
|
34
|
+
"""
|
35
|
+
Generate mock embedding using MD5 hash.
|
36
|
+
|
37
|
+
This is a workaround for OpenRouter which doesn't support embeddings.
|
38
|
+
The mock embedding is deterministic based on text content.
|
39
|
+
|
40
|
+
Args:
|
41
|
+
text: Text to generate embedding for
|
42
|
+
model: Model name (used for cost estimation)
|
43
|
+
|
44
|
+
Returns:
|
45
|
+
EmbeddingResponse with mock embedding vector and warning
|
46
|
+
"""
|
47
|
+
start_time = time.time()
|
48
|
+
|
49
|
+
logger.warning(
|
50
|
+
"Using mock embedding generation. "
|
51
|
+
"OpenRouter doesn't support embedding models."
|
52
|
+
)
|
53
|
+
|
54
|
+
# Create mock embedding from text hash
|
55
|
+
mock_embedding = self._create_mock_vector(text)
|
56
|
+
|
57
|
+
# Estimate tokens and cost
|
58
|
+
tokens_used = len(text.split()) # Rough estimate
|
59
|
+
cost = calculate_embedding_cost(tokens_used, model, self.models_cache)
|
60
|
+
|
61
|
+
response_time = time.time() - start_time
|
62
|
+
|
63
|
+
logger.debug(
|
64
|
+
f"Generated mock embedding: {tokens_used} tokens (estimated), "
|
65
|
+
f"${cost:.6f}, {response_time:.2f}s"
|
66
|
+
)
|
67
|
+
|
68
|
+
return EmbeddingResponse(
|
69
|
+
embedding=mock_embedding,
|
70
|
+
tokens=tokens_used,
|
71
|
+
cost=cost,
|
72
|
+
model=model,
|
73
|
+
text_length=len(text),
|
74
|
+
dimension=len(mock_embedding),
|
75
|
+
response_time=response_time,
|
76
|
+
warning="Mock embedding - OpenRouter doesn't support embedding models"
|
77
|
+
)
|
78
|
+
|
79
|
+
def _create_mock_vector(self, text: str) -> list:
|
80
|
+
"""
|
81
|
+
Create mock embedding vector from text hash.
|
82
|
+
|
83
|
+
Uses MD5 hash to create a deterministic vector that's consistent
|
84
|
+
for the same text but different for different texts.
|
85
|
+
|
86
|
+
Args:
|
87
|
+
text: Input text
|
88
|
+
|
89
|
+
Returns:
|
90
|
+
List of floats representing the mock embedding
|
91
|
+
"""
|
92
|
+
# Generate MD5 hash of text
|
93
|
+
text_hash = hashlib.md5(text.encode()).hexdigest()
|
94
|
+
|
95
|
+
# Convert hex pairs to normalized floats (0.0 - 1.0)
|
96
|
+
mock_embedding = [
|
97
|
+
float(int(text_hash[i:i+2], 16)) / 255.0
|
98
|
+
for i in range(0, min(32, len(text_hash)), 2)
|
99
|
+
]
|
100
|
+
|
101
|
+
# Pad to standard embedding size
|
102
|
+
while len(mock_embedding) < self.EMBEDDING_DIMENSION:
|
103
|
+
mock_embedding.append(0.0)
|
104
|
+
|
105
|
+
# Truncate to exact dimension
|
106
|
+
return mock_embedding[:self.EMBEDDING_DIMENSION]
|
@@ -0,0 +1,79 @@
|
|
1
|
+
"""
|
2
|
+
OpenAI embedder for real embedding generation.
|
3
|
+
|
4
|
+
Uses OpenAI Embeddings API to generate high-quality embeddings.
|
5
|
+
"""
|
6
|
+
|
7
|
+
import time
|
8
|
+
import logging
|
9
|
+
from typing import Optional
|
10
|
+
|
11
|
+
from ..costs import calculate_embedding_cost
|
12
|
+
from ..models import EmbeddingResponse
|
13
|
+
|
14
|
+
logger = logging.getLogger(__name__)
|
15
|
+
|
16
|
+
|
17
|
+
class OpenAIEmbedder:
|
18
|
+
"""Generates real embeddings using OpenAI API."""
|
19
|
+
|
20
|
+
def __init__(self, models_cache=None):
|
21
|
+
"""
|
22
|
+
Initialize OpenAI embedder.
|
23
|
+
|
24
|
+
Args:
|
25
|
+
models_cache: Optional models cache for cost calculation
|
26
|
+
"""
|
27
|
+
self.models_cache = models_cache
|
28
|
+
|
29
|
+
def generate(self, client, text: str, model: str) -> EmbeddingResponse:
|
30
|
+
"""
|
31
|
+
Generate real embedding via OpenAI API.
|
32
|
+
|
33
|
+
Args:
|
34
|
+
client: OpenAI client instance
|
35
|
+
text: Text to generate embedding for
|
36
|
+
model: Embedding model to use
|
37
|
+
|
38
|
+
Returns:
|
39
|
+
EmbeddingResponse with embedding vector and metadata
|
40
|
+
"""
|
41
|
+
start_time = time.time()
|
42
|
+
|
43
|
+
# Remove provider prefix if present
|
44
|
+
api_model = model
|
45
|
+
if model.startswith("openai/"):
|
46
|
+
api_model = model.replace("openai/", "")
|
47
|
+
|
48
|
+
logger.debug(f"Generating embedding with model: {api_model}")
|
49
|
+
|
50
|
+
# Make API call
|
51
|
+
response = client.embeddings.create(
|
52
|
+
input=text,
|
53
|
+
model=api_model
|
54
|
+
)
|
55
|
+
|
56
|
+
# Extract embedding data
|
57
|
+
embedding_data = response.data[0]
|
58
|
+
embedding_vector = embedding_data.embedding
|
59
|
+
|
60
|
+
# Calculate tokens and cost
|
61
|
+
tokens_used = response.usage.total_tokens
|
62
|
+
cost = calculate_embedding_cost(tokens_used, model, self.models_cache)
|
63
|
+
|
64
|
+
response_time = time.time() - start_time
|
65
|
+
|
66
|
+
logger.debug(
|
67
|
+
f"Generated embedding: {tokens_used} tokens, "
|
68
|
+
f"${cost:.6f}, {response_time:.2f}s"
|
69
|
+
)
|
70
|
+
|
71
|
+
return EmbeddingResponse(
|
72
|
+
embedding=embedding_vector,
|
73
|
+
tokens=tokens_used,
|
74
|
+
cost=cost,
|
75
|
+
model=model,
|
76
|
+
text_length=len(text),
|
77
|
+
dimension=len(embedding_vector),
|
78
|
+
response_time=response_time
|
79
|
+
)
|
@@ -0,0 +1,163 @@
|
|
1
|
+
"""
|
2
|
+
Models query API for LLM client.
|
3
|
+
|
4
|
+
Provides simplified interface to query models cache.
|
5
|
+
"""
|
6
|
+
|
7
|
+
import logging
|
8
|
+
from typing import Dict, List, Optional, Any
|
9
|
+
|
10
|
+
from ..models_cache import ModelsCache, ModelInfo
|
11
|
+
|
12
|
+
logger = logging.getLogger(__name__)
|
13
|
+
|
14
|
+
|
15
|
+
class ModelsQueryAPI:
|
16
|
+
"""Provides query interface to models cache."""
|
17
|
+
|
18
|
+
def __init__(self, models_cache: Optional[ModelsCache] = None):
|
19
|
+
"""
|
20
|
+
Initialize models query API.
|
21
|
+
|
22
|
+
Args:
|
23
|
+
models_cache: Optional models cache instance
|
24
|
+
"""
|
25
|
+
self.models_cache = models_cache
|
26
|
+
|
27
|
+
async def fetch_models(self, force_refresh: bool = False) -> Dict[str, ModelInfo]:
|
28
|
+
"""
|
29
|
+
Fetch available models with pricing information.
|
30
|
+
|
31
|
+
Args:
|
32
|
+
force_refresh: Force refresh even if cache is valid
|
33
|
+
|
34
|
+
Returns:
|
35
|
+
Dictionary of model_id -> ModelInfo
|
36
|
+
"""
|
37
|
+
if not self.models_cache:
|
38
|
+
logger.warning("Models cache not available for this provider")
|
39
|
+
return {}
|
40
|
+
|
41
|
+
return await self.models_cache.fetch_models(force_refresh=force_refresh)
|
42
|
+
|
43
|
+
def get_model_info(self, model_id: str) -> Optional[ModelInfo]:
|
44
|
+
"""
|
45
|
+
Get information about a specific model.
|
46
|
+
|
47
|
+
Args:
|
48
|
+
model_id: Model identifier
|
49
|
+
|
50
|
+
Returns:
|
51
|
+
ModelInfo or None if not found
|
52
|
+
"""
|
53
|
+
if not self.models_cache:
|
54
|
+
return None
|
55
|
+
|
56
|
+
return self.models_cache.get_model(model_id)
|
57
|
+
|
58
|
+
def get_models_by_price(
|
59
|
+
self,
|
60
|
+
min_price: float = 0.0,
|
61
|
+
max_price: float = float('inf')
|
62
|
+
) -> List[ModelInfo]:
|
63
|
+
"""
|
64
|
+
Get models within a price range.
|
65
|
+
|
66
|
+
Args:
|
67
|
+
min_price: Minimum price
|
68
|
+
max_price: Maximum price
|
69
|
+
|
70
|
+
Returns:
|
71
|
+
List of ModelInfo objects
|
72
|
+
"""
|
73
|
+
if not self.models_cache:
|
74
|
+
return []
|
75
|
+
|
76
|
+
return self.models_cache.get_models_by_price_range(min_price, max_price)
|
77
|
+
|
78
|
+
def get_free_models(self) -> List[ModelInfo]:
|
79
|
+
"""
|
80
|
+
Get all free models.
|
81
|
+
|
82
|
+
Returns:
|
83
|
+
List of free ModelInfo objects
|
84
|
+
"""
|
85
|
+
if not self.models_cache:
|
86
|
+
return []
|
87
|
+
|
88
|
+
return self.models_cache.get_free_models()
|
89
|
+
|
90
|
+
def get_budget_models(self, max_price: float = 1.0) -> List[ModelInfo]:
|
91
|
+
"""
|
92
|
+
Get budget-friendly models.
|
93
|
+
|
94
|
+
Args:
|
95
|
+
max_price: Maximum price threshold
|
96
|
+
|
97
|
+
Returns:
|
98
|
+
List of budget ModelInfo objects
|
99
|
+
"""
|
100
|
+
if not self.models_cache:
|
101
|
+
return []
|
102
|
+
|
103
|
+
return self.models_cache.get_budget_models(max_price)
|
104
|
+
|
105
|
+
def get_premium_models(self, min_price: float = 10.0) -> List[ModelInfo]:
|
106
|
+
"""
|
107
|
+
Get premium models.
|
108
|
+
|
109
|
+
Args:
|
110
|
+
min_price: Minimum price threshold
|
111
|
+
|
112
|
+
Returns:
|
113
|
+
List of premium ModelInfo objects
|
114
|
+
"""
|
115
|
+
if not self.models_cache:
|
116
|
+
return []
|
117
|
+
|
118
|
+
return self.models_cache.get_premium_models(min_price)
|
119
|
+
|
120
|
+
def search_models(self, query: str) -> List[ModelInfo]:
|
121
|
+
"""
|
122
|
+
Search models by name, description, or tags.
|
123
|
+
|
124
|
+
Args:
|
125
|
+
query: Search query string
|
126
|
+
|
127
|
+
Returns:
|
128
|
+
List of matching ModelInfo objects
|
129
|
+
"""
|
130
|
+
if not self.models_cache:
|
131
|
+
return []
|
132
|
+
|
133
|
+
return self.models_cache.search_models(query)
|
134
|
+
|
135
|
+
def get_models_summary(self) -> Dict[str, Any]:
|
136
|
+
"""
|
137
|
+
Get summary of available models.
|
138
|
+
|
139
|
+
Returns:
|
140
|
+
Dictionary with models summary statistics
|
141
|
+
"""
|
142
|
+
if not self.models_cache:
|
143
|
+
return {"error": "Models cache not available for this provider"}
|
144
|
+
|
145
|
+
return self.models_cache.get_models_summary()
|
146
|
+
|
147
|
+
def get_models_cache_info(self) -> Dict[str, Any]:
|
148
|
+
"""
|
149
|
+
Get models cache information.
|
150
|
+
|
151
|
+
Returns:
|
152
|
+
Dictionary with cache information
|
153
|
+
"""
|
154
|
+
if not self.models_cache:
|
155
|
+
return {"error": "Models cache not available for this provider"}
|
156
|
+
|
157
|
+
return self.models_cache.get_cache_info()
|
158
|
+
|
159
|
+
def clear_models_cache(self):
|
160
|
+
"""Clear the models cache."""
|
161
|
+
if self.models_cache:
|
162
|
+
self.models_cache.clear_cache()
|
163
|
+
logger.info("Models cache cleared")
|
@@ -0,0 +1,15 @@
|
|
1
|
+
"""
|
2
|
+
Provider management for LLM client.
|
3
|
+
|
4
|
+
Handles initialization, configuration, and selection of LLM providers.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from .config_builder import ConfigBuilder
|
8
|
+
from .provider_manager import ProviderManager
|
9
|
+
from .provider_selector import ProviderSelector
|
10
|
+
|
11
|
+
__all__ = [
|
12
|
+
'ConfigBuilder',
|
13
|
+
'ProviderManager',
|
14
|
+
'ProviderSelector',
|
15
|
+
]
|
@@ -0,0 +1,103 @@
|
|
1
|
+
"""
|
2
|
+
Configuration builder for LLM providers.
|
3
|
+
|
4
|
+
Builds provider-specific configurations and headers.
|
5
|
+
"""
|
6
|
+
|
7
|
+
import logging
|
8
|
+
from typing import Dict, Any, Optional
|
9
|
+
|
10
|
+
logger = logging.getLogger(__name__)
|
11
|
+
|
12
|
+
|
13
|
+
class ConfigBuilder:
|
14
|
+
"""Builds configuration for LLM providers."""
|
15
|
+
|
16
|
+
@staticmethod
|
17
|
+
def get_openrouter_headers(django_config: Optional[Any] = None) -> Dict[str, str]:
|
18
|
+
"""
|
19
|
+
Build headers for OpenRouter API.
|
20
|
+
|
21
|
+
Args:
|
22
|
+
django_config: Django configuration object
|
23
|
+
|
24
|
+
Returns:
|
25
|
+
Dictionary of headers for OpenRouter
|
26
|
+
"""
|
27
|
+
headers = {}
|
28
|
+
|
29
|
+
if django_config:
|
30
|
+
try:
|
31
|
+
site_url = getattr(django_config, 'site_url', 'http://localhost:8000')
|
32
|
+
project_name = getattr(django_config, 'project_name', 'Django CFG')
|
33
|
+
headers.update({
|
34
|
+
"HTTP-Referer": site_url,
|
35
|
+
"X-Title": project_name
|
36
|
+
})
|
37
|
+
except Exception as e:
|
38
|
+
logger.warning(f"Failed to extract config for OpenRouter headers: {e}")
|
39
|
+
|
40
|
+
return headers
|
41
|
+
|
42
|
+
@staticmethod
|
43
|
+
def get_provider_config(
|
44
|
+
provider: str,
|
45
|
+
django_config: Optional[Any] = None
|
46
|
+
) -> Dict[str, Any]:
|
47
|
+
"""
|
48
|
+
Get full provider configuration.
|
49
|
+
|
50
|
+
Args:
|
51
|
+
provider: Provider name ("openai" or "openrouter")
|
52
|
+
django_config: Django configuration object
|
53
|
+
|
54
|
+
Returns:
|
55
|
+
Provider configuration dictionary
|
56
|
+
|
57
|
+
Raises:
|
58
|
+
ValueError: If provider is not supported
|
59
|
+
"""
|
60
|
+
base_configs = {
|
61
|
+
"openrouter": {
|
62
|
+
"base_url": "https://openrouter.ai/api/v1",
|
63
|
+
"headers": ConfigBuilder.get_openrouter_headers(django_config)
|
64
|
+
},
|
65
|
+
"openai": {
|
66
|
+
"base_url": "https://api.openai.com/v1",
|
67
|
+
"headers": {}
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
if provider not in base_configs:
|
72
|
+
raise ValueError(f"Unsupported provider: {provider}")
|
73
|
+
|
74
|
+
config = base_configs[provider].copy()
|
75
|
+
|
76
|
+
# Add custom headers from LLM config if available
|
77
|
+
if django_config:
|
78
|
+
try:
|
79
|
+
if hasattr(django_config, 'llm') and django_config.llm:
|
80
|
+
llm_config = django_config.llm
|
81
|
+
if hasattr(llm_config, 'custom_headers'):
|
82
|
+
config["headers"].update(llm_config.custom_headers)
|
83
|
+
except Exception as e:
|
84
|
+
logger.warning(f"Failed to add custom headers: {e}")
|
85
|
+
|
86
|
+
return config
|
87
|
+
|
88
|
+
@staticmethod
|
89
|
+
def get_default_model(provider: str) -> str:
|
90
|
+
"""
|
91
|
+
Get default model for provider.
|
92
|
+
|
93
|
+
Args:
|
94
|
+
provider: Provider name
|
95
|
+
|
96
|
+
Returns:
|
97
|
+
Default model ID
|
98
|
+
"""
|
99
|
+
default_models = {
|
100
|
+
"openrouter": "openai/gpt-4o-mini",
|
101
|
+
"openai": "gpt-4o-mini"
|
102
|
+
}
|
103
|
+
return default_models.get(provider, "gpt-4o-mini")
|
@@ -0,0 +1,148 @@
|
|
1
|
+
"""
|
2
|
+
Provider manager for LLM client.
|
3
|
+
|
4
|
+
Manages initialization and access to LLM provider clients.
|
5
|
+
"""
|
6
|
+
|
7
|
+
import logging
|
8
|
+
from typing import Dict, Optional, Any
|
9
|
+
from openai import OpenAI
|
10
|
+
|
11
|
+
from .config_builder import ConfigBuilder
|
12
|
+
|
13
|
+
logger = logging.getLogger(__name__)
|
14
|
+
|
15
|
+
|
16
|
+
class ProviderManager:
|
17
|
+
"""Manages LLM provider clients and API keys."""
|
18
|
+
|
19
|
+
def __init__(
|
20
|
+
self,
|
21
|
+
apikey_openrouter: Optional[str] = None,
|
22
|
+
apikey_openai: Optional[str] = None,
|
23
|
+
preferred_provider: Optional[str] = None,
|
24
|
+
django_config: Optional[Any] = None
|
25
|
+
):
|
26
|
+
"""
|
27
|
+
Initialize provider manager.
|
28
|
+
|
29
|
+
Args:
|
30
|
+
apikey_openrouter: OpenRouter API key
|
31
|
+
apikey_openai: OpenAI API key
|
32
|
+
preferred_provider: Preferred provider ("openai" or "openrouter")
|
33
|
+
django_config: Django configuration object
|
34
|
+
"""
|
35
|
+
self.apikey_openrouter = apikey_openrouter
|
36
|
+
self.apikey_openai = apikey_openai
|
37
|
+
self.preferred_provider = preferred_provider
|
38
|
+
self.django_config = django_config
|
39
|
+
|
40
|
+
# Initialize clients dictionary
|
41
|
+
self.clients: Dict[str, OpenAI] = {}
|
42
|
+
|
43
|
+
# Initialize clients for available providers
|
44
|
+
self._init_openrouter_client()
|
45
|
+
self._init_openai_client()
|
46
|
+
|
47
|
+
# Determine primary provider
|
48
|
+
self.primary_provider = self._determine_primary_provider()
|
49
|
+
|
50
|
+
# Get primary client
|
51
|
+
self.primary_client = self.clients[self.primary_provider]
|
52
|
+
|
53
|
+
logger.info(f"Initialized ProviderManager with primary provider: {self.primary_provider}")
|
54
|
+
|
55
|
+
def _init_openrouter_client(self):
|
56
|
+
"""Initialize OpenRouter client if API key is available."""
|
57
|
+
if self.apikey_openrouter:
|
58
|
+
try:
|
59
|
+
headers = ConfigBuilder.get_openrouter_headers(self.django_config)
|
60
|
+
self.clients["openrouter"] = OpenAI(
|
61
|
+
base_url="https://openrouter.ai/api/v1",
|
62
|
+
api_key=self.apikey_openrouter,
|
63
|
+
default_headers=headers
|
64
|
+
)
|
65
|
+
logger.info("OpenRouter client initialized")
|
66
|
+
except Exception as e:
|
67
|
+
logger.error(f"Failed to initialize OpenRouter client: {e}")
|
68
|
+
|
69
|
+
def _init_openai_client(self):
|
70
|
+
"""Initialize OpenAI client if API key is available."""
|
71
|
+
if self.apikey_openai:
|
72
|
+
try:
|
73
|
+
self.clients["openai"] = OpenAI(api_key=self.apikey_openai)
|
74
|
+
logger.info("OpenAI client initialized")
|
75
|
+
except Exception as e:
|
76
|
+
logger.error(f"Failed to initialize OpenAI client: {e}")
|
77
|
+
|
78
|
+
def _determine_primary_provider(self) -> str:
|
79
|
+
"""
|
80
|
+
Determine primary provider based on preference and available keys.
|
81
|
+
|
82
|
+
Returns:
|
83
|
+
Primary provider name
|
84
|
+
|
85
|
+
Raises:
|
86
|
+
ValueError: If no provider is available
|
87
|
+
"""
|
88
|
+
# If preferred provider is explicitly set and available, use it
|
89
|
+
if self.preferred_provider:
|
90
|
+
if self.preferred_provider == "openai" and "openai" in self.clients:
|
91
|
+
return "openai"
|
92
|
+
elif self.preferred_provider == "openrouter" and "openrouter" in self.clients:
|
93
|
+
return "openrouter"
|
94
|
+
else:
|
95
|
+
logger.warning(
|
96
|
+
f"Preferred provider '{self.preferred_provider}' not available, "
|
97
|
+
f"falling back to auto-detection"
|
98
|
+
)
|
99
|
+
|
100
|
+
# Auto-detection: prefer OpenAI for better compatibility
|
101
|
+
if "openai" in self.clients:
|
102
|
+
return "openai"
|
103
|
+
elif "openrouter" in self.clients:
|
104
|
+
return "openrouter"
|
105
|
+
else:
|
106
|
+
raise ValueError(
|
107
|
+
"At least one API key (openrouter or openai) must be provided"
|
108
|
+
)
|
109
|
+
|
110
|
+
def get_client(self, provider: Optional[str] = None) -> OpenAI:
|
111
|
+
"""
|
112
|
+
Get client for specific provider or primary.
|
113
|
+
|
114
|
+
Args:
|
115
|
+
provider: Provider name (None for primary)
|
116
|
+
|
117
|
+
Returns:
|
118
|
+
OpenAI client instance
|
119
|
+
|
120
|
+
Raises:
|
121
|
+
ValueError: If provider is not available
|
122
|
+
"""
|
123
|
+
if provider:
|
124
|
+
if provider not in self.clients:
|
125
|
+
raise ValueError(f"Provider '{provider}' not available")
|
126
|
+
return self.clients[provider]
|
127
|
+
return self.primary_client
|
128
|
+
|
129
|
+
def has_provider(self, provider: str) -> bool:
|
130
|
+
"""
|
131
|
+
Check if provider is available.
|
132
|
+
|
133
|
+
Args:
|
134
|
+
provider: Provider name
|
135
|
+
|
136
|
+
Returns:
|
137
|
+
True if provider is available
|
138
|
+
"""
|
139
|
+
return provider in self.clients
|
140
|
+
|
141
|
+
def get_available_providers(self) -> list:
|
142
|
+
"""
|
143
|
+
Get list of available providers.
|
144
|
+
|
145
|
+
Returns:
|
146
|
+
List of provider names
|
147
|
+
"""
|
148
|
+
return list(self.clients.keys())
|
@@ -0,0 +1,60 @@
|
|
1
|
+
"""
|
2
|
+
Provider selector for LLM client.
|
3
|
+
|
4
|
+
Selects optimal provider for specific tasks.
|
5
|
+
"""
|
6
|
+
|
7
|
+
import logging
|
8
|
+
from typing import TYPE_CHECKING
|
9
|
+
|
10
|
+
if TYPE_CHECKING:
|
11
|
+
from .provider_manager import ProviderManager
|
12
|
+
|
13
|
+
logger = logging.getLogger(__name__)
|
14
|
+
|
15
|
+
|
16
|
+
class ProviderSelector:
|
17
|
+
"""Selects optimal provider for specific tasks."""
|
18
|
+
|
19
|
+
def __init__(self, provider_manager: 'ProviderManager'):
|
20
|
+
"""
|
21
|
+
Initialize provider selector.
|
22
|
+
|
23
|
+
Args:
|
24
|
+
provider_manager: ProviderManager instance
|
25
|
+
"""
|
26
|
+
self.provider_manager = provider_manager
|
27
|
+
|
28
|
+
def get_provider_for_task(self, task: str = "chat") -> str:
|
29
|
+
"""
|
30
|
+
Get the best provider for a specific task.
|
31
|
+
|
32
|
+
Args:
|
33
|
+
task: Task type ("chat", "embedding", "completion")
|
34
|
+
|
35
|
+
Returns:
|
36
|
+
Provider name for the task
|
37
|
+
"""
|
38
|
+
# For embeddings, always prefer OpenAI if available
|
39
|
+
# OpenRouter doesn't have proper embedding support
|
40
|
+
if task == "embedding" and self.provider_manager.has_provider("openai"):
|
41
|
+
logger.debug("Selecting OpenAI for embedding task")
|
42
|
+
return "openai"
|
43
|
+
|
44
|
+
# For other tasks, use primary provider
|
45
|
+
provider = self.provider_manager.primary_provider
|
46
|
+
logger.debug(f"Selecting {provider} for {task} task")
|
47
|
+
return provider
|
48
|
+
|
49
|
+
def should_use_mock_embedding(self, provider: str) -> bool:
|
50
|
+
"""
|
51
|
+
Determine if mock embedding should be used for provider.
|
52
|
+
|
53
|
+
Args:
|
54
|
+
provider: Provider name
|
55
|
+
|
56
|
+
Returns:
|
57
|
+
True if mock embedding should be used
|
58
|
+
"""
|
59
|
+
# OpenRouter doesn't support real embeddings
|
60
|
+
return provider == "openrouter"
|