databricks-tellr-app 0.3.13.dev3__tar.gz → 0.3.13.dev11__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.13.dev3 → databricks_tellr_app-0.3.13.dev11}/PKG-INFO +1 -1
  2. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/databricks_tellr_app.egg-info/PKG-INFO +1 -1
  3. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/databricks_tellr_app.egg-info/SOURCES.txt +0 -14
  4. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/pyproject.toml +1 -1
  5. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/services/chat_service.py +75 -19
  6. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/services/export_job_queue.py +23 -10
  7. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/services/session_manager.py +27 -0
  8. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/google_slides_prompts_defaults.py +18 -28
  9. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/html_to_google_slides.py +185 -246
  10. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/html_to_pptx.py +453 -73
  11. databricks_tellr_app-0.3.13.dev3/src/services/converter_jail/__init__.py +0 -10
  12. databricks_tellr_app-0.3.13.dev3/src/services/converter_jail/ast_guard.py +0 -58
  13. databricks_tellr_app-0.3.13.dev3/src/services/converter_jail/codeprep.py +0 -220
  14. databricks_tellr_app-0.3.13.dev3/src/services/converter_jail/gslides_runner.py +0 -78
  15. databricks_tellr_app-0.3.13.dev3/src/services/converter_jail/jail.py +0 -230
  16. databricks_tellr_app-0.3.13.dev3/src/services/converter_jail/pptx_runner.py +0 -124
  17. databricks_tellr_app-0.3.13.dev3/src/services/converter_jail/protocol.py +0 -41
  18. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/README.md +0 -0
  19. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/databricks_tellr_app/__init__.py +0 -0
  20. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/databricks_tellr_app/run.py +0 -0
  21. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/databricks_tellr_app.egg-info/dependency_links.txt +0 -0
  22. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/databricks_tellr_app.egg-info/requires.txt +0 -0
  23. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/databricks_tellr_app.egg-info/top_level.txt +0 -0
  24. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/setup.cfg +0 -0
  25. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/setup.py +0 -0
  26. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/__init__.py +0 -0
  27. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/__init__.py +0 -0
  28. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/_otel_bootstrap.py +0 -0
  29. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/fixtures/tour_demo_deck.json +0 -0
  30. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/main.py +0 -0
  31. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/mcp_auth.py +0 -0
  32. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/mcp_server.py +0 -0
  33. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/middleware/__init__.py +0 -0
  34. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/middleware/request_logging.py +0 -0
  35. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/__init__.py +0 -0
  36. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/admin.py +0 -0
  37. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/admin_usage.py +0 -0
  38. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/agent_config.py +0 -0
  39. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/chat.py +0 -0
  40. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/deck_contributors.py +0 -0
  41. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/export.py +0 -0
  42. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/feedback.py +0 -0
  43. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/google_slides.py +0 -0
  44. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/images.py +0 -0
  45. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/local_version.py +0 -0
  46. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/profiles.py +0 -0
  47. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/sessions.py +0 -0
  48. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/settings/__init__.py +0 -0
  49. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/settings/contributors.py +0 -0
  50. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/settings/deck_prompts.py +0 -0
  51. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/settings/identities.py +0 -0
  52. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/settings/slide_styles.py +0 -0
  53. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/setup.py +0 -0
  54. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/slides.py +0 -0
  55. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/tools.py +0 -0
  56. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/tour.py +0 -0
  57. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/verification.py +0 -0
  58. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/version.py +0 -0
  59. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/schemas/__init__.py +0 -0
  60. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/schemas/agent_config.py +0 -0
  61. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/schemas/feedback.py +0 -0
  62. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/schemas/requests.py +0 -0
  63. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/schemas/responses.py +0 -0
  64. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/schemas/settings/__init__.py +0 -0
  65. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/schemas/settings/requests.py +0 -0
  66. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/schemas/settings/responses.py +0 -0
  67. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/schemas/streaming.py +0 -0
  68. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/services/__init__.py +0 -0
  69. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/services/feedback_service.py +0 -0
  70. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/services/job_queue.py +0 -0
  71. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/services/session_naming.py +0 -0
  72. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/services/usage_events.py +0 -0
  73. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/services/usage_service.py +0 -0
  74. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/utils/__init__.py +0 -0
  75. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/utils/validation.py +0 -0
  76. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/core/__init__.py +0 -0
  77. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/core/config_loader.py +0 -0
  78. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/core/context_utils.py +0 -0
  79. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/core/database.py +0 -0
  80. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/core/databricks_client.py +0 -0
  81. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/core/defaults.py +0 -0
  82. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/core/encryption.py +0 -0
  83. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/core/init_default_profile.py +0 -0
  84. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/core/lakebase.py +0 -0
  85. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/core/migrate_profiles_to_agent_config.py +0 -0
  86. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/core/mlflow_agent_spans.py +0 -0
  87. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/core/mlflow_tracing.py +0 -0
  88. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/core/otel_logging.py +0 -0
  89. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/core/permission_context.py +0 -0
  90. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/core/prompt_modules.py +0 -0
  91. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/core/settings_db.py +0 -0
  92. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/core/user_context.py +0 -0
  93. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/database/__init__.py +0 -0
  94. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/database/models/__init__.py +0 -0
  95. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/database/models/deck_contributor.py +0 -0
  96. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/database/models/feedback.py +0 -0
  97. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/database/models/genie_space.py +0 -0
  98. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/database/models/google_global_credentials.py +0 -0
  99. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/database/models/google_oauth_token.py +0 -0
  100. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/database/models/identity.py +0 -0
  101. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/database/models/image.py +0 -0
  102. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/database/models/profile.py +0 -0
  103. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/database/models/profile_contributor.py +0 -0
  104. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/database/models/prompts.py +0 -0
  105. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/database/models/request_log.py +0 -0
  106. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/database/models/session.py +0 -0
  107. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/database/models/slide_deck_prompt.py +0 -0
  108. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/database/models/slide_style_library.py +0 -0
  109. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/database/models/usage_event.py +0 -0
  110. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/database/models/user_preference.py +0 -0
  111. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/domain/__init__.py +0 -0
  112. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/domain/slide.py +0 -0
  113. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/domain/slide_deck.py +0 -0
  114. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/__init__.py +0 -0
  115. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/agent.py +0 -0
  116. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/agent_factory.py +0 -0
  117. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/config_service.py +0 -0
  118. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/config_validator.py +0 -0
  119. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/drive_uploader.py +0 -0
  120. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/evaluation/__init__.py +0 -0
  121. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/evaluation/llm_judge.py +0 -0
  122. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/genie_service.py +0 -0
  123. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/google_slides_auth.py +0 -0
  124. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/identity_provider.py +0 -0
  125. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/identity_providers/__init__.py +0 -0
  126. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/identity_providers/account_provider.py +0 -0
  127. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/identity_providers/local_provider.py +0 -0
  128. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/identity_providers/workspace_provider.py +0 -0
  129. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/image_service.py +0 -0
  130. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/image_tools.py +0 -0
  131. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/permission_service.py +0 -0
  132. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/pptx_from_html_huashu.py +0 -0
  133. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/pptx_from_records.py +0 -0
  134. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/pptx_prompts_defaults.py +0 -0
  135. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/profile_service.py +0 -0
  136. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/streaming_callback.py +0 -0
  137. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/tools/__init__.py +0 -0
  138. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/tools/agent_bricks_tool.py +0 -0
  139. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/tools/genie_tool.py +0 -0
  140. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/tools/mcp_tool.py +0 -0
  141. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/tools/model_endpoint_tool.py +0 -0
  142. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/tools/vector_tool.py +0 -0
  143. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/validator.py +0 -0
  144. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/utils/__init__.py +0 -0
  145. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/utils/css_utils.py +0 -0
  146. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/utils/error_handling.py +0 -0
  147. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/utils/html_safety.py +0 -0
  148. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/utils/html_utils.py +0 -0
  149. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/utils/image_utils.py +0 -0
  150. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/utils/js_validator.py +0 -0
  151. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/utils/logging_config.py +0 -0
  152. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/utils/pi_filter.py +0 -0
  153. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/utils/slide_hash.py +0 -0
  154. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/utils/spotlight.py +0 -0
  155. {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/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.13.dev3
3
+ Version: 0.3.13.dev11
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.13.dev3
3
+ Version: 0.3.13.dev11
4
4
  Summary: Tellr application package for Databricks Apps
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
@@ -115,13 +115,6 @@ setup.py
115
115
  ./src/services/profile_service.py
116
116
  ./src/services/streaming_callback.py
117
117
  ./src/services/validator.py
118
- ./src/services/converter_jail/__init__.py
119
- ./src/services/converter_jail/ast_guard.py
120
- ./src/services/converter_jail/codeprep.py
121
- ./src/services/converter_jail/gslides_runner.py
122
- ./src/services/converter_jail/jail.py
123
- ./src/services/converter_jail/pptx_runner.py
124
- ./src/services/converter_jail/protocol.py
125
118
  ./src/services/evaluation/__init__.py
126
119
  ./src/services/evaluation/llm_judge.py
127
120
  ./src/services/identity_providers/__init__.py
@@ -265,13 +258,6 @@ src/services/pptx_prompts_defaults.py
265
258
  src/services/profile_service.py
266
259
  src/services/streaming_callback.py
267
260
  src/services/validator.py
268
- src/services/converter_jail/__init__.py
269
- src/services/converter_jail/ast_guard.py
270
- src/services/converter_jail/codeprep.py
271
- src/services/converter_jail/gslides_runner.py
272
- src/services/converter_jail/jail.py
273
- src/services/converter_jail/pptx_runner.py
274
- src/services/converter_jail/protocol.py
275
261
  src/services/evaluation/__init__.py
276
262
  src/services/evaluation/llm_judge.py
277
263
  src/services/identity_providers/__init__.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.13.dev3"
7
+ version = "0.3.13.dev11"
8
8
  description = "Tellr application package for Databricks Apps"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -80,6 +80,11 @@ class ChatService:
80
80
  # This avoids re-parsing HTML on every request
81
81
  self._deck_cache: Dict[str, SlideDeck] = {}
82
82
 
83
+ # DB version each cached deck corresponds to. The cache is per-process
84
+ # while prod runs multiple uvicorn workers sharing one database, so a
85
+ # cache hit is only valid if the DB version hasn't moved on.
86
+ self._deck_cache_versions: Dict[str, int] = {}
87
+
83
88
  logger.info("ChatService initialized successfully")
84
89
 
85
90
  def _substitute_images_for_response(self, deck_dict, raw_html=None):
@@ -600,7 +605,7 @@ class ChatService:
600
605
  slide_deck_dict = current_deck.to_dict()
601
606
 
602
607
  try:
603
- session_manager.save_slide_deck(
608
+ save_result = session_manager.save_slide_deck(
604
609
  session_id=session_id,
605
610
  title=current_deck.title,
606
611
  html_content=current_deck.knit(),
@@ -610,6 +615,7 @@ class ChatService:
610
615
  modified_by=_user,
611
616
  expected_version=_deck_version_before_llm,
612
617
  )
618
+ self._record_deck_version(session_id, save_result)
613
619
  except VersionConflictError:
614
620
  logger.warning(
615
621
  "Chat save rejected: deck was edited during LLM call, reloading",
@@ -1385,7 +1391,7 @@ class ChatService:
1385
1391
  slide_deck_dict = current_deck.to_dict()
1386
1392
 
1387
1393
  try:
1388
- session_manager.save_slide_deck(
1394
+ save_result = session_manager.save_slide_deck(
1389
1395
  session_id=session_id,
1390
1396
  title=current_deck.title,
1391
1397
  html_content=current_deck.knit(),
@@ -1395,6 +1401,7 @@ class ChatService:
1395
1401
  modified_by=_user,
1396
1402
  expected_version=_deck_version_before_llm,
1397
1403
  )
1404
+ self._record_deck_version(session_id, save_result)
1398
1405
  except VersionConflictError:
1399
1406
  logger.warning(
1400
1407
  "Chat save rejected: deck was edited during LLM call, reloading",
@@ -1921,18 +1928,63 @@ class ChatService:
1921
1928
  context = "\n\n[Attached images]\n" + "\n".join(image_descriptions)
1922
1929
  return message + context
1923
1930
 
1931
+ def _deck_versions(self) -> Dict[str, int]:
1932
+ """Return the cached-deck version map, creating it if needed.
1933
+
1934
+ Lazy creation keeps instances built without __init__ (test harnesses
1935
+ use ChatService.__new__) working. Callers must hold _cache_lock.
1936
+ """
1937
+ try:
1938
+ return self._deck_cache_versions
1939
+ except AttributeError:
1940
+ self._deck_cache_versions = {}
1941
+ return self._deck_cache_versions
1942
+
1943
+ def _record_deck_version(self, session_id: str, save_result: Optional[Dict[str, Any]]) -> None:
1944
+ """Remember which DB version the cached deck now corresponds to.
1945
+
1946
+ Call after save_slide_deck so the next _get_or_load_deck cache hit
1947
+ validates cleanly instead of reloading from the database.
1948
+ """
1949
+ version = (save_result or {}).get("version")
1950
+ with self._cache_lock:
1951
+ if version is not None:
1952
+ self._deck_versions()[session_id] = version
1953
+ else:
1954
+ self._deck_versions().pop(session_id, None)
1955
+
1924
1956
  def _get_or_load_deck(self, session_id: str) -> Optional[SlideDeck]:
1925
1957
  """Get deck from cache or load from database.
1926
1958
 
1927
1959
  Thread-safe access to deck cache using _cache_lock.
1928
-
1960
+
1961
+ The cache is per-process while prod runs multiple uvicorn workers
1962
+ sharing one database, so a cached deck is only served if its recorded
1963
+ version matches the current DB version; otherwise it is reloaded.
1964
+
1929
1965
  Uses deck_dict (slides array with individual scripts) when available,
1930
1966
  falling back to from_html_string for legacy data.
1931
1967
  """
1932
1968
  # Check cache first (with lock)
1933
1969
  with self._cache_lock:
1934
- if session_id in self._deck_cache:
1935
- return self._deck_cache[session_id]
1970
+ cached_deck = self._deck_cache.get(session_id)
1971
+ cached_version = self._deck_versions().get(session_id)
1972
+
1973
+ if cached_deck is not None:
1974
+ db_version = self._get_deck_version(session_id)
1975
+ if db_version is None or cached_version == db_version:
1976
+ return cached_deck
1977
+ logger.info(
1978
+ "Deck cache stale, reloading from database",
1979
+ extra={
1980
+ "session_id": session_id,
1981
+ "cached_version": cached_version,
1982
+ "db_version": db_version,
1983
+ },
1984
+ )
1985
+ with self._cache_lock:
1986
+ self._deck_cache.pop(session_id, None)
1987
+ self._deck_versions().pop(session_id, None)
1936
1988
 
1937
1989
  # Try to load from database (outside lock to avoid blocking)
1938
1990
  session_manager = get_session_manager()
@@ -1966,6 +2018,10 @@ class ChatService:
1966
2018
  # Store in cache (with lock)
1967
2019
  with self._cache_lock:
1968
2020
  self._deck_cache[session_id] = deck
2021
+ if deck_data.get("version") is not None:
2022
+ self._deck_versions()[session_id] = deck_data["version"]
2023
+ else:
2024
+ self._deck_versions().pop(session_id, None)
1969
2025
  return deck
1970
2026
  except Exception as e:
1971
2027
  logger.warning(f"Failed to load deck from database: {e}")
@@ -1975,23 +2031,18 @@ class ChatService:
1975
2031
  def _get_deck_version(self, session_id: str) -> Optional[int]:
1976
2032
  """Read the current deck version from the database.
1977
2033
 
1978
- Called once before the LLM runs to capture the version for
1979
- optimistic locking. Uses the existing get_slide_deck which
1980
- returns the full deck dict including the version column.
1981
-
1982
- On Lakebase/PostgreSQL this is a single-row indexed lookup (~1-2ms).
2034
+ Used on every deck-cache hit (multi-worker cache validation) and
2035
+ before LLM calls (optimistic locking), so it must stay cheap: a
2036
+ single-column indexed lookup, never a full deck fetch.
1983
2037
 
1984
2038
  Returns:
1985
2039
  Current deck version number, or None if no deck exists.
1986
2040
  """
1987
2041
  session_manager = get_session_manager()
1988
2042
  try:
1989
- deck_data = session_manager.get_slide_deck(session_id)
1990
- if deck_data:
1991
- return deck_data.get("version")
2043
+ return session_manager.get_slide_deck_version(session_id)
1992
2044
  except Exception:
1993
- pass
1994
- return None
2045
+ return None
1995
2046
 
1996
2047
  @staticmethod
1997
2048
  def _reindex_slide_ids(deck: "SlideDeck") -> None:
@@ -2008,6 +2059,7 @@ class ChatService:
2008
2059
  """Remove the cached deck for a session so the next read hits the DB."""
2009
2060
  with self._cache_lock:
2010
2061
  self._deck_cache.pop(session_id, None)
2062
+ self._deck_versions().pop(session_id, None)
2011
2063
 
2012
2064
  def _replace_slide_htmls_from_cache(self, session_id: str, slide_context: Dict[str, Any]) -> Dict[str, Any]:
2013
2065
  """Replace frontend-supplied slide_htmls with backend cache versions.
@@ -2540,7 +2592,7 @@ class ChatService:
2540
2592
  # Persist to database
2541
2593
  deck_dict = current_deck.to_dict()
2542
2594
  session_manager = get_session_manager()
2543
- session_manager.save_slide_deck(
2595
+ save_result = session_manager.save_slide_deck(
2544
2596
  session_id=session_id,
2545
2597
  title=current_deck.title,
2546
2598
  html_content=current_deck.knit(),
@@ -2549,6 +2601,7 @@ class ChatService:
2549
2601
  deck_dict=deck_dict,
2550
2602
  expected_version=expected_version,
2551
2603
  )
2604
+ self._record_deck_version(session_id, save_result)
2552
2605
 
2553
2606
  # Create save point
2554
2607
  try:
@@ -2616,7 +2669,7 @@ class ChatService:
2616
2669
  # Persist to database
2617
2670
  deck_dict = current_deck.to_dict()
2618
2671
  session_manager = get_session_manager()
2619
- session_manager.save_slide_deck(
2672
+ save_result = session_manager.save_slide_deck(
2620
2673
  session_id=session_id,
2621
2674
  title=current_deck.title,
2622
2675
  html_content=current_deck.knit(),
@@ -2625,6 +2678,7 @@ class ChatService:
2625
2678
  deck_dict=deck_dict,
2626
2679
  expected_version=expected_version,
2627
2680
  )
2681
+ self._record_deck_version(session_id, save_result)
2628
2682
 
2629
2683
  # Create save point immediately after persisting
2630
2684
  try:
@@ -2681,7 +2735,7 @@ class ChatService:
2681
2735
  # Persist to database
2682
2736
  deck_dict = current_deck.to_dict()
2683
2737
  session_manager = get_session_manager()
2684
- session_manager.save_slide_deck(
2738
+ save_result = session_manager.save_slide_deck(
2685
2739
  session_id=session_id,
2686
2740
  title=current_deck.title,
2687
2741
  html_content=current_deck.knit(),
@@ -2690,6 +2744,7 @@ class ChatService:
2690
2744
  deck_dict=deck_dict,
2691
2745
  expected_version=expected_version,
2692
2746
  )
2747
+ self._record_deck_version(session_id, save_result)
2693
2748
 
2694
2749
  # Create save point
2695
2750
  try:
@@ -2744,7 +2799,7 @@ class ChatService:
2744
2799
  # Persist to database
2745
2800
  deck_dict = current_deck.to_dict()
2746
2801
  session_manager = get_session_manager()
2747
- session_manager.save_slide_deck(
2802
+ save_result = session_manager.save_slide_deck(
2748
2803
  session_id=session_id,
2749
2804
  title=current_deck.title,
2750
2805
  html_content=current_deck.knit(),
@@ -2753,6 +2808,7 @@ class ChatService:
2753
2808
  deck_dict=deck_dict,
2754
2809
  expected_version=expected_version,
2755
2810
  )
2811
+ self._record_deck_version(session_id, save_result)
2756
2812
 
2757
2813
  # Create save point
2758
2814
  try:
@@ -307,6 +307,9 @@ async def convert_slides_with_progress(
307
307
  output_path: Path to save PPTX
308
308
  chart_images_per_slide: Chart images per slide
309
309
  """
310
+ from pptx import Presentation
311
+ from pptx.util import Inches
312
+
310
313
  total_slides = len(slides_html)
311
314
 
312
315
  # -- Phase 1: Prepare assets + parallel LLM code generation ---------------
@@ -333,17 +336,27 @@ async def convert_slides_with_progress(
333
336
  slide_inputs, on_codegen_progress=_on_codegen_progress,
334
337
  )
335
338
 
336
- # -- Phase 2: Sequential execution INSIDE the subprocess jail -------------
337
- def _relay(current: int, total: int, message: str) -> None:
338
- update_export_progress(job_id, current, total, status_message=message)
339
+ # -- Phase 2: Sequential execution ----------------------------------------
340
+ prs = Presentation()
341
+ prs.slide_width = Inches(10)
342
+ prs.slide_height = Inches(7.5)
339
343
 
340
- # to_thread: keep the long blocking jail wait off the event loop (this
341
- # coroutine runs on the loop; _relay is fired from the jail's stdout
342
- # reader thread and update_export_progress opens its own session per call).
343
- await asyncio.to_thread(
344
- converter._run_pptx_conversion,
345
- codes, slide_inputs, output_path, progress_cb=_relay,
346
- )
344
+ for i, (code, (html_str, _chart_files, _content_files, assets_dir)) in enumerate(
345
+ zip(codes, slide_inputs), 1,
346
+ ):
347
+ update_export_progress(
348
+ job_id, i, total_slides,
349
+ status_message=f"Building slide {i}/{total_slides}…",
350
+ )
351
+
352
+ converter._execute_slide(code, prs, html_str, assets_dir, i)
353
+
354
+ logger.debug(
355
+ f"Processed slide {i}/{total_slides}",
356
+ extra={"job_id": job_id, "slide": i, "total": total_slides},
357
+ )
358
+
359
+ prs.save(output_path)
347
360
 
348
361
 
349
362
  async def export_worker() -> None:
@@ -723,6 +723,33 @@ class SessionManager:
723
723
  "version": deck.version,
724
724
  }
725
725
 
726
+ def get_slide_deck_version(self, session_id: str) -> Optional[int]:
727
+ """Return only the deck's current version number.
728
+
729
+ Selects a single column — no deck_json parse, verification merge, or
730
+ display-name resolution — so it is cheap enough to run on every
731
+ deck-cache hit (multi-worker cache validation) and before LLM calls
732
+ (optimistic locking).
733
+
734
+ Args:
735
+ session_id: Session to check (contributor sessions resolve to the
736
+ owner's deck)
737
+
738
+ Returns:
739
+ Current version number, or None if the session/deck doesn't exist
740
+ """
741
+ with get_db_session() as db:
742
+ try:
743
+ session = self._get_session_or_raise(db, session_id)
744
+ except SessionNotFoundError:
745
+ return None
746
+ deck_owner = self._get_deck_owner_session(db, session)
747
+ return (
748
+ db.query(SessionSlideDeck.version)
749
+ .filter(SessionSlideDeck.session_id == deck_owner.id)
750
+ .scalar()
751
+ )
752
+
726
753
  def get_slide_deck(self, session_id: str) -> Optional[Dict[str, Any]]:
727
754
  """Get slide deck for a session with verification merged by content hash.
728
755
 
@@ -69,9 +69,8 @@ TWO-COLUMN LAYOUT (.two-column):
69
69
  - Left: left=0.4", width=4.3"; Right: left=5.0", width=4.5"; Gap: 0.3"
70
70
 
71
71
  TABLES (<table>):
72
- - createTable first (rows, cols, size, position), with an explicit objectId
73
- - AFTER it in the returned list: insertText per cell + updateTextStyle + updateTableCellProperties
74
- (the host executes requests in order, so the table exists before its cells are filled)
72
+ - createTable in FIRST batchUpdate (rows, cols, size, position)
73
+ - Then insertText per cell + updateTextStyle + updateTableCellProperties in SECOND batchUpdate
75
74
  - updateTableCellProperties requires: 'tableRange': {'location': {'rowIndex': r, 'columnIndex': c}, 'rowSpan': 1, 'columnSpan': 1}
76
75
  - Headers: background from CSS (typically dark), text white, font 8pt bold
77
76
  - Cells: font 7-8pt, preserve colors, left-align text, right-align numbers
@@ -108,22 +107,17 @@ REGULAR SLIDES:
108
107
  Subtitle must fit in 0.28" (10pt ≈ 0.14" per line → 2 lines max).
109
108
 
110
109
  CHARTS (CRITICAL):
111
- - If chart images are listed in the user message, you MUST reference them by
112
- placeholder — do NOT upload anything, do NOT call any Google API.
113
- - For each chart image `filename` in assets_dir, add a createImage request with
114
- url set to the placeholder 'tellr-asset://' + filename. The host uploads the
115
- file to Drive and substitutes the real URL before execution.
116
- Example: {'createImage': {'objectId': 'img_' + str(uuid.uuid4())[:8],
117
- 'url': 'tellr-asset://' + filename,
118
- 'elementProperties': {'pageObjectId': page_id, 'size': {...}, 'transform': {...}}}}
110
+ - If chart images are listed in the user message, you MUST use them as pre-captured screenshots.
119
111
  - Do NOT recreate charts with matplotlib, plotly, or any library. The images are already rendered.
112
+ - Upload to Drive via MediaFileUpload, set anyone/reader permission, then createImage.
120
113
  - Chart only (no metric cards): left=0.4", top=1.1", width=9.0", height=4.0" — fills the body zone.
121
114
  - Chart + metrics: use CHART + METRICS SIDE-BY-SIDE layout above.
122
115
  - If NO chart images are listed, skip chart rendering entirely — do not attempt to recreate.
123
116
 
124
117
  CONTENT IMAGES (logos, icons — CRITICAL):
125
- - Reference each content image the same way: url = 'tellr-asset://' + filename.
126
- - NEVER upload; NEVER create Drive files or set permissions yourself. The host does that.
118
+ - If content images are listed in the user message, you MUST upload and add them to the slide.
119
+ - These are pre-extracted image files (PNG) saved in assets_dir — ready to upload.
120
+ - Upload to Drive the same way as charts: MediaFileUpload → files().create → permissions().create → createImage.
127
121
  - Position to match the HTML layout (e.g. a logo in the top-right header area → right-aligned near the title).
128
122
  - Typical logo sizes: width=0.6"-1.0", height=0.3"-0.5". Do NOT make logos larger than needed.
129
123
  - Place logos/icons in the header zone (top=0.15"-0.4") so they don't overlap body content.
@@ -171,27 +165,23 @@ API PATTERNS (CRITICAL — wrong nesting causes 400 errors):
171
165
 
172
166
  ALLOWED IMPORTS:
173
167
  import os, json, uuid, re
174
- (Do NOT import googleapiclient — you never touch the network.)
168
+ from googleapiclient.http import MediaFileUpload # ONLY when uploading images
175
169
 
176
170
  EXECUTION:
177
171
  - ALL code MUST be inside the function body. Nothing at module level except imports and helpers.
178
- - Build ONE requests list and RETURN it. Never call batchUpdate or any API
179
- yourself — the host executes the returned requests in order.
180
- - Do NOT wrap request-building in try/except.
172
+ - Build requests list, then ONE batchUpdate (except tables need two).
173
+ - Do NOT wrap batchUpdate in try/except.
181
174
  - Every createShape needs a unique objectId: 'txt_' + str(uuid.uuid4())[:8]
182
175
 
183
176
  Return ONLY Python code, no markdown fences."""
184
177
 
185
178
  # ── Multi-slide prompts ──────────────────────────────────────────────
186
179
 
187
- DEFAULT_GSLIDES_SYSTEM_PROMPT = """Generate Python code with a build_slide_requests(html_str, assets_dir, page_id) function that RETURNS a list of Google Slides batchUpdate request dicts.
180
+ DEFAULT_GSLIDES_SYSTEM_PROMPT = """Generate Python code with add_slide_to_presentation(slides_service, drive_service, presentation_id, page_id, html_str, assets_dir) function.
188
181
 
189
182
  CONTEXT:
190
- - You do NOT have and do NOT need any Google service objects or network access.
191
- - Do NOT call batchUpdate or any other Google API method — never execute requests, upload files, or create permissions yourself.
192
- - The target slide page already exists; reference it via the page_id argument.
193
- - Return (do not execute) a Python list of request dicts. The trusted host
194
- executes them, uploads any referenced images, and handles chunking/retries.
183
+ - All arguments are pre-created. Do NOT import googleapiclient or build services.
184
+ - The slide page already exists (page_id). Do NOT call createSlide — only add content.
195
185
 
196
186
  HELPERS (include in your code):
197
187
  def emu(inches): return int(inches * 914400)
@@ -202,22 +192,22 @@ def hex_to_rgb(h):
202
192
  SLIDE: 16:9 widescreen — 10" × 5.625" (9144000 × 5143500 EMU).
203
193
  Bounds: left ≥ 0.4", top ≥ 0.2", left + width ≤ 9.6", top + height ≤ 5.4"
204
194
 
205
- ELEMENT CREATION (append each request dict to a list, then `return requests`):
206
- - TEXT_BOX: createShape + insertText + updateTextStyle (textRange {'type':'ALL'}) + updateParagraphStyle
195
+ ELEMENT CREATION:
196
+ - TEXT_BOX: createShape + insertText + updateTextStyle (textRange: {'type':'ALL'}) + updateParagraphStyle
207
197
  - RECTANGLE/ROUND_RECTANGLE: createShape + updateShapeProperties
208
198
  - Size: {'width': {'magnitude': emu(w), 'unit': 'EMU'}, 'height': {'magnitude': emu(h), 'unit': 'EMU'}}
209
199
  - Position: {'scaleX':1,'scaleY':1,'translateX':emu(left),'translateY':emu(top),'unit':'EMU'}
210
200
 
211
- The code MUST define build_slide_requests(html_str, assets_dir, page_id) and RETURN the requests list.
201
+ The code MUST define the function add_slide_to_presentation.
212
202
  """ + _GSLIDES_SHARED_RULES
213
203
 
214
- DEFAULT_GSLIDES_USER_PROMPT = """Convert the HTML below to a list of Google Slides batchUpdate requests.
204
+ DEFAULT_GSLIDES_USER_PROMPT = """Convert the HTML below to a Google Slide.
215
205
 
216
206
  {html_content}
217
207
 
218
208
  {screenshot_note}
219
209
 
220
- Return Python code defining build_slide_requests(html_str, assets_dir, page_id) that returns the requests list."""
210
+ Return Python code with add_slide_to_presentation(slides_service, drive_service, presentation_id, page_id, html_str, assets_dir)."""
221
211
 
222
212
  # ── Single-slide prompts ─────────────────────────────────────────────
223
213