databricks-tellr-app 0.3.11.dev7__tar.gz → 0.3.11.dev9__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.
Files changed (155) hide show
  1. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/PKG-INFO +1 -1
  2. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/databricks_tellr_app.egg-info/PKG-INFO +1 -1
  3. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/databricks_tellr_app.egg-info/SOURCES.txt +8 -14
  4. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/pyproject.toml +1 -1
  5. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/main.py +10 -3
  6. databricks_tellr_app-0.3.11.dev9/src/api/routes/admin_usage.py +145 -0
  7. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/routes/agent_config.py +3 -56
  8. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/routes/export.py +2 -4
  9. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/routes/feedback.py +27 -0
  10. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/routes/google_slides.py +1 -5
  11. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/routes/sessions.py +5 -2
  12. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/routes/settings/__init__.py +0 -2
  13. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/schemas/agent_config.py +0 -8
  14. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/services/chat_service.py +5 -38
  15. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/services/export_job_queue.py +2 -4
  16. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/services/feedback_service.py +43 -0
  17. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/services/session_manager.py +19 -3
  18. databricks_tellr_app-0.3.11.dev9/src/api/services/usage_events.py +117 -0
  19. databricks_tellr_app-0.3.11.dev9/src/api/services/usage_service.py +522 -0
  20. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/core/database.py +0 -117
  21. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/core/prompt_modules.py +3 -53
  22. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/database/models/__init__.py +3 -12
  23. databricks_tellr_app-0.3.11.dev9/src/database/models/usage_event.py +39 -0
  24. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/services/agent_factory.py +5 -95
  25. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/services/tools/__init__.py +0 -4
  26. databricks_tellr_app-0.3.11.dev7/src/api/routes/settings/design_systems.py +0 -847
  27. databricks_tellr_app-0.3.11.dev7/src/database/models/design_system.py +0 -357
  28. databricks_tellr_app-0.3.11.dev7/src/services/design_system_compiler.py +0 -603
  29. databricks_tellr_app-0.3.11.dev7/src/services/design_system_service.py +0 -1004
  30. databricks_tellr_app-0.3.11.dev7/src/services/design_system_templates.py +0 -641
  31. databricks_tellr_app-0.3.11.dev7/src/services/tools/ds_asset_tool.py +0 -105
  32. databricks_tellr_app-0.3.11.dev7/src/utils/ds_asset_utils.py +0 -76
  33. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/README.md +0 -0
  34. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/databricks_tellr_app/__init__.py +0 -0
  35. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/databricks_tellr_app/run.py +0 -0
  36. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/databricks_tellr_app.egg-info/dependency_links.txt +0 -0
  37. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/databricks_tellr_app.egg-info/requires.txt +0 -0
  38. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/databricks_tellr_app.egg-info/top_level.txt +0 -0
  39. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/setup.cfg +0 -0
  40. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/setup.py +0 -0
  41. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/__init__.py +0 -0
  42. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/__init__.py +0 -0
  43. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/_otel_bootstrap.py +0 -0
  44. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/fixtures/tour_demo_deck.json +0 -0
  45. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/mcp_auth.py +0 -0
  46. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/mcp_server.py +0 -0
  47. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/middleware/__init__.py +0 -0
  48. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/middleware/request_logging.py +0 -0
  49. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/routes/__init__.py +0 -0
  50. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/routes/admin.py +0 -0
  51. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/routes/chat.py +0 -0
  52. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/routes/deck_contributors.py +0 -0
  53. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/routes/images.py +0 -0
  54. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/routes/local_version.py +0 -0
  55. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/routes/profiles.py +0 -0
  56. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/routes/settings/contributors.py +0 -0
  57. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/routes/settings/deck_prompts.py +0 -0
  58. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/routes/settings/identities.py +0 -0
  59. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/routes/settings/slide_styles.py +0 -0
  60. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/routes/setup.py +0 -0
  61. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/routes/slides.py +0 -0
  62. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/routes/tools.py +0 -0
  63. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/routes/tour.py +0 -0
  64. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/routes/verification.py +0 -0
  65. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/routes/version.py +0 -0
  66. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/schemas/__init__.py +0 -0
  67. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/schemas/feedback.py +0 -0
  68. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/schemas/requests.py +0 -0
  69. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/schemas/responses.py +0 -0
  70. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/schemas/settings/__init__.py +0 -0
  71. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/schemas/settings/requests.py +0 -0
  72. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/schemas/settings/responses.py +0 -0
  73. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/schemas/streaming.py +0 -0
  74. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/services/__init__.py +0 -0
  75. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/services/job_queue.py +0 -0
  76. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/services/session_naming.py +0 -0
  77. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/utils/__init__.py +0 -0
  78. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/api/utils/validation.py +0 -0
  79. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/core/__init__.py +0 -0
  80. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/core/config_loader.py +0 -0
  81. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/core/context_utils.py +0 -0
  82. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/core/databricks_client.py +0 -0
  83. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/core/defaults.py +0 -0
  84. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/core/encryption.py +0 -0
  85. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/core/init_default_profile.py +0 -0
  86. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/core/lakebase.py +0 -0
  87. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/core/migrate_profiles_to_agent_config.py +0 -0
  88. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/core/mlflow_agent_spans.py +0 -0
  89. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/core/mlflow_tracing.py +0 -0
  90. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/core/otel_logging.py +0 -0
  91. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/core/permission_context.py +0 -0
  92. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/core/settings_db.py +0 -0
  93. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/core/user_context.py +0 -0
  94. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/database/__init__.py +0 -0
  95. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/database/models/deck_contributor.py +0 -0
  96. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/database/models/feedback.py +0 -0
  97. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/database/models/genie_space.py +0 -0
  98. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/database/models/google_global_credentials.py +0 -0
  99. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/database/models/google_oauth_token.py +0 -0
  100. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/database/models/identity.py +0 -0
  101. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/database/models/image.py +0 -0
  102. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/database/models/profile.py +0 -0
  103. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/database/models/profile_contributor.py +0 -0
  104. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/database/models/prompts.py +0 -0
  105. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/database/models/request_log.py +0 -0
  106. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/database/models/session.py +0 -0
  107. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/database/models/slide_deck_prompt.py +0 -0
  108. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/database/models/slide_style_library.py +0 -0
  109. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/database/models/user_preference.py +0 -0
  110. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/domain/__init__.py +0 -0
  111. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/domain/slide.py +0 -0
  112. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/domain/slide_deck.py +0 -0
  113. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/services/__init__.py +0 -0
  114. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/services/agent.py +0 -0
  115. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/services/config_service.py +0 -0
  116. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/services/config_validator.py +0 -0
  117. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/services/drive_uploader.py +0 -0
  118. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/services/evaluation/__init__.py +0 -0
  119. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/services/evaluation/llm_judge.py +0 -0
  120. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/services/genie_service.py +0 -0
  121. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/services/google_slides_auth.py +0 -0
  122. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/services/google_slides_prompts_defaults.py +0 -0
  123. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/services/html_to_google_slides.py +0 -0
  124. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/services/html_to_pptx.py +0 -0
  125. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/services/identity_provider.py +0 -0
  126. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/services/identity_providers/__init__.py +0 -0
  127. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/services/identity_providers/account_provider.py +0 -0
  128. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/services/identity_providers/local_provider.py +0 -0
  129. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/services/identity_providers/workspace_provider.py +0 -0
  130. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/services/image_service.py +0 -0
  131. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/services/image_tools.py +0 -0
  132. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/services/permission_service.py +0 -0
  133. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/services/pptx_from_html_huashu.py +0 -0
  134. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/services/pptx_from_records.py +0 -0
  135. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/services/pptx_prompts_defaults.py +0 -0
  136. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/services/profile_service.py +0 -0
  137. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/services/streaming_callback.py +0 -0
  138. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/services/tools/agent_bricks_tool.py +0 -0
  139. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/services/tools/genie_tool.py +0 -0
  140. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/services/tools/mcp_tool.py +0 -0
  141. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/services/tools/model_endpoint_tool.py +0 -0
  142. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/services/tools/vector_tool.py +0 -0
  143. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/services/validator.py +0 -0
  144. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/utils/__init__.py +0 -0
  145. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/utils/css_utils.py +0 -0
  146. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/utils/error_handling.py +0 -0
  147. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/utils/html_safety.py +0 -0
  148. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/utils/html_utils.py +0 -0
  149. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/utils/image_utils.py +0 -0
  150. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/utils/js_validator.py +0 -0
  151. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/utils/logging_config.py +0 -0
  152. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/utils/pi_filter.py +0 -0
  153. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/utils/slide_hash.py +0 -0
  154. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/utils/spotlight.py +0 -0
  155. {databricks_tellr_app-0.3.11.dev7 → databricks_tellr_app-0.3.11.dev9}/src/utils/text_caps.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: databricks-tellr-app
3
- Version: 0.3.11.dev7
3
+ Version: 0.3.11.dev9
4
4
  Summary: Tellr application package for Databricks Apps
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: databricks-tellr-app
3
- Version: 0.3.11.dev7
3
+ Version: 0.3.11.dev9
4
4
  Summary: Tellr application package for Databricks Apps
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
@@ -14,6 +14,7 @@ setup.py
14
14
  ./src/api/middleware/request_logging.py
15
15
  ./src/api/routes/__init__.py
16
16
  ./src/api/routes/admin.py
17
+ ./src/api/routes/admin_usage.py
17
18
  ./src/api/routes/agent_config.py
18
19
  ./src/api/routes/chat.py
19
20
  ./src/api/routes/deck_contributors.py
@@ -33,7 +34,6 @@ setup.py
33
34
  ./src/api/routes/settings/__init__.py
34
35
  ./src/api/routes/settings/contributors.py
35
36
  ./src/api/routes/settings/deck_prompts.py
36
- ./src/api/routes/settings/design_systems.py
37
37
  ./src/api/routes/settings/identities.py
38
38
  ./src/api/routes/settings/slide_styles.py
39
39
  ./src/api/schemas/__init__.py
@@ -52,6 +52,8 @@ setup.py
52
52
  ./src/api/services/job_queue.py
53
53
  ./src/api/services/session_manager.py
54
54
  ./src/api/services/session_naming.py
55
+ ./src/api/services/usage_events.py
56
+ ./src/api/services/usage_service.py
55
57
  ./src/api/utils/__init__.py
56
58
  ./src/api/utils/validation.py
57
59
  ./src/core/__init__.py
@@ -74,7 +76,6 @@ setup.py
74
76
  ./src/database/__init__.py
75
77
  ./src/database/models/__init__.py
76
78
  ./src/database/models/deck_contributor.py
77
- ./src/database/models/design_system.py
78
79
  ./src/database/models/feedback.py
79
80
  ./src/database/models/genie_space.py
80
81
  ./src/database/models/google_global_credentials.py
@@ -88,6 +89,7 @@ setup.py
88
89
  ./src/database/models/session.py
89
90
  ./src/database/models/slide_deck_prompt.py
90
91
  ./src/database/models/slide_style_library.py
92
+ ./src/database/models/usage_event.py
91
93
  ./src/database/models/user_preference.py
92
94
  ./src/domain/__init__.py
93
95
  ./src/domain/slide.py
@@ -97,9 +99,6 @@ setup.py
97
99
  ./src/services/agent_factory.py
98
100
  ./src/services/config_service.py
99
101
  ./src/services/config_validator.py
100
- ./src/services/design_system_compiler.py
101
- ./src/services/design_system_service.py
102
- ./src/services/design_system_templates.py
103
102
  ./src/services/drive_uploader.py
104
103
  ./src/services/genie_service.py
105
104
  ./src/services/google_slides_auth.py
@@ -124,14 +123,12 @@ setup.py
124
123
  ./src/services/identity_providers/workspace_provider.py
125
124
  ./src/services/tools/__init__.py
126
125
  ./src/services/tools/agent_bricks_tool.py
127
- ./src/services/tools/ds_asset_tool.py
128
126
  ./src/services/tools/genie_tool.py
129
127
  ./src/services/tools/mcp_tool.py
130
128
  ./src/services/tools/model_endpoint_tool.py
131
129
  ./src/services/tools/vector_tool.py
132
130
  ./src/utils/__init__.py
133
131
  ./src/utils/css_utils.py
134
- ./src/utils/ds_asset_utils.py
135
132
  ./src/utils/error_handling.py
136
133
  ./src/utils/html_safety.py
137
134
  ./src/utils/html_utils.py
@@ -160,6 +157,7 @@ src/api/middleware/__init__.py
160
157
  src/api/middleware/request_logging.py
161
158
  src/api/routes/__init__.py
162
159
  src/api/routes/admin.py
160
+ src/api/routes/admin_usage.py
163
161
  src/api/routes/agent_config.py
164
162
  src/api/routes/chat.py
165
163
  src/api/routes/deck_contributors.py
@@ -179,7 +177,6 @@ src/api/routes/version.py
179
177
  src/api/routes/settings/__init__.py
180
178
  src/api/routes/settings/contributors.py
181
179
  src/api/routes/settings/deck_prompts.py
182
- src/api/routes/settings/design_systems.py
183
180
  src/api/routes/settings/identities.py
184
181
  src/api/routes/settings/slide_styles.py
185
182
  src/api/schemas/__init__.py
@@ -198,6 +195,8 @@ src/api/services/feedback_service.py
198
195
  src/api/services/job_queue.py
199
196
  src/api/services/session_manager.py
200
197
  src/api/services/session_naming.py
198
+ src/api/services/usage_events.py
199
+ src/api/services/usage_service.py
201
200
  src/api/utils/__init__.py
202
201
  src/api/utils/validation.py
203
202
  src/core/__init__.py
@@ -220,7 +219,6 @@ src/core/user_context.py
220
219
  src/database/__init__.py
221
220
  src/database/models/__init__.py
222
221
  src/database/models/deck_contributor.py
223
- src/database/models/design_system.py
224
222
  src/database/models/feedback.py
225
223
  src/database/models/genie_space.py
226
224
  src/database/models/google_global_credentials.py
@@ -234,6 +232,7 @@ src/database/models/request_log.py
234
232
  src/database/models/session.py
235
233
  src/database/models/slide_deck_prompt.py
236
234
  src/database/models/slide_style_library.py
235
+ src/database/models/usage_event.py
237
236
  src/database/models/user_preference.py
238
237
  src/domain/__init__.py
239
238
  src/domain/slide.py
@@ -243,9 +242,6 @@ src/services/agent.py
243
242
  src/services/agent_factory.py
244
243
  src/services/config_service.py
245
244
  src/services/config_validator.py
246
- src/services/design_system_compiler.py
247
- src/services/design_system_service.py
248
- src/services/design_system_templates.py
249
245
  src/services/drive_uploader.py
250
246
  src/services/genie_service.py
251
247
  src/services/google_slides_auth.py
@@ -270,14 +266,12 @@ src/services/identity_providers/local_provider.py
270
266
  src/services/identity_providers/workspace_provider.py
271
267
  src/services/tools/__init__.py
272
268
  src/services/tools/agent_bricks_tool.py
273
- src/services/tools/ds_asset_tool.py
274
269
  src/services/tools/genie_tool.py
275
270
  src/services/tools/mcp_tool.py
276
271
  src/services/tools/model_endpoint_tool.py
277
272
  src/services/tools/vector_tool.py
278
273
  src/utils/__init__.py
279
274
  src/utils/css_utils.py
280
- src/utils/ds_asset_utils.py
281
275
  src/utils/error_handling.py
282
276
  src/utils/html_safety.py
283
277
  src/utils/html_utils.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "databricks-tellr-app"
7
- version = "0.3.11.dev7"
7
+ version = "0.3.11.dev9"
8
8
  description = "Tellr application package for Databricks Apps"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -16,7 +16,7 @@ from fastapi.middleware.cors import CORSMiddleware
16
16
  from fastapi.responses import FileResponse
17
17
  from fastapi.staticfiles import StaticFiles
18
18
 
19
- from src.api.routes import admin, agent_config, chat, export, feedback, images, profiles, sessions, slides, tools, tour, verification, version, google_slides, setup, local_version
19
+ from src.api.routes import admin, admin_usage, agent_config, chat, export, feedback, images, profiles, sessions, slides, tools, tour, verification, version, google_slides, setup, local_version
20
20
  from src.api.routes.deck_contributors import router as deck_contributors_router
21
21
  from src.core.databricks_client import get_or_create_user_client, set_user_client
22
22
  from src.core.user_context import get_current_user as get_ctx_user, set_current_user
@@ -27,7 +27,6 @@ from src.core.permission_context import (
27
27
  from src.api.routes.settings import (
28
28
  contributors_router,
29
29
  deck_prompts_router,
30
- design_systems_router,
31
30
  identities_router,
32
31
  slide_styles_router,
33
32
  )
@@ -382,6 +381,14 @@ async def user_auth_middleware(request: Request, call_next):
382
381
  )
383
382
  set_permission_context(permission_ctx)
384
383
 
384
+ # Record login usage-event (visit-deduped, non-blocking, all envs)
385
+ if user_name:
386
+ try:
387
+ from src.api.services.usage_events import record_login
388
+ record_login(user_name)
389
+ except Exception as e:
390
+ logger.debug(f"Failed to record login usage event: {e}")
391
+
385
392
  # Record user login for local identity table (non-blocking)
386
393
  if user_id and user_name and IS_PRODUCTION:
387
394
  try:
@@ -412,6 +419,7 @@ app.add_middleware(RequestLoggingMiddleware)
412
419
 
413
420
  # Include API routers
414
421
  app.include_router(admin.router)
422
+ app.include_router(admin_usage.router)
415
423
  app.include_router(agent_config.router)
416
424
  app.include_router(chat.router)
417
425
  app.include_router(feedback.router)
@@ -435,7 +443,6 @@ app.include_router(contributors_router, prefix="/api/settings", tags=["settings"
435
443
  app.include_router(deck_prompts_router, prefix="/api/settings", tags=["settings"])
436
444
  app.include_router(identities_router, prefix="/api/settings", tags=["settings"])
437
445
  app.include_router(slide_styles_router, prefix="/api/settings", tags=["settings"])
438
- app.include_router(design_systems_router, prefix="/api/settings", tags=["settings"])
439
446
 
440
447
  # MCP server — mount the FastMCP streamable-HTTP ASGI app at /mcp.
441
448
  # Must be registered before the SPA catch-all (which is added lazily by
@@ -0,0 +1,145 @@
1
+ """Admin usage-analytics endpoints (ungated, like the rest of /admin)."""
2
+
3
+ import logging
4
+ from datetime import date as dt_date
5
+ from datetime import datetime
6
+
7
+ from fastapi import APIRouter, Depends, HTTPException, Query, status
8
+ from sqlalchemy.orm import Session
9
+
10
+ from src.api.services.usage_service import MAX_WINDOW_DAYS, UsageService
11
+ from src.core.database import get_db
12
+
13
+ logger = logging.getLogger(__name__)
14
+ router = APIRouter(prefix="/api/admin/usage", tags=["admin-usage"])
15
+
16
+
17
+ def _parse_date(value: str, name: str) -> dt_date:
18
+ try:
19
+ return datetime.strptime(value, "%Y-%m-%d").date()
20
+ except ValueError:
21
+ raise HTTPException(
22
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
23
+ detail=f"{name} must be a YYYY-MM-DD date",
24
+ )
25
+
26
+
27
+ def _window_kwargs(
28
+ days: int | None,
29
+ start: str | None,
30
+ end: str | None,
31
+ all_data: bool,
32
+ ) -> dict:
33
+ """Validate window query params into UsageService kwargs.
34
+
35
+ Precedence: all > start/end range > days > default (7, applied by the
36
+ service). ``start`` and ``end`` must be provided together.
37
+ """
38
+ if all_data:
39
+ return {"all_data": True}
40
+ if start is not None or end is not None:
41
+ if start is None or end is None:
42
+ raise HTTPException(
43
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
44
+ detail="start and end must be provided together",
45
+ )
46
+ start_date = _parse_date(start, "start")
47
+ end_date = _parse_date(end, "end")
48
+ if start_date > end_date:
49
+ raise HTTPException(
50
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
51
+ detail="start must be on or before end",
52
+ )
53
+ return {"start": start_date, "end": end_date}
54
+ if days is not None:
55
+ if not 1 <= days <= MAX_WINDOW_DAYS:
56
+ raise HTTPException(
57
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
58
+ detail=f"days must be between 1 and {MAX_WINDOW_DAYS}",
59
+ )
60
+ return {"days": days}
61
+ return {}
62
+
63
+
64
+ def _handle(callable_, *args, **kwargs):
65
+ try:
66
+ return callable_(*args, **kwargs)
67
+ except HTTPException:
68
+ raise
69
+ except Exception as e:
70
+ logger.error(f"Usage analytics error: {e}", exc_info=True)
71
+ raise HTTPException(
72
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
73
+ detail="Failed to compute usage analytics",
74
+ )
75
+
76
+
77
+ _DAYS = Query(default=None, description=f"Rolling window, 1..{MAX_WINDOW_DAYS}")
78
+ _START = Query(default=None, description="Range start (YYYY-MM-DD, inclusive)")
79
+ _END = Query(default=None, description="Range end (YYYY-MM-DD, inclusive)")
80
+ _ALL = Query(default=False, alias="all", description="Report over all data")
81
+
82
+
83
+ @router.get("/summary")
84
+ def get_summary(
85
+ days: int | None = _DAYS,
86
+ start: str | None = _START,
87
+ end: str | None = _END,
88
+ all_data: bool = _ALL,
89
+ db: Session = Depends(get_db),
90
+ ):
91
+ kwargs = _window_kwargs(days, start, end, all_data)
92
+ return _handle(UsageService().get_summary, db, **kwargs)
93
+
94
+
95
+ @router.get("/daily")
96
+ def get_daily(
97
+ days: int | None = _DAYS,
98
+ start: str | None = _START,
99
+ end: str | None = _END,
100
+ all_data: bool = _ALL,
101
+ db: Session = Depends(get_db),
102
+ ):
103
+ kwargs = _window_kwargs(days, start, end, all_data)
104
+ return _handle(UsageService().get_daily, db, **kwargs)
105
+
106
+
107
+ @router.get("/top-users")
108
+ def get_top_users(
109
+ days: int | None = _DAYS,
110
+ start: str | None = _START,
111
+ end: str | None = _END,
112
+ all_data: bool = _ALL,
113
+ db: Session = Depends(get_db),
114
+ ):
115
+ kwargs = _window_kwargs(days, start, end, all_data)
116
+ return _handle(UsageService().get_top_users, db, **kwargs)
117
+
118
+
119
+ @router.get("/funnel")
120
+ def get_funnel(
121
+ days: int | None = _DAYS,
122
+ start: str | None = _START,
123
+ end: str | None = _END,
124
+ all_data: bool = _ALL,
125
+ db: Session = Depends(get_db),
126
+ ):
127
+ kwargs = _window_kwargs(days, start, end, all_data)
128
+ return _handle(UsageService().get_funnel, db, **kwargs)
129
+
130
+
131
+ @router.get("/retention")
132
+ def get_retention(db: Session = Depends(get_db)):
133
+ return _handle(UsageService().get_retention, db)
134
+
135
+
136
+ @router.get("/heatmap")
137
+ def get_heatmap(
138
+ days: int | None = _DAYS,
139
+ start: str | None = _START,
140
+ end: str | None = _END,
141
+ all_data: bool = _ALL,
142
+ db: Session = Depends(get_db),
143
+ ):
144
+ kwargs = _window_kwargs(days, start, end, all_data)
145
+ return _handle(UsageService().get_heatmap, db, **kwargs)
@@ -21,61 +21,10 @@ router = APIRouter(prefix="/api/sessions/{session_id}/agent-config", tags=["agen
21
21
 
22
22
 
23
23
  def _validate_references(config: AgentConfig) -> None:
24
- """Validate the library references and SANITIZE the template pin, in place.
25
-
26
- ``design_system_id``, ``slide_style_id`` and ``deck_prompt_id`` stay STRICT
27
- (422 on a missing/inactive entry — the existing convention). The template
28
- pin is SELF-HEALING instead: template ids are re-minted by the sanctioned
29
- delete+re-upload workflow, so a persisted config can legitimately hold a
30
- stale pin — rejecting it would wedge EVERY later config update. When
31
- ``template_id`` does not resolve to a template belonging to the selected
32
- design system (pin with no design system, another system's template, or a
33
- missing/re-materialized template), it is cleared in place with a warning;
34
- the caller persists and returns the sanitized config so the frontend state
35
- syncs. This mirrors the deliberately lenient generation path.
36
- """
37
- from src.database.models import (
38
- DesignSystem,
39
- DesignSystemTemplate,
40
- SlideDeckPromptLibrary,
41
- SlideStyleLibrary,
42
- )
24
+ """Validate that slide_style_id and deck_prompt_id reference existing library entries."""
25
+ from src.database.models import SlideStyleLibrary, SlideDeckPromptLibrary
43
26
 
44
27
  with get_db_session() as db:
45
- if config.design_system_id is not None:
46
- design_system = (
47
- db.query(DesignSystem)
48
- .filter(
49
- DesignSystem.id == config.design_system_id,
50
- DesignSystem.is_active == True, # noqa: E712
51
- )
52
- .first()
53
- )
54
- if not design_system:
55
- raise HTTPException(
56
- status_code=422,
57
- detail=f"design_system_id {config.design_system_id} not found",
58
- )
59
- if config.template_id is not None:
60
- template = None
61
- if config.design_system_id is not None:
62
- template = (
63
- db.query(DesignSystemTemplate)
64
- .filter(
65
- DesignSystemTemplate.id == config.template_id,
66
- DesignSystemTemplate.design_system_id == config.design_system_id,
67
- )
68
- .first()
69
- )
70
- if template is None:
71
- logger.warning(
72
- "Clearing stale template pin %s (design_system_id=%s): the "
73
- "template does not exist or does not belong to the selected "
74
- "design system; saving the config without it",
75
- config.template_id,
76
- config.design_system_id,
77
- )
78
- config.template_id = None
79
28
  if config.slide_style_id is not None:
80
29
  style = (
81
30
  db.query(SlideStyleLibrary)
@@ -151,9 +100,7 @@ async def get_agent_config(session_id: str):
151
100
  async def put_agent_config(session_id: str, config: AgentConfig):
152
101
  """Replace the full agent config for a session."""
153
102
  # Pydantic already validated duplicates via model_validator.
154
- # Now validate foreign-key references; a stale template pin is sanitized
155
- # (cleared in place) rather than rejected, so what is persisted and
156
- # returned below is the effective config.
103
+ # Now validate foreign-key references.
157
104
  _validate_references(config)
158
105
 
159
106
  try:
@@ -405,14 +405,12 @@ async def export_to_pptx(request: ExportPPTXRequest):
405
405
  if not slide_deck or not slide_deck.get("slides"):
406
406
  raise HTTPException(status_code=404, detail="No slides available")
407
407
 
408
- # Substitute {{image:ID}} + {{ds-asset:ID}} placeholders with base64 data URIs
409
- # so the PPTX converter can extract and embed the actual images/brand assets
410
- from src.utils.ds_asset_utils import substitute_deck_dict_ds_assets
408
+ # Substitute {{image:ID}} placeholders with base64 data URIs
409
+ # so the PPTX converter can extract and embed the actual images
411
410
  from src.utils.image_utils import substitute_deck_dict_images
412
411
  from src.core.database import get_db_session
413
412
  with get_db_session() as db:
414
413
  substitute_deck_dict_images(slide_deck, db)
415
- substitute_deck_dict_ds_assets(slide_deck, db)
416
414
 
417
415
  slide_count = len(slide_deck.get("slides", []))
418
416
  log_msg = (
@@ -88,6 +88,33 @@ def get_stats_report(weeks: int = Query(default=12, ge=1, le=52), db: Session =
88
88
  )
89
89
 
90
90
 
91
+ @router.get("/list")
92
+ def list_feedback(
93
+ weeks: int = Query(default=12, ge=1, le=52),
94
+ category: str | None = Query(default=None),
95
+ severity: str | None = Query(default=None),
96
+ page: int = Query(default=1, ge=1),
97
+ page_size: int = Query(default=20, ge=1, le=100),
98
+ db: Session = Depends(get_db),
99
+ ):
100
+ try:
101
+ service = FeedbackService()
102
+ return service.list_feedback(
103
+ db=db,
104
+ weeks=weeks,
105
+ category=category,
106
+ severity=severity,
107
+ page=page,
108
+ page_size=page_size,
109
+ )
110
+ except Exception as e:
111
+ logger.error(f"Feedback list error: {e}", exc_info=True)
112
+ raise HTTPException(
113
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
114
+ detail="Failed to list feedback",
115
+ )
116
+
117
+
91
118
  @router.get("/report/summary")
92
119
  def get_feedback_summary(weeks: int = Query(default=4, ge=1, le=52), db: Session = Depends(get_db)):
93
120
  try:
@@ -276,13 +276,11 @@ async def start_google_slides_export(
276
276
  if not slide_deck or not slide_deck.get("slides"):
277
277
  raise HTTPException(status_code=404, detail="No slides available")
278
278
 
279
- # Substitute {{image:ID}} + {{ds-asset:ID}} placeholders with base64 data URIs
280
- from src.utils.ds_asset_utils import substitute_deck_dict_ds_assets
279
+ # Substitute {{image:ID}} placeholders with base64 data URIs
281
280
  from src.utils.image_utils import substitute_deck_dict_images
282
281
  from src.core.database import get_db_session
283
282
  with get_db_session() as db:
284
283
  substitute_deck_dict_images(slide_deck, db)
285
- substitute_deck_dict_ds_assets(slide_deck, db)
286
284
 
287
285
  slides_data = slide_deck.get("slides", [])
288
286
  total = len(slides_data)
@@ -504,11 +502,9 @@ async def export_google_slides_from_huashu(
504
502
  # legacy /export route). Use a fresh session because the request's `db`
505
503
  # is held by the route's transaction context.
506
504
  from src.core.database import get_db_session
507
- from src.utils.ds_asset_utils import substitute_deck_dict_ds_assets
508
505
  from src.utils.image_utils import substitute_deck_dict_images
509
506
  with get_db_session() as imdb:
510
507
  substitute_deck_dict_images(slide_deck, imdb)
511
- substitute_deck_dict_ds_assets(slide_deck, imdb)
512
508
 
513
509
  title = slide_deck.get("title") or "Presentation"
514
510
  slides_data = slide_deck.get("slides") or []
@@ -25,6 +25,7 @@ from src.api.services.session_manager import (
25
25
  SessionNotFoundError,
26
26
  get_session_manager,
27
27
  )
28
+ from src.api.services.usage_events import record_deck_retrieved
28
29
  from src.core.database import get_db, get_db_session
29
30
  from src.core.permission_context import get_permission_context
30
31
  from src.core.user_context import get_current_user
@@ -149,12 +150,10 @@ def _check_deck_permission_for_session(
149
150
  def _substitute_deck_images(deck_dict: dict) -> None:
150
151
  """Substitute {{image:ID}} placeholders in a deck dict with base64 data URIs."""
151
152
  from src.core.database import get_db_session
152
- from src.utils.ds_asset_utils import substitute_deck_dict_ds_assets
153
153
  from src.utils.image_utils import substitute_deck_dict_images
154
154
 
155
155
  with get_db_session() as db:
156
156
  substitute_deck_dict_images(deck_dict, db)
157
- substitute_deck_dict_ds_assets(deck_dict, db)
158
157
 
159
158
 
160
159
  @router.post("")
@@ -469,6 +468,10 @@ async def get_session(session_id: str, db: Session = Depends(get_db)):
469
468
  # Check permission
470
469
  permission = _require_session_access(session, db, PermissionLevel.CAN_VIEW)
471
470
 
471
+ # Record deck-open usage event (deduped per user+deck, non-blocking)
472
+ if current_user:
473
+ record_deck_retrieved(current_user, session.get("id"))
474
+
472
475
  # Only the session creator sees chat messages — conversations are private
473
476
  is_creator = session.get("created_by") == current_user
474
477
  messages = []
@@ -1,14 +1,12 @@
1
1
  """Configuration API routes."""
2
2
  from src.api.routes.settings.contributors import router as contributors_router
3
3
  from src.api.routes.settings.deck_prompts import router as deck_prompts_router
4
- from src.api.routes.settings.design_systems import router as design_systems_router
5
4
  from src.api.routes.settings.identities import router as identities_router
6
5
  from src.api.routes.settings.slide_styles import router as slide_styles_router
7
6
 
8
7
  __all__ = [
9
8
  "contributors_router",
10
9
  "deck_prompts_router",
11
- "design_systems_router",
12
10
  "identities_router",
13
11
  "slide_styles_router",
14
12
  ]
@@ -59,14 +59,6 @@ class AgentConfig(BaseModel):
59
59
  """Agent configuration stored as JSON on sessions and profiles."""
60
60
  tools: list[ToolEntry] = Field(default_factory=list)
61
61
  slide_style_id: Optional[int] = None
62
- # A selected design system compiles to prompt text and, when set, takes
63
- # precedence over slide_style_id (see agent_factory._get_prompt_content).
64
- design_system_id: Optional[int] = None
65
- # Optionally pins ONE of the selected design system's templates
66
- # (design_system_template.id). Meaningful only alongside design_system_id;
67
- # generation IGNORES it (with a log) unless the template exists and belongs
68
- # to that design system, so a stale pin can never fail a request.
69
- template_id: Optional[int] = None
70
62
  deck_prompt_id: Optional[int] = None
71
63
  system_prompt: Optional[str] = None
72
64
  slide_editing_instructions: Optional[str] = None
@@ -35,10 +35,6 @@ from src.utils.html_utils import (
35
35
  extract_canvas_ids_from_html,
36
36
  split_script_by_canvas,
37
37
  )
38
- from src.utils.ds_asset_utils import (
39
- substitute_deck_dict_ds_assets,
40
- substitute_ds_asset_placeholders,
41
- )
42
38
  from src.utils.image_utils import substitute_deck_dict_images, substitute_image_placeholders
43
39
 
44
40
  logger = logging.getLogger(__name__)
@@ -87,13 +83,11 @@ class ChatService:
87
83
  logger.info("ChatService initialized successfully")
88
84
 
89
85
  def _substitute_images_for_response(self, deck_dict, raw_html=None):
90
- """Apply image + design-system asset substitution before sending to client.
86
+ """Apply image placeholder substitution before sending to client.
91
87
 
92
- Converts {{image:ID}} placeholders (image_assets) and {{ds-asset:ID}}
93
- placeholders (design_system_asset) to base64 data URIs in deck dicts and
94
- raw HTML. Called at API response boundaries so that stored/cached HTML
95
- keeps lightweight placeholders (avoiding LLM context bloat). The two
96
- namespaces are resolved independently.
88
+ Converts {{image:ID}} placeholders to base64 data URIs in deck dicts
89
+ and raw HTML. Called at API response boundaries so that stored/cached
90
+ HTML keeps lightweight placeholders (avoiding LLM context bloat).
97
91
  """
98
92
  from src.core.database import get_db_session
99
93
 
@@ -103,39 +97,12 @@ class ChatService:
103
97
  needs_html = raw_html and "{{image:" in raw_html
104
98
  needs_deck_html = deck_dict and deck_dict.get("html_content") and "{{image:" in deck_dict.get("html_content", "")
105
99
 
106
- # Design-system brand assets ({{ds-asset:ID}}) — parallel, orthogonal namespace.
107
- ds_needs_deck = deck_dict and any(
108
- "{{ds-asset:" in s.get("html", "") for s in deck_dict.get("slides", [])
109
- )
110
- ds_needs_html = raw_html and "{{ds-asset:" in raw_html
111
- ds_needs_deck_html = bool(
112
- deck_dict
113
- and deck_dict.get("html_content")
114
- and "{{ds-asset:" in deck_dict.get("html_content", "")
115
- )
116
- # @font-face src url() fonts and background-image url() live in the deck's
117
- # top-level ``css``, not in slide html — gate on it too, else a deck whose
118
- # only brand-asset reference is in css skips the resolver entirely
119
- # (substitute_deck_dict_ds_assets covers the css field).
120
- ds_needs_deck_css = bool(
121
- deck_dict
122
- and deck_dict.get("css")
123
- and "{{ds-asset:" in deck_dict.get("css", "")
124
- )
125
-
126
- if (
127
- needs_deck or needs_html or needs_deck_html
128
- or ds_needs_deck or ds_needs_html or ds_needs_deck_html or ds_needs_deck_css
129
- ):
100
+ if needs_deck or needs_html or needs_deck_html:
130
101
  with get_db_session() as db:
131
102
  if needs_deck or needs_deck_html:
132
103
  substitute_deck_dict_images(deck_dict, db)
133
104
  if needs_html:
134
105
  raw_html = substitute_image_placeholders(raw_html, db)
135
- if ds_needs_deck or ds_needs_deck_html or ds_needs_deck_css:
136
- substitute_deck_dict_ds_assets(deck_dict, db)
137
- if ds_needs_html:
138
- raw_html = substitute_ds_asset_placeholders(raw_html, db)
139
106
  return deck_dict, raw_html
140
107
 
141
108
  def _build_agent_for_session(
@@ -203,14 +203,12 @@ async def process_export_job(job_id: str, payload: dict) -> None:
203
203
  if not slide_deck or not slide_deck.get("slides"):
204
204
  raise ValueError("No slides available")
205
205
 
206
- # Substitute {{image:ID}} + {{ds-asset:ID}} placeholders with base64 data URIs
207
- # so the PPTX converter can extract and embed the actual images/brand assets
208
- from src.utils.ds_asset_utils import substitute_deck_dict_ds_assets
206
+ # Substitute {{image:ID}} placeholders with base64 data URIs
207
+ # so the PPTX converter can extract and embed the actual images
209
208
  from src.utils.image_utils import substitute_deck_dict_images
210
209
  from src.core.database import get_db_session
211
210
  with get_db_session() as db:
212
211
  substitute_deck_dict_images(slide_deck, db)
213
- substitute_deck_dict_ds_assets(slide_deck, db)
214
212
 
215
213
  slides = slide_deck.get("slides", [])
216
214
  total_slides = len(slides)