aegis-stack 0.2.0rc2__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.
- aegis/__init__.py +5 -0
- aegis/__main__.py +51 -0
- aegis/cli/__init__.py +6 -0
- aegis/cli/callbacks.py +114 -0
- aegis/cli/interactive.py +611 -0
- aegis/cli/utils.py +70 -0
- aegis/cli/validators.py +34 -0
- aegis/commands/__init__.py +6 -0
- aegis/commands/add.py +353 -0
- aegis/commands/add_service.py +332 -0
- aegis/commands/components.py +35 -0
- aegis/commands/init.py +370 -0
- aegis/commands/remove.py +227 -0
- aegis/commands/services.py +52 -0
- aegis/commands/update.py +252 -0
- aegis/commands/version.py +12 -0
- aegis/config/__init__.py +1 -0
- aegis/config/shared_files.py +136 -0
- aegis/core/CLAUDE.md +377 -0
- aegis/core/__init__.py +6 -0
- aegis/core/component_files.py +228 -0
- aegis/core/component_utils.py +220 -0
- aegis/core/components.py +127 -0
- aegis/core/copier_manager.py +315 -0
- aegis/core/copier_updater.py +475 -0
- aegis/core/dependency_resolver.py +119 -0
- aegis/core/manual_updater.py +554 -0
- aegis/core/post_gen_tasks.py +547 -0
- aegis/core/service_resolver.py +261 -0
- aegis/core/services.py +157 -0
- aegis/core/template_generator.py +266 -0
- aegis/core/version_compatibility.py +259 -0
- aegis/templates/CLAUDE.md +591 -0
- aegis/templates/cookiecutter-aegis-project/cookiecutter.json +39 -0
- aegis/templates/cookiecutter-aegis-project/hooks/post_gen_project.py +214 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/.dockerignore +71 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/.env.example.j2 +130 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/.gitignore +131 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/Dockerfile +53 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/Makefile +236 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/README.md.j2 +196 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/alembic/alembic.ini.j2 +111 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/alembic/env.py.j2 +91 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/alembic/script.py.mako +25 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/alembic/versions/001_initial_auth.py.j2 +51 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/__init__.py +5 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/__init__.py +6 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/ai.py.j2 +700 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/ai_rendering.py +361 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/auth.py.j2 +253 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/health.py.j2 +419 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/load_test.py.j2 +656 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/main.py.j2 +65 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/marko_terminal_renderer.py +489 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/tasks.py.j2 +328 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/{% if cookiecutter.include_scheduler == /"yes/" %}tasks.py{% endif %}" +340 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/__init__.py +0 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/__init__.py +0 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/ai/__init__.py +8 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/ai/router.py +329 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/auth/__init__.py +1 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/auth/router.py +64 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/deps.py +58 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/health.py +163 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/models.py.j2 +280 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/routing.py.j2 +32 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/scheduler.py.j2 +121 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/worker.py.j2 +478 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/hooks.py +144 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/main.py +31 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/middleware/__init__.py +1 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/middleware/cors.py +20 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/shutdown/__init__.py +1 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/shutdown/cleanup.py +14 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/startup/__init__.py +1 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/startup/component_health.py.j2 +418 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/startup/database_init.py.j2 +83 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/__init__.py +5 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/controls/__init__.py +27 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/controls/table.py +78 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/controls/text.py +142 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/__init__.py.j2 +47 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/ai_card.py +287 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/auth_card.py +198 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/base_card.py +256 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/card_factory.py +227 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/card_utils.py +333 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/database_card.py +420 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/fastapi_card.py +328 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/flet_card.py +267 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/redis_card.py +322 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/scheduler_card.py +352 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/services_card.py +233 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/worker_card.py +684 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/main.py.j2 +653 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/theme.py +48 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/scheduler/__init__.py +1 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/scheduler/main.py.j2 +156 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/CLAUDE.md.j2 +213 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/__init__.py +6 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/constants.py.j2 +30 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/pools.py +97 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/queues/__init__.py +1 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/queues/load_test.py +55 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/queues/media.py +49 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/queues/system.py +44 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/registry.py +139 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/tasks/__init__.py +120 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/tasks/load_tasks.py +507 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/tasks/simple_system_tasks.py +33 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/tasks/system_tasks.py +281 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/core/config.py.j2 +178 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/core/constants.py +58 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/core/db.py.j2 +176 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/core/log.py +92 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/core/security.py +62 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/entrypoints/__init__.py +1 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/entrypoints/webserver.py +40 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/entrypoints/{% if cookiecutter.include_scheduler == /"yes/" %}scheduler.py{% endif %}" +21 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/integrations/__init__.py +0 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/integrations/main.py +62 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/models/__init__.py +1 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/models/user.py +44 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/py.typed +0 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/__init__.py +1 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/ai/__init__.py +8 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/ai/config.py +130 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/ai/conversation.py +213 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/ai/health.py +96 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/ai/models.py +229 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/ai/providers.py +370 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/ai/service.py +388 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/auth/__init__.py +1 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/auth/auth_service.py +41 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/auth/health.py +164 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/auth/user_service.py +83 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/backend/middleware_inspector.py.j2 +223 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/backend/models.py.j2 +70 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/backend/route_inspector.py.j2 +155 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/load_test.py +679 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/load_test_models.py +266 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/scheduler/__init__.py.j2 +21 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/scheduler/models.py.j2 +119 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/scheduler/scheduled_task_manager.py.j2 +273 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/scheduler/task_monitor.py.j2 +189 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/shared/__init__.py +15 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/shared/models.py +26 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/system/__init__.py +52 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/system/alerts.py +94 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/system/backup.py.j2 +119 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/system/health.py.j2 +1333 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/system/models.py +243 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/system/ui.py +52 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/assets/aegis-manifesto-dark.png +0 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/assets/aegis-manifesto-square-backup.png +0 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/assets/aegis-manifesto.png +0 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/.dockerignore +71 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/.env.example.j2 +64 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/.gitignore +131 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/Dockerfile +53 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/Makefile +211 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/README.md.j2 +172 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/docker-compose.yml.j2 +78 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/mkdocs.yml.j2 +62 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/pyproject.toml.j2 +120 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/uv.lock +1673 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/docker-compose.yml.j2 +200 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/docs/api.md +191 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/docs/components/scheduler.md +0 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/docs/components/scheduler.md.j2 +621 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/docs/development.md +215 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/docs/health.md +240 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/docs/javascripts/mermaid-config.js +62 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/docs/stylesheets/mermaid.css +95 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/mkdocs.yml.j2 +62 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/pyproject.toml.j2 +131 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/scripts/entrypoint.sh +87 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/scripts/entrypoint.sh.j2 +93 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/scripts/gen_docs.py +16 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/api/__init__.py +1 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/api/test_auth_endpoints.py.j2 +307 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/api/test_health_endpoints.py.j2 +262 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/api/test_scheduler_endpoints.py.j2 +214 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/api/test_worker_endpoints.py.j2 +165 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/cli/test_ai_rendering.py +427 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/cli/test_conversation_memory.py +465 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/components/test_scheduler.py +43 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/conftest.py.j2 +195 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/__init__.py +1 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/ai/__init__.py +1 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/ai/conftest.py +78 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/ai/test_health.py +157 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/ai/test_models.py +164 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/ai/test_service.py +198 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_auth_integration.py.j2 +528 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_component_integration.py.j2 +387 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_conversation_persistence.py +342 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_health_logic.py.j2 +663 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_load_test_models.py +619 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_load_test_service.py +603 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_middleware_inspector.py.j2 +248 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_scheduled_task_manager.py.j2 +292 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_system_service.py +98 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_worker_health_registration.py.j2 +257 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/test_core.py +49 -0
- aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/uv.lock +1673 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/.copier-answers.yml.jinja +21 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/.dockerignore +71 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/.env.example.jinja +130 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/.gitignore +131 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/Dockerfile +53 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/Makefile.jinja +236 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/README.md.jinja +196 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/alembic/alembic.ini.jinja +111 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/alembic/env.py.jinja +91 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/alembic/script.py.mako +25 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/alembic/versions/001_initial_auth.py.jinja +51 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/__init__.py.jinja +5 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/cli/__init__.py.jinja +6 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/cli/ai.py.jinja +700 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/cli/ai_rendering.py +360 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/cli/auth.py.jinja +253 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/cli/health.py.jinja +419 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/cli/load_test.py.jinja +656 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/cli/main.py.jinja +65 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/cli/marko_terminal_renderer.py +489 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/cli/tasks.py.jinja +328 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/__init__.py +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/__init__.py +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/ai/__init__.py +8 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/ai/router.py +329 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/auth/__init__.py +1 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/auth/router.py +64 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/deps.py +58 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/health.py.jinja +163 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/models.py.jinja +280 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/routing.py.jinja +32 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/scheduler.py.jinja +121 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/worker.py.jinja +478 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/hooks.py +144 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/main.py +31 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/middleware/__init__.py +1 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/middleware/cors.py +20 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/shutdown/__init__.py +1 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/shutdown/cleanup.py +14 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/startup/__init__.py +1 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/startup/component_health.py.jinja +418 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/startup/database_init.py.jinja +83 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/__init__.py +5 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/controls/__init__.py +27 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/controls/table.py +78 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/controls/text.py +142 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/__init__.py.jinja +47 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/ai_card.py +287 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/auth_card.py +198 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/base_card.py +256 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/card_factory.py +227 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/card_utils.py +333 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/database_card.py +420 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/fastapi_card.py +328 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/flet_card.py +267 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/redis_card.py +322 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/scheduler_card.py +352 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/services_card.py +233 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/worker_card.py +684 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/main.py.jinja +653 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/theme.py +48 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/scheduler/__init__.py +1 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/scheduler/main.py.jinja +156 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/CLAUDE.md.jinja +213 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/__init__.py +6 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/constants.py.jinja +30 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/pools.py +97 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/queues/__init__.py +1 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/queues/load_test.py +55 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/queues/media.py +49 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/queues/system.py +44 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/registry.py +139 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/tasks/__init__.py +120 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/tasks/load_tasks.py +507 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/tasks/simple_system_tasks.py +33 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/tasks/system_tasks.py +281 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/core/config.py.jinja +178 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/core/constants.py +58 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/core/db.py.jinja +176 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/core/log.py +92 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/core/security.py +62 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/entrypoints/__init__.py +1 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/entrypoints/scheduler.py.jinja +21 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/entrypoints/webserver.py +39 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/integrations/__init__.py +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/integrations/main.py +61 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/models/__init__.py +1 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/models/user.py +44 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/py.typed +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/__init__.py +1 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/ai/__init__.py +8 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/ai/config.py +130 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/ai/conversation.py +213 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/ai/health.py +96 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/ai/models.py +229 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/ai/providers.py.jinja +370 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/ai/service.py +387 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/auth/__init__.py +1 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/auth/auth_service.py +40 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/auth/health.py +162 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/auth/user_service.py +82 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/backend/middleware_inspector.py.jinja +223 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/backend/models.py.jinja +70 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/backend/route_inspector.py.jinja +155 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/load_test.py +678 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/load_test_models.py +265 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/scheduler/__init__.py.jinja +21 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/scheduler/models.py.jinja +119 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/scheduler/scheduled_task_manager.py.jinja +273 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/scheduler/task_monitor.py.jinja +189 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/shared/__init__.py +15 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/shared/models.py +26 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/system/__init__.py +52 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/system/alerts.py +94 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/system/backup.py.jinja +119 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/system/health.py.jinja +1333 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/system/models.py +243 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/system/ui.py +52 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!57223!aegis-manifesto.png +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!57224!aegis-manifesto-dark.png +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!57225!aegis-manifesto-square-backup.png +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!57533!aegis-manifesto.png +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!57534!aegis-manifesto-dark.png +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!57538!aegis-manifesto-square-backup.png +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!57897!aegis-manifesto.png +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!57898!aegis-manifesto-dark.png +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!57904!aegis-manifesto-square-backup.png +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!58315!aegis-manifesto.png +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!58316!aegis-manifesto-dark.png +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!58324!aegis-manifesto-square-backup.png +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!58837!aegis-manifesto.png +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!58838!aegis-manifesto-dark.png +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!58849!aegis-manifesto-square-backup.png +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/assets/aegis-manifesto-dark.png +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/assets/aegis-manifesto-square-backup.png +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/assets/aegis-manifesto.png +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/clean-validation/.env.example.jinja +64 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/clean-validation/README.md.jinja +172 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/clean-validation/docker-compose.yml.jinja +78 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/clean-validation/mkdocs.yml.jinja +62 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/clean-validation/pyproject.toml.jinja +120 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/docker-compose.yml.jinja +200 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/docs/api.md.jinja +191 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/docs/components/scheduler.md +0 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/docs/components/scheduler.md.jinja +621 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/docs/development.md.jinja +215 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/docs/health.md.jinja +240 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/docs/javascripts/mermaid-config.js +62 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/docs/stylesheets/mermaid.css +95 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/mkdocs.yml.jinja +62 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/pyproject.toml.jinja +131 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/scripts/entrypoint.sh +87 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/scripts/entrypoint.sh.jinja +93 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/scripts/gen_docs.py +16 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/api/__init__.py +1 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/api/test_auth_endpoints.py.jinja +307 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/api/test_health_endpoints.py.jinja +262 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/api/test_scheduler_endpoints.py.jinja +214 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/api/test_worker_endpoints.py.jinja +165 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/cli/test_ai_rendering.py +427 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/cli/test_conversation_memory.py +465 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/components/test_scheduler.py +43 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/conftest.py.jinja +195 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/__init__.py +1 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/ai/__init__.py +1 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/ai/conftest.py +78 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/ai/test_health.py +157 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/ai/test_models.py +164 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/ai/test_service.py +198 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_auth_integration.py.jinja +528 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_component_integration.py.jinja +387 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_conversation_persistence.py +342 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_health_logic.py.jinja +663 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_load_test_models.py +619 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_load_test_service.py +603 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_middleware_inspector.py.jinja +248 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_scheduled_task_manager.py.jinja +292 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_system_service.py +98 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_worker_health_registration.py.jinja +257 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/tests/test_core.py +49 -0
- aegis/templates/copier-aegis-project/{{ project_slug }}/uv.lock +1673 -0
- aegis_stack-0.2.0rc2.dist-info/METADATA +165 -0
- aegis_stack-0.2.0rc2.dist-info/RECORD +392 -0
- aegis_stack-0.2.0rc2.dist-info/WHEEL +4 -0
- aegis_stack-0.2.0rc2.dist-info/entry_points.txt +3 -0
- aegis_stack-0.2.0rc2.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Database initialization startup hook.
|
|
3
|
+
|
|
4
|
+
Ensures database directory structure exists and verifies connectivity
|
|
5
|
+
when the backend starts up (only when database component is included).
|
|
6
|
+
"""
|
|
7
|
+
{% if include_database %}
|
|
8
|
+
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from app.core.db import init_database
|
|
11
|
+
from app.core.log import logger
|
|
12
|
+
|
|
13
|
+
{% if include_auth %}
|
|
14
|
+
# Import models to register them with SQLModel metadata
|
|
15
|
+
from app.models.user import User # noqa: F401
|
|
16
|
+
{% endif %}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
async def startup_database_init() -> None:
|
|
20
|
+
"""
|
|
21
|
+
Initialize database directory structure and verify connectivity.
|
|
22
|
+
|
|
23
|
+
This hook runs when the backend starts to ensure the database
|
|
24
|
+
directory exists and connection works. For auth service projects,
|
|
25
|
+
migrations should already be applied during project generation.
|
|
26
|
+
"""
|
|
27
|
+
try:
|
|
28
|
+
# Ensure database directory exists
|
|
29
|
+
from app.core.db import DATABASE_PATH
|
|
30
|
+
db_path = Path(DATABASE_PATH)
|
|
31
|
+
db_path.parent.mkdir(parents=True, exist_ok=True)
|
|
32
|
+
|
|
33
|
+
{% if include_auth %}
|
|
34
|
+
# Auth service - verify database and migration status
|
|
35
|
+
try:
|
|
36
|
+
from app.core.db import db_session
|
|
37
|
+
from sqlmodel import select, func, text
|
|
38
|
+
from sqlalchemy import inspect
|
|
39
|
+
|
|
40
|
+
with db_session(autocommit=False) as session:
|
|
41
|
+
# Check 1: Basic database connectivity
|
|
42
|
+
session.exec(text("SELECT 1"))
|
|
43
|
+
|
|
44
|
+
# Check 2: Auth tables exist (User table specifically)
|
|
45
|
+
session.exec(select(func.count()).select_from(User))
|
|
46
|
+
|
|
47
|
+
# Check 3: Alembic migration system is set up
|
|
48
|
+
inspector = inspect(session.connection())
|
|
49
|
+
table_names = inspector.get_table_names()
|
|
50
|
+
|
|
51
|
+
if "alembic_version" in table_names:
|
|
52
|
+
logger.info(
|
|
53
|
+
"✅ Database connectivity and auth schema verified "
|
|
54
|
+
"(migrations applied)"
|
|
55
|
+
)
|
|
56
|
+
else:
|
|
57
|
+
logger.warning(
|
|
58
|
+
"⚠️ alembic_version table missing - migrations may not be "
|
|
59
|
+
"fully applied"
|
|
60
|
+
)
|
|
61
|
+
logger.warning(
|
|
62
|
+
"💡 Run 'alembic upgrade head' to ensure all migrations "
|
|
63
|
+
"are applied"
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
except Exception as e:
|
|
67
|
+
logger.warning(f"⚠️ Database check failed: {e}")
|
|
68
|
+
logger.warning("💡 Run 'alembic upgrade head' to apply migrations")
|
|
69
|
+
# Don't fail startup - let the app run and show clear errors
|
|
70
|
+
{% else %}
|
|
71
|
+
# Database component only - ensure tables exist
|
|
72
|
+
init_database()
|
|
73
|
+
logger.info("🗃️ Database initialization completed")
|
|
74
|
+
{% endif %}
|
|
75
|
+
|
|
76
|
+
except Exception as e:
|
|
77
|
+
logger.error(f"❌ Database initialization failed: {e}")
|
|
78
|
+
raise
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
# Export the startup hook function
|
|
82
|
+
startup_hook = startup_database_init
|
|
83
|
+
{% endif %}
|
aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/controls/__init__.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Frontend UI controls for styled components."""
|
|
2
|
+
|
|
3
|
+
from .table import (
|
|
4
|
+
TableCellText,
|
|
5
|
+
TableHeaderText,
|
|
6
|
+
TableNameText,
|
|
7
|
+
)
|
|
8
|
+
from .text import (
|
|
9
|
+
ConfirmationText,
|
|
10
|
+
LabelText,
|
|
11
|
+
MetricText,
|
|
12
|
+
PrimaryText,
|
|
13
|
+
SecondaryText,
|
|
14
|
+
TitleText,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"PrimaryText",
|
|
19
|
+
"SecondaryText",
|
|
20
|
+
"TitleText",
|
|
21
|
+
"ConfirmationText",
|
|
22
|
+
"MetricText",
|
|
23
|
+
"LabelText",
|
|
24
|
+
"TableHeaderText",
|
|
25
|
+
"TableCellText",
|
|
26
|
+
"TableNameText",
|
|
27
|
+
]
|
aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/controls/table.py
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Table-specific text controls for consistent styling across cards.
|
|
3
|
+
|
|
4
|
+
These controls provide standardized text styling for table headers, cells, and
|
|
5
|
+
entity names to ensure consistency between worker, database, and other component cards.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
import flet as ft
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TableHeaderText(ft.Text): # type: ignore[misc]
|
|
14
|
+
"""
|
|
15
|
+
Table header text control with consistent styling.
|
|
16
|
+
|
|
17
|
+
Used for column headers in component cards. Provides medium weight text
|
|
18
|
+
with reduced opacity for visual hierarchy.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def __init__(self, text: str, **kwargs: Any) -> None:
|
|
22
|
+
# Set defaults that can be overridden
|
|
23
|
+
defaults = {
|
|
24
|
+
"weight": ft.FontWeight.W_500,
|
|
25
|
+
"size": 12,
|
|
26
|
+
"color": ft.Colors.GREY_600,
|
|
27
|
+
}
|
|
28
|
+
defaults.update(kwargs)
|
|
29
|
+
|
|
30
|
+
super().__init__(
|
|
31
|
+
text,
|
|
32
|
+
**defaults,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class TableCellText(ft.Text): # type: ignore[misc]
|
|
37
|
+
"""
|
|
38
|
+
Table cell text control for data values.
|
|
39
|
+
|
|
40
|
+
Used for displaying data values in table cells. Provides consistent
|
|
41
|
+
sizing and coloring for tabular data.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
def __init__(self, text: str, **kwargs: Any) -> None:
|
|
45
|
+
# Set defaults that can be overridden
|
|
46
|
+
defaults = {
|
|
47
|
+
"size": 11,
|
|
48
|
+
"color": ft.Colors.ON_SURFACE,
|
|
49
|
+
}
|
|
50
|
+
defaults.update(kwargs)
|
|
51
|
+
|
|
52
|
+
super().__init__(
|
|
53
|
+
text,
|
|
54
|
+
**defaults,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class TableNameText(ft.Text): # type: ignore[misc]
|
|
59
|
+
"""
|
|
60
|
+
Table entity name text control.
|
|
61
|
+
|
|
62
|
+
Used for displaying entity names (queues, tables, etc.) in table rows.
|
|
63
|
+
Provides consistent styling for entity identifiers.
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
def __init__(self, text: str, **kwargs: Any) -> None:
|
|
67
|
+
# Set defaults that can be overridden
|
|
68
|
+
defaults = {
|
|
69
|
+
"weight": ft.FontWeight.W_400,
|
|
70
|
+
"size": 11,
|
|
71
|
+
"color": ft.Colors.ON_SURFACE,
|
|
72
|
+
}
|
|
73
|
+
defaults.update(kwargs)
|
|
74
|
+
|
|
75
|
+
super().__init__(
|
|
76
|
+
text,
|
|
77
|
+
**defaults,
|
|
78
|
+
)
|
aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/controls/text.py
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Custom text controls with proper theme-aware styling.
|
|
3
|
+
|
|
4
|
+
These components automatically use semantic Flet colors that adapt to light/dark themes,
|
|
5
|
+
following the same patterns as ee-toolset for consistent visual design.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
import flet as ft
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class PrimaryText(ft.Text): # type: ignore[misc]
|
|
14
|
+
"""
|
|
15
|
+
Primary text component using theme-aware ON_SURFACE color.
|
|
16
|
+
|
|
17
|
+
Automatically adapts to light/dark themes with proper contrast.
|
|
18
|
+
Use for main content text, labels, and primary information.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def __init__(self, value: str, opacity: float = 1.0, **kwargs: Any) -> None:
|
|
22
|
+
super().__init__(
|
|
23
|
+
value=value,
|
|
24
|
+
opacity=opacity,
|
|
25
|
+
no_wrap=False,
|
|
26
|
+
color=ft.Colors.ON_SURFACE, # Theme-aware primary text color
|
|
27
|
+
font_family="Roboto",
|
|
28
|
+
size=16,
|
|
29
|
+
weight=ft.FontWeight.W_400,
|
|
30
|
+
**kwargs,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class SecondaryText(ft.Text): # type: ignore[misc]
|
|
35
|
+
"""
|
|
36
|
+
Secondary text component using theme-aware ON_SURFACE_VARIANT color.
|
|
37
|
+
|
|
38
|
+
Automatically adapts to light/dark themes with reduced contrast.
|
|
39
|
+
Use for supporting text, captions, and less prominent information.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
def __init__(
|
|
43
|
+
self, value: str, opacity: float = 1.0, no_wrap: bool = False, **kwargs: Any
|
|
44
|
+
) -> None:
|
|
45
|
+
super().__init__(
|
|
46
|
+
value=value,
|
|
47
|
+
opacity=opacity,
|
|
48
|
+
no_wrap=no_wrap,
|
|
49
|
+
color=ft.Colors.GREY_600, # Theme-aware secondary text color
|
|
50
|
+
font_family="Roboto",
|
|
51
|
+
size=14,
|
|
52
|
+
weight=ft.FontWeight.W_400,
|
|
53
|
+
**kwargs,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class TitleText(ft.Text): # type: ignore[misc]
|
|
58
|
+
"""
|
|
59
|
+
Title text component for headings and prominent labels.
|
|
60
|
+
|
|
61
|
+
Uses theme-aware colors with larger size and bold weight.
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
def __init__(self, value: str, opacity: float = 1.0, **kwargs: Any) -> None:
|
|
65
|
+
# Set defaults, but allow kwargs to override
|
|
66
|
+
defaults = {
|
|
67
|
+
"color": ft.Colors.ON_SURFACE, # Theme-aware primary text color
|
|
68
|
+
"font_family": "Roboto",
|
|
69
|
+
"size": 24,
|
|
70
|
+
"weight": ft.FontWeight.W_700,
|
|
71
|
+
}
|
|
72
|
+
# Update defaults with any provided kwargs
|
|
73
|
+
defaults.update(kwargs)
|
|
74
|
+
|
|
75
|
+
super().__init__(
|
|
76
|
+
value=value,
|
|
77
|
+
opacity=opacity,
|
|
78
|
+
**defaults,
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class ConfirmationText(ft.Text): # type: ignore[misc]
|
|
83
|
+
"""
|
|
84
|
+
Confirmation/error text component with error coloring.
|
|
85
|
+
|
|
86
|
+
Uses theme-aware error colors for warnings, confirmations, and alerts.
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
def __init__(self, value: str, opacity: float = 1.0, **kwargs: Any) -> None:
|
|
90
|
+
super().__init__(
|
|
91
|
+
value=value,
|
|
92
|
+
opacity=opacity,
|
|
93
|
+
color=ft.Colors.ERROR, # Theme-aware error color
|
|
94
|
+
font_family="Roboto",
|
|
95
|
+
size=14,
|
|
96
|
+
weight=ft.FontWeight.W_400,
|
|
97
|
+
**kwargs,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class MetricText(ft.Text): # type: ignore[misc]
|
|
102
|
+
"""
|
|
103
|
+
Specialized text for displaying metrics and numerical values.
|
|
104
|
+
|
|
105
|
+
Uses bold weight and primary color for emphasis on data points.
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
def __init__(self, value: str, opacity: float = 1.0, **kwargs: Any) -> None:
|
|
109
|
+
super().__init__(
|
|
110
|
+
value=value,
|
|
111
|
+
opacity=opacity,
|
|
112
|
+
color=ft.Colors.ON_SURFACE, # Theme-aware primary text color
|
|
113
|
+
font_family="Roboto",
|
|
114
|
+
size=16,
|
|
115
|
+
weight=ft.FontWeight.W_700, # Bold for emphasis
|
|
116
|
+
**kwargs,
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class LabelText(ft.Text): # type: ignore[misc]
|
|
121
|
+
"""
|
|
122
|
+
Label text component for form labels and small descriptive text.
|
|
123
|
+
|
|
124
|
+
Uses smaller size with medium weight for clear labeling.
|
|
125
|
+
"""
|
|
126
|
+
|
|
127
|
+
def __init__(self, value: str, opacity: float = 1.0, **kwargs: Any) -> None:
|
|
128
|
+
# Set defaults, but allow kwargs to override
|
|
129
|
+
defaults = {
|
|
130
|
+
"color": ft.Colors.GREY_600, # Theme-aware secondary color
|
|
131
|
+
"font_family": "Roboto",
|
|
132
|
+
"size": 12,
|
|
133
|
+
"weight": ft.FontWeight.W_600, # Medium weight for labels
|
|
134
|
+
}
|
|
135
|
+
# Update defaults with any provided kwargs
|
|
136
|
+
defaults.update(kwargs)
|
|
137
|
+
|
|
138
|
+
super().__init__(
|
|
139
|
+
value=value,
|
|
140
|
+
opacity=opacity,
|
|
141
|
+
**defaults,
|
|
142
|
+
)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""Dashboard component cards."""
|
|
2
|
+
|
|
3
|
+
from .fastapi_card import FastAPICard
|
|
4
|
+
from .flet_card import FletCard
|
|
5
|
+
{%- if include_ai %}
|
|
6
|
+
from .ai_card import AICard
|
|
7
|
+
{%- endif %}
|
|
8
|
+
{%- if include_auth %}
|
|
9
|
+
from .auth_card import AuthCard
|
|
10
|
+
from .services_card import ServicesCard
|
|
11
|
+
{%- endif %}
|
|
12
|
+
{%- if include_database %}
|
|
13
|
+
from .database_card import DatabaseCard
|
|
14
|
+
{%- endif %}
|
|
15
|
+
{%- if include_redis %}
|
|
16
|
+
from .redis_card import RedisCard
|
|
17
|
+
{%- endif %}
|
|
18
|
+
{%- if include_scheduler %}
|
|
19
|
+
from .scheduler_card import SchedulerCard
|
|
20
|
+
{%- endif %}
|
|
21
|
+
{%- if include_worker %}
|
|
22
|
+
from .worker_card import WorkerCard
|
|
23
|
+
{%- endif %}
|
|
24
|
+
|
|
25
|
+
__all__ = [
|
|
26
|
+
"FastAPICard",
|
|
27
|
+
"FletCard",
|
|
28
|
+
{%- if include_ai %}
|
|
29
|
+
"AICard",
|
|
30
|
+
{%- endif %}
|
|
31
|
+
{%- if include_auth %}
|
|
32
|
+
"AuthCard",
|
|
33
|
+
"ServicesCard",
|
|
34
|
+
{%- endif %}
|
|
35
|
+
{%- if include_database %}
|
|
36
|
+
"DatabaseCard",
|
|
37
|
+
{%- endif %}
|
|
38
|
+
{%- if include_redis %}
|
|
39
|
+
"RedisCard",
|
|
40
|
+
{%- endif %}
|
|
41
|
+
{%- if include_scheduler %}
|
|
42
|
+
"SchedulerCard",
|
|
43
|
+
{%- endif %}
|
|
44
|
+
{%- if include_worker %}
|
|
45
|
+
"WorkerCard",
|
|
46
|
+
{%- endif %}
|
|
47
|
+
]
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AI Service Card
|
|
3
|
+
|
|
4
|
+
Modern card component for displaying AI service status, provider configuration,
|
|
5
|
+
and conversation metrics in a clean 2-column layout.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import flet as ft
|
|
9
|
+
from app.components.frontend.controls import LabelText, PrimaryText
|
|
10
|
+
from app.services.system.models import ComponentStatus
|
|
11
|
+
|
|
12
|
+
from .card_utils import (
|
|
13
|
+
create_hover_handler,
|
|
14
|
+
create_standard_card_container,
|
|
15
|
+
create_tech_badge,
|
|
16
|
+
get_status_colors,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class AICard:
|
|
21
|
+
"""
|
|
22
|
+
A clean AI service card with provider info and key metrics.
|
|
23
|
+
|
|
24
|
+
Features:
|
|
25
|
+
- Real AI service metrics from health checks
|
|
26
|
+
- Clean 2-column layout (auth card pattern)
|
|
27
|
+
- Provider-specific color coding
|
|
28
|
+
- Highlighted metric containers
|
|
29
|
+
- Config validation display
|
|
30
|
+
- Responsive design
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
# Provider color mapping for visual consistency
|
|
34
|
+
PROVIDER_COLORS = {
|
|
35
|
+
"groq": ft.Colors.PURPLE,
|
|
36
|
+
"openai": ft.Colors.GREEN,
|
|
37
|
+
"anthropic": ft.Colors.ORANGE,
|
|
38
|
+
"google": ft.Colors.BLUE,
|
|
39
|
+
"mistral": ft.Colors.INDIGO,
|
|
40
|
+
"cohere": ft.Colors.TEAL,
|
|
41
|
+
"gemini": ft.Colors.BLUE,
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
def __init__(self, component_data: ComponentStatus):
|
|
45
|
+
"""Initialize with AI service data from health check."""
|
|
46
|
+
self.component_data = component_data
|
|
47
|
+
self.metadata = component_data.metadata or {}
|
|
48
|
+
|
|
49
|
+
def _get_provider_color(self, provider: str) -> str:
|
|
50
|
+
"""Get color for provider badge."""
|
|
51
|
+
return self.PROVIDER_COLORS.get(provider.lower(), ft.Colors.GREY)
|
|
52
|
+
|
|
53
|
+
def _truncate_model_name(self, model: str) -> str:
|
|
54
|
+
"""Intelligently truncate model name for display."""
|
|
55
|
+
if not model:
|
|
56
|
+
return "Unknown"
|
|
57
|
+
|
|
58
|
+
# Keep it concise but recognizable
|
|
59
|
+
if len(model) <= 20:
|
|
60
|
+
return model
|
|
61
|
+
|
|
62
|
+
# Handle common patterns
|
|
63
|
+
if "claude" in model.lower():
|
|
64
|
+
# "claude-3-5-sonnet-20241022" -> "claude-3.5-sonnet"
|
|
65
|
+
parts = model.split("-")
|
|
66
|
+
if len(parts) >= 4:
|
|
67
|
+
return f"{parts[0]}-{parts[1]}.{parts[2]}-{parts[3]}"
|
|
68
|
+
elif "llama" in model.lower():
|
|
69
|
+
# "llama-3.1-70b-versatile" -> "llama-3.1-70b"
|
|
70
|
+
parts = model.split("-")
|
|
71
|
+
if len(parts) >= 3:
|
|
72
|
+
return "-".join(parts[:3])
|
|
73
|
+
elif "gpt" in model.lower():
|
|
74
|
+
# "gpt-4-turbo-preview" -> "gpt-4-turbo"
|
|
75
|
+
parts = model.split("-")
|
|
76
|
+
if len(parts) >= 3:
|
|
77
|
+
return "-".join(parts[:3])
|
|
78
|
+
|
|
79
|
+
# Fallback: truncate with ellipsis
|
|
80
|
+
return model[:20] + "..."
|
|
81
|
+
|
|
82
|
+
def _create_metric_container(
|
|
83
|
+
self, label: str, value: str, color: str = ft.Colors.BLUE
|
|
84
|
+
) -> ft.Container:
|
|
85
|
+
"""Create a properly sized metric container."""
|
|
86
|
+
return ft.Container(
|
|
87
|
+
content=ft.Column(
|
|
88
|
+
[
|
|
89
|
+
LabelText(label),
|
|
90
|
+
ft.Container(height=8), # Spacing
|
|
91
|
+
PrimaryText(value),
|
|
92
|
+
],
|
|
93
|
+
spacing=0,
|
|
94
|
+
horizontal_alignment=ft.CrossAxisAlignment.START,
|
|
95
|
+
),
|
|
96
|
+
padding=ft.padding.all(16),
|
|
97
|
+
bgcolor=ft.Colors.with_opacity(0.08, color),
|
|
98
|
+
border_radius=8,
|
|
99
|
+
border=ft.border.all(1, ft.Colors.with_opacity(0.15, color)),
|
|
100
|
+
height=80, # Match auth card metric height
|
|
101
|
+
expand=True,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
def _create_left_section(self) -> ft.Container:
|
|
105
|
+
"""Create the left section with tech badge."""
|
|
106
|
+
return ft.Container(
|
|
107
|
+
content=ft.Column(
|
|
108
|
+
[
|
|
109
|
+
self._create_technology_badge(),
|
|
110
|
+
],
|
|
111
|
+
spacing=0,
|
|
112
|
+
),
|
|
113
|
+
width=200,
|
|
114
|
+
padding=ft.padding.all(16),
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
def _create_technology_badge(self) -> ft.Container:
|
|
118
|
+
"""Create technology badge for AI service."""
|
|
119
|
+
_, primary_color, _ = get_status_colors(self.component_data)
|
|
120
|
+
|
|
121
|
+
# Get provider for subtitle
|
|
122
|
+
provider = self.metadata.get("provider", "Unknown")
|
|
123
|
+
provider_display = provider.title()
|
|
124
|
+
|
|
125
|
+
return create_tech_badge(
|
|
126
|
+
title="AI Service",
|
|
127
|
+
subtitle=f"{provider_display} + PydanticAI",
|
|
128
|
+
icon="🤖",
|
|
129
|
+
badge_text="CHAT",
|
|
130
|
+
badge_color=primary_color,
|
|
131
|
+
primary_color=primary_color,
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
def _get_config_status_display(self) -> tuple[str, str]:
|
|
135
|
+
"""
|
|
136
|
+
Get config status display text and color.
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
Tuple of (status_text, color)
|
|
140
|
+
"""
|
|
141
|
+
config_valid = self.metadata.get("configuration_valid", False)
|
|
142
|
+
validation_errors = self.metadata.get("validation_errors", [])
|
|
143
|
+
|
|
144
|
+
if config_valid:
|
|
145
|
+
return ("✅ Valid", ft.Colors.GREEN)
|
|
146
|
+
|
|
147
|
+
# Show specific error if only one
|
|
148
|
+
if len(validation_errors) == 1:
|
|
149
|
+
error_msg = validation_errors[0]
|
|
150
|
+
if "api key" in error_msg.lower():
|
|
151
|
+
return ("Missing API Key", ft.Colors.RED)
|
|
152
|
+
elif "disabled" in error_msg.lower():
|
|
153
|
+
return ("Disabled", ft.Colors.ORANGE)
|
|
154
|
+
else:
|
|
155
|
+
return ("Invalid", ft.Colors.RED)
|
|
156
|
+
|
|
157
|
+
# Multiple errors
|
|
158
|
+
if len(validation_errors) > 1:
|
|
159
|
+
return (f"Issues ({len(validation_errors)})", ft.Colors.RED)
|
|
160
|
+
|
|
161
|
+
# Shouldn't reach here, but just in case
|
|
162
|
+
return ("Unknown", ft.Colors.GREY)
|
|
163
|
+
|
|
164
|
+
def _get_response_time_color(self, response_time: float | None) -> str:
|
|
165
|
+
"""Get color for response time based on value."""
|
|
166
|
+
if not response_time:
|
|
167
|
+
return ft.Colors.GREY
|
|
168
|
+
|
|
169
|
+
if response_time < 100:
|
|
170
|
+
return ft.Colors.GREEN
|
|
171
|
+
elif response_time < 500:
|
|
172
|
+
return ft.Colors.ORANGE
|
|
173
|
+
else:
|
|
174
|
+
return ft.Colors.RED
|
|
175
|
+
|
|
176
|
+
def _create_metrics_section(self) -> ft.Container:
|
|
177
|
+
"""Create the metrics section with a clean grid layout."""
|
|
178
|
+
# Get real data from metadata
|
|
179
|
+
provider = self.metadata.get("provider", "Unknown")
|
|
180
|
+
model = self.metadata.get("model", "Unknown")
|
|
181
|
+
total_conversations = self.metadata.get("total_conversations", 0)
|
|
182
|
+
response_time = self.component_data.response_time_ms
|
|
183
|
+
enabled = self.metadata.get("enabled", True)
|
|
184
|
+
|
|
185
|
+
# Format values for display
|
|
186
|
+
provider_display = provider.title()
|
|
187
|
+
provider_color = self._get_provider_color(provider)
|
|
188
|
+
model_display = self._truncate_model_name(model)
|
|
189
|
+
conversations_display = str(total_conversations)
|
|
190
|
+
streaming_display = "✅ Available"
|
|
191
|
+
config_status, config_color = self._get_config_status_display()
|
|
192
|
+
response_time_display = f"{response_time:.1f}ms" if response_time else "N/A"
|
|
193
|
+
response_time_color = self._get_response_time_color(response_time)
|
|
194
|
+
|
|
195
|
+
# If service disabled, show that prominently
|
|
196
|
+
if not enabled:
|
|
197
|
+
config_status = "🔴 Disabled"
|
|
198
|
+
config_color = ft.Colors.RED
|
|
199
|
+
|
|
200
|
+
# Create metrics grid (3 rows x 2 columns)
|
|
201
|
+
return ft.Container(
|
|
202
|
+
content=ft.Column(
|
|
203
|
+
[
|
|
204
|
+
# Row 1: Provider and Model
|
|
205
|
+
ft.Row(
|
|
206
|
+
[
|
|
207
|
+
self._create_metric_container(
|
|
208
|
+
"Provider", provider_display, provider_color
|
|
209
|
+
),
|
|
210
|
+
self._create_metric_container(
|
|
211
|
+
"Model", model_display, ft.Colors.BLUE
|
|
212
|
+
),
|
|
213
|
+
],
|
|
214
|
+
expand=True,
|
|
215
|
+
),
|
|
216
|
+
ft.Container(height=12), # Vertical spacing
|
|
217
|
+
# Row 2: Conversations and Streaming
|
|
218
|
+
ft.Row(
|
|
219
|
+
[
|
|
220
|
+
self._create_metric_container(
|
|
221
|
+
"Conversations", conversations_display, ft.Colors.PURPLE
|
|
222
|
+
),
|
|
223
|
+
self._create_metric_container(
|
|
224
|
+
"Streaming", streaming_display, ft.Colors.GREEN
|
|
225
|
+
),
|
|
226
|
+
],
|
|
227
|
+
expand=True,
|
|
228
|
+
),
|
|
229
|
+
ft.Container(height=12), # Vertical spacing
|
|
230
|
+
# Row 3: Config Status and Response Time
|
|
231
|
+
ft.Row(
|
|
232
|
+
[
|
|
233
|
+
self._create_metric_container(
|
|
234
|
+
"Configuration", config_status, config_color
|
|
235
|
+
),
|
|
236
|
+
self._create_metric_container(
|
|
237
|
+
"Response Time",
|
|
238
|
+
response_time_display,
|
|
239
|
+
response_time_color,
|
|
240
|
+
),
|
|
241
|
+
],
|
|
242
|
+
expand=True,
|
|
243
|
+
),
|
|
244
|
+
],
|
|
245
|
+
spacing=0,
|
|
246
|
+
),
|
|
247
|
+
expand=True,
|
|
248
|
+
padding=ft.padding.all(16),
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
def build(self) -> ft.Container:
|
|
252
|
+
"""Build and return the complete AI service card."""
|
|
253
|
+
# Get colors based on component status
|
|
254
|
+
background_color, primary_color, border_color = get_status_colors(
|
|
255
|
+
self.component_data
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
# Create clean 2-column layout
|
|
259
|
+
content = ft.Row(
|
|
260
|
+
[
|
|
261
|
+
self._create_left_section(),
|
|
262
|
+
ft.Container(
|
|
263
|
+
width=1,
|
|
264
|
+
height=160, # Adjust height to match content
|
|
265
|
+
bgcolor=ft.Colors.with_opacity(0.1, ft.Colors.GREY_400),
|
|
266
|
+
margin=ft.margin.symmetric(horizontal=16),
|
|
267
|
+
),
|
|
268
|
+
self._create_metrics_section(),
|
|
269
|
+
],
|
|
270
|
+
expand=True,
|
|
271
|
+
vertical_alignment=ft.CrossAxisAlignment.START,
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
# Create the container
|
|
275
|
+
card_container = create_standard_card_container(
|
|
276
|
+
content=content,
|
|
277
|
+
primary_color=primary_color,
|
|
278
|
+
border_color=border_color,
|
|
279
|
+
width=None,
|
|
280
|
+
hover_handler=None,
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
# Create hover handler for the card
|
|
284
|
+
hover_handler = create_hover_handler(card_container)
|
|
285
|
+
card_container.on_hover = hover_handler
|
|
286
|
+
|
|
287
|
+
return card_container
|