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.
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/PKG-INFO +1 -1
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/databricks_tellr_app.egg-info/PKG-INFO +1 -1
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/databricks_tellr_app.egg-info/SOURCES.txt +0 -14
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/pyproject.toml +1 -1
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/services/chat_service.py +75 -19
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/services/export_job_queue.py +23 -10
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/services/session_manager.py +27 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/google_slides_prompts_defaults.py +18 -28
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/html_to_google_slides.py +185 -246
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/html_to_pptx.py +453 -73
- databricks_tellr_app-0.3.13.dev3/src/services/converter_jail/__init__.py +0 -10
- databricks_tellr_app-0.3.13.dev3/src/services/converter_jail/ast_guard.py +0 -58
- databricks_tellr_app-0.3.13.dev3/src/services/converter_jail/codeprep.py +0 -220
- databricks_tellr_app-0.3.13.dev3/src/services/converter_jail/gslides_runner.py +0 -78
- databricks_tellr_app-0.3.13.dev3/src/services/converter_jail/jail.py +0 -230
- databricks_tellr_app-0.3.13.dev3/src/services/converter_jail/pptx_runner.py +0 -124
- databricks_tellr_app-0.3.13.dev3/src/services/converter_jail/protocol.py +0 -41
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/README.md +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/databricks_tellr_app/__init__.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/databricks_tellr_app/run.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/databricks_tellr_app.egg-info/dependency_links.txt +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/databricks_tellr_app.egg-info/requires.txt +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/databricks_tellr_app.egg-info/top_level.txt +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/setup.cfg +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/setup.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/__init__.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/__init__.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/_otel_bootstrap.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/fixtures/tour_demo_deck.json +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/main.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/mcp_auth.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/mcp_server.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/middleware/__init__.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/middleware/request_logging.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/__init__.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/admin.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/admin_usage.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/agent_config.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/chat.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/deck_contributors.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/export.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/feedback.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/google_slides.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/images.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/local_version.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/profiles.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/sessions.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/settings/__init__.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/settings/contributors.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/settings/deck_prompts.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/settings/identities.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/settings/slide_styles.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/setup.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/slides.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/tools.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/tour.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/verification.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/routes/version.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/schemas/__init__.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/schemas/agent_config.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/schemas/feedback.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/schemas/requests.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/schemas/responses.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/schemas/settings/__init__.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/schemas/settings/requests.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/schemas/settings/responses.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/schemas/streaming.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/services/__init__.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/services/feedback_service.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/services/job_queue.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/services/session_naming.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/services/usage_events.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/services/usage_service.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/utils/__init__.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/api/utils/validation.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/core/__init__.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/core/config_loader.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/core/context_utils.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/core/database.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/core/databricks_client.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/core/defaults.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/core/encryption.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/core/init_default_profile.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/core/lakebase.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/core/migrate_profiles_to_agent_config.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/core/mlflow_agent_spans.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/core/mlflow_tracing.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/core/otel_logging.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/core/permission_context.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/core/prompt_modules.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/core/settings_db.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/core/user_context.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/database/__init__.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/database/models/__init__.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/database/models/deck_contributor.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/database/models/feedback.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/database/models/genie_space.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/database/models/google_global_credentials.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/database/models/google_oauth_token.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/database/models/identity.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/database/models/image.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/database/models/profile.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/database/models/profile_contributor.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/database/models/prompts.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/database/models/request_log.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/database/models/session.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/database/models/slide_deck_prompt.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/database/models/slide_style_library.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/database/models/usage_event.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/database/models/user_preference.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/domain/__init__.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/domain/slide.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/domain/slide_deck.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/__init__.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/agent.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/agent_factory.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/config_service.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/config_validator.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/drive_uploader.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/evaluation/__init__.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/evaluation/llm_judge.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/genie_service.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/google_slides_auth.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/identity_provider.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/identity_providers/__init__.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/identity_providers/account_provider.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/identity_providers/local_provider.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/identity_providers/workspace_provider.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/image_service.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/image_tools.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/permission_service.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/pptx_from_html_huashu.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/pptx_from_records.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/pptx_prompts_defaults.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/profile_service.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/streaming_callback.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/tools/__init__.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/tools/agent_bricks_tool.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/tools/genie_tool.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/tools/mcp_tool.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/tools/model_endpoint_tool.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/tools/vector_tool.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/services/validator.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/utils/__init__.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/utils/css_utils.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/utils/error_handling.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/utils/html_safety.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/utils/html_utils.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/utils/image_utils.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/utils/js_validator.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/utils/logging_config.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/utils/pi_filter.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/utils/slide_hash.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/utils/spotlight.py +0 -0
- {databricks_tellr_app-0.3.13.dev3 → databricks_tellr_app-0.3.13.dev11}/src/utils/text_caps.py +0 -0
|
@@ -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
|
|
@@ -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
|
-
|
|
1935
|
-
|
|
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
|
-
|
|
1979
|
-
optimistic locking
|
|
1980
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
337
|
-
|
|
338
|
-
|
|
339
|
+
# -- Phase 2: Sequential execution ----------------------------------------
|
|
340
|
+
prs = Presentation()
|
|
341
|
+
prs.slide_width = Inches(10)
|
|
342
|
+
prs.slide_height = Inches(7.5)
|
|
339
343
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
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
|
|
73
|
-
-
|
|
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
|
|
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
|
-
-
|
|
126
|
-
-
|
|
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
|
-
|
|
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
|
|
179
|
-
|
|
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
|
|
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
|
-
-
|
|
191
|
-
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|