databricks-tellr-app 0.4.3.dev1__tar.gz → 0.4.3.dev3__tar.gz
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.
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/PKG-INFO +1 -1
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/databricks_tellr_app.egg-info/PKG-INFO +1 -1
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/pyproject.toml +1 -1
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/routes/chat.py +2 -2
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/routes/export.py +4 -4
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/routes/google_slides.py +11 -9
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/routes/images.py +27 -45
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/routes/sessions.py +1 -1
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/routes/settings/identities.py +3 -3
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/routes/setup.py +2 -2
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/routes/slides.py +13 -13
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/routes/verification.py +3 -3
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/schemas/requests.py +2 -2
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/services/chat_service.py +9 -12
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/core/database.py +0 -40
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/database/models/image.py +1 -15
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/image_service.py +9 -9
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/image_tools.py +2 -2
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/utils/image_utils.py +4 -5
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/README.md +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/databricks_tellr_app/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/databricks_tellr_app/run.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/databricks_tellr_app.egg-info/SOURCES.txt +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/databricks_tellr_app.egg-info/dependency_links.txt +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/databricks_tellr_app.egg-info/requires.txt +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/databricks_tellr_app.egg-info/top_level.txt +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/setup.cfg +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/setup.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/_otel_bootstrap.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/fixtures/tour_demo_deck.json +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/main.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/mcp_auth.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/mcp_server.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/middleware/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/middleware/csrf.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/middleware/request_logging.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/middleware/security_headers.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/routes/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/routes/_authz.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/routes/admin.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/routes/admin_usage.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/routes/agent_config.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/routes/deck_contributors.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/routes/feedback.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/routes/local_version.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/routes/profiles.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/routes/settings/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/routes/settings/contributors.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/routes/settings/deck_prompts.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/routes/settings/design_systems.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/routes/settings/slide_styles.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/routes/tools.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/routes/tour.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/routes/version.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/schemas/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/schemas/agent_config.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/schemas/feedback.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/schemas/responses.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/schemas/settings/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/schemas/settings/requests.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/schemas/settings/responses.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/schemas/streaming.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/services/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/services/export_job_queue.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/services/feedback_service.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/services/job_queue.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/services/session_manager.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/services/session_naming.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/services/usage_events.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/services/usage_service.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/utils/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/utils/validation.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/core/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/core/config_loader.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/core/context_utils.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/core/databricks_client.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/core/defaults.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/core/encryption.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/core/init_default_profile.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/core/lakebase.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/core/migrate_profiles_to_agent_config.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/core/mlflow_agent_spans.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/core/mlflow_tracing.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/core/otel_logging.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/core/permission_context.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/core/prompt_modules.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/core/settings_db.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/core/user_context.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/database/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/database/models/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/database/models/deck_contributor.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/database/models/design_system.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/database/models/encryption_key.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/database/models/feedback.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/database/models/genie_space.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/database/models/google_global_credentials.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/database/models/google_oauth_token.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/database/models/identity.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/database/models/profile.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/database/models/profile_contributor.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/database/models/prompts.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/database/models/request_log.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/database/models/session.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/database/models/slide_deck_prompt.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/database/models/slide_style_library.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/database/models/usage_event.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/database/models/user_preference.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/database/types.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/domain/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/domain/slide.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/domain/slide_deck.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/agent.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/agent_factory.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/config_service.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/config_validator.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/converter_jail/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/converter_jail/ast_guard.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/converter_jail/codeprep.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/converter_jail/gslides_runner.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/converter_jail/jail.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/converter_jail/pptx_runner.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/converter_jail/protocol.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/design_system_compiler.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/design_system_service.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/design_system_templates.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/drive_uploader.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/evaluation/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/evaluation/llm_judge.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/genie_service.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/google_slides_auth.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/google_slides_prompts_defaults.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/html_to_google_slides.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/html_to_pptx.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/identity_provider.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/identity_providers/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/identity_providers/account_provider.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/identity_providers/local_provider.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/identity_providers/workspace_provider.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/permission_service.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/pptx_from_html_huashu.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/pptx_from_records.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/pptx_prompts_defaults.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/profile_service.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/streaming_callback.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/tools/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/tools/agent_bricks_tool.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/tools/ds_asset_tool.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/tools/genie_tool.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/tools/mcp_tool.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/tools/model_endpoint_tool.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/tools/vector_tool.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/services/validator.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/utils/__init__.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/utils/css_utils.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/utils/ds_asset_utils.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/utils/error_handling.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/utils/html_safety.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/utils/html_utils.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/utils/js_validator.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/utils/logging_config.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/utils/pi_filter.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/utils/slide_hash.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/utils/spotlight.py +0 -0
- {databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/utils/text_caps.py +0 -0
|
@@ -384,7 +384,7 @@ async def send_message(
|
|
|
384
384
|
logger.error(f"Chat request failed: {e}", exc_info=True)
|
|
385
385
|
raise HTTPException(
|
|
386
386
|
status_code=500,
|
|
387
|
-
detail=
|
|
387
|
+
detail="Failed to process message",
|
|
388
388
|
) from e
|
|
389
389
|
finally:
|
|
390
390
|
await asyncio.to_thread(
|
|
@@ -662,7 +662,7 @@ async def submit_chat_async(
|
|
|
662
662
|
session_manager.release_session_lock, request.session_id
|
|
663
663
|
)
|
|
664
664
|
logger.error(f"Failed to submit async chat: {e}")
|
|
665
|
-
raise HTTPException(status_code=500, detail=
|
|
665
|
+
raise HTTPException(status_code=500, detail="Internal server error")
|
|
666
666
|
|
|
667
667
|
|
|
668
668
|
@router.get("/chat/poll/{request_id}")
|
{databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/routes/export.py
RENAMED
|
@@ -754,13 +754,13 @@ async def export_to_pptx(request: ExportPPTXRequest):
|
|
|
754
754
|
temp_dir.rmdir()
|
|
755
755
|
except Exception:
|
|
756
756
|
pass
|
|
757
|
-
raise HTTPException(status_code=500, detail=
|
|
757
|
+
raise HTTPException(status_code=500, detail="Export failed")
|
|
758
758
|
|
|
759
759
|
except HTTPException:
|
|
760
760
|
raise
|
|
761
761
|
except Exception as e:
|
|
762
762
|
logger.error("PPTX export failed", exc_info=True, extra={"error": str(e)})
|
|
763
|
-
raise HTTPException(status_code=500, detail=
|
|
763
|
+
raise HTTPException(status_code=500, detail="Export failed")
|
|
764
764
|
|
|
765
765
|
|
|
766
766
|
# =============================================================================
|
|
@@ -893,7 +893,7 @@ async def start_pptx_export_async(request: ExportPPTXRequest):
|
|
|
893
893
|
except Exception as e:
|
|
894
894
|
total_time = time.time() - start_time
|
|
895
895
|
logger.error(f"Failed to start async export after {total_time:.2f}s: {e}", exc_info=True)
|
|
896
|
-
raise HTTPException(status_code=500, detail=
|
|
896
|
+
raise HTTPException(status_code=500, detail="Failed to start export")
|
|
897
897
|
|
|
898
898
|
|
|
899
899
|
@router.get("/pptx/poll/{job_id}", response_model=ExportJobResponse)
|
|
@@ -1038,7 +1038,7 @@ async def export_pptx_editable_from_records(request: ExportPPTXFromRecordsReques
|
|
|
1038
1038
|
pptx_bytes = build_pptx(title, request.slides, font_mode=font_mode)
|
|
1039
1039
|
except Exception as e:
|
|
1040
1040
|
logger.exception(f"Editable PPTX emission failed: {e}")
|
|
1041
|
-
raise HTTPException(status_code=500, detail=
|
|
1041
|
+
raise HTTPException(status_code=500, detail="Editable PPTX export failed")
|
|
1042
1042
|
|
|
1043
1043
|
safe = "".join(c if c.isalnum() or c in "-_" else "_" for c in title).strip("_") or "slides"
|
|
1044
1044
|
from fastapi.responses import Response
|
{databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/routes/google_slides.py
RENAMED
|
@@ -198,17 +198,19 @@ async def auth_callback(
|
|
|
198
198
|
"Google Slides OAuth callback successful",
|
|
199
199
|
extra={"user": _get_user_identity()},
|
|
200
200
|
)
|
|
201
|
-
except Exception
|
|
201
|
+
except Exception:
|
|
202
|
+
# F-CR-2 (SDR-4437): never reflect the raw exception into the HTML page —
|
|
203
|
+
# it is logged server-side above. Show a static, generic failure message.
|
|
202
204
|
logger.error("OAuth callback failed", exc_info=True)
|
|
203
205
|
return HTMLResponse(
|
|
204
|
-
content=
|
|
206
|
+
content="""
|
|
205
207
|
<html><body>
|
|
206
208
|
<h2>Authorization Failed</h2>
|
|
207
|
-
<p>
|
|
209
|
+
<p>Authorization could not be completed. Please close this window and try again.</p>
|
|
208
210
|
<script>
|
|
209
|
-
if (window.opener) {
|
|
210
|
-
window.opener.postMessage({
|
|
211
|
-
}
|
|
211
|
+
if (window.opener) {
|
|
212
|
+
window.opener.postMessage({ type: 'google-slides-auth', success: false }, '*');
|
|
213
|
+
}
|
|
212
214
|
setTimeout(() => window.close(), 3000);
|
|
213
215
|
</script>
|
|
214
216
|
</body></html>
|
|
@@ -284,7 +286,7 @@ async def start_google_slides_export(
|
|
|
284
286
|
slide_deck = chat_service.get_slides(request_body.session_id)
|
|
285
287
|
except Exception as exc:
|
|
286
288
|
logger.error("Failed to fetch slides", exc_info=True)
|
|
287
|
-
raise HTTPException(status_code=500, detail=
|
|
289
|
+
raise HTTPException(status_code=500, detail="Failed to fetch slides") from exc
|
|
288
290
|
|
|
289
291
|
if not slide_deck or not slide_deck.get("slides"):
|
|
290
292
|
raise HTTPException(status_code=404, detail="No slides available")
|
|
@@ -448,7 +450,7 @@ async def export_google_slides_from_records(
|
|
|
448
450
|
)
|
|
449
451
|
except Exception as exc:
|
|
450
452
|
logger.error("Drive upload failed", exc_info=True)
|
|
451
|
-
raise HTTPException(status_code=502, detail=
|
|
453
|
+
raise HTTPException(status_code=502, detail="Drive upload failed") from exc
|
|
452
454
|
|
|
453
455
|
session_manager.set_google_slides_info(
|
|
454
456
|
session_id=request.session_id,
|
|
@@ -598,7 +600,7 @@ async def export_google_slides_from_huashu(
|
|
|
598
600
|
logger.error("Drive upload failed (huashu path)", exc_info=True)
|
|
599
601
|
raise HTTPException(
|
|
600
602
|
status_code=502,
|
|
601
|
-
detail=
|
|
603
|
+
detail="Drive upload failed",
|
|
602
604
|
) from exc
|
|
603
605
|
|
|
604
606
|
session_manager.set_google_slides_info(
|
{databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/routes/images.py
RENAMED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
"""Image upload and management API endpoints."""
|
|
2
|
-
import base64
|
|
3
2
|
import logging
|
|
4
3
|
import os
|
|
5
4
|
from typing import List, Optional
|
|
@@ -21,7 +20,7 @@ router = APIRouter(prefix="/api/images", tags=["images"])
|
|
|
21
20
|
|
|
22
21
|
class ImageResponse(BaseModel):
|
|
23
22
|
"""Response schema for image metadata."""
|
|
24
|
-
id:
|
|
23
|
+
id: int
|
|
25
24
|
filename: str
|
|
26
25
|
original_filename: str
|
|
27
26
|
mime_type: str
|
|
@@ -47,7 +46,7 @@ class ImageListResponse(BaseModel):
|
|
|
47
46
|
|
|
48
47
|
class ImageDataResponse(BaseModel):
|
|
49
48
|
"""Response containing image base64 data."""
|
|
50
|
-
id:
|
|
49
|
+
id: int
|
|
51
50
|
mime_type: str
|
|
52
51
|
base64_data: str
|
|
53
52
|
data_uri: str # Ready-to-use: "data:image/png;base64,..."
|
|
@@ -81,7 +80,7 @@ def _get_current_user() -> str:
|
|
|
81
80
|
|
|
82
81
|
def _image_to_response(img: ImageAsset) -> ImageResponse:
|
|
83
82
|
return ImageResponse(
|
|
84
|
-
id=img.
|
|
83
|
+
id=img.id,
|
|
85
84
|
filename=img.filename,
|
|
86
85
|
original_filename=img.original_filename,
|
|
87
86
|
mime_type=img.mime_type,
|
|
@@ -168,75 +167,58 @@ def list_images(
|
|
|
168
167
|
)
|
|
169
168
|
|
|
170
169
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
so a wrong caller cannot even confirm the image exists.
|
|
175
|
-
"""
|
|
176
|
-
if image.category == "ephemeral" and image.uploaded_by != _get_current_user():
|
|
177
|
-
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Image not found")
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
@router.get("/{token}", response_model=ImageResponse)
|
|
181
|
-
def get_image(token: str, db: Session = Depends(get_db)):
|
|
182
|
-
"""Get image metadata by opaque token."""
|
|
170
|
+
@router.get("/{image_id}", response_model=ImageResponse)
|
|
171
|
+
def get_image(image_id: int, db: Session = Depends(get_db)):
|
|
172
|
+
"""Get image metadata by ID."""
|
|
183
173
|
try:
|
|
184
174
|
image = db.query(ImageAsset).filter(
|
|
185
|
-
ImageAsset.
|
|
175
|
+
ImageAsset.id == image_id,
|
|
186
176
|
ImageAsset.is_active == True,
|
|
187
177
|
).first()
|
|
188
178
|
if not image:
|
|
189
179
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Image not found")
|
|
190
|
-
_deny_ephemeral_cross_user(image)
|
|
191
180
|
return _image_to_response(image)
|
|
192
181
|
except HTTPException:
|
|
193
182
|
raise
|
|
194
183
|
except Exception as e:
|
|
195
|
-
logger.error(f"Error getting image: {e}", exc_info=True)
|
|
184
|
+
logger.error(f"Error getting image {image_id}: {e}", exc_info=True)
|
|
196
185
|
raise HTTPException(
|
|
197
186
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
198
187
|
detail="Failed to get image",
|
|
199
188
|
)
|
|
200
189
|
|
|
201
190
|
|
|
202
|
-
@router.get("/{
|
|
203
|
-
def get_image_data(
|
|
204
|
-
"""Get full image as base64 data (for embedding in slides)
|
|
191
|
+
@router.get("/{image_id}/data", response_model=ImageDataResponse)
|
|
192
|
+
def get_image_data(image_id: int, db: Session = Depends(get_db)):
|
|
193
|
+
"""Get full image as base64 data (for embedding in slides)."""
|
|
205
194
|
try:
|
|
206
|
-
|
|
207
|
-
ImageAsset.token == token,
|
|
208
|
-
ImageAsset.is_active == True,
|
|
209
|
-
).first()
|
|
210
|
-
if not image:
|
|
211
|
-
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Image not found")
|
|
212
|
-
_deny_ephemeral_cross_user(image)
|
|
213
|
-
b64_data = base64.b64encode(image.image_data).decode("utf-8")
|
|
195
|
+
b64_data, mime_type = image_service.get_image_base64(db, image_id)
|
|
214
196
|
return ImageDataResponse(
|
|
215
|
-
id=
|
|
216
|
-
mime_type=
|
|
197
|
+
id=image_id,
|
|
198
|
+
mime_type=mime_type,
|
|
217
199
|
base64_data=b64_data,
|
|
218
|
-
data_uri=f"data:{
|
|
200
|
+
data_uri=f"data:{mime_type};base64,{b64_data}",
|
|
219
201
|
)
|
|
220
|
-
except
|
|
221
|
-
raise
|
|
202
|
+
except ValueError as e:
|
|
203
|
+
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(e))
|
|
222
204
|
except Exception as e:
|
|
223
|
-
logger.error(f"Error getting image data: {e}", exc_info=True)
|
|
205
|
+
logger.error(f"Error getting image data {image_id}: {e}", exc_info=True)
|
|
224
206
|
raise HTTPException(
|
|
225
207
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
226
208
|
detail="Failed to get image data",
|
|
227
209
|
)
|
|
228
210
|
|
|
229
211
|
|
|
230
|
-
@router.put("/{
|
|
212
|
+
@router.put("/{image_id}", response_model=ImageResponse)
|
|
231
213
|
def update_image(
|
|
232
|
-
|
|
214
|
+
image_id: int,
|
|
233
215
|
request: ImageUpdateRequest,
|
|
234
216
|
db: Session = Depends(get_db),
|
|
235
217
|
):
|
|
236
218
|
"""Update image metadata (tags, description, category)."""
|
|
237
219
|
try:
|
|
238
220
|
image = db.query(ImageAsset).filter(
|
|
239
|
-
ImageAsset.
|
|
221
|
+
ImageAsset.id == image_id,
|
|
240
222
|
ImageAsset.is_active == True,
|
|
241
223
|
).first()
|
|
242
224
|
if not image:
|
|
@@ -264,20 +246,20 @@ def update_image(
|
|
|
264
246
|
raise
|
|
265
247
|
except Exception as e:
|
|
266
248
|
db.rollback()
|
|
267
|
-
logger.error(f"Error updating image: {e}", exc_info=True)
|
|
249
|
+
logger.error(f"Error updating image {image_id}: {e}", exc_info=True)
|
|
268
250
|
raise HTTPException(
|
|
269
251
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
270
252
|
detail="Failed to update image",
|
|
271
253
|
)
|
|
272
254
|
|
|
273
255
|
|
|
274
|
-
@router.delete("/{
|
|
275
|
-
def delete_image(
|
|
256
|
+
@router.delete("/{image_id}", status_code=status.HTTP_204_NO_CONTENT)
|
|
257
|
+
def delete_image(image_id: int, db: Session = Depends(get_db)):
|
|
276
258
|
"""Soft-delete an image."""
|
|
277
259
|
try:
|
|
278
260
|
user = _get_current_user()
|
|
279
261
|
image = db.query(ImageAsset).filter(
|
|
280
|
-
ImageAsset.
|
|
262
|
+
ImageAsset.id == image_id,
|
|
281
263
|
ImageAsset.is_active == True, # noqa: E712
|
|
282
264
|
).first()
|
|
283
265
|
if not image:
|
|
@@ -288,14 +270,14 @@ def delete_image(token: str, db: Session = Depends(get_db)):
|
|
|
288
270
|
status_code=status.HTTP_403_FORBIDDEN,
|
|
289
271
|
detail="You don't have permission to modify this image",
|
|
290
272
|
)
|
|
291
|
-
image_service.delete_image(db,
|
|
273
|
+
image_service.delete_image(db, image_id, user)
|
|
292
274
|
except HTTPException:
|
|
293
275
|
raise
|
|
294
276
|
except ValueError as e:
|
|
295
277
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(e))
|
|
296
278
|
except Exception as e:
|
|
297
279
|
db.rollback()
|
|
298
|
-
logger.error(f"Error deleting image: {e}", exc_info=True)
|
|
280
|
+
logger.error(f"Error deleting image {image_id}: {e}", exc_info=True)
|
|
299
281
|
raise HTTPException(
|
|
300
282
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
301
283
|
detail="Failed to delete image",
|
{databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/routes/sessions.py
RENAMED
|
@@ -553,7 +553,7 @@ async def duplicate_session(
|
|
|
553
553
|
logger.error(f"Failed to duplicate session: {e}", exc_info=True)
|
|
554
554
|
raise HTTPException(
|
|
555
555
|
status_code=500,
|
|
556
|
-
detail=
|
|
556
|
+
detail="Failed to duplicate session",
|
|
557
557
|
) from e
|
|
558
558
|
|
|
559
559
|
|
|
@@ -109,7 +109,7 @@ def list_users(
|
|
|
109
109
|
logger.error(f"Failed to list users: {e}", exc_info=True)
|
|
110
110
|
raise HTTPException(
|
|
111
111
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
112
|
-
detail=
|
|
112
|
+
detail="Failed to list users",
|
|
113
113
|
)
|
|
114
114
|
|
|
115
115
|
|
|
@@ -149,7 +149,7 @@ def list_groups(
|
|
|
149
149
|
logger.error(f"Failed to list groups: {e}", exc_info=True)
|
|
150
150
|
raise HTTPException(
|
|
151
151
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
152
|
-
detail=
|
|
152
|
+
detail="Failed to list groups",
|
|
153
153
|
)
|
|
154
154
|
|
|
155
155
|
|
|
@@ -203,5 +203,5 @@ def search_identities(
|
|
|
203
203
|
logger.error(f"Failed to search identities: {e}", exc_info=True)
|
|
204
204
|
raise HTTPException(
|
|
205
205
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
206
|
-
detail=
|
|
206
|
+
detail="Failed to search identities",
|
|
207
207
|
)
|
|
@@ -123,7 +123,7 @@ async def configure_workspace(request: ConfigureWorkspaceRequest):
|
|
|
123
123
|
logger.error(f"Failed to configure workspace: {e}")
|
|
124
124
|
raise HTTPException(
|
|
125
125
|
status_code=500,
|
|
126
|
-
detail=
|
|
126
|
+
detail="Failed to save configuration"
|
|
127
127
|
)
|
|
128
128
|
|
|
129
129
|
|
|
@@ -154,5 +154,5 @@ async def test_connection():
|
|
|
154
154
|
logger.error(f"Connection test failed: {e}")
|
|
155
155
|
raise HTTPException(
|
|
156
156
|
status_code=400,
|
|
157
|
-
detail=
|
|
157
|
+
detail="Connection failed"
|
|
158
158
|
)
|
{databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/routes/slides.py
RENAMED
|
@@ -105,7 +105,7 @@ async def get_slides(
|
|
|
105
105
|
raise
|
|
106
106
|
except Exception as e:
|
|
107
107
|
logger.error(f"Failed to get slides: {e}", exc_info=True)
|
|
108
|
-
raise HTTPException(status_code=500, detail=
|
|
108
|
+
raise HTTPException(status_code=500, detail="Internal server error")
|
|
109
109
|
|
|
110
110
|
|
|
111
111
|
@router.put("/reorder")
|
|
@@ -167,7 +167,7 @@ async def reorder_slides(request: ReorderRequest, db: Session = Depends(get_db))
|
|
|
167
167
|
raise HTTPException(status_code=400, detail=str(e))
|
|
168
168
|
except Exception as e:
|
|
169
169
|
logger.error(f"Failed to reorder slides: {e}", exc_info=True)
|
|
170
|
-
raise HTTPException(status_code=500, detail=
|
|
170
|
+
raise HTTPException(status_code=500, detail="Internal server error")
|
|
171
171
|
finally:
|
|
172
172
|
await asyncio.to_thread(
|
|
173
173
|
session_manager.release_session_lock,
|
|
@@ -235,7 +235,7 @@ async def update_slide(index: int, request: UpdateSlideRequest, db: Session = De
|
|
|
235
235
|
raise HTTPException(status_code=400, detail=str(e))
|
|
236
236
|
except Exception as e:
|
|
237
237
|
logger.error(f"Failed to update slide: {e}", exc_info=True)
|
|
238
|
-
raise HTTPException(status_code=500, detail=
|
|
238
|
+
raise HTTPException(status_code=500, detail="Internal server error")
|
|
239
239
|
finally:
|
|
240
240
|
await asyncio.to_thread(
|
|
241
241
|
session_manager.release_session_lock,
|
|
@@ -303,7 +303,7 @@ async def duplicate_slide(index: int, request: SlideActionRequest, db: Session =
|
|
|
303
303
|
raise HTTPException(status_code=400, detail=str(e))
|
|
304
304
|
except Exception as e:
|
|
305
305
|
logger.error(f"Failed to duplicate slide: {e}", exc_info=True)
|
|
306
|
-
raise HTTPException(status_code=500, detail=
|
|
306
|
+
raise HTTPException(status_code=500, detail="Internal server error")
|
|
307
307
|
finally:
|
|
308
308
|
await asyncio.to_thread(
|
|
309
309
|
session_manager.release_session_lock,
|
|
@@ -377,7 +377,7 @@ async def delete_slide(
|
|
|
377
377
|
raise HTTPException(status_code=400, detail=str(e))
|
|
378
378
|
except Exception as e:
|
|
379
379
|
logger.error(f"Failed to delete slide: {e}", exc_info=True)
|
|
380
|
-
raise HTTPException(status_code=500, detail=
|
|
380
|
+
raise HTTPException(status_code=500, detail="Internal server error")
|
|
381
381
|
finally:
|
|
382
382
|
await asyncio.to_thread(
|
|
383
383
|
session_manager.release_session_lock,
|
|
@@ -476,7 +476,7 @@ async def update_slide_verification(index: int, request: UpdateVerificationReque
|
|
|
476
476
|
raise
|
|
477
477
|
except Exception as e:
|
|
478
478
|
logger.error(f"Failed to update slide verification: {e}", exc_info=True)
|
|
479
|
-
raise HTTPException(status_code=500, detail=
|
|
479
|
+
raise HTTPException(status_code=500, detail="Internal server error")
|
|
480
480
|
|
|
481
481
|
|
|
482
482
|
# ============================================================================
|
|
@@ -546,7 +546,7 @@ async def create_version(request: CreateVersionRequest):
|
|
|
546
546
|
raise HTTPException(status_code=400, detail=str(e))
|
|
547
547
|
except Exception as e:
|
|
548
548
|
logger.error(f"Failed to create version: {e}", exc_info=True)
|
|
549
|
-
raise HTTPException(status_code=500, detail=
|
|
549
|
+
raise HTTPException(status_code=500, detail="Internal server error")
|
|
550
550
|
|
|
551
551
|
|
|
552
552
|
@router.patch("/versions/{version_number}/verification")
|
|
@@ -595,7 +595,7 @@ async def update_version_verification(
|
|
|
595
595
|
raise HTTPException(status_code=400, detail=str(e))
|
|
596
596
|
except Exception as e:
|
|
597
597
|
logger.error(f"Failed to update version verification: {e}", exc_info=True)
|
|
598
|
-
raise HTTPException(status_code=500, detail=
|
|
598
|
+
raise HTTPException(status_code=500, detail="Internal server error")
|
|
599
599
|
|
|
600
600
|
|
|
601
601
|
class SyncVerificationRequest(BaseModel):
|
|
@@ -663,7 +663,7 @@ async def sync_latest_version_verification(request: SyncVerificationRequest):
|
|
|
663
663
|
|
|
664
664
|
except Exception as e:
|
|
665
665
|
logger.error(f"Failed to sync version verification: {e}", exc_info=True)
|
|
666
|
-
raise HTTPException(status_code=500, detail=
|
|
666
|
+
raise HTTPException(status_code=500, detail="Internal server error")
|
|
667
667
|
|
|
668
668
|
|
|
669
669
|
@router.get("/versions")
|
|
@@ -701,7 +701,7 @@ async def list_versions(session_id: str = Query(..., description="Session ID")):
|
|
|
701
701
|
return {"versions": [], "current_version": None}
|
|
702
702
|
except Exception as e:
|
|
703
703
|
logger.error(f"Failed to list versions: {e}", exc_info=True)
|
|
704
|
-
raise HTTPException(status_code=500, detail=
|
|
704
|
+
raise HTTPException(status_code=500, detail="Internal server error")
|
|
705
705
|
|
|
706
706
|
|
|
707
707
|
# NOTE: must be registered BEFORE the parameterized "/versions/{version_number}"
|
|
@@ -738,7 +738,7 @@ async def get_current_version(session_id: str = Query(..., description="Session
|
|
|
738
738
|
return {"current_version": None}
|
|
739
739
|
except Exception as e:
|
|
740
740
|
logger.error(f"Failed to get current version: {e}", exc_info=True)
|
|
741
|
-
raise HTTPException(status_code=500, detail=
|
|
741
|
+
raise HTTPException(status_code=500, detail="Internal server error")
|
|
742
742
|
|
|
743
743
|
|
|
744
744
|
@router.get("/versions/{version_number}")
|
|
@@ -789,7 +789,7 @@ async def preview_version(
|
|
|
789
789
|
raise
|
|
790
790
|
except Exception as e:
|
|
791
791
|
logger.error(f"Failed to preview version: {e}", exc_info=True)
|
|
792
|
-
raise HTTPException(status_code=500, detail=
|
|
792
|
+
raise HTTPException(status_code=500, detail="Internal server error")
|
|
793
793
|
|
|
794
794
|
|
|
795
795
|
@router.post("/versions/{version_number}/restore")
|
|
@@ -859,7 +859,7 @@ async def restore_version(version_number: int, request: RestoreVersionRequest):
|
|
|
859
859
|
raise HTTPException(status_code=400, detail=str(e))
|
|
860
860
|
except Exception as e:
|
|
861
861
|
logger.error(f"Failed to restore version: {e}", exc_info=True)
|
|
862
|
-
raise HTTPException(status_code=500, detail=
|
|
862
|
+
raise HTTPException(status_code=500, detail="Internal server error")
|
|
863
863
|
finally:
|
|
864
864
|
await asyncio.to_thread(
|
|
865
865
|
session_manager.release_session_lock,
|
{databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/routes/verification.py
RENAMED
|
@@ -291,7 +291,7 @@ async def verify_slide(slide_index: int, request: VerifySlideRequest):
|
|
|
291
291
|
logger.error(f"Verification failed: {e}", exc_info=True)
|
|
292
292
|
raise HTTPException(
|
|
293
293
|
status_code=500,
|
|
294
|
-
detail=
|
|
294
|
+
detail="Verification failed",
|
|
295
295
|
)
|
|
296
296
|
|
|
297
297
|
|
|
@@ -413,7 +413,7 @@ async def submit_feedback(slide_index: int, request: FeedbackRequest):
|
|
|
413
413
|
logger.error(f"Failed to submit feedback: {e}", exc_info=True)
|
|
414
414
|
raise HTTPException(
|
|
415
415
|
status_code=500,
|
|
416
|
-
detail=
|
|
416
|
+
detail="Failed to submit feedback",
|
|
417
417
|
)
|
|
418
418
|
|
|
419
419
|
|
|
@@ -541,6 +541,6 @@ async def get_genie_link(
|
|
|
541
541
|
logger.error(f"Failed to get Genie link: {e}", exc_info=True)
|
|
542
542
|
raise HTTPException(
|
|
543
543
|
status_code=500,
|
|
544
|
-
detail=
|
|
544
|
+
detail="Failed to get Genie link",
|
|
545
545
|
)
|
|
546
546
|
|
{databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/schemas/requests.py
RENAMED
|
@@ -74,9 +74,9 @@ class ChatRequest(BaseModel):
|
|
|
74
74
|
default=None,
|
|
75
75
|
description="Optional context containing the slides to edit",
|
|
76
76
|
)
|
|
77
|
-
image_ids: Optional[list[
|
|
77
|
+
image_ids: Optional[list[int]] = Field(
|
|
78
78
|
default=None,
|
|
79
|
-
description="
|
|
79
|
+
description="IDs of images attached to this message (from upload or paste)",
|
|
80
80
|
)
|
|
81
81
|
agent_config: Optional[dict] = Field(
|
|
82
82
|
default=None,
|
{databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/api/services/chat_service.py
RENAMED
|
@@ -345,7 +345,7 @@ class ChatService:
|
|
|
345
345
|
session_id: str,
|
|
346
346
|
message: str,
|
|
347
347
|
slide_context: Optional[Dict[str, Any]] = None,
|
|
348
|
-
image_ids: Optional[List[
|
|
348
|
+
image_ids: Optional[List[int]] = None,
|
|
349
349
|
) -> Dict[str, Any]:
|
|
350
350
|
"""Send a message to the agent and get response.
|
|
351
351
|
|
|
@@ -828,7 +828,7 @@ class ChatService:
|
|
|
828
828
|
message: str,
|
|
829
829
|
slide_context: Optional[Dict[str, Any]] = None,
|
|
830
830
|
request_id: Optional[str] = None,
|
|
831
|
-
image_ids: Optional[List[
|
|
831
|
+
image_ids: Optional[List[int]] = None,
|
|
832
832
|
is_first_message_override: Optional[bool] = None,
|
|
833
833
|
) -> Generator[StreamEvent, None, None]:
|
|
834
834
|
"""Send a message and yield streaming events.
|
|
@@ -1993,30 +1993,27 @@ class ChatService:
|
|
|
1993
1993
|
|
|
1994
1994
|
return ([], None)
|
|
1995
1995
|
|
|
1996
|
-
def _inject_image_context(self, message: str, image_ids: List[
|
|
1997
|
-
"""Append image metadata to user message so the agent knows about attached images.
|
|
1998
|
-
|
|
1999
|
-
``image_ids`` are opaque image tokens (SDR-4437 F-TM-7), not int PKs.
|
|
2000
|
-
"""
|
|
1996
|
+
def _inject_image_context(self, message: str, image_ids: List[int]) -> str:
|
|
1997
|
+
"""Append image metadata to user message so the agent knows about attached images."""
|
|
2001
1998
|
from src.core.database import get_db_session
|
|
2002
1999
|
from src.services import image_service
|
|
2003
2000
|
|
|
2004
2001
|
image_descriptions = []
|
|
2005
2002
|
with get_db_session() as db:
|
|
2006
|
-
for
|
|
2003
|
+
for img_id in image_ids:
|
|
2007
2004
|
try:
|
|
2008
2005
|
img = db.query(image_service.ImageAsset).filter(
|
|
2009
|
-
image_service.ImageAsset.
|
|
2006
|
+
image_service.ImageAsset.id == img_id,
|
|
2010
2007
|
image_service.ImageAsset.is_active == True,
|
|
2011
2008
|
).first()
|
|
2012
2009
|
if img:
|
|
2013
2010
|
image_descriptions.append(
|
|
2014
|
-
f'- Image ID {img.
|
|
2011
|
+
f'- Image ID {img.id}: "{img.original_filename}" '
|
|
2015
2012
|
f'({img.description or "no description"}). '
|
|
2016
|
-
f'Use: <img src="{{{{image:{img.
|
|
2013
|
+
f'Use: <img src="{{{{image:{img.id}}}}}" alt="{img.description or img.original_filename}" />'
|
|
2017
2014
|
)
|
|
2018
2015
|
except Exception as e:
|
|
2019
|
-
logger.warning(f"Failed to load image {
|
|
2016
|
+
logger.warning(f"Failed to load image {img_id} for context injection: {e}")
|
|
2020
2017
|
|
|
2021
2018
|
if not image_descriptions:
|
|
2022
2019
|
return message
|
|
@@ -524,8 +524,6 @@ def _run_migrations(engine, schema: str | None = None):
|
|
|
524
524
|
# --- image_assets.tags: json → jsonb (PostgreSQL) for native @> queries ---
|
|
525
525
|
_migrate_image_assets_tags_json_to_jsonb(conn, schema, _qual, is_sqlite)
|
|
526
526
|
|
|
527
|
-
# --- image_assets.token: unguessable external id + backfill (SDR-4437 F-TM-7) ---
|
|
528
|
-
_migrate_image_assets_add_token(conn, inspector, schema, _qual, is_sqlite)
|
|
529
527
|
# --- agent_config: style precedence in the DB, for the raw-SQL writers no
|
|
530
528
|
# --- Python-side bind hook can see (PostgreSQL only; no-op on SQLite) ---
|
|
531
529
|
_migrate_agent_config_precedence_trigger(
|
|
@@ -1060,44 +1058,6 @@ def _ensure_llm_judge_backend_default(
|
|
|
1060
1058
|
)
|
|
1061
1059
|
|
|
1062
1060
|
|
|
1063
|
-
def _migrate_image_assets_add_token(conn, inspector, schema, _qual, is_sqlite) -> None:
|
|
1064
|
-
"""Add the unguessable ``token`` column to image_assets and backfill (SDR-4437 F-TM-7).
|
|
1065
|
-
|
|
1066
|
-
The int PK is enumerable, so image reads now key on an opaque token. Fresh
|
|
1067
|
-
installs get the column via create_all(); existing tables need this ALTER +
|
|
1068
|
-
per-row backfill. Idempotent: gated on the column's absence.
|
|
1069
|
-
"""
|
|
1070
|
-
import secrets
|
|
1071
|
-
|
|
1072
|
-
from sqlalchemy import text
|
|
1073
|
-
|
|
1074
|
-
table = "image_assets"
|
|
1075
|
-
try:
|
|
1076
|
-
cols = {c["name"] for c in inspector.get_columns(table, schema=schema)}
|
|
1077
|
-
except Exception:
|
|
1078
|
-
return
|
|
1079
|
-
if not cols or "token" in cols:
|
|
1080
|
-
return
|
|
1081
|
-
|
|
1082
|
-
q = _qual(table)
|
|
1083
|
-
logger.info(f"Migration: adding token column to {table} (SDR-4437 F-TM-7)")
|
|
1084
|
-
# Add nullable first so the ALTER succeeds on a populated table.
|
|
1085
|
-
conn.execute(text(f"ALTER TABLE {q} ADD COLUMN token VARCHAR(64)"))
|
|
1086
|
-
|
|
1087
|
-
# Backfill every existing row with a distinct unguessable token.
|
|
1088
|
-
row_ids = [r[0] for r in conn.execute(text(f"SELECT id FROM {q} WHERE token IS NULL")).fetchall()]
|
|
1089
|
-
for row_id in row_ids:
|
|
1090
|
-
conn.execute(
|
|
1091
|
-
text(f"UPDATE {q} SET token = :tok WHERE id = :id"),
|
|
1092
|
-
{"tok": secrets.token_urlsafe(32), "id": row_id},
|
|
1093
|
-
)
|
|
1094
|
-
|
|
1095
|
-
# Enforce uniqueness (and non-null on PostgreSQL, now that every row has a token).
|
|
1096
|
-
conn.execute(text(
|
|
1097
|
-
f"CREATE UNIQUE INDEX IF NOT EXISTS ix_image_assets_token ON {q} (token)"
|
|
1098
|
-
))
|
|
1099
|
-
if not is_sqlite:
|
|
1100
|
-
conn.execute(text(f"ALTER TABLE {q} ALTER COLUMN token SET NOT NULL"))
|
|
1101
1061
|
#: The one place the precedence rule is written in SQL. ``$$``-quoted so the body
|
|
1102
1062
|
#: needs no escaping, and named after the rule rather than the tables, since both
|
|
1103
1063
|
#: ``agent_config`` columns share it.
|
{databricks_tellr_app-0.4.3.dev1 → databricks_tellr_app-0.4.3.dev3}/src/database/models/image.py
RENAMED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
"""Image asset model — metadata and binary data stored together in Lakebase."""
|
|
2
|
-
import secrets
|
|
3
2
|
from datetime import datetime
|
|
4
3
|
|
|
5
4
|
from sqlalchemy import Boolean, Column, DateTime, Integer, JSON, LargeBinary, String, Text
|
|
@@ -11,17 +10,6 @@ from src.core.database import Base
|
|
|
11
10
|
_TagsColumn = JSON().with_variant(JSONB(), "postgresql")
|
|
12
11
|
|
|
13
12
|
|
|
14
|
-
def _new_image_token() -> str:
|
|
15
|
-
"""Unguessable external identifier (SDR-4437 F-TM-7).
|
|
16
|
-
|
|
17
|
-
The autoincrement int PK is enumerable, so it is never exposed. This
|
|
18
|
-
opaque token is the only identifier that leaves the server — it is what
|
|
19
|
-
the API returns, what chat sends in ``image_ids``, and what goes in
|
|
20
|
-
``{{image:...}}`` slide placeholders.
|
|
21
|
-
"""
|
|
22
|
-
return secrets.token_urlsafe(32)
|
|
23
|
-
|
|
24
|
-
|
|
25
13
|
class ImageAsset(Base):
|
|
26
14
|
"""Uploaded image with binary data stored directly in PostgreSQL.
|
|
27
15
|
|
|
@@ -32,9 +20,7 @@ class ImageAsset(Base):
|
|
|
32
20
|
|
|
33
21
|
__tablename__ = "image_assets"
|
|
34
22
|
|
|
35
|
-
id = Column(Integer, primary_key=True)
|
|
36
|
-
# Unguessable external identifier (SDR-4437 F-TM-7). token_urlsafe(32) → 43 chars.
|
|
37
|
-
token = Column(String(64), unique=True, nullable=False, index=True, default=_new_image_token)
|
|
23
|
+
id = Column(Integer, primary_key=True)
|
|
38
24
|
filename = Column(String(255), nullable=False) # Generated: {uuid}.{ext}
|
|
39
25
|
original_filename = Column(String(255), nullable=False) # User's original filename
|
|
40
26
|
mime_type = Column(String(50), nullable=False) # image/png, image/jpeg, image/gif, image/svg+xml
|