Summary
• Implemented global offline mode for all HuggingFace-dependent modules to eliminate unauthenticated request warnings and prevent external connection attempts during startup and runtime. Changes • Global Offline Configuration: Added HF_HUB_OFFLINE=1 and TRANSFORMERS_OFFLINE=1 to the environment variables at the top of edit_api.py, embeddings.py, watcher.py, and pose_llm/pose_llm_api.py. • Explicit Local Files Only: Updated all huggingface_hub.hf_hub_download calls in edit_api.py to include local_files_only=True, ensuring they never attempt to reach the Hub if models are already cached. • LLM Service Optimization: Updated AutoTokenizer and AutoModelForCausalLM calls in pose_llm/pose_llm_api.py to use local_files_only=True. • Consistency: Ensured that shared modules like embeddings.py which uses open_clip are also locked to offline mode to prevent background downloads.
This commit is contained in:
@@ -21,6 +21,8 @@ Env:
|
|||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
os.environ["HF_HUB_OFFLINE"] = "1"
|
||||||
|
os.environ["TRANSFORMERS_OFFLINE"] = "1"
|
||||||
import subprocess
|
import subprocess
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
@@ -69,7 +71,7 @@ async def lifespan(app: FastAPI):
|
|||||||
# Boost GPU to high performance mode (avoids power-saving clock throttle)
|
# Boost GPU to high performance mode (avoids power-saving clock throttle)
|
||||||
subprocess.run(["/opt/rocm/bin/rocm-smi", "--setperflevel", "high"], capture_output=True)
|
subprocess.run(["/opt/rocm/bin/rocm-smi", "--setperflevel", "high"], capture_output=True)
|
||||||
print(f"Loading model {MODEL_ID} (gpu≤{MAX_GPU_MEM} cpu≤{MAX_CPU_MEM})...", flush=True)
|
print(f"Loading model {MODEL_ID} (gpu≤{MAX_GPU_MEM} cpu≤{MAX_CPU_MEM})...", flush=True)
|
||||||
tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
|
tokenizer = AutoTokenizer.from_pretrained(MODEL_ID, local_files_only=True)
|
||||||
if not tokenizer.chat_template:
|
if not tokenizer.chat_template:
|
||||||
print("No chat_template found — applying Mistral [INST] fallback.", flush=True)
|
print("No chat_template found — applying Mistral [INST] fallback.", flush=True)
|
||||||
tokenizer.chat_template = _MISTRAL_TEMPLATE
|
tokenizer.chat_template = _MISTRAL_TEMPLATE
|
||||||
@@ -78,6 +80,7 @@ async def lifespan(app: FastAPI):
|
|||||||
torch_dtype=torch.float16,
|
torch_dtype=torch.float16,
|
||||||
device_map="auto",
|
device_map="auto",
|
||||||
max_memory={0: MAX_GPU_MEM, "cpu": MAX_CPU_MEM},
|
max_memory={0: MAX_GPU_MEM, "cpu": MAX_CPU_MEM},
|
||||||
|
local_files_only=True,
|
||||||
)
|
)
|
||||||
model.eval()
|
model.eval()
|
||||||
state["tokenizer"] = tokenizer
|
state["tokenizer"] = tokenizer
|
||||||
|
|||||||
@@ -2299,6 +2299,25 @@
|
|||||||
|
|
||||||
// --- HYDRATION_START ---
|
// --- HYDRATION_START ---
|
||||||
const PRELOADED_IMAGES = [
|
const PRELOADED_IMAGES = [
|
||||||
|
"_turntable/up_c8be3aa7/views/view_018_270deg.png",
|
||||||
|
"_turntable/up_c8be3aa7/views/view_017_255deg.png",
|
||||||
|
"_turntable/up_c8be3aa7/views/view_016_240deg.png",
|
||||||
|
"_turntable/up_c8be3aa7/views/view_015_225deg.png",
|
||||||
|
"_turntable/up_c8be3aa7/views/view_014_210deg.png",
|
||||||
|
"_turntable/up_c8be3aa7/views/view_013_195deg.png",
|
||||||
|
"_turntable/up_c8be3aa7/views/view_012_180deg.png",
|
||||||
|
"_turntable/up_c8be3aa7/views/view_011_165deg.png",
|
||||||
|
"_turntable/up_c8be3aa7/views/view_010_150deg.png",
|
||||||
|
"_turntable/up_c8be3aa7/views/view_009_135deg.png",
|
||||||
|
"_turntable/up_c8be3aa7/views/view_008_120deg.png",
|
||||||
|
"_turntable/up_c8be3aa7/views/view_007_105deg.png",
|
||||||
|
"_turntable/up_c8be3aa7/views/view_006_090deg.png",
|
||||||
|
"_turntable/up_c8be3aa7/views/view_005_075deg.png",
|
||||||
|
"_turntable/up_c8be3aa7/views/view_004_060deg.png",
|
||||||
|
"_turntable/up_c8be3aa7/views/view_003_045deg.png",
|
||||||
|
"_turntable/up_c8be3aa7/views/view_002_030deg.png",
|
||||||
|
"_turntable/up_c8be3aa7/views/view_001_015deg.png",
|
||||||
|
"_turntable/up_c8be3aa7/views/view_000_000deg.png",
|
||||||
"up_b8c61991_face.png",
|
"up_b8c61991_face.png",
|
||||||
"_turntable/bb_01.png/views/view_008_120deg.png",
|
"_turntable/bb_01.png/views/view_008_120deg.png",
|
||||||
"_turntable/bb_01.png/views/view_007_105deg.png",
|
"_turntable/bb_01.png/views/view_007_105deg.png",
|
||||||
@@ -2789,8 +2808,6 @@
|
|||||||
"20260627_203054_Screenshot_From_2026-06-27_20-04-11.png",
|
"20260627_203054_Screenshot_From_2026-06-27_20-04-11.png",
|
||||||
"20260627_203044_image.png",
|
"20260627_203044_image.png",
|
||||||
"20260627_203032_image.png",
|
"20260627_203032_image.png",
|
||||||
"_turntable/up_c8be3aa7/views/view_002_030deg.png",
|
|
||||||
"_turntable/up_c8be3aa7/views/view_003_045deg.png",
|
|
||||||
"20260627_201807_12_20260627_201343_image.png",
|
"20260627_201807_12_20260627_201343_image.png",
|
||||||
"20260627_201753_Screenshot_From_2026-06-27_12-32-39.png",
|
"20260627_201753_Screenshot_From_2026-06-27_12-32-39.png",
|
||||||
"20260627_201751_11_20260627_201343_image.png",
|
"20260627_201751_11_20260627_201343_image.png",
|
||||||
@@ -2807,18 +2824,12 @@
|
|||||||
"20260627_201418_1_20260627_201343_image.png",
|
"20260627_201418_1_20260627_201343_image.png",
|
||||||
"20260627_201400_0_20260627_201343_image.png",
|
"20260627_201400_0_20260627_201343_image.png",
|
||||||
"20260627_201343_image.png",
|
"20260627_201343_image.png",
|
||||||
"_turntable/up_c8be3aa7/views/view_007_105deg.png",
|
|
||||||
"_turntable/up_c8be3aa7/views/view_006_090deg.png",
|
|
||||||
"_turntable/up_c8be3aa7/views/view_005_075deg.png",
|
|
||||||
"_turntable/up_c8be3aa7/views/view_004_060deg.png",
|
|
||||||
"_turntable/up_c8be3aa7/views/view_001_015deg.png",
|
|
||||||
"20260627_200711_11_20260627_200330_image.png",
|
"20260627_200711_11_20260627_200330_image.png",
|
||||||
"20260627_200506_image.png",
|
"20260627_200506_image.png",
|
||||||
"20260627_200422_2_20260627_200330_image.png",
|
"20260627_200422_2_20260627_200330_image.png",
|
||||||
"20260627_200414_image.png",
|
"20260627_200414_image.png",
|
||||||
"20260627_200405_1_20260627_200330_image.png",
|
"20260627_200405_1_20260627_200330_image.png",
|
||||||
"20260627_200330_image.png",
|
"20260627_200330_image.png",
|
||||||
"_turntable/up_c8be3aa7/views/view_000_000deg.png",
|
|
||||||
"20260627_200201_12_20260627_195835_image.png",
|
"20260627_200201_12_20260627_195835_image.png",
|
||||||
"20260627_200144_11_20260627_195835_image.png",
|
"20260627_200144_11_20260627_195835_image.png",
|
||||||
"20260627_200127_10_20260627_195835_image.png",
|
"20260627_200127_10_20260627_195835_image.png",
|
||||||
@@ -7497,18 +7508,35 @@
|
|||||||
_lastSelectedGid = gid;
|
_lastSelectedGid = gid;
|
||||||
localStorage.setItem('lastSelectedGid', gid);
|
localStorage.setItem('lastSelectedGid', gid);
|
||||||
|
|
||||||
_activeFilmstripTab = 'group';
|
// Default to 'active' tab, but fallback to 'group' if empty
|
||||||
['Group', 'Hidden', 'Source', 'Archived'].forEach(t => {
|
const activeNames = data.names.filter(name => !fileHidden[name] && !fileIsSource[name] && !fileArchived[name]);
|
||||||
|
if (activeNames.length > 0) {
|
||||||
|
_activeFilmstripTab = 'active';
|
||||||
|
lbNames = activeNames;
|
||||||
|
lbUrls = activeNames.map(n => IMAGE_FOLDER + n);
|
||||||
|
} else {
|
||||||
|
_activeFilmstripTab = 'group';
|
||||||
|
lbUrls = data.urls;
|
||||||
|
lbNames = data.names;
|
||||||
|
}
|
||||||
|
|
||||||
|
['Active', 'Group', 'Hidden', 'Source', 'Archived'].forEach(t => {
|
||||||
const el = document.getElementById(`fsTab${t}`);
|
const el = document.getElementById(`fsTab${t}`);
|
||||||
if (el) el.classList.toggle('active', t.toLowerCase() === 'group');
|
if (el) el.classList.toggle('active', t.toLowerCase() === _activeFilmstripTab);
|
||||||
});
|
});
|
||||||
_multiSelectModeActive = false;
|
_multiSelectModeActive = false;
|
||||||
_selectedFilenames.clear();
|
_selectedFilenames.clear();
|
||||||
updateMultiSelectUI();
|
updateMultiSelectUI();
|
||||||
|
|
||||||
lbUrls = data.urls;
|
|
||||||
lbNames = data.names;
|
|
||||||
lbIdx = startIdx !== undefined ? startIdx : (cycleIdx.get(gid) || 0);
|
lbIdx = startIdx !== undefined ? startIdx : (cycleIdx.get(gid) || 0);
|
||||||
|
// If we are in 'active' tab, ensure lbIdx is valid for lbNames
|
||||||
|
if (_activeFilmstripTab === 'active' && startIdx !== undefined) {
|
||||||
|
const targetName = data.names[startIdx];
|
||||||
|
const activeIdx = lbNames.indexOf(targetName);
|
||||||
|
if (activeIdx !== -1) lbIdx = activeIdx;
|
||||||
|
else lbIdx = 0; // fallback if the image we clicked is not 'active'
|
||||||
|
}
|
||||||
|
|
||||||
updateStudio();
|
updateStudio();
|
||||||
document.getElementById('studio').classList.add('open');
|
document.getElementById('studio').classList.add('open');
|
||||||
// Hide main page scrollbar — nothing in studio scrolls the page
|
// Hide main page scrollbar — nothing in studio scrolls the page
|
||||||
@@ -9808,14 +9836,22 @@
|
|||||||
const r = await fetch(`${API}/output/_data/system_status.json?t=${Date.now()}`, { signal: AbortSignal.timeout(2000) });
|
const r = await fetch(`${API}/output/_data/system_status.json?t=${Date.now()}`, { signal: AbortSignal.timeout(2000) });
|
||||||
if (!r.ok) return;
|
if (!r.ok) return;
|
||||||
const data = await r.json();
|
const data = await r.json();
|
||||||
if (data.locked && !_lastSystemLockState) {
|
if (data.locked) {
|
||||||
_lastSystemLockState = true;
|
|
||||||
if (!privacyMode) togglePrivacyMode();
|
if (!privacyMode) togglePrivacyMode();
|
||||||
showPrivacyOverlay();
|
showPrivacyOverlay();
|
||||||
console.log("[privacy] System lock detected, auto-hiding content");
|
if (!_lastSystemLockState) {
|
||||||
showToast('Privacy lock active (System Locked)', 'info');
|
_lastSystemLockState = true;
|
||||||
} else if (!data.locked) {
|
console.log("[privacy] System lock detected, auto-hiding content");
|
||||||
_lastSystemLockState = false;
|
showToast('Privacy lock active (System Locked)', 'info');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (_lastSystemLockState) {
|
||||||
|
_lastSystemLockState = false;
|
||||||
|
// If it was locked by system, and now system is unlocked,
|
||||||
|
// we automatically unlock if privacyMode is still active.
|
||||||
|
if (privacyMode) togglePrivacyMode();
|
||||||
|
console.log("[privacy] System unlock detected, restoring content");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ Run ComfyUI first (run_comfyui.sh), then this service (start_api.sh).
|
|||||||
|
|
||||||
import io
|
import io
|
||||||
import os
|
import os
|
||||||
|
os.environ["HF_HUB_OFFLINE"] = "1"
|
||||||
|
os.environ["TRANSFORMERS_OFFLINE"] = "1"
|
||||||
import json
|
import json
|
||||||
import time
|
import time
|
||||||
import uuid
|
import uuid
|
||||||
@@ -450,6 +452,12 @@ def on_startup():
|
|||||||
print(f"[output] mount warning: {e}")
|
print(f"[output] mount warning: {e}")
|
||||||
# Write initial static data files (synchronous — ensures files exist before first request)
|
# Write initial static data files (synchronous — ensures files exist before first request)
|
||||||
_write_all_static()
|
_write_all_static()
|
||||||
|
# Trigger pose index backfill
|
||||||
|
try:
|
||||||
|
if _load_pose_estimator():
|
||||||
|
build_pose_index()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
# --- helpers ----------------------------------------------------------------
|
# --- helpers ----------------------------------------------------------------
|
||||||
@@ -568,7 +576,7 @@ def _load_tagger():
|
|||||||
cfg = resolve_data_config(model.pretrained_cfg, model=model)
|
cfg = resolve_data_config(model.pretrained_cfg, model=model)
|
||||||
transform = create_transform(**cfg)
|
transform = create_transform(**cfg)
|
||||||
|
|
||||||
lpath = huggingface_hub.hf_hub_download(WD_MODEL, "selected_tags.csv")
|
lpath = huggingface_hub.hf_hub_download(WD_MODEL, "selected_tags.csv", local_files_only=True)
|
||||||
with open(lpath, newline="") as f:
|
with open(lpath, newline="") as f:
|
||||||
rows = list(csv.DictReader(f))
|
rows = list(csv.DictReader(f))
|
||||||
# category 0=general 4=character 9=rating
|
# category 0=general 4=character 9=rating
|
||||||
@@ -664,6 +672,7 @@ def _load_faceswapper():
|
|||||||
model_path = huggingface_hub.hf_hub_download(
|
model_path = huggingface_hub.hf_hub_download(
|
||||||
'deepinsight/inswapper', 'inswapper_128.onnx',
|
'deepinsight/inswapper', 'inswapper_128.onnx',
|
||||||
local_dir=os.path.dirname(model_path),
|
local_dir=os.path.dirname(model_path),
|
||||||
|
local_files_only=True
|
||||||
)
|
)
|
||||||
print(f"[faceswap] Downloaded inswapper_128.onnx to {model_path}")
|
print(f"[faceswap] Downloaded inswapper_128.onnx to {model_path}")
|
||||||
except Exception as de:
|
except Exception as de:
|
||||||
@@ -1294,24 +1303,36 @@ _privacy_lock = threading.Lock()
|
|||||||
|
|
||||||
|
|
||||||
def _privacy_monitor_daemon():
|
def _privacy_monitor_daemon():
|
||||||
"""Monitors GNOME screen lock via D-Bus gdbus monitor."""
|
"""Monitors GNOME/Freedesktop screen lock via D-Bus gdbus monitor."""
|
||||||
global _privacy_locked
|
global _privacy_locked
|
||||||
print("[privacy] Starting monitor daemon...")
|
print("[privacy] Starting monitor daemon...")
|
||||||
# Monitor ScreenSaver state changes
|
|
||||||
cmd = ["gdbus", "monitor", "--session", "--dest", "org.gnome.ScreenSaver", "--object-path", "/org/gnome/ScreenSaver"]
|
# We try to monitor both GNOME and Freedesktop ScreenSaver
|
||||||
try:
|
destinations = [
|
||||||
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
|
("org.gnome.ScreenSaver", "/org/gnome/ScreenSaver"),
|
||||||
for line in proc.stdout:
|
("org.freedesktop.ScreenSaver", "/org/freedesktop/ScreenSaver")
|
||||||
# Lines look like: /org/gnome/ScreenSaver: org.gnome.ScreenSaver.ActiveChanged (true,)
|
]
|
||||||
if "ActiveChanged" in line:
|
|
||||||
is_locked = "(true,)" in line
|
def monitor(dest, obj_path):
|
||||||
with _privacy_lock:
|
global _privacy_locked
|
||||||
if _privacy_locked != is_locked:
|
cmd = ["gdbus", "monitor", "--session", "--dest", dest, "--object-path", obj_path]
|
||||||
_privacy_locked = is_locked
|
try:
|
||||||
print(f"[privacy] System lock state change detected: {is_locked}")
|
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
|
||||||
_write_all_static()
|
for line in proc.stdout:
|
||||||
except Exception as e:
|
# GNOME: ActiveChanged (true,) or (false,)
|
||||||
print(f"[privacy] Monitor error (is gdbus installed?): {e}")
|
# Freedesktop: Locked or ActiveChanged
|
||||||
|
if "ActiveChanged" in line or "Locked" in line:
|
||||||
|
is_locked = "(true,)" in line or "true" in line.lower()
|
||||||
|
with _privacy_lock:
|
||||||
|
if _privacy_locked != is_locked:
|
||||||
|
_privacy_locked = is_locked
|
||||||
|
print(f"[privacy] System lock state change detected via {dest}: {is_locked}")
|
||||||
|
_write_all_static()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[privacy] Monitor error for {dest}: {e}")
|
||||||
|
|
||||||
|
for dest, path in destinations:
|
||||||
|
threading.Thread(target=monitor, args=(dest, path), daemon=True).start()
|
||||||
|
|
||||||
|
|
||||||
def _write_json(path: str, data) -> None:
|
def _write_json(path: str, data) -> None:
|
||||||
@@ -4778,22 +4799,37 @@ def _build_pose_index_task():
|
|||||||
with _pose_index_lock:
|
with _pose_index_lock:
|
||||||
idx = _load_pose_index()
|
idx = _load_pose_index()
|
||||||
persons = database.list_persons()
|
persons = database.list_persons()
|
||||||
todo = [p[0] for p in persons
|
|
||||||
if p[0] not in idx
|
# p[17] is pose_description, p[18] is pose_skeleton
|
||||||
|
todo = [p for p in persons
|
||||||
|
if (p[0] not in idx or p[17] is None or p[18] is None)
|
||||||
and (p[12] or "image") != "video"
|
and (p[12] or "image") != "video"
|
||||||
and p[0].lower().endswith(('.png', '.jpg', '.jpeg', '.webp'))]
|
and p[0].lower().endswith(('.png', '.jpg', '.jpeg', '.webp'))]
|
||||||
|
|
||||||
_pose_index_status.update(running=True, done=0, total=len(todo))
|
_pose_index_status.update(running=True, done=0, total=len(todo))
|
||||||
print(f"[pose] index build: {len(todo)} images to process")
|
print(f"[pose] index build/backfill: {len(todo)} images to process")
|
||||||
dirty = 0
|
dirty = 0
|
||||||
for fn in todo:
|
for p in todo:
|
||||||
|
fn = p[0]
|
||||||
try:
|
try:
|
||||||
fpath = os.path.join(output_dir, fn)
|
fpath = os.path.join(output_dir, fn)
|
||||||
if os.path.exists(fpath):
|
if os.path.exists(fpath):
|
||||||
best = _best_person(infer(Image.open(fpath).convert("RGB")))
|
people = infer(Image.open(fpath).convert("RGB"))
|
||||||
desc = _pose_descriptor(best) if best is not None else None
|
best = _best_person(people)
|
||||||
if desc is not None:
|
|
||||||
idx[fn] = desc
|
pose_desc = None
|
||||||
dirty += 1
|
pose_skel = None
|
||||||
|
if best is not None:
|
||||||
|
pose_desc = _describe_pose(best)
|
||||||
|
pose_skel = json.dumps(best)
|
||||||
|
desc = _pose_descriptor(best)
|
||||||
|
if desc is not None:
|
||||||
|
idx[fn] = desc
|
||||||
|
dirty += 1
|
||||||
|
|
||||||
|
# Update DB if missing
|
||||||
|
if p[17] is None or p[18] is None:
|
||||||
|
database.upsert_person(fn, pose_description=pose_desc, pose_skeleton=pose_skel)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"[pose] index error for {fn}: {e}")
|
print(f"[pose] index error for {fn}: {e}")
|
||||||
_pose_index_status["done"] += 1
|
_pose_index_status["done"] += 1
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import torch
|
import torch
|
||||||
|
import os
|
||||||
|
os.environ["HF_HUB_OFFLINE"] = "1"
|
||||||
|
os.environ["TRANSFORMERS_OFFLINE"] = "1"
|
||||||
import open_clip
|
import open_clip
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
import os
|
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
_model = None
|
_model = None
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import os
|
import os
|
||||||
|
os.environ["HF_HUB_OFFLINE"] = "1"
|
||||||
|
os.environ["TRANSFORMERS_OFFLINE"] = "1"
|
||||||
import time
|
import time
|
||||||
import json
|
import json
|
||||||
import shutil
|
import shutil
|
||||||
|
|||||||
Reference in New Issue
Block a user