204 lines
6.3 KiB
Python
204 lines
6.3 KiB
Python
# SPDX-License-Identifier: Apache-2.0
|
|
"""Config-driven native InterleaveThinker orchestration runner."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from collections.abc import Callable
|
|
from dataclasses import dataclass
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
from fastvideo.entrypoints.interleave.config import (
|
|
InterleaveCriticConfig,
|
|
InterleaveImageBackendConfig,
|
|
InterleavePlannerConfig,
|
|
InterleaveRunConfig,
|
|
resolve_interleave_instruction,
|
|
)
|
|
from fastvideo.entrypoints.interleave.generator import (
|
|
FastVideoImageGeneratorBackend,
|
|
ImageGeneratorBackend,
|
|
NanoBananaImageGeneratorBackend,
|
|
)
|
|
from fastvideo.entrypoints.interleave.orchestrator import (
|
|
AcceptAllCritic,
|
|
CriticProvider,
|
|
InterleaveOrchestrator,
|
|
PlannerProvider,
|
|
SinglePromptPlanner,
|
|
)
|
|
from fastvideo.entrypoints.interleave.providers import (
|
|
InterleaveThinkerCriticProvider,
|
|
InterleaveThinkerPlannerProvider,
|
|
)
|
|
from fastvideo.entrypoints.interleave.schema import InterleaveTrace
|
|
from fastvideo.entrypoints.interleave.trace import save_trace
|
|
from fastvideo.train.models.interleave_thinker import (
|
|
InterleaveThinkerCriticModel,
|
|
InterleaveThinkerPlannerModel,
|
|
)
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class InterleaveRunResult:
|
|
trace: InterleaveTrace
|
|
trace_path: str
|
|
|
|
|
|
def run_interleave_config(
|
|
config: InterleaveRunConfig,
|
|
*,
|
|
image_backend: ImageGeneratorBackend | None = None,
|
|
) -> InterleaveRunResult:
|
|
"""Run one native interleaved generation trace from a typed config."""
|
|
|
|
cleanup: Callable[[], None] = lambda: None
|
|
if image_backend is None:
|
|
image_backend, cleanup = build_image_backend(config)
|
|
|
|
try:
|
|
orchestrator = InterleaveOrchestrator(
|
|
planner=build_planner(config.planner),
|
|
generator=image_backend,
|
|
critic=build_critic(config.critic),
|
|
)
|
|
trace = orchestrator.run(
|
|
resolve_interleave_instruction(config),
|
|
initial_image_path=config.interleave.initial_image_path,
|
|
metadata={
|
|
"image_backend": config.image_backend.kind,
|
|
"planner": config.planner.kind,
|
|
"critic": config.critic.kind,
|
|
},
|
|
)
|
|
trace_path = resolve_trace_path(config)
|
|
save_trace(
|
|
trace,
|
|
trace_path,
|
|
include_images=config.interleave.include_images_in_trace,
|
|
)
|
|
return InterleaveRunResult(
|
|
trace=trace,
|
|
trace_path=str(trace_path),
|
|
)
|
|
finally:
|
|
cleanup()
|
|
|
|
|
|
def resolve_trace_path(config: InterleaveRunConfig) -> Path:
|
|
if config.interleave.trace_path:
|
|
return Path(config.interleave.trace_path)
|
|
return Path(config.interleave.output_dir) / "trace.json"
|
|
|
|
|
|
def build_planner(config: InterleavePlannerConfig) -> PlannerProvider:
|
|
if config.kind == "single_prompt":
|
|
return SinglePromptPlanner(max_attempts=config.max_attempts_per_step)
|
|
|
|
model = InterleaveThinkerPlannerModel(
|
|
**_actor_model_kwargs(config),
|
|
)
|
|
return InterleaveThinkerPlannerProvider(
|
|
model,
|
|
num_generations=config.num_generations,
|
|
temperature=config.temperature,
|
|
top_p=config.top_p,
|
|
max_new_tokens=config.max_new_tokens or config.max_response_length,
|
|
max_attempts_per_step=config.max_attempts_per_step,
|
|
)
|
|
|
|
|
|
def build_critic(config: InterleaveCriticConfig) -> CriticProvider | None:
|
|
if config.kind == "none":
|
|
return None
|
|
if config.kind == "accept_all":
|
|
return AcceptAllCritic()
|
|
|
|
model = InterleaveThinkerCriticModel(
|
|
**_actor_model_kwargs(config),
|
|
)
|
|
return InterleaveThinkerCriticProvider(
|
|
model,
|
|
num_generations=config.num_generations,
|
|
temperature=config.temperature,
|
|
top_p=config.top_p,
|
|
max_new_tokens=config.max_new_tokens or config.max_response_length,
|
|
)
|
|
|
|
|
|
def build_image_backend(config: InterleaveRunConfig) -> tuple[ImageGeneratorBackend, Callable[[], None]]:
|
|
image_config = config.image_backend
|
|
output_dir = image_config.output_dir or config.interleave.output_dir
|
|
if image_config.kind == "nano_banana":
|
|
return (
|
|
NanoBananaImageGeneratorBackend(
|
|
model=image_config.model,
|
|
api_key=image_config.api_key,
|
|
base_url=image_config.base_url,
|
|
output_dir=output_dir,
|
|
aspect_ratio=image_config.aspect_ratio,
|
|
image_size=image_config.image_size,
|
|
max_attempts=image_config.max_attempts,
|
|
retry_delay_s=image_config.retry_delay_s,
|
|
),
|
|
lambda: None,
|
|
)
|
|
return _build_fastvideo_image_backend(config, image_config, output_dir)
|
|
|
|
|
|
def _build_fastvideo_image_backend(
|
|
config: InterleaveRunConfig,
|
|
image_config: InterleaveImageBackendConfig,
|
|
output_dir: str,
|
|
) -> tuple[ImageGeneratorBackend, Callable[[], None]]:
|
|
del image_config
|
|
if config.generator is None:
|
|
raise ValueError("FastVideo image backend requires config.generator")
|
|
|
|
from fastvideo import VideoGenerator
|
|
|
|
generator = VideoGenerator.from_config(config.generator)
|
|
|
|
def cleanup() -> None:
|
|
generator.shutdown()
|
|
|
|
return (
|
|
FastVideoImageGeneratorBackend(
|
|
generator,
|
|
output_dir=output_dir,
|
|
default_request=config.request,
|
|
),
|
|
cleanup,
|
|
)
|
|
|
|
|
|
def _actor_model_kwargs(config: InterleavePlannerConfig | InterleaveCriticConfig) -> dict[str, Any]:
|
|
kwargs: dict[str, Any] = {
|
|
"load_backend": config.load_backend,
|
|
"trainable": config.trainable,
|
|
"image_dir": config.image_dir,
|
|
"torch_dtype": config.torch_dtype,
|
|
"device_map": config.device_map,
|
|
"attn_implementation": config.attn_implementation,
|
|
"trust_remote_code": config.trust_remote_code,
|
|
"use_cache": config.use_cache,
|
|
"max_prompt_length": config.max_prompt_length,
|
|
"max_response_length": config.max_response_length,
|
|
"lora": config.lora,
|
|
}
|
|
if config.init_from is not None:
|
|
kwargs["init_from"] = config.init_from
|
|
if config.processor_from is not None:
|
|
kwargs["processor_from"] = config.processor_from
|
|
return kwargs
|
|
|
|
|
|
__all__ = [
|
|
"InterleaveRunResult",
|
|
"build_critic",
|
|
"build_image_backend",
|
|
"build_planner",
|
|
"resolve_trace_path",
|
|
"run_interleave_config",
|
|
]
|