Upload 15 files
Browse files- src/model_scan.py +211 -2
- src/version.py +2 -2
- src/worker_payload.py +3 -3
src/model_scan.py
CHANGED
|
@@ -69,6 +69,197 @@ IMAGE_OUTPUT_HINT_RE = re.compile(
|
|
| 69 |
r"(\.images\s*\[|generated image|text-to-image|image = pipe\()",
|
| 70 |
re.IGNORECASE,
|
| 71 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 72 |
|
| 73 |
|
| 74 |
def infer_expected_output_type(
|
|
@@ -429,13 +620,19 @@ def analyze_model_metadata(
|
|
| 429 |
has_diffusers_example = bool(card_signals["has_diffusers_example"])
|
| 430 |
pipeline_class = str(card_signals["pipeline_class"] or "")
|
| 431 |
runtime_hints = list(card_signals["runtime_hints"] or [])
|
| 432 |
-
|
| 433 |
pipeline_tag=pipeline_tag,
|
| 434 |
library_name=library_name,
|
| 435 |
tags=tags,
|
| 436 |
pipeline_class=pipeline_class,
|
| 437 |
readme=readme,
|
| 438 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 439 |
|
| 440 |
score = 50
|
| 441 |
good: list[str] = []
|
|
@@ -457,8 +654,10 @@ def analyze_model_metadata(
|
|
| 457 |
else:
|
| 458 |
score -= 12
|
| 459 |
risk.append("No pipeline tag detected; task type may be ambiguous for an autonomous builder.")
|
|
|
|
|
|
|
| 460 |
if expected_output_type:
|
| 461 |
-
good.append(f"
|
| 462 |
|
| 463 |
if library_name:
|
| 464 |
score += 10
|
|
@@ -599,6 +798,11 @@ def analyze_model_metadata(
|
|
| 599 |
"risk_signals": risk[:10],
|
| 600 |
"recommendations": recommendations[:6],
|
| 601 |
"expected_output_type": expected_output_type or "",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 602 |
"build_risk": build_risk,
|
| 603 |
"kernel_strategy": kernel_strategy,
|
| 604 |
"metadata": {
|
|
@@ -616,6 +820,11 @@ def analyze_model_metadata(
|
|
| 616 |
"pipeline_class": pipeline_class,
|
| 617 |
"runtime_hints": runtime_hints,
|
| 618 |
"expected_output_type": expected_output_type or "",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 619 |
"diffusers_standard": bool(is_diffusers and has_model_index and has_safetensors),
|
| 620 |
"build_risk_level": build_risk["level"],
|
| 621 |
"recommended_session_minutes": build_risk["recommended_session_minutes"],
|
|
|
|
| 69 |
r"(\.images\s*\[|generated image|text-to-image|image = pipe\()",
|
| 70 |
re.IGNORECASE,
|
| 71 |
)
|
| 72 |
+
INPUT_MODALITY_ORDER = ("text", "image", "audio", "video", "file")
|
| 73 |
+
INPUT_MODALITY_HINTS = {
|
| 74 |
+
"text": (
|
| 75 |
+
"text prompt",
|
| 76 |
+
"input prompt",
|
| 77 |
+
"prompt:",
|
| 78 |
+
"prompt=",
|
| 79 |
+
"gr.textbox",
|
| 80 |
+
"textbox",
|
| 81 |
+
),
|
| 82 |
+
"image": (
|
| 83 |
+
"image_path",
|
| 84 |
+
"input image",
|
| 85 |
+
"image input",
|
| 86 |
+
"source image",
|
| 87 |
+
"reference image",
|
| 88 |
+
"avatar image",
|
| 89 |
+
"person image",
|
| 90 |
+
"gr.image",
|
| 91 |
+
"pil.image",
|
| 92 |
+
"upload image",
|
| 93 |
+
),
|
| 94 |
+
"audio": (
|
| 95 |
+
"audio_path",
|
| 96 |
+
"input audio",
|
| 97 |
+
"audio input",
|
| 98 |
+
"source audio",
|
| 99 |
+
"speech audio",
|
| 100 |
+
"voice audio",
|
| 101 |
+
"single audio",
|
| 102 |
+
"multi audio",
|
| 103 |
+
"gr.audio",
|
| 104 |
+
".wav",
|
| 105 |
+
),
|
| 106 |
+
"video": (
|
| 107 |
+
"video_path",
|
| 108 |
+
"input video",
|
| 109 |
+
"video input",
|
| 110 |
+
"source video",
|
| 111 |
+
"reference video",
|
| 112 |
+
"gr.video",
|
| 113 |
+
".mp4",
|
| 114 |
+
),
|
| 115 |
+
"file": (
|
| 116 |
+
"file_path",
|
| 117 |
+
"input file",
|
| 118 |
+
"file input",
|
| 119 |
+
"upload file",
|
| 120 |
+
"gr.file",
|
| 121 |
+
),
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
|
| 125 |
+
def _ordered_modalities(values: set[str]) -> list[str]:
|
| 126 |
+
return [name for name in INPUT_MODALITY_ORDER if name in values]
|
| 127 |
+
|
| 128 |
+
|
| 129 |
+
def infer_expected_inputs(
|
| 130 |
+
*,
|
| 131 |
+
pipeline_tag: str | None = None,
|
| 132 |
+
tags: list[str] | None = None,
|
| 133 |
+
readme: str | None = None,
|
| 134 |
+
) -> list[str]:
|
| 135 |
+
modalities: set[str] = set()
|
| 136 |
+
task = (pipeline_tag or "").strip().lower()
|
| 137 |
+
tag_set = {str(t).lower() for t in (tags or [])}
|
| 138 |
+
task_like = {task, *tag_set}
|
| 139 |
+
|
| 140 |
+
for item in task_like:
|
| 141 |
+
if item.startswith("text-to-") or item in {
|
| 142 |
+
"text-generation",
|
| 143 |
+
"text2text-generation",
|
| 144 |
+
"summarization",
|
| 145 |
+
"translation",
|
| 146 |
+
"question-answering",
|
| 147 |
+
"fill-mask",
|
| 148 |
+
"sentence-similarity",
|
| 149 |
+
"token-classification",
|
| 150 |
+
"zero-shot-classification",
|
| 151 |
+
}:
|
| 152 |
+
modalities.add("text")
|
| 153 |
+
if item.startswith("image-to-") or item in {"image-classification", "object-detection", "image-segmentation"}:
|
| 154 |
+
modalities.add("image")
|
| 155 |
+
if item.startswith("audio-to-") or item in {"automatic-speech-recognition", "audio-classification"}:
|
| 156 |
+
modalities.add("audio")
|
| 157 |
+
if item.startswith("video-to-"):
|
| 158 |
+
modalities.add("video")
|
| 159 |
+
|
| 160 |
+
text = (readme or "").lower()
|
| 161 |
+
for modality, hints in INPUT_MODALITY_HINTS.items():
|
| 162 |
+
if any(hint in text for hint in hints):
|
| 163 |
+
modalities.add(modality)
|
| 164 |
+
if re.search(r"\bprompt\b", text) and any(word in text for word in ("pipe(", "generate", "demo", "gradio")):
|
| 165 |
+
modalities.add("text")
|
| 166 |
+
|
| 167 |
+
return _ordered_modalities(modalities)
|
| 168 |
+
|
| 169 |
+
|
| 170 |
+
def infer_output_guess(
|
| 171 |
+
*,
|
| 172 |
+
pipeline_tag: str | None = None,
|
| 173 |
+
library_name: str | None = None,
|
| 174 |
+
tags: list[str] | None = None,
|
| 175 |
+
pipeline_class: str | None = None,
|
| 176 |
+
readme: str | None = None,
|
| 177 |
+
) -> dict[str, Any]:
|
| 178 |
+
expected = infer_expected_output_type(
|
| 179 |
+
pipeline_tag=pipeline_tag,
|
| 180 |
+
library_name=library_name,
|
| 181 |
+
tags=tags,
|
| 182 |
+
pipeline_class=pipeline_class,
|
| 183 |
+
readme=readme,
|
| 184 |
+
)
|
| 185 |
+
task = (pipeline_tag or "").strip().lower()
|
| 186 |
+
tag_set = {str(t).lower() for t in (tags or [])}
|
| 187 |
+
cls = (pipeline_class or "").strip().lower()
|
| 188 |
+
text = (readme or "").lower()
|
| 189 |
+
library = (library_name or "").strip().lower()
|
| 190 |
+
combined = " ".join([library, cls, " ".join(sorted(tag_set)), text])
|
| 191 |
+
evidence: list[str] = []
|
| 192 |
+
confidence = "low"
|
| 193 |
+
source = "none"
|
| 194 |
+
|
| 195 |
+
if task in TASK_OUTPUT_TYPE_MAP:
|
| 196 |
+
confidence = "high"
|
| 197 |
+
source = "pipeline_tag"
|
| 198 |
+
evidence.append(f"pipeline_tag={task} maps to {TASK_OUTPUT_TYPE_MAP[task]}.")
|
| 199 |
+
elif {"text-to-video", "image-to-video"} & tag_set:
|
| 200 |
+
confidence = "high"
|
| 201 |
+
source = "tags"
|
| 202 |
+
evidence.append("Hub tags include text-to-video or image-to-video.")
|
| 203 |
+
elif {"text-to-image", "image-to-image", "diffusers"} & tag_set and expected == "image":
|
| 204 |
+
confidence = "medium"
|
| 205 |
+
source = "tags"
|
| 206 |
+
evidence.append("Hub tags indicate a Diffusers image workflow.")
|
| 207 |
+
elif {"text-to-audio", "text-to-speech", "audio"} & tag_set and expected == "audio":
|
| 208 |
+
confidence = "medium"
|
| 209 |
+
source = "tags"
|
| 210 |
+
evidence.append("Hub tags indicate an audio generation workflow.")
|
| 211 |
+
elif any(hint in cls for hint in IMAGE_PIPELINE_HINTS) and expected == "image":
|
| 212 |
+
confidence = "medium"
|
| 213 |
+
source = "pipeline_class"
|
| 214 |
+
evidence.append(f"Pipeline class {pipeline_class} looks image-oriented.")
|
| 215 |
+
elif "video" in cls and expected == "video":
|
| 216 |
+
confidence = "high"
|
| 217 |
+
source = "pipeline_class"
|
| 218 |
+
evidence.append(f"Pipeline class {pipeline_class} looks video-oriented.")
|
| 219 |
+
elif "audio" in cls or "speech" in cls:
|
| 220 |
+
confidence = "medium"
|
| 221 |
+
source = "pipeline_class"
|
| 222 |
+
evidence.append(f"Pipeline class {pipeline_class} looks audio-oriented.")
|
| 223 |
+
|
| 224 |
+
if VIDEO_OUTPUT_HINT_RE.search(combined) or re.search(r"\.frames\s*\[", text):
|
| 225 |
+
if expected == "video":
|
| 226 |
+
confidence = "high"
|
| 227 |
+
source = "model_card"
|
| 228 |
+
evidence.append("Model card or library name mentions video/avatar generation markers.")
|
| 229 |
+
elif IMAGE_OUTPUT_HINT_RE.search(text) and expected == "image":
|
| 230 |
+
if confidence == "low":
|
| 231 |
+
confidence = "medium"
|
| 232 |
+
source = "model_card"
|
| 233 |
+
evidence.append("Model card includes image output usage such as pipe(...).images.")
|
| 234 |
+
elif re.search(r"\.audios?\s*\[|generated audio|text-to-speech|soundfile|\.wav", text) and expected == "audio":
|
| 235 |
+
if confidence == "low":
|
| 236 |
+
confidence = "medium"
|
| 237 |
+
source = "model_card"
|
| 238 |
+
evidence.append("Model card includes audio output markers.")
|
| 239 |
+
elif re.search(r"generated_text|tokenizer\.decode|text-generation|response\s*=", text) and expected == "text":
|
| 240 |
+
if confidence == "low":
|
| 241 |
+
confidence = "medium"
|
| 242 |
+
source = "model_card"
|
| 243 |
+
evidence.append("Model card includes text output markers.")
|
| 244 |
+
|
| 245 |
+
if expected == "any":
|
| 246 |
+
confidence = "low"
|
| 247 |
+
if not evidence:
|
| 248 |
+
evidence.append("Custom or ambiguous library without a strong generated-output signal; keeping output flexible.")
|
| 249 |
+
elif not expected:
|
| 250 |
+
evidence.append("No strong generated-output signal found in pre-scan metadata.")
|
| 251 |
+
elif not evidence:
|
| 252 |
+
evidence.append(f"Pre-scan inferred {expected} from weak metadata signals.")
|
| 253 |
+
|
| 254 |
+
return {
|
| 255 |
+
"schema_version": "pre_scan_output_guess.v1",
|
| 256 |
+
"expected_output_type": expected or "",
|
| 257 |
+
"confidence": confidence,
|
| 258 |
+
"source": source,
|
| 259 |
+
"authority": "pre_scan_guess",
|
| 260 |
+
"final_authority": "runtime_contract_or_gradio_schema",
|
| 261 |
+
"evidence": evidence[:6],
|
| 262 |
+
}
|
| 263 |
|
| 264 |
|
| 265 |
def infer_expected_output_type(
|
|
|
|
| 620 |
has_diffusers_example = bool(card_signals["has_diffusers_example"])
|
| 621 |
pipeline_class = str(card_signals["pipeline_class"] or "")
|
| 622 |
runtime_hints = list(card_signals["runtime_hints"] or [])
|
| 623 |
+
output_guess = infer_output_guess(
|
| 624 |
pipeline_tag=pipeline_tag,
|
| 625 |
library_name=library_name,
|
| 626 |
tags=tags,
|
| 627 |
pipeline_class=pipeline_class,
|
| 628 |
readme=readme,
|
| 629 |
)
|
| 630 |
+
expected_output_type = output_guess["expected_output_type"] or None
|
| 631 |
+
expected_inputs = infer_expected_inputs(
|
| 632 |
+
pipeline_tag=pipeline_tag,
|
| 633 |
+
tags=tags,
|
| 634 |
+
readme=readme,
|
| 635 |
+
)
|
| 636 |
|
| 637 |
score = 50
|
| 638 |
good: list[str] = []
|
|
|
|
| 654 |
else:
|
| 655 |
score -= 12
|
| 656 |
risk.append("No pipeline tag detected; task type may be ambiguous for an autonomous builder.")
|
| 657 |
+
if expected_inputs:
|
| 658 |
+
good.append("Inputs detected by pre-scan: " + ", ".join(expected_inputs) + ".")
|
| 659 |
if expected_output_type:
|
| 660 |
+
good.append(f"Pre-scan output guess: {expected_output_type} (confidence {output_guess['confidence']}).")
|
| 661 |
|
| 662 |
if library_name:
|
| 663 |
score += 10
|
|
|
|
| 798 |
"risk_signals": risk[:10],
|
| 799 |
"recommendations": recommendations[:6],
|
| 800 |
"expected_output_type": expected_output_type or "",
|
| 801 |
+
"expected_inputs": expected_inputs,
|
| 802 |
+
"output_confidence": output_guess["confidence"],
|
| 803 |
+
"output_authority": output_guess["authority"],
|
| 804 |
+
"output_evidence": output_guess["evidence"],
|
| 805 |
+
"pre_scan_output": output_guess,
|
| 806 |
"build_risk": build_risk,
|
| 807 |
"kernel_strategy": kernel_strategy,
|
| 808 |
"metadata": {
|
|
|
|
| 820 |
"pipeline_class": pipeline_class,
|
| 821 |
"runtime_hints": runtime_hints,
|
| 822 |
"expected_output_type": expected_output_type or "",
|
| 823 |
+
"expected_inputs": expected_inputs,
|
| 824 |
+
"output_confidence": output_guess["confidence"],
|
| 825 |
+
"output_authority": output_guess["authority"],
|
| 826 |
+
"output_evidence": output_guess["evidence"],
|
| 827 |
+
"pre_scan_output": output_guess,
|
| 828 |
"diffusers_standard": bool(is_diffusers and has_model_index and has_safetensors),
|
| 829 |
"build_risk_level": build_risk["level"],
|
| 830 |
"recommended_session_minutes": build_risk["recommended_session_minutes"],
|
src/version.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
from __future__ import annotations
|
| 2 |
|
| 3 |
-
ASF_APP_VERSION = "v198.26.
|
| 4 |
-
ASF_RELEASE_NAME = "Agentic Space Factory v198.26.
|
| 5 |
|
| 6 |
|
| 7 |
def resolve_app_version(value: str | None = None) -> str:
|
|
|
|
| 1 |
from __future__ import annotations
|
| 2 |
|
| 3 |
+
ASF_APP_VERSION = "v198.26.61"
|
| 4 |
+
ASF_RELEASE_NAME = "Agentic Space Factory v198.26.61"
|
| 5 |
|
| 6 |
|
| 7 |
def resolve_app_version(value: str | None = None) -> str:
|
src/worker_payload.py
CHANGED
|
@@ -39,8 +39,8 @@ DEFAULT_PREFERRED_SPACE_HARDWARE = "zero-a10g"
|
|
| 39 |
DEFAULT_FALLBACK_SPACE_HARDWARE = "a10g-large"
|
| 40 |
DEFAULT_MODEL_ID = "sshleifer/tiny-gpt2"
|
| 41 |
MAX_PI_REPAIR_ATTEMPTS = 3
|
| 42 |
-
APP_VERSION = "v198.26.
|
| 43 |
-
app_version = "v198.26.
|
| 44 |
|
| 45 |
# Internal agent/recovery files may be needed inside the transient Pi
|
| 46 |
# workspace, but they should not be published to the generated Space or shown
|
|
@@ -18892,7 +18892,7 @@ def smoke_generate(target_space_id: str, token: str, run_dir: Path, events_path:
|
|
| 18892 |
# write_json(run_dir / "tests" / "payload_source.json", payload_source_record)
|
| 18893 |
# write_json(run_dir / "tests" / "replay_source.json", replay_source)
|
| 18894 |
# write_json(run_dir / "tests" / "validation_preflight.json", validation_preflight)
|
| 18895 |
-
app_version = "v198.26.
|
| 18896 |
engine_version = "unified_gradio_validation_harness_v198_25_3"
|
| 18897 |
parent_build_run_id = os.environ.get("PARENT_BUILD_RUN_ID", "").strip()
|
| 18898 |
validation_mode = os.environ.get("VALIDATION_MODE") or os.environ.get("SPACE_TEST_POLICY_MODE") or "linked"
|
|
|
|
| 39 |
DEFAULT_FALLBACK_SPACE_HARDWARE = "a10g-large"
|
| 40 |
DEFAULT_MODEL_ID = "sshleifer/tiny-gpt2"
|
| 41 |
MAX_PI_REPAIR_ATTEMPTS = 3
|
| 42 |
+
APP_VERSION = "v198.26.61"
|
| 43 |
+
app_version = "v198.26.61"
|
| 44 |
|
| 45 |
# Internal agent/recovery files may be needed inside the transient Pi
|
| 46 |
# workspace, but they should not be published to the generated Space or shown
|
|
|
|
| 18892 |
# write_json(run_dir / "tests" / "payload_source.json", payload_source_record)
|
| 18893 |
# write_json(run_dir / "tests" / "replay_source.json", replay_source)
|
| 18894 |
# write_json(run_dir / "tests" / "validation_preflight.json", validation_preflight)
|
| 18895 |
+
app_version = "v198.26.61"
|
| 18896 |
engine_version = "unified_gradio_validation_harness_v198_25_3"
|
| 18897 |
parent_build_run_id = os.environ.get("PARENT_BUILD_RUN_ID", "").strip()
|
| 18898 |
validation_mode = os.environ.get("VALIDATION_MODE") or os.environ.get("SPACE_TEST_POLICY_MODE") or "linked"
|