Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/development/INTERNATIONALIZATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ Typed JSON under `ui/src/i18n/locales/<lng>/<namespace>.json`.
| `styleSheet` | Style sheet library, import and delete chrome |
| `projects` | Durable projects catalog |
| `auditDev` | Internal audio-hallucination audit panel |
| `scene3d` | 3D Video, Hunyuan3D, Rig & Animate |
| `shell` | Intro, LAN gate, preflight/OOM/download banners |
| `characters` | Character Creator and Character Kits |
| `comics` | Comic Studio |
| `studio` | Direct generation sidebar (prompt, inputs, modes, tools) |

Add a namespace only when a new product surface needs its own file. Do not grow a single giant JSON.

Expand Down
7 changes: 5 additions & 2 deletions tests/test_h3_window_planner.py
Original file line number Diff line number Diff line change
Expand Up @@ -388,14 +388,17 @@ def test_ui_and_runtime_use_explicit_prompt_arrays(self):
advanced = (ROOT / "ui" / "src" / "components" / "Sidebar" / "AdvancedSettings.tsx").read_text(encoding="utf-8")
prompt_input = (ROOT / "ui" / "src" / "components" / "Sidebar" / "PromptInput.tsx").read_text(encoding="utf-8")
main_content = (ROOT / "ui" / "src" / "components" / "MainContent" / "MainContent.tsx").read_text(encoding="utf-8")
studio = json.loads((ROOT / "ui" / "src" / "i18n" / "locales" / "en" / "studio.json").read_text(encoding="utf-8"))
guide = APP / "services" / "llm_guides" / "enhance" / "minimax_h3_sliding_windows.md"
self.assertIn("h3_window_prompts=None", handler)
self.assertIn("Using {len(prompts)} explicit", handler)
self.assertIn('/api/v1/llm/plan-h3-windows', llm_router)
self.assertIn("h3_window_plan_signature", launch)
self.assertIn("api.planH3Windows", store)
self.assertIn("Plan Prompt Across Windows", advanced)
self.assertIn("Exact H3 prompts", prompt_input)
self.assertIn("t('advanced.planWindows')", advanced)
self.assertEqual(studio["advanced"]["planWindows"], "Plan Prompt Across Windows")
self.assertIn("t('prompt.h3Exact'", prompt_input)
self.assertIn("Exact H3 prompts", studio["prompt"]["h3Exact"])
self.assertIn("H3WindowPromptTextarea", prompt_input)
self.assertIn("textarea.scrollHeight", prompt_input)
self.assertNotIn("max-h-[360px] overflow-y-auto", prompt_input)
Expand Down
38 changes: 27 additions & 11 deletions tests/test_minimax_h3.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
_ASPECT_RATIO_GRID_PATH = _ROOT / "ui" / "src" / "components" / "Sidebar" / "AspectRatioGrid.tsx"
_MODEL_SELECTOR_PATH = _ROOT / "ui" / "src" / "components" / "Sidebar" / "ModelSelector.tsx"
_LORA_SELECTOR_PATH = _ROOT / "ui" / "src" / "components" / "SettingsDrawer" / "LoraSelector.tsx"
_STUDIO_EN_PATH = _ROOT / "ui" / "src" / "i18n" / "locales" / "en" / "studio.json"
_ENHANCE_GUIDES_PATH = _APP / "services" / "enhance_guides.py"
_PROMPT_POLISH_PATH = _APP / "services" / "director" / "prompt_polish.py"
_H3_ENHANCE_GUIDE_PATH = _APP / "services" / "llm_guides" / "enhance" / "minimax_h3_video.md"
Expand Down Expand Up @@ -799,6 +800,7 @@ def test_ref2va_default_and_handler_contract_are_separate_from_fl2va(self):
self.assertIn("audio references", model_def["selector_help"])

def test_h3_selector_names_and_audio_badges_are_user_facing(self):
studio = json.loads(_STUDIO_EN_PATH.read_text(encoding="utf-8"))
expected_names = {
_DEFAULT_PATH: "H3 First / Last — Pruned",
_LEGACY_DEFAULT_PATH: "H3 Legacy Quality — ConvRot",
Expand All @@ -820,8 +822,10 @@ def test_h3_selector_names_and_audio_badges_are_user_facing(self):
self.assertIn("converts Pruned adapters", full_omni["lora_compatibility_note"])

selector = _read(_MODEL_SELECTOR_PATH)
self.assertIn("Audio Out", selector)
self.assertIn("Audio In", selector)
self.assertIn("t('model.audioOut')", selector)
self.assertIn("t('model.audioIn')", selector)
self.assertEqual(studio["model"]["audioOut"], "Audio Out")
self.assertEqual(studio["model"]["audioIn"], "Audio In")
self.assertNotIn("badges.push('Audio')", selector)
self.assertIn("lora_compatibility_note", _read(_LORA_SELECTOR_PATH))
launch = _read(_LAUNCH_PATH)
Expand Down Expand Up @@ -877,6 +881,7 @@ def test_studio_h3_duration_and_window_controls_are_model_aware(self):
advanced = _read(_ADVANCED_SETTINGS_PATH)
store = _read(_STORE_PATH)
launch = _read(_LAUNCH_PATH)
studio = json.loads(_STUDIO_EN_PATH.read_text(encoding="utf-8"))

self.assertIn(
"supportsSlidingWindows = modelOptions?.sliding_window === true",
Expand All @@ -894,7 +899,8 @@ def test_studio_h3_duration_and_window_controls_are_model_aware(self):
self.assertIn("unsupportedAutoResolution", duration)
self.assertIn("fallbackResolution", duration)
self.assertIn("sliding_window_memory_override", store)
self.assertIn("full prompt auto-paced", duration)
self.assertIn("t('duration.autoPaced')", duration)
self.assertEqual(studio["duration"]["autoPaced"], "full prompt auto-paced")
self.assertIn('"sliding_window_memory_policy": md.get(', launch)
self.assertIn('h3_window_adjustment.get("unsupported")', launch)

Expand Down Expand Up @@ -989,6 +995,7 @@ def test_omni_reference_request_and_ui_are_wired_end_to_end(self):
llm_slice = _read(_LLM_SLICE_PATH)
section = _read(_OMNI_REFERENCE_SECTION_PATH)
generate_button = _read(_GENERATE_BUTTON_PATH)
studio = json.loads(_STUDIO_EN_PATH.read_text(encoding="utf-8"))
self.assertIn('if _generation_model_def.get("omni_reference"):', launch)
self.assertIn("validate_reference_manifest", launch)
self.assertIn("per_clip_minimax_h3_references", launch)
Expand All @@ -1004,13 +1011,19 @@ def test_omni_reference_request_and_ui_are_wired_end_to_end(self):
self.assertIn("intent=AUDIO REUSE / PERFORMANCE DRIVER", llm_slice)
self.assertIn("intent=VOICE REFERENCE", llm_slice)
self.assertIn('draggable', section)
self.assertIn("Include soundtrack", section)
self.assertIn("Attach audio", section)
self.assertIn("t('omni.includeSoundtrack')", section)
self.assertIn("t('omni.attachAudio')", section)
self.assertIn("audio_path", section)
self.assertIn("Maximum detail", section)
self.assertIn("Voice reference", section)
self.assertIn("Drive / reuse audio", section)
self.assertIn("Sound / music style", section)
self.assertIn("t('omni.max')", section)
self.assertIn("t('omni.voiceRef')", section)
self.assertIn("t('omni.drive')", section)
self.assertIn("t('omni.style')", section)
self.assertEqual(studio["omni"]["includeSoundtrack"], "Include soundtrack")
self.assertEqual(studio["omni"]["attachAudio"], "Attach audio")
self.assertEqual(studio["omni"]["max"], "Maximum detail")
self.assertEqual(studio["omni"]["voiceRef"], "Voice reference")
self.assertEqual(studio["omni"]["drive"], "Drive / reuse audio")
self.assertEqual(studio["omni"]["style"], "Sound / music style")
self.assertIn("const hasOmniVisualReference = useStore(s =>", generate_button)
self.assertNotIn(
"useStore(s => s.params.minimax_h3_references ?? [])",
Expand Down Expand Up @@ -1315,6 +1328,7 @@ def test_managed_turbo_choice_is_discoverable_for_full_and_pruned(self):
sidebar = _read(_SIDEBAR_PATH)
advanced = _read(_ADVANCED_SETTINGS_PATH)
types_source = _read(_TYPES_PATH)
studio = json.loads(_STUDIO_EN_PATH.read_text(encoding="utf-8"))

self.assertIn("def _minimax_h3_turbo_option", launch)
self.assertIn('names.add(turbo_option["filename"])', launch)
Expand All @@ -1324,11 +1338,13 @@ def test_managed_turbo_choice_is_discoverable_for_full_and_pruned(self):
self.assertIn("_minimax_h3_runtime_advisory", launch)
self.assertIn("normalize_minimax_h3_turbo_request", launch)
self.assertIn("<MiniMaxH3TurboToggle />", sidebar)
self.assertIn("Experimental", toggle)
self.assertIn("t('chrome.experimental')", toggle)
self.assertIn("setParam('num_inference_steps', option.steps)", toggle)
self.assertIn("toggleLora(option.filename)", toggle)
self.assertIn("setLoraWeight(option.filename, 0, option.weight)", toggle)
self.assertIn("Use Pruned Turbo", toggle)
self.assertIn("t('h3Turbo.usePruned')", toggle)
self.assertEqual(studio["chrome"]["experimental"], "Experimental")
self.assertEqual(studio["h3Turbo"]["usePruned"], "Use Pruned Turbo")
self.assertIn("recommended_model_type", toggle)
self.assertIn("disabled={h3TurboMode}", advanced)
self.assertIn("minimax_h3_turbo_mode?: boolean", types_source)
Expand Down
25 changes: 19 additions & 6 deletions tests/test_phase1_issue_fixes.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import ast
import importlib.util
import json
import math
import os
import sys
Expand Down Expand Up @@ -68,6 +69,9 @@
"Sidebar",
"OutpaintCanvas.tsx",
)
_STUDIO_EN_PATH = os.path.join(
_ROOT, "ui", "src", "i18n", "locales", "en", "studio.json",
)

_requires_torch = unittest.skipUnless(
importlib.util.find_spec("torch") is not None,
Expand Down Expand Up @@ -1725,7 +1729,9 @@ def test_ui_replaces_misleading_controls_with_one_recommended_toggle(self):
controls = _read(_OUTPAINT_CONTROLS_PATH)
client = api_client_source()
store = _read(_STORE_PATH)
self.assertIn("Preserve original scene", controls)
studio = json.loads(_read(_STUDIO_EN_PATH))
self.assertIn("t('outpaint.preserveScene')", controls)
self.assertEqual(studio["outpaint"]["preserveScene"], "Preserve original scene")
self.assertIn("outpaintMaskPreserving: true", store)
self.assertIn("mask_preserving_outpaint?: boolean", client)
self.assertIn("outpaint_aspect?:", client)
Expand Down Expand Up @@ -1760,9 +1766,12 @@ def test_outpaint_generate_button_explains_zero_generation_area(self):
"GenerateButton.tsx",
)
)
studio = json.loads(_read(_STUDIO_EN_PATH))
self.assertIn("needsOutpaintArea", generate_button)
self.assertIn("Choose canvas", generate_button)
self.assertIn("area for Outpaint to generate", generate_button)
self.assertIn("t('generate.chooseCanvas')", generate_button)
self.assertIn("t('generate.outpaintAreaHint')", generate_button)
self.assertEqual(studio["generate"]["chooseCanvas"], "Choose canvas")
self.assertIn("area for Outpaint to generate", studio["generate"]["outpaintAreaHint"])

def test_backend_uses_official_lora_and_internal_blend(self):
launch = _read(_LAUNCH_PATH)
Expand Down Expand Up @@ -2692,14 +2701,18 @@ def test_server_and_frontend_use_durable_visibility(self):
class TestFramesControlVideoAudio(unittest.TestCase):
def test_control_video_presence_is_not_derived_from_audio_mode(self):
source = _read(_INPUTS_PATH)
studio = json.loads(_read(_STUDIO_EN_PATH))
self.assertIn(
"const hasControlVid = supportsControlVid && "
"!!params.video_guide",
source,
)
self.assertIn("Generate soundtrack from text prompt", source)
self.assertIn("Generate new audio from control video", source)
self.assertIn("The control video remains attached", source)
self.assertIn("t('inputs.generateFromText')", source)
self.assertIn("t('inputs.generateFromControl')", source)
self.assertIn("t('inputs.controlStays')", source)
self.assertEqual(studio["inputs"]["generateFromText"], "Generate soundtrack from text prompt")
self.assertEqual(studio["inputs"]["generateFromControl"], "Generate new audio from control video")
self.assertIn("The control video remains attached", studio["inputs"]["controlStays"])
self.assertIn("rawControlProcess", source)
self.assertNotIn("supportsSoundtrack && !hasControlVid", source)
self.assertNotIn("supportsControlVid && !hasSoundtrack", source)
Expand Down
Loading