prompture 1.0.56.dev1__tar.gz → 1.0.56.dev2__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.
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.env.copy +4 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/CLAUDE.md +18 -3
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/PKG-INFO +79 -7
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/README.md +78 -6
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/_version.py +2 -2
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/__init__.py +32 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_openai_img_gen_driver.py +11 -5
- prompture-1.0.56.dev2/prompture/drivers/async_runway_img_gen_driver.py +137 -0
- prompture-1.0.56.dev2/prompture/drivers/async_runway_tts_driver.py +167 -0
- prompture-1.0.56.dev2/prompture/drivers/async_runway_video_gen_driver.py +132 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/openai_img_gen_driver.py +42 -6
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/provider_descriptors.py +29 -0
- prompture-1.0.56.dev2/prompture/drivers/runway_audio_transform_driver.py +251 -0
- prompture-1.0.56.dev2/prompture/drivers/runway_capabilities.py +190 -0
- prompture-1.0.56.dev2/prompture/drivers/runway_img_gen_driver.py +345 -0
- prompture-1.0.56.dev2/prompture/drivers/runway_tts_driver.py +225 -0
- prompture-1.0.56.dev2/prompture/drivers/runway_video_gen_driver.py +386 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/discovery.py +30 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/settings.py +4 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture.egg-info/PKG-INFO +79 -7
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture.egg-info/SOURCES.txt +8 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.claude/skills/add-driver/SKILL.md +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.claude/skills/add-driver/references/driver-template.md +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.claude/skills/add-example/SKILL.md +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.claude/skills/add-field/SKILL.md +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.claude/skills/add-persona/SKILL.md +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.claude/skills/add-test/SKILL.md +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.claude/skills/add-tool/SKILL.md +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.claude/skills/create-pr/SKILL.md +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.claude/skills/run-tests/SKILL.md +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.claude/skills/scaffold-extraction/SKILL.md +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.claude/skills/update-pricing/SKILL.md +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.github/FUNDING.yml +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.github/ISSUE_TEMPLATE/pricing_cost_mismatch.yml +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.github/ISSUE_TEMPLATE/provider_driver_bug.yml +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.github/ISSUE_TEMPLATE/schema_extraction_failure.yml +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.github/scripts/update_docs_version.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.github/scripts/update_wrapper_version.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.github/workflows/dev.yml +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.github/workflows/documentation.yml +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.github/workflows/pricing-freshness.yml +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.github/workflows/publish.yml +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.github/workflows/security.yml +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/.safety-project.ini +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/AGENTS.md +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/BREAKING_CHANGES.md +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/CONTRIBUTING.md +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/LICENSE +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/MANIFEST.in +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/ROADMAP.md +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/SECURITY.md +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/dev.ps1 +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/dev.sh +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/mypy_errors.txt +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/packages/README.md +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/packages/llm_to_json/README.md +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/packages/llm_to_json/llm_to_json/__init__.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/packages/llm_to_json/pyproject.toml +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/packages/llm_to_json/test.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/packages/llm_to_toon/README.md +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/packages/llm_to_toon/llm_to_toon/__init__.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/packages/llm_to_toon/pyproject.toml +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/packages/llm_to_toon/test.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/__init__.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/agents/__init__.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/agents/agent.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/agents/async_agent.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/agents/async_conversation.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/agents/conversation.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/agents/persona.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/agents/simulated_tools.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/agents/skills.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/agents/tools_schema.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/agents/types.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/aio/__init__.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/bridges/__init__.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/bridges/tukuy_backend.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/cli/__init__.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/cli/cli.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/cli/formatters.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/cli/runner.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/cli/server.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/airllm_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_airllm_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_azure_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_base.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_cachibot_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_claude_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_elevenlabs_stt_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_elevenlabs_tts_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_embedding_base.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_google_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_google_img_gen_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_google_vertexai_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_grok_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_grok_img_gen_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_grok_video_gen_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_groq_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_hugging_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_img_gen_base.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_lmstudio_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_local_http_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_modelscope_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_moonshot_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_ollama_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_ollama_embedding_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_openai_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_openai_embedding_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_openai_stt_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_openai_tts_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_openrouter_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_registry.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_stability_img_gen_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_stt_base.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_tts_base.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_video_gen_base.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_zai_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/audio_registry.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/azure_config.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/azure_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/base.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/cachibot_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/claude_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/driver_registry.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/elevenlabs_stt_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/elevenlabs_tts_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/embedding_base.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/embedding_registry.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/google_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/google_img_gen_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/google_vertexai_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/grok_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/grok_img_gen_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/grok_video_gen_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/groq_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/hugging_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/img_gen_base.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/img_gen_registry.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/lmstudio_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/local_http_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/modelscope_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/moonshot_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/ollama_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/ollama_embedding_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/openai_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/openai_embedding_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/openai_stt_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/openai_tts_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/openrouter_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/registry.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/stability_img_gen_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/stt_base.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/tts_base.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/video_gen_base.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/video_gen_registry.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/vision_helpers.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/zai_driver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/exceptions.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/extraction/__init__.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/extraction/async_core.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/extraction/core.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/extraction/fields.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/extraction/reasoning.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/extraction/strategy.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/extraction/tools.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/extraction/tukuy_bridge.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/extraction/validator.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/groups/__init__.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/groups/async_groups.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/groups/consensus.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/groups/debate.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/groups/groups.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/groups/types.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/__init__.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/budget.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/cache.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/callbacks.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/capabilities.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/cost_mixin.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/ledger.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/logging.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/model_rates.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/pricing.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/provider_env.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/rates/anthropic.json +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/rates/azure.json +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/rates/google.json +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/rates/google_vertexai.json +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/rates/groq.json +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/rates/moonshot.json +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/rates/openai.json +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/rates/openrouter.json +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/rates/xai.json +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/session.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/tracker.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/infra/tukuy_backend.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/ingestion/__init__.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/ingestion/chunking.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/ingestion/detect.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/ingestion/document.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/ingestion/parsers/__init__.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/ingestion/parsers/base.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/ingestion/parsers/csv_parser.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/ingestion/parsers/docx.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/ingestion/parsers/html.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/ingestion/parsers/markdown.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/ingestion/parsers/pdf.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/ingestion/parsers/xlsx.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/integrations/__init__.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/integrations/tukuy_bridge.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/media/__init__.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/media/audio.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/media/image.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/media/video.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/pages/01-why-prompture.md +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/pages/02-installation.md +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/pages/03-quickstart.md +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/pages/04-toon-input.md +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/pages/05-test-harness.md +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/pages/06-stability.md +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/pages/07-migration.md +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/persistence/__init__.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/persistence/history.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/persistence/serialization.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/persistence/store.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/pipeline/__init__.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/pipeline/pipeline.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/pipeline/resolver.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/pipeline/routing.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/py.typed +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/scaffold/__init__.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/scaffold/generator.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/scaffold/templates/Dockerfile.j2 +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/scaffold/templates/README.md.j2 +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/scaffold/templates/config.py.j2 +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/scaffold/templates/env.example.j2 +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/scaffold/templates/main.py.j2 +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/scaffold/templates/models.py.j2 +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/scaffold/templates/requirements.txt.j2 +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/testing/__init__.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/testing/driver_contract.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture.egg-info/dependency_links.txt +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture.egg-info/entry_points.txt +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture.egg-info/requires.txt +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture.egg-info/top_level.txt +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture_cost_tracking.md +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/pyproject.toml +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/requirements.txt +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/scripts/check_pricing_freshness.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/setup.cfg +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/specs/basic_extraction.json +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/specs/schema_validation.json +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/specs/strategy_comparison.json +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/test.py +0 -0
- {prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/test_version_diagnosis.py +0 -0
|
@@ -90,3 +90,7 @@ AIRLLM_COMPRESSION=
|
|
|
90
90
|
|
|
91
91
|
# ─── Stability AI (image generation) ────────────────────────────────────────
|
|
92
92
|
STABILITY_API_KEY=
|
|
93
|
+
|
|
94
|
+
# ─── Runway (image / video / audio) ─────────────────────────────────────────
|
|
95
|
+
# Either RUNWAY_API_KEY or RUNWAYML_API_SECRET is accepted.
|
|
96
|
+
RUNWAY_API_KEY=
|
|
@@ -61,15 +61,15 @@ Configuration is in `pyproject.toml` under `[tool.ruff]`.
|
|
|
61
61
|
### Module Layout
|
|
62
62
|
|
|
63
63
|
- **`prompture/core.py`** — Primary business logic. All extraction functions live here: `ask_for_json()` (low-level schema enforcement), `extract_and_jsonify()` / `manual_extract_and_jsonify()` (text-to-JSON), `extract_with_model()` / `stepwise_extract_with_model()` (Pydantic-based), `extract_from_data()` / `extract_from_pandas()` (TOON input), `render_output()` (raw text formatting).
|
|
64
|
-
- **`prompture/drivers/`** — One module per LLM
|
|
64
|
+
- **`prompture/drivers/`** — One module per provider × modality. LLM drivers (openai, claude, google, groq, grok, azure, ollama, lmstudio, openrouter, local_http, huggingface, airllm, moonshot, modelscope, zai, cachibot, …) implement `generate(prompt, options)`; non-LLM drivers implement modality-specific methods (`generate_image`, `generate_video`, `synthesize`, etc.). Each provider also has an `async_*` sibling. Registration is centralized in `provider_descriptors.py` via `ProviderDescriptor` with lazy `DriverSpec.cls_path` resolution.
|
|
65
65
|
- **`prompture/drivers/__init__.py`** — Central `DRIVER_REGISTRY` dict mapping provider name to factory lambda. `get_driver_for_model("provider/model")` parses the string and instantiates the right driver. `get_driver("provider")` is the legacy interface.
|
|
66
66
|
- **`prompture/tools.py`** — Utilities: JSON/TOON text cleanup, type conversion (shorthand numbers, multilingual booleans, datetimes), field schema generation.
|
|
67
67
|
- **`prompture/logging.py`** — Library logging configuration: `JSONFormatter` for structured JSON-lines output, `configure_logging()` for enabling library-level logging via Python stdlib `logging`.
|
|
68
68
|
- **`prompture/callbacks.py`** — `DriverCallbacks` dataclass with `on_request`, `on_response`, `on_error` hooks for driver-level observability.
|
|
69
69
|
- **`prompture/session.py`** — `UsageSession` dataclass for tracking token counts, costs, and errors across multiple driver calls.
|
|
70
70
|
- **`prompture/field_definitions.py`** — Thread-safe global field registry with 50+ predefined fields, template variable substitution (`{{current_year}}`, `{{current_date}}`), and Pydantic Field generation via `field_from_registry()`.
|
|
71
|
-
- **`prompture/settings.py`** — Pydantic-settings `Settings` class loading provider API keys/endpoints from `.env`.
|
|
72
|
-
- **`prompture/discovery.py`** — `get_available_models()`
|
|
71
|
+
- **`prompture/infra/settings.py`** — Pydantic-settings `Settings` class loading provider API keys/endpoints from `.env`.
|
|
72
|
+
- **`prompture/infra/discovery.py`** — `get_available_models()` plus per-modality helpers (`get_available_image_gen_models`, `get_available_video_gen_models`, `get_available_audio_models`). Auto-detects models from configured providers via static `*_PRICING` / `KNOWN_MODELS` tables, dynamic provider listing endpoints (Ollama, ElevenLabs), and models.dev capability fallback.
|
|
73
73
|
- **`prompture/runner.py`** — Spec-driven test suite runner for cross-model comparison.
|
|
74
74
|
- **`prompture/validator.py`** — JSON schema validation via jsonschema with fallback.
|
|
75
75
|
|
|
@@ -80,6 +80,21 @@ Configuration is in `pyproject.toml` under `[tool.ruff]`.
|
|
|
80
80
|
- **Output formats**: JSON (default) and TOON (experimental, for compact output). Controlled via `output_format` parameter.
|
|
81
81
|
- **TOON input conversion** uses `python-toon` and `tukuy` packages to reduce token usage by 45-60% when sending structured data to LLMs.
|
|
82
82
|
|
|
83
|
+
### Multi-Modal Drivers
|
|
84
|
+
|
|
85
|
+
Beyond LLMs, drivers exist for adjacent modalities. Each modality has its own base class, registry, and factory:
|
|
86
|
+
|
|
87
|
+
- **Image generation** (`ImageGenDriver` / `img_gen_registry.get_img_gen_driver_for_model`) — OpenAI DALL-E + GPT image, Google Imagen, Grok, Stability AI, Runway.
|
|
88
|
+
- **Video generation** (`VideoGenDriver` / `video_gen_registry.get_video_gen_driver_for_model`) — Grok Imagine Video; Runway (text/image/video → video via a single driver, mode auto-detected from options).
|
|
89
|
+
- **TTS** (`TTSDriver` / `audio_registry.get_tts_driver_for_model`) — OpenAI, ElevenLabs, Runway (TTS + sound effects).
|
|
90
|
+
- **STT** (`STTDriver` / `audio_registry.get_stt_driver_for_model`) — OpenAI Whisper, ElevenLabs.
|
|
91
|
+
- **Embeddings** (`EmbeddingDriver`) — OpenAI, Ollama.
|
|
92
|
+
- **Standalone helpers** (not modality-registered) — `RunwayAudioTransformDriver` for voice dubbing / isolation / speech-to-speech; instantiated directly.
|
|
93
|
+
|
|
94
|
+
**Runway is the only provider spanning image + video + TTS + sound-effects + voice transforms under one API key** (`RUNWAY_API_KEY` or `RUNWAYML_API_SECRET`). Per-model capabilities live in `prompture/drivers/runway_capabilities.py` (`RUNWAY_MODEL_INFO`, `get_runway_model_info`, `get_runway_models_by_op`, `get_runway_models_by_modality`) — use this when you need to answer "which models support text_to_video?" without instantiating drivers.
|
|
95
|
+
|
|
96
|
+
Discovery for non-LLM modalities: `infra/discovery.py` exposes `get_available_image_gen_models`, `get_available_video_gen_models`, `get_available_audio_models(modality="tts" | "stt" | None)`.
|
|
97
|
+
|
|
83
98
|
### Testing
|
|
84
99
|
|
|
85
100
|
Tests live in `tests/`. Integration tests that call live LLMs are marked with `@pytest.mark.integration` and skipped by default. The default test model is set in `tests/conftest.py` as `DEFAULT_MODEL`. Shared fixtures and assertion helpers (`assert_valid_usage_metadata`, `assert_jsonify_response_structure`) are in `conftest.py`.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: prompture
|
|
3
|
-
Version: 1.0.56.
|
|
3
|
+
Version: 1.0.56.dev2
|
|
4
4
|
Summary: Ask LLMs to return structured JSON and run cross-model tests. API-first.
|
|
5
5
|
Author-email: Juan Denis <juan@vene.co>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -95,8 +95,8 @@ print(person.name) # Maria
|
|
|
95
95
|
## Key Features
|
|
96
96
|
|
|
97
97
|
- **Structured output** — JSON schema enforcement and direct Pydantic model population
|
|
98
|
-
- **
|
|
99
|
-
- **Multi-modal** — Drivers for embeddings, image generation (DALL-E, Imagen, Grok, Stability), video generation (Grok Imagine Video), text-to-speech, and speech-to-text (Whisper, ElevenLabs)
|
|
98
|
+
- **18+ providers** — OpenAI, Claude, Google, Groq, Grok, Azure, Ollama, LM Studio, OpenRouter, HuggingFace, Moonshot, ModelScope, Z.ai, Vertex AI, AirLLM, CachiBot, Runway, and generic HTTP
|
|
99
|
+
- **Multi-modal** — Drivers for embeddings, image generation (DALL-E, Imagen, Grok, Stability, Runway), video generation (Grok Imagine Video, Runway text/image/video → video), text-to-speech (OpenAI, ElevenLabs, Runway), sound effects, voice dubbing / isolation / conversion (Runway), and speech-to-text (Whisper, ElevenLabs)
|
|
100
100
|
- **Multi-model fallback** — Try a list of models in sequence with per-attempt cost, token, and capability accounting
|
|
101
101
|
- **Strategy cascade** — Auto-selects between provider-native JSON mode, tool-call extraction, and prompted repair so extraction works on any model
|
|
102
102
|
- **TOON input conversion** — 45-60% token savings when sending structured data via [Token-Oriented Object Notation](https://github.com/jhd3197/python-toon)
|
|
@@ -191,17 +191,20 @@ Model strings use `"provider/model"` format. The provider prefix routes to the c
|
|
|
191
191
|
| `huggingface` | `hf/model-name` | Free (local) |
|
|
192
192
|
| `airllm` | `airllm/Qwen2-7B` | Free (local) |
|
|
193
193
|
| `local_http` | `local_http/self-hosted` | Free |
|
|
194
|
+
| `runway` | `runway/gen4.5` (video), `runway/gpt_image_2` (image), `runway/eleven_multilingual_v2` (TTS) | Automatic |
|
|
194
195
|
|
|
195
|
-
Aliases (`anthropic`, `gemini`, `chatgpt`, `xai`, `lm_studio`, `zhipu`, `hf`, `dalle`) route to their canonical providers.
|
|
196
|
+
Aliases (`anthropic`, `gemini`, `chatgpt`, `xai`, `lm_studio`, `zhipu`, `hf`, `dalle`, `runwayml`) route to their canonical providers.
|
|
196
197
|
|
|
197
198
|
## Multi-Modal
|
|
198
199
|
|
|
199
200
|
Beyond text LLMs, Prompture exposes drivers for adjacent modalities under the same `provider/model` routing:
|
|
200
201
|
|
|
201
202
|
- **Embeddings** — OpenAI (`text-embedding-3-*`) and Ollama (`nomic-embed-text`)
|
|
202
|
-
- **Image generation** — OpenAI DALL-E, Google Imagen, Grok, Stability AI
|
|
203
|
-
- **Video generation** — Grok Imagine Video
|
|
204
|
-
- **Text-to-speech** — OpenAI (`tts-1`)
|
|
203
|
+
- **Image generation** — OpenAI DALL-E + GPT image, Google Imagen, Grok, Stability AI, Runway (`gen4_image`, `gen4_image_turbo`, `gpt_image_2`, `gemini_image3_pro`, `gemini_2.5_flash`)
|
|
204
|
+
- **Video generation** — Grok Imagine Video; Runway text/image/video → video (`gen4.5`, `gen4_turbo`, `gen3a_turbo`, `gen4_aleph`, `veo3`, `veo3.1`, `veo3.1_fast`)
|
|
205
|
+
- **Text-to-speech** — OpenAI (`tts-1`), ElevenLabs, Runway (`eleven_multilingual_v2`)
|
|
206
|
+
- **Sound effects** — Runway (`eleven_text_to_sound_v2`)
|
|
207
|
+
- **Audio transforms** — Runway voice dubbing, voice isolation, speech-to-speech (`RunwayAudioTransformDriver`)
|
|
205
208
|
- **Speech-to-text** — OpenAI Whisper and ElevenLabs
|
|
206
209
|
|
|
207
210
|
```python
|
|
@@ -235,6 +238,61 @@ For local smoke tests without waiting on the render, pass `{"poll": False}` to g
|
|
|
235
238
|
|
|
236
239
|
Runnable example: `python examples/grok_video_generation_example.py`.
|
|
237
240
|
|
|
241
|
+
### Runway
|
|
242
|
+
|
|
243
|
+
Runway is a single API surface covering image, video, and audio. One key (`RUNWAY_API_KEY`, or `RUNWAYML_API_SECRET`) unlocks all of it:
|
|
244
|
+
|
|
245
|
+
```python
|
|
246
|
+
from prompture.drivers.img_gen_registry import get_img_gen_driver_for_model
|
|
247
|
+
from prompture.drivers.video_gen_registry import get_video_gen_driver_for_model
|
|
248
|
+
from prompture.drivers.audio_registry import get_tts_driver_for_model
|
|
249
|
+
from prompture.drivers import RunwayAudioTransformDriver
|
|
250
|
+
|
|
251
|
+
# Image — text_to_image, optionally with reference images
|
|
252
|
+
img = get_img_gen_driver_for_model("runway/gpt_image_2").generate_image(
|
|
253
|
+
"A cinematic wide shot of a neon-lit Tokyo alleyway at night in the rain",
|
|
254
|
+
{"ratio": "1920:1080", "quality": "high"},
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
# Video — one driver, three modes (auto-detected from inputs)
|
|
258
|
+
vid = get_video_gen_driver_for_model("runway/gen4.5").generate_video(
|
|
259
|
+
"wide cinematic shot of a rocket launching from desert dunes",
|
|
260
|
+
{"ratio": "1280:720", "duration": 5}, # text_to_video
|
|
261
|
+
)
|
|
262
|
+
# Pass `image=...` → image_to_video; `video=...` → video_to_video (gen4_aleph).
|
|
263
|
+
|
|
264
|
+
# Speech and sound effects
|
|
265
|
+
tts = get_tts_driver_for_model("runway/eleven_multilingual_v2").synthesize(
|
|
266
|
+
"Hello from Runway via Prompture.", {"voice": "Maya"},
|
|
267
|
+
)
|
|
268
|
+
sfx = get_tts_driver_for_model("runway/eleven_text_to_sound_v2").synthesize(
|
|
269
|
+
"Heavy tropical rain on a metal roof", {"duration": 5},
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
# Voice transforms (audio in → audio out, not a registered modality)
|
|
273
|
+
dub = RunwayAudioTransformDriver().dub("https://.../speech.mp3", target_lang="es")
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
Inspect any model's capabilities (operations, endpoints, cost) as data — no need to instantiate the driver:
|
|
277
|
+
|
|
278
|
+
```python
|
|
279
|
+
from prompture.drivers import get_runway_model_info, get_runway_models_by_op
|
|
280
|
+
|
|
281
|
+
get_runway_model_info("gen4.5")
|
|
282
|
+
# {'modality': 'video',
|
|
283
|
+
# 'operations': ['text_to_video', 'image_to_video'],
|
|
284
|
+
# 'endpoints': ['/v1/text_to_video', '/v1/image_to_video'],
|
|
285
|
+
# 'cost': '$0.12 per second'}
|
|
286
|
+
|
|
287
|
+
get_runway_models_by_op("text_to_video")
|
|
288
|
+
# ['gen4.5', 'veo3', 'veo3.1', 'veo3.1_fast']
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
Runnable examples:
|
|
292
|
+
- `python examples/runway_image_generation_example.py`
|
|
293
|
+
- `python examples/runway_video_generation_example.py`
|
|
294
|
+
- `python examples/runway_audio_example.py`
|
|
295
|
+
|
|
238
296
|
## Usage
|
|
239
297
|
|
|
240
298
|
### One-Shot Pydantic Extraction
|
|
@@ -508,6 +566,20 @@ for model in models:
|
|
|
508
566
|
print(model) # "openai/gpt-4", "ollama/llama3:latest", ...
|
|
509
567
|
```
|
|
510
568
|
|
|
569
|
+
For non-LLM modalities, use the matching helper:
|
|
570
|
+
|
|
571
|
+
```python
|
|
572
|
+
from prompture.infra.discovery import (
|
|
573
|
+
get_available_image_gen_models,
|
|
574
|
+
get_available_video_gen_models,
|
|
575
|
+
get_available_audio_models,
|
|
576
|
+
)
|
|
577
|
+
|
|
578
|
+
get_available_image_gen_models() # ['runway/gpt_image_2', 'openai/dall-e-3', ...]
|
|
579
|
+
get_available_video_gen_models() # ['runway/gen4.5', 'runway/gen4_aleph', ...]
|
|
580
|
+
get_available_audio_models(modality="tts") # ['runway/eleven_multilingual_v2', ...]
|
|
581
|
+
```
|
|
582
|
+
|
|
511
583
|
### Logging and Debugging
|
|
512
584
|
|
|
513
585
|
```python
|
|
@@ -31,8 +31,8 @@ print(person.name) # Maria
|
|
|
31
31
|
## Key Features
|
|
32
32
|
|
|
33
33
|
- **Structured output** — JSON schema enforcement and direct Pydantic model population
|
|
34
|
-
- **
|
|
35
|
-
- **Multi-modal** — Drivers for embeddings, image generation (DALL-E, Imagen, Grok, Stability), video generation (Grok Imagine Video), text-to-speech, and speech-to-text (Whisper, ElevenLabs)
|
|
34
|
+
- **18+ providers** — OpenAI, Claude, Google, Groq, Grok, Azure, Ollama, LM Studio, OpenRouter, HuggingFace, Moonshot, ModelScope, Z.ai, Vertex AI, AirLLM, CachiBot, Runway, and generic HTTP
|
|
35
|
+
- **Multi-modal** — Drivers for embeddings, image generation (DALL-E, Imagen, Grok, Stability, Runway), video generation (Grok Imagine Video, Runway text/image/video → video), text-to-speech (OpenAI, ElevenLabs, Runway), sound effects, voice dubbing / isolation / conversion (Runway), and speech-to-text (Whisper, ElevenLabs)
|
|
36
36
|
- **Multi-model fallback** — Try a list of models in sequence with per-attempt cost, token, and capability accounting
|
|
37
37
|
- **Strategy cascade** — Auto-selects between provider-native JSON mode, tool-call extraction, and prompted repair so extraction works on any model
|
|
38
38
|
- **TOON input conversion** — 45-60% token savings when sending structured data via [Token-Oriented Object Notation](https://github.com/jhd3197/python-toon)
|
|
@@ -127,17 +127,20 @@ Model strings use `"provider/model"` format. The provider prefix routes to the c
|
|
|
127
127
|
| `huggingface` | `hf/model-name` | Free (local) |
|
|
128
128
|
| `airllm` | `airllm/Qwen2-7B` | Free (local) |
|
|
129
129
|
| `local_http` | `local_http/self-hosted` | Free |
|
|
130
|
+
| `runway` | `runway/gen4.5` (video), `runway/gpt_image_2` (image), `runway/eleven_multilingual_v2` (TTS) | Automatic |
|
|
130
131
|
|
|
131
|
-
Aliases (`anthropic`, `gemini`, `chatgpt`, `xai`, `lm_studio`, `zhipu`, `hf`, `dalle`) route to their canonical providers.
|
|
132
|
+
Aliases (`anthropic`, `gemini`, `chatgpt`, `xai`, `lm_studio`, `zhipu`, `hf`, `dalle`, `runwayml`) route to their canonical providers.
|
|
132
133
|
|
|
133
134
|
## Multi-Modal
|
|
134
135
|
|
|
135
136
|
Beyond text LLMs, Prompture exposes drivers for adjacent modalities under the same `provider/model` routing:
|
|
136
137
|
|
|
137
138
|
- **Embeddings** — OpenAI (`text-embedding-3-*`) and Ollama (`nomic-embed-text`)
|
|
138
|
-
- **Image generation** — OpenAI DALL-E, Google Imagen, Grok, Stability AI
|
|
139
|
-
- **Video generation** — Grok Imagine Video
|
|
140
|
-
- **Text-to-speech** — OpenAI (`tts-1`)
|
|
139
|
+
- **Image generation** — OpenAI DALL-E + GPT image, Google Imagen, Grok, Stability AI, Runway (`gen4_image`, `gen4_image_turbo`, `gpt_image_2`, `gemini_image3_pro`, `gemini_2.5_flash`)
|
|
140
|
+
- **Video generation** — Grok Imagine Video; Runway text/image/video → video (`gen4.5`, `gen4_turbo`, `gen3a_turbo`, `gen4_aleph`, `veo3`, `veo3.1`, `veo3.1_fast`)
|
|
141
|
+
- **Text-to-speech** — OpenAI (`tts-1`), ElevenLabs, Runway (`eleven_multilingual_v2`)
|
|
142
|
+
- **Sound effects** — Runway (`eleven_text_to_sound_v2`)
|
|
143
|
+
- **Audio transforms** — Runway voice dubbing, voice isolation, speech-to-speech (`RunwayAudioTransformDriver`)
|
|
141
144
|
- **Speech-to-text** — OpenAI Whisper and ElevenLabs
|
|
142
145
|
|
|
143
146
|
```python
|
|
@@ -171,6 +174,61 @@ For local smoke tests without waiting on the render, pass `{"poll": False}` to g
|
|
|
171
174
|
|
|
172
175
|
Runnable example: `python examples/grok_video_generation_example.py`.
|
|
173
176
|
|
|
177
|
+
### Runway
|
|
178
|
+
|
|
179
|
+
Runway is a single API surface covering image, video, and audio. One key (`RUNWAY_API_KEY`, or `RUNWAYML_API_SECRET`) unlocks all of it:
|
|
180
|
+
|
|
181
|
+
```python
|
|
182
|
+
from prompture.drivers.img_gen_registry import get_img_gen_driver_for_model
|
|
183
|
+
from prompture.drivers.video_gen_registry import get_video_gen_driver_for_model
|
|
184
|
+
from prompture.drivers.audio_registry import get_tts_driver_for_model
|
|
185
|
+
from prompture.drivers import RunwayAudioTransformDriver
|
|
186
|
+
|
|
187
|
+
# Image — text_to_image, optionally with reference images
|
|
188
|
+
img = get_img_gen_driver_for_model("runway/gpt_image_2").generate_image(
|
|
189
|
+
"A cinematic wide shot of a neon-lit Tokyo alleyway at night in the rain",
|
|
190
|
+
{"ratio": "1920:1080", "quality": "high"},
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
# Video — one driver, three modes (auto-detected from inputs)
|
|
194
|
+
vid = get_video_gen_driver_for_model("runway/gen4.5").generate_video(
|
|
195
|
+
"wide cinematic shot of a rocket launching from desert dunes",
|
|
196
|
+
{"ratio": "1280:720", "duration": 5}, # text_to_video
|
|
197
|
+
)
|
|
198
|
+
# Pass `image=...` → image_to_video; `video=...` → video_to_video (gen4_aleph).
|
|
199
|
+
|
|
200
|
+
# Speech and sound effects
|
|
201
|
+
tts = get_tts_driver_for_model("runway/eleven_multilingual_v2").synthesize(
|
|
202
|
+
"Hello from Runway via Prompture.", {"voice": "Maya"},
|
|
203
|
+
)
|
|
204
|
+
sfx = get_tts_driver_for_model("runway/eleven_text_to_sound_v2").synthesize(
|
|
205
|
+
"Heavy tropical rain on a metal roof", {"duration": 5},
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
# Voice transforms (audio in → audio out, not a registered modality)
|
|
209
|
+
dub = RunwayAudioTransformDriver().dub("https://.../speech.mp3", target_lang="es")
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Inspect any model's capabilities (operations, endpoints, cost) as data — no need to instantiate the driver:
|
|
213
|
+
|
|
214
|
+
```python
|
|
215
|
+
from prompture.drivers import get_runway_model_info, get_runway_models_by_op
|
|
216
|
+
|
|
217
|
+
get_runway_model_info("gen4.5")
|
|
218
|
+
# {'modality': 'video',
|
|
219
|
+
# 'operations': ['text_to_video', 'image_to_video'],
|
|
220
|
+
# 'endpoints': ['/v1/text_to_video', '/v1/image_to_video'],
|
|
221
|
+
# 'cost': '$0.12 per second'}
|
|
222
|
+
|
|
223
|
+
get_runway_models_by_op("text_to_video")
|
|
224
|
+
# ['gen4.5', 'veo3', 'veo3.1', 'veo3.1_fast']
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Runnable examples:
|
|
228
|
+
- `python examples/runway_image_generation_example.py`
|
|
229
|
+
- `python examples/runway_video_generation_example.py`
|
|
230
|
+
- `python examples/runway_audio_example.py`
|
|
231
|
+
|
|
174
232
|
## Usage
|
|
175
233
|
|
|
176
234
|
### One-Shot Pydantic Extraction
|
|
@@ -444,6 +502,20 @@ for model in models:
|
|
|
444
502
|
print(model) # "openai/gpt-4", "ollama/llama3:latest", ...
|
|
445
503
|
```
|
|
446
504
|
|
|
505
|
+
For non-LLM modalities, use the matching helper:
|
|
506
|
+
|
|
507
|
+
```python
|
|
508
|
+
from prompture.infra.discovery import (
|
|
509
|
+
get_available_image_gen_models,
|
|
510
|
+
get_available_video_gen_models,
|
|
511
|
+
get_available_audio_models,
|
|
512
|
+
)
|
|
513
|
+
|
|
514
|
+
get_available_image_gen_models() # ['runway/gpt_image_2', 'openai/dall-e-3', ...]
|
|
515
|
+
get_available_video_gen_models() # ['runway/gen4.5', 'runway/gen4_aleph', ...]
|
|
516
|
+
get_available_audio_models(modality="tts") # ['runway/eleven_multilingual_v2', ...]
|
|
517
|
+
```
|
|
518
|
+
|
|
447
519
|
### Logging and Debugging
|
|
448
520
|
|
|
449
521
|
```python
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '1.0.56.
|
|
22
|
-
__version_tuple__ = version_tuple = (1, 0, 56, '
|
|
21
|
+
__version__ = version = '1.0.56.dev2'
|
|
22
|
+
__version_tuple__ = version_tuple = (1, 0, 56, 'dev2')
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -57,6 +57,9 @@ from .async_openai_img_gen_driver import AsyncOpenAIImageGenDriver
|
|
|
57
57
|
from .async_openai_stt_driver import AsyncOpenAISTTDriver
|
|
58
58
|
from .async_openai_tts_driver import AsyncOpenAITTSDriver
|
|
59
59
|
from .async_openrouter_driver import AsyncOpenRouterDriver
|
|
60
|
+
from .async_runway_img_gen_driver import AsyncRunwayImageGenDriver
|
|
61
|
+
from .async_runway_tts_driver import AsyncRunwayTTSDriver
|
|
62
|
+
from .async_runway_video_gen_driver import AsyncRunwayVideoGenDriver
|
|
60
63
|
from .async_stability_img_gen_driver import AsyncStabilityImageGenDriver
|
|
61
64
|
from .async_stt_base import AsyncSTTDriver
|
|
62
65
|
from .async_tts_base import AsyncTTSDriver
|
|
@@ -164,6 +167,22 @@ from .registry import (
|
|
|
164
167
|
unregister_tts_driver,
|
|
165
168
|
unregister_video_gen_driver,
|
|
166
169
|
)
|
|
170
|
+
from .runway_audio_transform_driver import RunwayAudioTransformDriver
|
|
171
|
+
from .runway_capabilities import (
|
|
172
|
+
ALL_MODALITIES as RUNWAY_ALL_MODALITIES,
|
|
173
|
+
)
|
|
174
|
+
from .runway_capabilities import (
|
|
175
|
+
ALL_OPERATIONS as RUNWAY_ALL_OPERATIONS,
|
|
176
|
+
)
|
|
177
|
+
from .runway_capabilities import (
|
|
178
|
+
RUNWAY_MODEL_INFO,
|
|
179
|
+
get_runway_model_info,
|
|
180
|
+
get_runway_models_by_modality,
|
|
181
|
+
get_runway_models_by_op,
|
|
182
|
+
)
|
|
183
|
+
from .runway_img_gen_driver import RunwayImageGenDriver
|
|
184
|
+
from .runway_tts_driver import RunwayTTSDriver
|
|
185
|
+
from .runway_video_gen_driver import RunwayVideoGenDriver
|
|
167
186
|
from .stability_img_gen_driver import StabilityImageGenDriver
|
|
168
187
|
from .stt_base import STTDriver
|
|
169
188
|
from .tts_base import TTSDriver
|
|
@@ -448,6 +467,9 @@ __all__ = [
|
|
|
448
467
|
"PROVIDER_DRIVER_MAP",
|
|
449
468
|
# Provider name mapping
|
|
450
469
|
"PROVIDER_NAME_MAP",
|
|
470
|
+
"RUNWAY_ALL_MODALITIES",
|
|
471
|
+
"RUNWAY_ALL_OPERATIONS",
|
|
472
|
+
"RUNWAY_MODEL_INFO",
|
|
451
473
|
# Sync LLM drivers
|
|
452
474
|
"AirLLMDriver",
|
|
453
475
|
# Async LLM drivers
|
|
@@ -483,6 +505,9 @@ __all__ = [
|
|
|
483
505
|
"AsyncOpenAISTTDriver",
|
|
484
506
|
"AsyncOpenAITTSDriver",
|
|
485
507
|
"AsyncOpenRouterDriver",
|
|
508
|
+
"AsyncRunwayImageGenDriver",
|
|
509
|
+
"AsyncRunwayTTSDriver",
|
|
510
|
+
"AsyncRunwayVideoGenDriver",
|
|
486
511
|
"AsyncSTTDriver",
|
|
487
512
|
"AsyncStabilityImageGenDriver",
|
|
488
513
|
"AsyncTTSDriver",
|
|
@@ -519,6 +544,10 @@ __all__ = [
|
|
|
519
544
|
"OpenAISTTDriver",
|
|
520
545
|
"OpenAITTSDriver",
|
|
521
546
|
"OpenRouterDriver",
|
|
547
|
+
"RunwayAudioTransformDriver",
|
|
548
|
+
"RunwayImageGenDriver",
|
|
549
|
+
"RunwayTTSDriver",
|
|
550
|
+
"RunwayVideoGenDriver",
|
|
522
551
|
# STT/TTS base classes
|
|
523
552
|
"STTDriver",
|
|
524
553
|
"StabilityImageGenDriver",
|
|
@@ -554,6 +583,9 @@ __all__ = [
|
|
|
554
583
|
"get_embedding_driver_for_model",
|
|
555
584
|
"get_img_gen_driver_factory",
|
|
556
585
|
"get_img_gen_driver_for_model",
|
|
586
|
+
"get_runway_model_info",
|
|
587
|
+
"get_runway_models_by_modality",
|
|
588
|
+
"get_runway_models_by_op",
|
|
557
589
|
"get_stt_driver_factory",
|
|
558
590
|
"get_stt_driver_for_model",
|
|
559
591
|
"get_tts_driver_factory",
|
{prompture-1.0.56.dev1 → prompture-1.0.56.dev2}/prompture/drivers/async_openai_img_gen_driver.py
RENAMED
|
@@ -48,15 +48,18 @@ class AsyncOpenAIImageGenDriver(ImageCostMixin, AsyncImageGenDriver):
|
|
|
48
48
|
raise RuntimeError("openai package (>=1.0.0) is not installed")
|
|
49
49
|
|
|
50
50
|
model = options.get("model", self.model)
|
|
51
|
+
is_gpt_image = model.startswith("gpt-image")
|
|
52
|
+
is_dalle3 = "dall-e-3" in model
|
|
53
|
+
|
|
51
54
|
size = options.get("size", "1024x1024")
|
|
52
|
-
|
|
55
|
+
default_quality = "high" if is_gpt_image else "standard"
|
|
56
|
+
quality = options.get("quality", default_quality)
|
|
53
57
|
n = options.get("n", 1)
|
|
54
58
|
style = options.get("style", "vivid")
|
|
55
59
|
|
|
56
60
|
images = []
|
|
57
61
|
revised_prompt = None
|
|
58
62
|
|
|
59
|
-
is_dalle3 = "dall-e-3" in model
|
|
60
63
|
batch_size = 1 if is_dalle3 else n
|
|
61
64
|
|
|
62
65
|
remaining = n
|
|
@@ -68,11 +71,14 @@ class AsyncOpenAIImageGenDriver(ImageCostMixin, AsyncImageGenDriver):
|
|
|
68
71
|
"prompt": prompt,
|
|
69
72
|
"n": batch_n,
|
|
70
73
|
"size": size,
|
|
71
|
-
"response_format": "b64_json",
|
|
72
74
|
}
|
|
73
|
-
if
|
|
75
|
+
if is_gpt_image:
|
|
74
76
|
kwargs["quality"] = quality
|
|
75
|
-
|
|
77
|
+
else:
|
|
78
|
+
kwargs["response_format"] = "b64_json"
|
|
79
|
+
if is_dalle3:
|
|
80
|
+
kwargs["quality"] = quality
|
|
81
|
+
kwargs["style"] = style
|
|
76
82
|
|
|
77
83
|
resp = await self.client.images.generate(**kwargs)
|
|
78
84
|
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"""Async Runway image generation driver. Mirrors :mod:`runway_img_gen_driver`."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import logging
|
|
7
|
+
import os
|
|
8
|
+
import time
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
import httpx
|
|
12
|
+
|
|
13
|
+
from ..infra.cost_mixin import ImageCostMixin
|
|
14
|
+
from .async_img_gen_base import AsyncImageGenDriver
|
|
15
|
+
from .runway_img_gen_driver import (
|
|
16
|
+
_API_VERSION,
|
|
17
|
+
_DEFAULT_ENDPOINT,
|
|
18
|
+
_TERMINAL_FAIL,
|
|
19
|
+
_TERMINAL_OK,
|
|
20
|
+
RunwayImageGenDriver,
|
|
21
|
+
_format_error,
|
|
22
|
+
_get_runway_api_key,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
logger = logging.getLogger(__name__)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class AsyncRunwayImageGenDriver(ImageCostMixin, AsyncImageGenDriver):
|
|
29
|
+
"""Async image generation via Runway ``POST /v1/text_to_image``."""
|
|
30
|
+
|
|
31
|
+
supports_multiple = RunwayImageGenDriver.supports_multiple
|
|
32
|
+
supports_size_variants = RunwayImageGenDriver.supports_size_variants
|
|
33
|
+
supported_sizes = RunwayImageGenDriver.supported_sizes
|
|
34
|
+
max_images = RunwayImageGenDriver.max_images
|
|
35
|
+
|
|
36
|
+
KNOWN_MODELS = RunwayImageGenDriver.KNOWN_MODELS
|
|
37
|
+
IMAGE_PRICING = RunwayImageGenDriver.IMAGE_PRICING
|
|
38
|
+
|
|
39
|
+
def __init__(
|
|
40
|
+
self,
|
|
41
|
+
api_key: str | None = None,
|
|
42
|
+
model: str = "gen4_image",
|
|
43
|
+
endpoint: str | None = None,
|
|
44
|
+
):
|
|
45
|
+
self.api_key = _get_runway_api_key(api_key)
|
|
46
|
+
self.model = model
|
|
47
|
+
self.endpoint = (
|
|
48
|
+
endpoint or os.getenv("RUNWAY_ENDPOINT") or _DEFAULT_ENDPOINT
|
|
49
|
+
).rstrip("/")
|
|
50
|
+
|
|
51
|
+
@classmethod
|
|
52
|
+
def list_models(cls, *, api_key: str | None = None, **kw: object) -> list[str] | None:
|
|
53
|
+
key = _get_runway_api_key(api_key)
|
|
54
|
+
if not key:
|
|
55
|
+
return None
|
|
56
|
+
return list(cls.KNOWN_MODELS)
|
|
57
|
+
|
|
58
|
+
def _headers(self) -> dict[str, str]:
|
|
59
|
+
return {
|
|
60
|
+
"Authorization": f"Bearer {self.api_key}",
|
|
61
|
+
"X-Runway-Version": _API_VERSION,
|
|
62
|
+
"Content-Type": "application/json",
|
|
63
|
+
"Accept": "application/json",
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async def generate_image(self, prompt: str, options: dict[str, Any]) -> dict[str, Any]:
|
|
67
|
+
if not self.api_key:
|
|
68
|
+
raise RuntimeError(
|
|
69
|
+
"RUNWAY_API_KEY (or RUNWAYML_API_SECRET) is not configured"
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
# Reuse the sync driver's body-building logic to avoid duplication.
|
|
73
|
+
builder = RunwayImageGenDriver.__new__(RunwayImageGenDriver)
|
|
74
|
+
builder.model = self.model
|
|
75
|
+
model, body = builder._build_body(prompt, options)
|
|
76
|
+
headers = self._headers()
|
|
77
|
+
|
|
78
|
+
async with httpx.AsyncClient(timeout=120.0) as client:
|
|
79
|
+
resp = await client.post(
|
|
80
|
+
f"{self.endpoint}/v1/text_to_image", headers=headers, json=body
|
|
81
|
+
)
|
|
82
|
+
if resp.status_code >= 400:
|
|
83
|
+
raise RuntimeError(
|
|
84
|
+
f"Runway text_to_image failed: {_format_error(resp.status_code, resp)}"
|
|
85
|
+
)
|
|
86
|
+
task = resp.json()
|
|
87
|
+
task_id = task.get("id")
|
|
88
|
+
if not task_id:
|
|
89
|
+
raise RuntimeError(f"Runway response missing task id: {task}")
|
|
90
|
+
|
|
91
|
+
if not options.get("poll", True):
|
|
92
|
+
return RunwayImageGenDriver._pending_response(
|
|
93
|
+
builder, task_id, model, body, task
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
final = await self._poll_until_done(
|
|
97
|
+
client,
|
|
98
|
+
task_id,
|
|
99
|
+
headers=headers,
|
|
100
|
+
poll_interval=float(options.get("poll_interval", 5)),
|
|
101
|
+
timeout_seconds=float(options.get("timeout", 600)),
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
return RunwayImageGenDriver._build_success_response(
|
|
105
|
+
builder, final, model, body, options
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
async def _poll_until_done(
|
|
109
|
+
self,
|
|
110
|
+
client: httpx.AsyncClient,
|
|
111
|
+
task_id: str,
|
|
112
|
+
*,
|
|
113
|
+
headers: dict[str, str],
|
|
114
|
+
poll_interval: float,
|
|
115
|
+
timeout_seconds: float,
|
|
116
|
+
) -> dict[str, Any]:
|
|
117
|
+
deadline = time.monotonic() + timeout_seconds
|
|
118
|
+
while True:
|
|
119
|
+
r = await client.get(
|
|
120
|
+
f"{self.endpoint}/v1/tasks/{task_id}", headers=headers
|
|
121
|
+
)
|
|
122
|
+
if r.status_code >= 400:
|
|
123
|
+
raise RuntimeError(
|
|
124
|
+
f"Runway task poll failed: {_format_error(r.status_code, r)}"
|
|
125
|
+
)
|
|
126
|
+
data = r.json()
|
|
127
|
+
status = data.get("status")
|
|
128
|
+
if status in _TERMINAL_OK:
|
|
129
|
+
return data
|
|
130
|
+
if status in _TERMINAL_FAIL:
|
|
131
|
+
failure = data.get("failure") or data.get("failureCode") or status
|
|
132
|
+
raise RuntimeError(f"Runway task {task_id} {status}: {failure}")
|
|
133
|
+
if time.monotonic() >= deadline:
|
|
134
|
+
raise TimeoutError(
|
|
135
|
+
f"Runway task {task_id} timed out (status={status})"
|
|
136
|
+
)
|
|
137
|
+
await asyncio.sleep(poll_interval)
|