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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,6 @@ _ui_backup/
# The whole directory can be deleted at any time; deleting it just means
# it gets re-downloaded next time.
/.cache/

# Local research notes (contain private training names)
/docs/research/
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -1613,7 +1613,7 @@ Test image generation + prior generation + Setup rewrite + Settings split + CLTa
- Backend: `versions.list_project_state_ckpts()` / `list_project_lora_ckpts()` + `/api/projects/{pid}/state_ckpts` / `/lora_ckpts` endpoints
- Fixes the root UX problem: previously you had to dig five levels deep from REPO_ROOT to `output/training_state_step*.pt` just to resume
- **Setup rewrite: GPU-aware torch on first install + venv stale check + --reinstall as a lifeline**
- `studio.bat` is pure ASCII now (no more crashes under cp936 cmd.exe) + a test as backstop
- `studio.bat` is pure ASCII now (no more crashes under non-UTF-8 cmd.exe) + a test as backstop
- bootstrap: prefers `py -3` on Windows, iterates version checks on Linux
- venv stale check + `--reinstall` flag (environment lifeline)
- GPU-aware torch on first install; big warning when a CPU-only build gets installed by mistake
Expand Down
2 changes: 1 addition & 1 deletion docs/announcements/2026-05-09-v0.5.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Test image generation + prior generation + Setup rewrite + Settings split + CLTa
- Backend: `versions.list_project_state_ckpts()` / `list_project_lora_ckpts()` + `/api/projects/{pid}/state_ckpts` / `/lora_ckpts` endpoints
- Fixes the root UX problem: previously you had to dig five levels deep from REPO_ROOT to `output/training_state_step*.pt` just to resume
- **Setup rewrite: GPU-aware torch on first install + venv stale check + --reinstall as a lifeline**
- `studio.bat` is pure ASCII now (no more crashes under cp936 cmd.exe) + a test as backstop
- `studio.bat` is pure ASCII now (no more crashes under non-UTF-8 cmd.exe) + a test as backstop
- bootstrap: prefers `py -3` on Windows, iterates version checks on Linux
- venv stale check + `--reinstall` flag (environment lifeline)
- GPU-aware torch on first install; big warning when a CPU-only build gets installed by mistake
Expand Down
2 changes: 1 addition & 1 deletion docs/design/preprocess-train-scope-plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -893,5 +893,5 @@ moves from project level to version/train/. Module boundaries are unchanged.
- `studio/api/routers/projects/curation.py:117-186,271,342` — thumb endpoint bucket=train + 2 duplicates endpoint URLs
- `studio/web/src/components/Sidebar.tsx:11-29,266-274,472` — STEP order / phase mapping / project-scope regex
- `studio/web/src/api/client.ts` — `VersionPhase` / `PHASE_ORDER` / `PHASE_SKIPPABLE`
- `studio/web/src/i18n/locales/{zh,en}.json` — "(optional)" copy + idx numbering
- `studio/web/src/i18n/locales/{ru,en}.json` — "(optional)" copy + idx numbering
- `studio/web/src/pages/project/steps/Preprocess*.tsx` — data contract + 4 sub-pages
2 changes: 1 addition & 1 deletion docs/design/queue-pause-spike-report.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ was never emitted."
### Parent stdout's own encoding

A minor pitfall unrelated to the main project: on Windows, the shell's default
codepage (cp936 / cp932) raises `UnicodeEncodeError` when encoding non-ASCII
ANSI codepage raises `UnicodeEncodeError` when encoding non-ASCII
`print` output. `env["PYTHONIOENCODING"] = "utf-8"` only takes effect for the
**child process** — the parent itself needs
`sys.stdout.reconfigure(encoding="utf-8")`. The real supervisor writes to
Expand Down
2 changes: 1 addition & 1 deletion runtime/anima_train.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
if _ps not in sys.path:
sys.path.insert(0, _ps)

# The Windows console defaults to cp936; logging / print writing non-ASCII text
# The Windows console defaults to the ANSI codepage; logging / print writing non-ASCII text
# raises UnicodeEncodeError, and the default handler's errors='backslashreplace'
# turns it into \uXXXX escapes -- that's the source of the garbled text seen in task logs.
# Force stdout/stderr to UTF-8 + replace so non-ASCII text / emoji always print directly.
Expand Down
432 changes: 216 additions & 216 deletions studio.bat

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions studio/domain/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@
- the `message` field is **English** -- the frontend looks up `code` in an
i18n table to render a localized string; `message` is only the English
fallback display. This avoids reviving the ADR-0008 §cross-D
Chinese-string-matching trap through DomainError.
localized-string-matching trap through DomainError.
- the `code` field is named **domain.action** (`preset.not_found` /
`curation.duplicate`).
- short-term (0.12.0), existing service errors like PresetError still have
Chinese messages (C3 only adds the base class, doesn't touch messages),
legacy messages (C3 only adds the base class, doesn't touch messages),
but **new code must** use an English message + i18n code.

Usage:
Expand Down
2 changes: 1 addition & 1 deletion studio/infrastructure/logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ def __init__(self) -> None:


def reconfigure_console_utf8() -> None:
"""Windows consoles default to cp932/cp936, so writing non-ASCII text / emoji raises
"""Windows consoles default to a legacy ANSI codepage, so writing non-ASCII text / emoji raises
UnicodeEncodeError. Forces stdout/stderr into UTF-8 + replace mode so the logger never
raises.

Expand Down
2 changes: 1 addition & 1 deletion studio/services/runtime/flash_attention.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ def detect_env() -> dict[str, Any]:
# the driver version is always stored separately as `driver_cuda_ver` for the UI to display and for troubleshooting (so the user can see
# a case like "driver supports cu130, PyTorch is cu128" and immediately understand why the wheel should be cu128).
driver_cuda_ver: Optional[str] = None
# Historically only caught (subprocess.SubprocessError, OSError); on a Windows Chinese locale (cp936),
# Historically only caught (subprocess.SubprocessError, OSError); on a non-UTF-8 Windows locale,
# decoding nvidia-smi output with text=True could raise UnicodeDecodeError (not one of those subclasses),
# causing a raw 500. Switched to errors='replace' to avoid that, and widened the except to Exception.
try:
Expand Down
2 changes: 1 addition & 1 deletion studio/supervisor/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -1365,7 +1365,7 @@ def _popen(
creationflags = 0
if os.name == "nt":
creationflags = subprocess.CREATE_NEW_PROCESS_GROUP # type: ignore[attr-defined]
# Windows defaults stdout to cp936; any worker writing Chinese text / emoji
# Windows defaults stdout to the ANSI codepage; any worker writing non-ASCII text / emoji
# would trigger a UnicodeEncodeError, and logging's default backslashreplace
# would turn it into \uXXXX, filling the task log with garbled text. Give
# every child process a UTF-8 + unbuffered fallback here.
Expand Down
10 changes: 0 additions & 10 deletions studio/web/src/api/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2180,16 +2180,6 @@ export interface ModelsRootMigrateStatus {
error: string
}

export interface AnnouncementPost {
id: string
date: string
tag: 'release' | 'notice' | 'migration'
title: { zh: string; en: string }
body: { zh: string; en: string }
pin: boolean
version: string | null
}

export const api = {
health: () => req<HealthResponse>('/api/health'),
systemStats: () => req<SystemStats>('/api/system/stats'),
Expand Down
2 changes: 1 addition & 1 deletion studio/web/src/components/TagsInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export function parseTags(s: string): string[] {
* - **Editing (focus)**: a plain-text `<input>`, commas / spaces typed freely. Controlled by the text, not the
* array, to avoid a "join-back on every keystroke" wiping out a comma / trailing space being typed. An autocomplete
* popover pops up below the input; keyboard up/down + Enter/Tab select.
* - **Idle (blur)**: renders tags as chips, scannable at a glance; shows the Chinese translation when there's a match.
* - **Idle (blur)**: renders tags as chips, scannable at a glance.
*
* On blur the text is normalized to `tags.join(', ')`, so re-entering edit mode shows the canonical form.
* Use this directly for cases that already have their own outer label (Settings' SettingsField); for a
Expand Down
2 changes: 1 addition & 1 deletion studio/web/src/pages/project/steps/Train.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,7 @@ export default function TrainPage() {
} catch (e) {
const msg = String(e)
// Match on the error code, not on the message: the message is localized
// (and was never Chinese to begin with), so a text match silently turned
// so a text match silently turned
// the overwrite prompt into a plain error toast.
if ((e as ApiError).code === 'preset.exists') {
const overwrite = await confirm(t('train.alreadyExists', { name: trimmed }), {
Expand Down
2 changes: 1 addition & 1 deletion studio/web/src/pages/tools/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ const MODEL_DESCRIPTION_KEYS: Record<string, string> = {
cltagger: 'settings.modelDescriptions.cltagger',
}

// Catalog names come from the backend in Chinese for the main models.
// The backend sends English catalog names; localize the main models on the frontend.
const MODEL_NAME_KEYS: Record<string, string> = {
anima_main: 'settings.modelNames.animaMain',
krea2_main: 'settings.modelNames.krea2Main',
Expand Down
4 changes: 2 additions & 2 deletions studio/workers/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
- calling run + sys.exit

Optional helper `reconfigure_console_utf8()` -- the Windows console defaults to
cp932/cp936, so writing non-ASCII / emoji raises UnicodeEncodeError; calling this once
a legacy ANSI codepage, so writing non-ASCII / emoji raises UnicodeEncodeError; calling this once
switches stdout/stderr to UTF-8 + replace mode. Currently only tag_worker needs it (other
workers don't write non-ASCII captions).
"""
Expand Down Expand Up @@ -68,7 +68,7 @@ def _worker_kind_from_argv() -> str:


def reconfigure_console_utf8() -> None:
"""The Windows console defaults to cp932/cp936, so writing non-ASCII / emoji raises
"""The Windows console defaults to a legacy ANSI codepage, so writing non-ASCII / emoji raises
UnicodeEncodeError. Forces stdout/stderr to UTF-8 + replace-unencodable-chars, so
progress output never throws.

Expand Down
2 changes: 1 addition & 1 deletion tests/test_studio_bat_ascii.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def test_studio_bat_is_pure_ascii() -> None:
f"studio.bat contains {len(bad_offsets)} non-ASCII byte(s) (first 5 detailed below):\n"
+ "\n".join(snippets)
+ "\n\nstudio.bat must stay pure ASCII -- cmd.exe parses it with the system ANSI "
"codepage before chcp 65001 runs, and UTF-8 Chinese bytes get split into garbled "
"codepage before chcp 65001 runs, and multi-byte UTF-8 characters get split into garbled "
"commands. Put any non-ASCII messages inside echo, routed through a Python "
"process that has already set PYTHONUTF8 / chcp 65001."
)
2 changes: 1 addition & 1 deletion tools/download_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
import sys
from pathlib import Path

# Windows consoles using cp936/cp932 raise UnicodeEncodeError on non-ASCII / emoji; force UTF-8.
# Windows consoles using a legacy ANSI codepage raise UnicodeEncodeError on non-ASCII / emoji; force UTF-8.
for _stream in (sys.stdout, sys.stderr):
try:
_stream.reconfigure(encoding="utf-8", errors="replace")
Expand Down
4 changes: 2 additions & 2 deletions tools/launcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@
# ---------------------------------------------------------------------------
#
# **Every string this file prints must be pure ASCII**, the same discipline as studio.bat.
# The Windows console decodes using the system ANSI codepage (Russian cp866, Chinese cp936,
# Japanese cp932); a frozen exe writing a single `->`-style arrow glyph is an instant
# The Windows console decodes using the system ANSI codepage (e.g. Russian cp866,
# Western cp1252); a frozen exe writing a single `->`-style arrow glyph is an instant
# UnicodeEncodeError crash -- and the crash usually happens **in the error path itself**
# (die()'s hint line), so the user doesn't see "Python isn't installed" but a PyInstaller
# traceback instead. Comments and docstrings aren't bound by this rule (they're never
Expand Down
2 changes: 1 addition & 1 deletion tools/mask_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
import sys
from pathlib import Path

# CJK output crashes under Windows console cp932; force utf-8
# Non-ASCII output crashes under Windows console cp932; force utf-8
if hasattr(sys.stdout, "reconfigure"):
sys.stdout.reconfigure(encoding="utf-8", errors="replace")

Expand Down
2 changes: 1 addition & 1 deletion tools/mem_probe.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ def read(self, target_pid: int) -> tuple[float, float, float]:

# ---------------------------------------------------------------- main loop
def main() -> None:
# The console may be cp932/gbk or some other non-utf-8 codepage (this machine uses cp932);
# The console may be cp932 or some other non-utf-8 codepage (this machine uses cp932);
# non-ASCII print output would raise UnicodeEncodeError and crash the probe itself.
# Force utf-8 + errors=replace uniformly.
for _s in (sys.stdout, sys.stderr):
Expand Down
Loading