pulse-engine 0.2.43__tar.gz → 0.2.44__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.
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/PKG-INFO +1 -1
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/pyproject.toml +1 -1
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/adapters/youtube_downloader.py +104 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/README.md +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/__init__.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/adapters/__init__.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/adapters/audio_transcription.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/adapters/batcher.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/adapters/digital_news.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/adapters/digital_news_metadata.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/adapters/document_event_campaign_mapper.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/adapters/exceptions.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/adapters/google_sheets.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/adapters/mart_export.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/adapters/models.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/adapters/opensearch_sql.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/adapters/opensearch_storage.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/adapters/prompts.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/adapters/report_generator.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/adapters/speech_content.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/adapters/speech_metadata.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/adapters/transcription/__init__.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/adapters/transcription/base.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/adapters/transcription/config.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/adapters/transcription/factory.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/adapters/transcription/providers/__init__.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/adapters/transcription/providers/deepgram.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/adapters/transcription/providers/openai_whisper.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/adapters/transcription/providers/selfhosted_job.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/adapters/transcription/providers/youtube_captions.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/adapters/transcription/service.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/adapters/transcription/source.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/adapters/twitter.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/adapters/youtube_metadata.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/api/__init__.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/api/v1/__init__.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/api/v1/auth.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/api/v1/health.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/api/v1/router.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/cli/__init__.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/cli/main.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/cli/templates/cookiecutter.json +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/cli/templates/pulse-{{cookiecutter.product_name}}/.gitignore +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/cli/templates/pulse-{{cookiecutter.product_name}}/Dockerfile +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/cli/templates/pulse-{{cookiecutter.product_name}}/pipeline.yaml +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/cli/templates/pulse-{{cookiecutter.product_name}}/pyproject.toml +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/cli/templates/pulse-{{cookiecutter.product_name}}/src/pulse_{{cookiecutter.product_slug}}/__init__.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/cli/templates/pulse-{{cookiecutter.product_name}}/tests/__init__.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/cli/templates/pulse-{{cookiecutter.product_name}}/tests/unit/__init__.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/cli/templates/pulse-{{cookiecutter.product_name}}/tests/unit/test_manifest.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/client.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/config.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/core/__init__.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/core/error_handlers.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/core/exceptions.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/core/job_token.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/core/logging.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/core/scope.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/core/security.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/cron/__init__.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/cron/models.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/cron/pipeline_sync.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/cron/repository.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/cron/router.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/cron/runner.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/cron/schemas.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/cron/service.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/cron/tasks.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/cron/translator.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/database.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/dependencies.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/deployment/__init__.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/deployment/infra_provisioner.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/evolution/__init__.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/evolution/adapter.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/evolution/client.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/evolution/models.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/evolution/router.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/evolution/service.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/extractor/__init__.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/extractor/adapters/__init__.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/extractor/base.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/main.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/mcp/__init__.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/mcp/__main__.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/mcp/server.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/mcp/tools_kb.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/mcp/tools_modules.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/mcp/tools_pipelines.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/mcp/tools_processor.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/middleware/__init__.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/middleware/rate_limit.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/middleware/request_id.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/middleware/security_headers.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/middleware/tenant.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/notifications/__init__.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/notifications/apprise_notifier.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/pipeline/__init__.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/pipeline/config_parser.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/pipeline/expression.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/pipeline/models.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/pipeline/repositories.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/pipeline/router_modules.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/pipeline/router_pipelines.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/pipeline/schemas.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/pipeline/service.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/pipeline/translators/__init__.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/pipeline/translators/airflow_status.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/pipeline/translators/airflow_translator.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/pipeline/translators/base.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/pipeline/translators/prefect_status.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/pipeline/translators/prefect_translator.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/processor/__init__.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/processor/base.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/processor/core/__init__.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/processor/core/analysis.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/processor/core/chunking.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/processor/core/prompts.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/processor/core/topic_splitter.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/processor/defaults/__init__.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/processor/defaults/core_processor.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/processor/defaults/postprocessor.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/processor/defaults/preprocessor.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/processor/llm/__init__.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/processor/llm/provider.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/processor/ocr/gemini.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/processor/pipeline.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/processor/postprocessor/__init__.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/processor/postprocessor/embeddings.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/processor/postprocessor/tasks.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/processor/preprocessor/__init__.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/processor/preprocessor/tasks.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/processor/router.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/processor/schemas.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/registry.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/reporting/__init__.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/reporting/agent.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/reporting/fixtures.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/reporting/models.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/reporting/prompts.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/reporting/service.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/reporting/staging.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/reporting/tools.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/reporting/validation.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/reporting/wiring.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/runners/__init__.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/runners/lambda_runner.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/runners/pipeline_runner.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/runners/prefect_pipeline_flow.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/runners/prefect_runner.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/s3.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/sandbox/__init__.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/sandbox/backend.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/sandbox/lambda_microvm.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/sandbox/microvm_agent/Dockerfile +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/sandbox/microvm_agent/__init__.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/sandbox/microvm_agent/server.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/sandbox/session.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/secrets.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/services/__init__.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/services/bootstrap.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/services/opensearch.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/skills/__init__.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/skills/catalog.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/skills/models.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/skills/repo.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/skills/seed.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/skills/seed_data/skill_files.json +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/skills/seed_data/skills.json +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/skills/sync.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/skills/tools.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/storage/__init__.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/storage/connectors/__init__.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/storage/connectors/athena.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/storage/connectors/base.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/storage/connectors/opensearch.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/storage/knowledge_base.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/storage/router.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/storage/schemas.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/testing/__init__.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/testing/fixtures.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/testing/mocks.py +0 -0
- {pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/worker.py +0 -0
|
@@ -207,10 +207,114 @@ class YouTubeDownloader:
|
|
|
207
207
|
path=path, used_proxy=used_proxy, used_cookies=used_cookies, error=error
|
|
208
208
|
)
|
|
209
209
|
|
|
210
|
+
async def has_captions(
|
|
211
|
+
self, video_id: str, *, languages: list[str] | None = None
|
|
212
|
+
) -> bool:
|
|
213
|
+
"""Whether YouTube holds captions for *video_id*, without downloading anything.
|
|
214
|
+
|
|
215
|
+
For a caller that stages audio only so transcription has something to fall back
|
|
216
|
+
on, this is the question worth asking first: a video with captions does not need
|
|
217
|
+
its audio pulled at all, and the pull is the expensive part.
|
|
218
|
+
|
|
219
|
+
Cheap by construction — `process=False` skips format resolution, so this is
|
|
220
|
+
one metadata call. The same direct → proxy → cookies escalation as `download`
|
|
221
|
+
applies: a bot-gated probe reports "no captions" rather than failing, and a
|
|
222
|
+
false negative costs a download rather than losing data.
|
|
223
|
+
|
|
224
|
+
`languages` narrows the question: only those codes count. A bare prefix match,
|
|
225
|
+
so "en" accepts "en-GB". Manual and automatic captions both count — the caller
|
|
226
|
+
decides what is good enough by whether it allows auto captions downstream.
|
|
227
|
+
|
|
228
|
+
Returns False when every attempt fails. That is the safe direction: the
|
|
229
|
+
caller downloads audio it might not have needed, rather than skipping audio
|
|
230
|
+
it did.
|
|
231
|
+
"""
|
|
232
|
+
manual, auto = await self._list_captions(
|
|
233
|
+
video_id, use_proxy=False, use_cookies=False
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
if manual is None and self._proxy_configured:
|
|
237
|
+
logger.info("youtube_captions_probe_retry_with_proxy", video_id=video_id)
|
|
238
|
+
manual, auto = await self._list_captions(
|
|
239
|
+
video_id, use_proxy=True, use_cookies=False
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
if manual is None and self._proxy_configured and self._cookies_secret_id:
|
|
243
|
+
logger.info("youtube_captions_probe_retry_with_cookies", video_id=video_id)
|
|
244
|
+
manual, auto = await self._list_captions(
|
|
245
|
+
video_id, use_proxy=True, use_cookies=True
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
if manual is None:
|
|
249
|
+
logger.warning("youtube_captions_probe_failed", video_id=video_id)
|
|
250
|
+
return False
|
|
251
|
+
|
|
252
|
+
found = sorted(set(manual) | set(auto or []))
|
|
253
|
+
if languages:
|
|
254
|
+
wanted = [code.strip().lower() for code in languages if code.strip()]
|
|
255
|
+
found = [
|
|
256
|
+
code
|
|
257
|
+
for code in found
|
|
258
|
+
if any(code.lower().startswith(want) for want in wanted)
|
|
259
|
+
]
|
|
260
|
+
|
|
261
|
+
logger.info("youtube_captions_probe", video_id=video_id, available=len(found))
|
|
262
|
+
return bool(found)
|
|
263
|
+
|
|
210
264
|
# ------------------------------------------------------------------
|
|
211
265
|
# Private helpers
|
|
212
266
|
# ------------------------------------------------------------------
|
|
213
267
|
|
|
268
|
+
async def _list_captions(
|
|
269
|
+
self, video_id: str, *, use_proxy: bool, use_cookies: bool
|
|
270
|
+
) -> tuple[list[str] | None, list[str] | None]:
|
|
271
|
+
"""(manual, automatic) caption languages, or (None, None) if the probe failed.
|
|
272
|
+
|
|
273
|
+
None is distinct from an empty list: one means the probe could not run, the
|
|
274
|
+
other means it ran and the video has no captions.
|
|
275
|
+
"""
|
|
276
|
+
import tempfile
|
|
277
|
+
|
|
278
|
+
with tempfile.TemporaryDirectory() as tmp_dir:
|
|
279
|
+
opts = _build_yt_dlp_opts(
|
|
280
|
+
output_template=str(Path(tmp_dir) / "%(id)s.%(ext)s"),
|
|
281
|
+
extra={"skip_download": True},
|
|
282
|
+
use_proxy=use_proxy,
|
|
283
|
+
)
|
|
284
|
+
if use_cookies:
|
|
285
|
+
cookies = await self._resolve_cookies()
|
|
286
|
+
if cookies:
|
|
287
|
+
cookies_path = Path(tmp_dir) / "cookies.txt"
|
|
288
|
+
cookies_path.write_text(cookies, encoding="utf-8")
|
|
289
|
+
cookies_path.chmod(0o600)
|
|
290
|
+
opts["cookiefile"] = str(cookies_path)
|
|
291
|
+
|
|
292
|
+
def _probe() -> tuple[list[str] | None, list[str] | None]:
|
|
293
|
+
import yt_dlp as _yt
|
|
294
|
+
|
|
295
|
+
url = f"https://www.youtube.com/watch?v={video_id}"
|
|
296
|
+
try:
|
|
297
|
+
with _yt.YoutubeDL(opts) as ydl:
|
|
298
|
+
# process=False keeps this to one metadata call: subtitle keys
|
|
299
|
+
# are populated before format processing, and format resolution
|
|
300
|
+
# is what fails on restricted format sets from datacentre IPs.
|
|
301
|
+
info = (
|
|
302
|
+
ydl.extract_info(url, download=False, process=False) or {}
|
|
303
|
+
)
|
|
304
|
+
except Exception as exc: # noqa: BLE001 — reported, not raised
|
|
305
|
+
logger.info(
|
|
306
|
+
"youtube_captions_probe_attempt_failed",
|
|
307
|
+
video_id=video_id,
|
|
308
|
+
error=str(exc)[:200],
|
|
309
|
+
)
|
|
310
|
+
return None, None
|
|
311
|
+
return (
|
|
312
|
+
list((info.get("subtitles") or {}).keys()),
|
|
313
|
+
list((info.get("automatic_captions") or {}).keys()),
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
return await asyncio.to_thread(_probe)
|
|
317
|
+
|
|
214
318
|
async def _resolve_cookies(self) -> str:
|
|
215
319
|
"""Return cookies.txt content, fetching from Secrets Manager if configured.
|
|
216
320
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/adapters/audio_transcription.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/adapters/digital_news_metadata.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/adapters/transcription/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/adapters/transcription/config.py
RENAMED
|
File without changes
|
{pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/adapters/transcription/factory.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/adapters/transcription/service.py
RENAMED
|
File without changes
|
{pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/adapters/transcription/source.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/cli/templates/cookiecutter.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/deployment/infra_provisioner.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/notifications/apprise_notifier.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/pipeline/translators/__init__.py
RENAMED
|
File without changes
|
{pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/pipeline/translators/airflow_status.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/pipeline/translators/prefect_status.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/processor/core/topic_splitter.py
RENAMED
|
File without changes
|
|
File without changes
|
{pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/processor/defaults/core_processor.py
RENAMED
|
File without changes
|
{pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/processor/defaults/postprocessor.py
RENAMED
|
File without changes
|
{pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/processor/defaults/preprocessor.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/processor/postprocessor/__init__.py
RENAMED
|
File without changes
|
{pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/processor/postprocessor/embeddings.py
RENAMED
|
File without changes
|
{pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/processor/postprocessor/tasks.py
RENAMED
|
File without changes
|
{pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/processor/preprocessor/__init__.py
RENAMED
|
File without changes
|
{pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/processor/preprocessor/tasks.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/runners/prefect_pipeline_flow.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/sandbox/microvm_agent/Dockerfile
RENAMED
|
File without changes
|
{pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/sandbox/microvm_agent/__init__.py
RENAMED
|
File without changes
|
{pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/sandbox/microvm_agent/server.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/skills/seed_data/skill_files.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pulse_engine-0.2.43 → pulse_engine-0.2.44}/src/pulse_engine/storage/connectors/opensearch.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|