ADAM October 2026 source release: PixelRow, INRFlow, Wan Video, Oasis player and field guide
f8c73f9 verified Download adam/tools/flow_generator.py from SyntheticMDProductions/AI_Development_Automation_Manager: direct link, hf CLI and curl.
- Browser
- Download file 14.1 kB
-
https://huggingface.co/SyntheticMDProductions/AI_Development_Automation_Manager/resolve/main/adam/tools/flow_generator.py
- Command line
-
hf download hf://SyntheticMDProductions/AI_Development_Automation_Manager/adam/tools/flow_generator.py
-
curl -L -o flow_generator.py https://huggingface.co/SyntheticMDProductions/AI_Development_Automation_Manager/resolve/main/adam/tools/flow_generator.py
14.1 kB
| """Image-generation bridge for the connected Flow Matching project.""" | |
| from __future__ import annotations | |
| import importlib.util | |
| import json | |
| import random | |
| import re | |
| import sys | |
| from datetime import datetime, timezone | |
| from pathlib import Path | |
| from types import ModuleType | |
| from adam.config import ConfigManager | |
| from adam.executor import ToolCancelled, ToolContext, ToolExecutionError | |
| from adam.generations import generation_metadata_path, generation_output_folder | |
| from adam.generation_previews import accepts_preview_callback, publish_generation_preview | |
| from adam.image_preferences import GenerationPreferenceEvaluator, PreferenceProfile | |
| _backend_module: ModuleType | None = None | |
| _backend_script: Path | None = None | |
| _loaded_model: object | None = None | |
| _loaded_model_path: Path | None = None | |
| def _load_backend(script: Path) -> ModuleType: | |
| global _backend_module, _backend_script | |
| if _backend_module is not None and _backend_script == script: | |
| return _backend_module | |
| module_name = "_adam_connected_flow_generator" | |
| spec = importlib.util.spec_from_file_location(module_name, script) | |
| if spec is None or spec.loader is None: | |
| raise ToolExecutionError("The connected Flow Matching generator could not be loaded.") | |
| module = importlib.util.module_from_spec(spec) | |
| sys.modules[module_name] = module | |
| try: | |
| spec.loader.exec_module(module) | |
| except Exception as exc: | |
| sys.modules.pop(module_name, None) | |
| raise ToolExecutionError(f"Could not load the Flow Matching generator: {exc}") from exc | |
| if not callable(getattr(module, "load_unet", None)) or not callable( | |
| getattr(module, "sample_flow", None) | |
| ): | |
| raise ToolExecutionError( | |
| "The connected Flow Matching app does not expose its generation functions." | |
| ) | |
| _backend_module = module | |
| _backend_script = script | |
| return module | |
| def _safe_label(value: str) -> str: | |
| label = value.strip()[:96] or "Flow" | |
| label = re.sub(r"[<>:\"/\\|?*\x00-\x1f]+", " ", label) | |
| label = re.sub(r"\s+", " ", label).strip(" .") | |
| return label or "Flow" | |
| def generate_flow_images( | |
| context: ToolContext, | |
| model_name: str, | |
| model_path: str, | |
| prompt: str, | |
| image_count: int, | |
| steps: int, | |
| seed: int, | |
| sampler: str, | |
| aspect_ratio: str, | |
| width: int = 0, | |
| height: int = 0, | |
| preview_interval: int = 0, | |
| smart_generation: bool = False, | |
| smart_wanted_results: int = 0, | |
| smart_max_candidates: int = 0, | |
| smart_min_score: float = 0.70, | |
| smart_mode: str = "threshold", | |
| smart_keep_rejected: bool = True, | |
| ) -> dict[str, object]: | |
| global _loaded_model, _loaded_model_path | |
| config = ConfigManager(context.root) | |
| flow_root = Path( | |
| str(config.get("tool_folders", {}).get("flow_trainer", "")) | |
| ).expanduser().resolve() | |
| script = flow_root / "flow_matching_app.py" | |
| if not script.is_file(): | |
| raise ToolExecutionError( | |
| "Flow Matching flow_matching_app.py was not found. Re-scan its folder in Settings." | |
| ) | |
| model = Path(model_path).expanduser().resolve() | |
| allowed_root = (flow_root / "output_flow_models").resolve() | |
| try: | |
| model.relative_to(allowed_root) | |
| except ValueError as exc: | |
| raise ToolExecutionError( | |
| "The Flow model must be inside the connected Flow Matching output folder." | |
| ) from exc | |
| try: | |
| info = json.loads((model / "flow_model_info.json").read_text(encoding="utf-8")) | |
| except (OSError, ValueError, TypeError, json.JSONDecodeError) as exc: | |
| raise ToolExecutionError("Choose a completed Flow Matching image model.") from exc | |
| if info.get("model_type") != "rectified_flow" or not ( | |
| model / "unet" / "config.json" | |
| ).is_file(): | |
| raise ToolExecutionError("Choose a completed Flow Matching image model.") | |
| missing_packages = [ | |
| package | |
| for package in ("torch", "torchvision", "diffusers", "PIL") | |
| if importlib.util.find_spec(package) is None | |
| ] | |
| if missing_packages: | |
| raise ToolExecutionError( | |
| "ADAM's Python environment is missing Flow generation packages: " | |
| + ", ".join(missing_packages) | |
| + ". Install the connected Flow Matching requirements, then restart ADAM." | |
| ) | |
| count = int(image_count) | |
| step_count = int(steps) | |
| smart_enabled = bool(smart_generation) | |
| wanted_results = int(smart_wanted_results or count) | |
| max_candidates = int(smart_max_candidates or count) | |
| if smart_enabled: | |
| if not 1 <= wanted_results <= 48: | |
| raise ToolExecutionError("Wanted Smart Generation results must be between 1 and 48.") | |
| if not wanted_results <= max_candidates <= 256: | |
| raise ToolExecutionError("Maximum Smart Generation candidates must be between wanted results and 256.") | |
| if not 0.0 <= float(smart_min_score) <= 1.0: | |
| raise ToolExecutionError("Minimum Smart Generation score must be between 0.00 and 1.00.") | |
| if str(smart_mode).casefold() not in {"threshold", "top_n"}: | |
| raise ToolExecutionError("Smart Generation mode must be threshold or top_n.") | |
| count = wanted_results | |
| if not 1 <= count <= 48: | |
| raise ToolExecutionError("Image count must be between 1 and 48.") | |
| if not 1 <= step_count <= 200: | |
| raise ToolExecutionError("Flow steps must be between 1 and 200.") | |
| method = sampler.strip().title() | |
| if method not in {"Heun", "Euler"}: | |
| raise ToolExecutionError("Flow generation supports the Heun and Euler methods.") | |
| allowed_aspects = { | |
| "1:1 (Square)", "4:3 (Landscape)", "3:4 (Portrait)", | |
| "3:2 (Landscape)", "2:3 (Portrait)", "16:9 (Widescreen)", | |
| "9:16 (Vertical)", | |
| } | |
| if aspect_ratio not in allowed_aspects: | |
| raise ToolExecutionError("Choose one of the supported Flow aspect ratios.") | |
| custom_width = int(width or 0) | |
| custom_height = int(height or 0) | |
| if bool(custom_width) != bool(custom_height): | |
| raise ToolExecutionError("Set both Flow image width and height, or leave both unset.") | |
| if custom_width and ( | |
| not 64 <= custom_width <= 2048 | |
| or not 64 <= custom_height <= 2048 | |
| or custom_width % 16 | |
| or custom_height % 16 | |
| ): | |
| raise ToolExecutionError( | |
| "Flow image width and height must each be between 64 and 2048 pixels and divisible by 16." | |
| ) | |
| if len(prompt) > 500: | |
| raise ToolExecutionError("The generation label must be 500 characters or shorter.") | |
| if not 0 <= int(preview_interval) <= step_count: | |
| raise ToolExecutionError("Preview interval must be between 0 and the total number of steps.") | |
| base_seed = int(seed) | |
| if base_seed <= 0: | |
| base_seed = random.randint(1, 2_147_483_647 - count) | |
| seed_count = max_candidates if smart_enabled else count | |
| if base_seed + seed_count - 1 > 2_147_483_647: | |
| raise ToolExecutionError("The seed is too large for this image count.") | |
| backend = _load_backend(script) | |
| preview_enabled = int(preview_interval) > 0 | |
| preview_supported = accepts_preview_callback(backend.sample_flow) | |
| if preview_enabled and not preview_supported: | |
| context.log("This connected Flow generator does not yet expose denoising previews; generation will continue normally.") | |
| try: | |
| import torch | |
| device = torch.device("cuda" if torch.cuda.is_available() else "cpu") | |
| dtype = torch.float16 if device.type == "cuda" else torch.float32 | |
| if _loaded_model is None or _loaded_model_path != model: | |
| _loaded_model = None | |
| if torch.cuda.is_available(): | |
| torch.cuda.empty_cache() | |
| context.log(f"Loading completed Flow Matching model: {model_name}") | |
| _loaded_model = backend.load_unet(model, device=device, dtype=dtype) | |
| _loaded_model_path = model | |
| except ToolCancelled: | |
| raise | |
| except Exception as exc: | |
| raise ToolExecutionError(f"Could not load the Flow Matching model: {exc}") from exc | |
| timestamp = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S") | |
| output = generation_output_folder(context.root, context.tool.id, _safe_label(model_name)) | |
| context.log("Flow Matching models generate learned visual samples; the label is metadata, not a text prompt.") | |
| image_paths: list[str] = [] | |
| image_evaluations: dict[str, dict[str, object]] = {} | |
| selected_paths: list[str] = [] | |
| generated_total = max_candidates if smart_enabled else count | |
| profile = PreferenceProfile(context.root, context.tool.id, _safe_label(model_name), str(model)) if smart_enabled else None | |
| evaluator = GenerationPreferenceEvaluator(context.root) if smart_enabled else None | |
| threshold = float(smart_min_score) | |
| top_n_mode = str(smart_mode).casefold() == "top_n" | |
| for index in range(generated_total): | |
| context.checkpoint() | |
| current_seed = base_seed + index | |
| def on_progress(done: int, total: int, image_index: int = index) -> None: | |
| completed = image_index + (done / max(1, total)) | |
| context.progress( | |
| max(1, min(99, round(completed * 100 / generated_total))), | |
| f"Generating image {image_index + 1} of {generated_total} 路 flow step {done} of {total}" if smart_enabled else f"Generating image {image_index + 1} of {count} 路 flow step {done} of {total}", | |
| ) | |
| try: | |
| settings = {"aspect_ratio": aspect_ratio} | |
| if custom_width: | |
| settings.update({"width": custom_width, "height": custom_height}) | |
| if preview_enabled and preview_supported: | |
| settings["preview_interval"] = int(preview_interval) | |
| settings["preview_callback"] = lambda payload, step=0, total_steps=step_count, current=index: publish_generation_preview( | |
| context, output, payload, image_index=current, image_count=count, | |
| step=step, total_steps=total_steps, | |
| ) | |
| images = backend.sample_flow( | |
| _loaded_model, | |
| 1, | |
| step_count, | |
| device, | |
| dtype, | |
| current_seed, | |
| method, | |
| on_progress, | |
| **settings, | |
| ) | |
| destination = output / f"{timestamp}_{context.job_id}_{method}_seed_{current_seed}.png" | |
| images[0].save(destination, format="PNG") | |
| except ToolCancelled: | |
| raise | |
| except Exception as exc: | |
| raise ToolExecutionError(f"Flow Matching generation failed: {exc}") from exc | |
| image_paths.append(str(destination)) | |
| if smart_enabled and profile is not None and evaluator is not None: | |
| score = evaluator.score(profile, [destination], keep_threshold=threshold, reject_threshold=profile.reject_threshold)[0] | |
| image_evaluations[str(destination.resolve())] = { | |
| "score": score.score, | |
| "confidence": score.confidence, | |
| "category": score.category, | |
| "reason": score.reason, | |
| } | |
| if not top_n_mode and score.score is not None and score.score >= threshold: | |
| selected_paths.append(str(destination)) | |
| if len(selected_paths) >= wanted_results: | |
| break | |
| created_at = datetime.now(timezone.utc).isoformat() | |
| if smart_enabled and top_n_mode: | |
| ranked = sorted( | |
| image_paths, | |
| key=lambda path: float(image_evaluations.get(str(Path(path).resolve()), {}).get("score") or -1.0), | |
| reverse=True, | |
| ) | |
| selected_paths = ranked[:wanted_results] | |
| if smart_enabled: | |
| ordered_images = [*selected_paths, *[path for path in image_paths if path not in set(selected_paths)]] | |
| else: | |
| ordered_images = image_paths | |
| metadata = { | |
| "version": 1, | |
| "provider_id": context.tool.id, | |
| "provider_name": context.tool.name, | |
| "model_name": _safe_label(model_name), | |
| "model_path": str(model), | |
| "prompt": prompt.strip(), | |
| "prompt_behavior": "label_only", | |
| "seed": base_seed, | |
| "image_seeds": [base_seed + index for index in range(count)], | |
| "image_count": len(ordered_images) if smart_enabled and smart_keep_rejected else count, | |
| "steps": step_count, | |
| "sampler": method, | |
| "aspect_ratio": aspect_ratio, | |
| "width": custom_width, | |
| "height": custom_height, | |
| "preview_interval": int(preview_interval), | |
| "preview_supported": preview_supported, | |
| "images": ordered_images if smart_keep_rejected or not smart_enabled else selected_paths, | |
| "image_evaluations": image_evaluations, | |
| "smart_generation": { | |
| "enabled": smart_enabled, | |
| "mode": str(smart_mode), | |
| "wanted_results": wanted_results if smart_enabled else count, | |
| "maximum_candidates": max_candidates if smart_enabled else count, | |
| "minimum_score": threshold, | |
| "selected_count": len(selected_paths) if smart_enabled else count, | |
| "candidate_count": len(image_paths), | |
| "profile_id": profile.id if profile else "", | |
| "keep_rejected_candidates": bool(smart_keep_rejected), | |
| }, | |
| "created_at": created_at, | |
| } | |
| generation_metadata_path(output, timestamp, context.job_id).write_text( | |
| json.dumps(metadata, indent=2), encoding="utf-8" | |
| ) | |
| if evaluator is not None: | |
| evaluator.vision.unload() | |
| if smart_enabled: | |
| context.progress(100, f"Smart Generation selected {len(selected_paths)} of {wanted_results} requested image(s) from {len(image_paths)} candidate(s)") | |
| else: | |
| context.progress(100, f"Generated {count} image(s)") | |
| return { | |
| "output_folder": str(output), | |
| "assets": [ | |
| { | |
| "kind": "generation", | |
| "name": f"{_safe_label(model_name)} 路 {timestamp}", | |
| "path": str(output), | |
| "trainer": "flow", | |
| } | |
| ], | |
| } | |