Spaces:
Sleeping
Feat/sunday sprint 2 (#15)
Browse files* Fix HF Gradio SDK build: drop editable requirements.
HF pip installs requirements.txt before copying the repo, so -e ./libs/*
paths fail. Load monorepo packages via sys.path in app.py instead.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Skip llama-cpp-python on HF Space build.
Compiling llama-cpp-python blocks HF builds for 10+ minutes. The Space
uses transformers presets; lazy-import llama_cpp only when selected.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Disable Gradio SSR on HF Space so app binds to 7860.
HF enables SSR by default; without a working Node proxy Gradio falls
back to port 7861 and the Space container crashes.
Co-authored-by: Cursor <cursoragent@cursor.com>
* css layout
* origin fix
* Use ?classic query param for Classic UI on HF Spaces.
Root-relative /classic links resolve to http://hf.space under the Hub
embed and trigger mixed-content errors. Studio links use ?classic; the
server redirects to a relative classic path on the same HTTPS origin.
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
- app.py +20 -0
- apps/gradio-space/src/gradio_space/app.py +1 -1
- apps/gradio-space/src/gradio_space/server.py +26 -3
- apps/gradio-space/static/studio/index.html +37 -25
- apps/gradio-space/static/studio/studio.css +220 -9
- apps/gradio-space/static/studio/studio.js +88 -8
- libs/inference/src/inference/factory.py +2 -1
- requirements.txt +4 -7
|
@@ -1,5 +1,25 @@
|
|
| 1 |
"""Hugging Face Gradio SDK entry point (ZeroGPU / Gradio Spaces)."""
|
| 2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
from gradio_space.server import main
|
| 4 |
|
| 5 |
if __name__ == "__main__":
|
|
|
|
| 1 |
"""Hugging Face Gradio SDK entry point (ZeroGPU / Gradio Spaces)."""
|
| 2 |
|
| 3 |
+
import os
|
| 4 |
+
|
| 5 |
+
# HF Spaces default SSR to True; Node proxy then binds 7860 and Python falls back to 7861.
|
| 6 |
+
os.environ["GRADIO_SSR_MODE"] = "False"
|
| 7 |
+
|
| 8 |
+
import sys
|
| 9 |
+
from pathlib import Path
|
| 10 |
+
|
| 11 |
+
_ROOT = Path(__file__).resolve().parent
|
| 12 |
+
for _src in (
|
| 13 |
+
"apps/gradio-space/src",
|
| 14 |
+
"libs/inference/src",
|
| 15 |
+
"libs/researchmind/src",
|
| 16 |
+
"libs/agent/src",
|
| 17 |
+
"libs/echocoach/src",
|
| 18 |
+
):
|
| 19 |
+
_path = str(_ROOT / _src)
|
| 20 |
+
if _path not in sys.path:
|
| 21 |
+
sys.path.insert(0, _path)
|
| 22 |
+
|
| 23 |
from gradio_space.server import main
|
| 24 |
|
| 25 |
if __name__ == "__main__":
|
|
@@ -24,7 +24,7 @@ def build_demo() -> gr.Blocks:
|
|
| 24 |
<div class="brand-block">
|
| 25 |
<h1>Build Small</h1>
|
| 26 |
<p>Local lesson slides, research, voice coaching — offline on small models.
|
| 27 |
-
<a href="/">Studio UI</a> ·
|
| 28 |
<a href="https://huggingface.co/build-small-hackathon" target="_blank">Hackathon</a></p>
|
| 29 |
</div>
|
| 30 |
"""
|
|
|
|
| 24 |
<div class="brand-block">
|
| 25 |
<h1>Build Small</h1>
|
| 26 |
<p>Local lesson slides, research, voice coaching — offline on small models.
|
| 27 |
+
<a href="../">Studio UI</a> ·
|
| 28 |
<a href="https://huggingface.co/build-small-hackathon" target="_blank">Hackathon</a></p>
|
| 29 |
</div>
|
| 30 |
"""
|
|
@@ -4,7 +4,8 @@ import os
|
|
| 4 |
from pathlib import Path
|
| 5 |
|
| 6 |
import gradio as gr
|
| 7 |
-
from fastapi
|
|
|
|
| 8 |
from fastapi.staticfiles import StaticFiles
|
| 9 |
|
| 10 |
from gradio import mount_gradio_app
|
|
@@ -36,8 +37,24 @@ def _all_allowed_paths() -> list[str]:
|
|
| 36 |
return list(dict.fromkeys(paths))
|
| 37 |
|
| 38 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 39 |
def create_server() -> gr.Server:
|
| 40 |
server = gr.Server(title="Build Small Studio")
|
|
|
|
| 41 |
|
| 42 |
register_studio_apis(server)
|
| 43 |
|
|
@@ -45,11 +62,16 @@ def create_server() -> gr.Server:
|
|
| 45 |
server.mount("/static/studio", StaticFiles(directory=str(_STATIC_DIR)), name="studio_static")
|
| 46 |
|
| 47 |
@server.get("/")
|
| 48 |
-
async def studio_index(
|
|
|
|
|
|
|
|
|
|
| 49 |
return FileResponse(_STATIC_DIR / "index.html")
|
| 50 |
|
| 51 |
@server.get("/studio")
|
| 52 |
-
async def studio_alias(
|
|
|
|
|
|
|
| 53 |
return FileResponse(_STATIC_DIR / "index.html")
|
| 54 |
|
| 55 |
demo = build_demo()
|
|
@@ -83,6 +105,7 @@ def main() -> None:
|
|
| 83 |
footer_links=[],
|
| 84 |
allowed_paths=_all_allowed_paths(),
|
| 85 |
show_error=True,
|
|
|
|
| 86 |
)
|
| 87 |
|
| 88 |
|
|
|
|
| 4 |
from pathlib import Path
|
| 5 |
|
| 6 |
import gradio as gr
|
| 7 |
+
from fastapi import Request
|
| 8 |
+
from fastapi.responses import FileResponse, RedirectResponse
|
| 9 |
from fastapi.staticfiles import StaticFiles
|
| 10 |
|
| 11 |
from gradio import mount_gradio_app
|
|
|
|
| 37 |
return list(dict.fromkeys(paths))
|
| 38 |
|
| 39 |
|
| 40 |
+
def _register_hf_https_middleware(server: gr.Server) -> None:
|
| 41 |
+
"""HF terminates TLS; the app sees HTTP and Gradio may emit http:// asset URLs."""
|
| 42 |
+
if not os.environ.get("SPACE_ID"):
|
| 43 |
+
return
|
| 44 |
+
|
| 45 |
+
@server.middleware("http")
|
| 46 |
+
async def force_https_scheme(request, call_next):
|
| 47 |
+
request.scope["scheme"] = "https"
|
| 48 |
+
return await call_next(request)
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
def _wants_classic_ui(request: Request) -> bool:
|
| 52 |
+
return "classic" in request.query_params
|
| 53 |
+
|
| 54 |
+
|
| 55 |
def create_server() -> gr.Server:
|
| 56 |
server = gr.Server(title="Build Small Studio")
|
| 57 |
+
_register_hf_https_middleware(server)
|
| 58 |
|
| 59 |
register_studio_apis(server)
|
| 60 |
|
|
|
|
| 62 |
server.mount("/static/studio", StaticFiles(directory=str(_STATIC_DIR)), name="studio_static")
|
| 63 |
|
| 64 |
@server.get("/")
|
| 65 |
+
async def studio_index(request: Request):
|
| 66 |
+
if _wants_classic_ui(request):
|
| 67 |
+
# Relative path keeps huggingface.co/spaces/.../classic on HTTPS (not http hf.space).
|
| 68 |
+
return RedirectResponse(url="classic", status_code=302)
|
| 69 |
return FileResponse(_STATIC_DIR / "index.html")
|
| 70 |
|
| 71 |
@server.get("/studio")
|
| 72 |
+
async def studio_alias(request: Request):
|
| 73 |
+
if _wants_classic_ui(request):
|
| 74 |
+
return RedirectResponse(url="classic", status_code=302)
|
| 75 |
return FileResponse(_STATIC_DIR / "index.html")
|
| 76 |
|
| 77 |
demo = build_demo()
|
|
|
|
| 105 |
footer_links=[],
|
| 106 |
allowed_paths=_all_allowed_paths(),
|
| 107 |
show_error=True,
|
| 108 |
+
ssr_mode=False,
|
| 109 |
)
|
| 110 |
|
| 111 |
|
|
@@ -21,6 +21,8 @@
|
|
| 21 |
<div id="studio-error" class="studio-banner studio-banner-error hidden" role="alert"></div>
|
| 22 |
<div id="studio-loading" class="studio-banner studio-banner-loading hidden">Working…</div>
|
| 23 |
|
|
|
|
|
|
|
| 24 |
<aside id="sidebar" class="sidebar">
|
| 25 |
<button type="button" id="sidebar-close" class="sidebar-close material-symbols-outlined" aria-label="Close menu">close</button>
|
| 26 |
<div class="sidebar-brand">
|
|
@@ -37,11 +39,11 @@
|
|
| 37 |
<button type="button" class="nav-item" data-view="language-lessons"><span class="material-symbols-outlined">translate</span>Language lessons</button>
|
| 38 |
<button type="button" class="nav-item" data-view="debug"><span class="material-symbols-outlined">bug_report</span>Debug</button>
|
| 39 |
<button type="button" id="btn-open-settings" class="nav-item"><span class="material-symbols-outlined">settings</span>Settings</button>
|
| 40 |
-
<a href="
|
| 41 |
</nav>
|
| 42 |
<div class="sidebar-footer">
|
| 43 |
<p class="sidebar-foot-label">Powered by local small models</p>
|
| 44 |
-
<a href="
|
| 45 |
</div>
|
| 46 |
</aside>
|
| 47 |
|
|
@@ -56,31 +58,41 @@
|
|
| 56 |
<button type="button" id="theme-toggle-btn" class="btn btn-ghost btn-icon" aria-label="Toggle light/dark theme" title="Toggle theme">
|
| 57 |
<span class="material-symbols-outlined" id="theme-icon">dark_mode</span>
|
| 58 |
</button>
|
| 59 |
-
<a href="
|
| 60 |
-
|
|
|
|
|
|
|
|
|
|
| 61 |
</div>
|
| 62 |
</header>
|
| 63 |
|
| 64 |
<div class="workspace-context-bar" id="workspace-context-bar">
|
| 65 |
-
<
|
| 66 |
-
<
|
| 67 |
-
<span
|
| 68 |
-
<
|
| 69 |
-
|
| 70 |
-
<
|
| 71 |
-
|
| 72 |
-
<
|
| 73 |
-
<
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
<
|
| 82 |
-
|
| 83 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 84 |
</div>
|
| 85 |
|
| 86 |
<main class="workspace" data-view="slides">
|
|
@@ -396,7 +408,7 @@
|
|
| 396 |
</div>
|
| 397 |
<p class="lessons-classic-link status-text">
|
| 398 |
Pitch metrics and monologue analysis live in
|
| 399 |
-
<a href="
|
| 400 |
</p>
|
| 401 |
</div>
|
| 402 |
</div>
|
|
@@ -478,7 +490,7 @@
|
|
| 478 |
<summary>Paths & files</summary>
|
| 479 |
<pre id="settings-paths" class="settings-pre"></pre>
|
| 480 |
</details>
|
| 481 |
-
<a href="
|
| 482 |
</aside>
|
| 483 |
</div>
|
| 484 |
|
|
|
|
| 21 |
<div id="studio-error" class="studio-banner studio-banner-error hidden" role="alert"></div>
|
| 22 |
<div id="studio-loading" class="studio-banner studio-banner-loading hidden">Working…</div>
|
| 23 |
|
| 24 |
+
<button type="button" id="sidebar-backdrop" class="sidebar-backdrop hidden" aria-label="Close menu"></button>
|
| 25 |
+
|
| 26 |
<aside id="sidebar" class="sidebar">
|
| 27 |
<button type="button" id="sidebar-close" class="sidebar-close material-symbols-outlined" aria-label="Close menu">close</button>
|
| 28 |
<div class="sidebar-brand">
|
|
|
|
| 39 |
<button type="button" class="nav-item" data-view="language-lessons"><span class="material-symbols-outlined">translate</span>Language lessons</button>
|
| 40 |
<button type="button" class="nav-item" data-view="debug"><span class="material-symbols-outlined">bug_report</span>Debug</button>
|
| 41 |
<button type="button" id="btn-open-settings" class="nav-item"><span class="material-symbols-outlined">settings</span>Settings</button>
|
| 42 |
+
<a href="?classic" class="nav-item nav-link"><span class="material-symbols-outlined">open_in_new</span>Classic UI</a>
|
| 43 |
</nav>
|
| 44 |
<div class="sidebar-footer">
|
| 45 |
<p class="sidebar-foot-label">Powered by local small models</p>
|
| 46 |
+
<a href="?classic">Open Classic UI</a>
|
| 47 |
</div>
|
| 48 |
</aside>
|
| 49 |
|
|
|
|
| 58 |
<button type="button" id="theme-toggle-btn" class="btn btn-ghost btn-icon" aria-label="Toggle light/dark theme" title="Toggle theme">
|
| 59 |
<span class="material-symbols-outlined" id="theme-icon">dark_mode</span>
|
| 60 |
</button>
|
| 61 |
+
<a href="?classic" class="btn btn-ghost topbar-classic-link" aria-label="Classic UI" title="Classic UI">
|
| 62 |
+
<span class="material-symbols-outlined">open_in_new</span>
|
| 63 |
+
<span class="topbar-classic-label">Classic UI</span>
|
| 64 |
+
</a>
|
| 65 |
+
<button type="button" id="btn-export" class="btn btn-primary topbar-export" disabled>Export</button>
|
| 66 |
</div>
|
| 67 |
</header>
|
| 68 |
|
| 69 |
<div class="workspace-context-bar" id="workspace-context-bar">
|
| 70 |
+
<details class="workspace-context-mobile" id="workspace-context-mobile">
|
| 71 |
+
<summary class="workspace-context-summary">
|
| 72 |
+
<span class="material-symbols-outlined workspace-context-summary-icon">tune</span>
|
| 73 |
+
<span id="workspace-context-summary-text" class="workspace-context-summary-text">Workspace</span>
|
| 74 |
+
<span class="material-symbols-outlined workspace-context-chevron">expand_more</span>
|
| 75 |
+
</summary>
|
| 76 |
+
<div class="workspace-context-inner">
|
| 77 |
+
<label class="field ws-field">
|
| 78 |
+
<span>Workspace topic</span>
|
| 79 |
+
<input id="workspace-topic" type="text" class="input" value="small model finetuning" placeholder="e.g. Small language model finetuning" />
|
| 80 |
+
</label>
|
| 81 |
+
<label class="field ws-field">
|
| 82 |
+
<span>ResearchMind session</span>
|
| 83 |
+
<select id="workspace-session" class="input">
|
| 84 |
+
<option value="">New session (on ingest)</option>
|
| 85 |
+
</select>
|
| 86 |
+
</label>
|
| 87 |
+
<button type="button" id="workspace-refresh-sessions" class="btn btn-ghost btn-icon" title="Refresh sessions">↻</button>
|
| 88 |
+
<details class="workspace-docs-details" id="workspace-docs-details">
|
| 89 |
+
<summary>Source scope (RAG)</summary>
|
| 90 |
+
<div id="workspace-doc-list" class="workspace-doc-list"></div>
|
| 91 |
+
<p id="workspace-rag-hint" class="status-text"></p>
|
| 92 |
+
<p id="workspace-memory" class="status-text workspace-memory"></p>
|
| 93 |
+
</details>
|
| 94 |
+
</div>
|
| 95 |
+
</details>
|
| 96 |
</div>
|
| 97 |
|
| 98 |
<main class="workspace" data-view="slides">
|
|
|
|
| 408 |
</div>
|
| 409 |
<p class="lessons-classic-link status-text">
|
| 410 |
Pitch metrics and monologue analysis live in
|
| 411 |
+
<a href="?classic">Classic UI → EchoCoach</a>.
|
| 412 |
</p>
|
| 413 |
</div>
|
| 414 |
</div>
|
|
|
|
| 490 |
<summary>Paths & files</summary>
|
| 491 |
<pre id="settings-paths" class="settings-pre"></pre>
|
| 492 |
</details>
|
| 493 |
+
<a href="?classic" class="btn btn-ghost btn-block">Open Classic UI</a>
|
| 494 |
</aside>
|
| 495 |
</div>
|
| 496 |
|
|
@@ -165,8 +165,10 @@ body {
|
|
| 165 |
display: flex;
|
| 166 |
align-items: center;
|
| 167 |
justify-content: space-between;
|
|
|
|
| 168 |
padding: 0 2rem;
|
| 169 |
z-index: 40;
|
|
|
|
| 170 |
}
|
| 171 |
|
| 172 |
.breadcrumb {
|
|
@@ -175,17 +177,67 @@ body {
|
|
| 175 |
gap: 0.5rem;
|
| 176 |
font-size: 0.9rem;
|
| 177 |
color: var(--secondary);
|
|
|
|
|
|
|
| 178 |
}
|
| 179 |
|
| 180 |
.breadcrumb strong {
|
| 181 |
color: var(--on-surface);
|
| 182 |
border-bottom: 2px solid var(--primary);
|
| 183 |
padding-bottom: 0.35rem;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 184 |
}
|
| 185 |
|
| 186 |
.crumb-sep { font-size: 1rem; }
|
| 187 |
|
| 188 |
-
.topbar-actions { display: flex; gap: 0.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 189 |
|
| 190 |
.workspace-context-bar {
|
| 191 |
position: fixed;
|
|
@@ -1282,19 +1334,178 @@ body {
|
|
| 1282 |
}
|
| 1283 |
}
|
| 1284 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1285 |
@media (max-width: 768px) {
|
| 1286 |
-
:root {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1287 |
.sidebar {
|
| 1288 |
transform: translateX(-100%);
|
| 1289 |
-
transition: transform 0.
|
| 1290 |
width: min(280px, 85vw);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1291 |
}
|
| 1292 |
-
.sidebar.open { transform: translateX(0); }
|
| 1293 |
-
.sidebar-close, .topbar-icon { display: inline-flex; background: none; border: none; cursor: pointer; color: var(--secondary); }
|
| 1294 |
-
.topbar { left: 0; padding: 0 1rem; }
|
| 1295 |
-
.workspace-context-bar { left: 0; padding: 0.5rem 1rem; }
|
| 1296 |
-
.workspace { margin-left: 0; padding-top: calc(var(--topbar-h) + var(--context-bar-h) + 1rem); }
|
| 1297 |
-
.studio-banner { left: 0; }
|
| 1298 |
}
|
| 1299 |
|
| 1300 |
/* Parity additions */
|
|
|
|
| 165 |
display: flex;
|
| 166 |
align-items: center;
|
| 167 |
justify-content: space-between;
|
| 168 |
+
gap: 0.75rem;
|
| 169 |
padding: 0 2rem;
|
| 170 |
z-index: 40;
|
| 171 |
+
min-width: 0;
|
| 172 |
}
|
| 173 |
|
| 174 |
.breadcrumb {
|
|
|
|
| 177 |
gap: 0.5rem;
|
| 178 |
font-size: 0.9rem;
|
| 179 |
color: var(--secondary);
|
| 180 |
+
min-width: 0;
|
| 181 |
+
flex: 1;
|
| 182 |
}
|
| 183 |
|
| 184 |
.breadcrumb strong {
|
| 185 |
color: var(--on-surface);
|
| 186 |
border-bottom: 2px solid var(--primary);
|
| 187 |
padding-bottom: 0.35rem;
|
| 188 |
+
min-width: 0;
|
| 189 |
+
overflow: hidden;
|
| 190 |
+
text-overflow: ellipsis;
|
| 191 |
+
white-space: nowrap;
|
| 192 |
}
|
| 193 |
|
| 194 |
.crumb-sep { font-size: 1rem; }
|
| 195 |
|
| 196 |
+
.topbar-actions { display: flex; gap: 0.5rem; align-items: center; flex-shrink: 0; }
|
| 197 |
+
|
| 198 |
+
.topbar-classic-link .material-symbols-outlined {
|
| 199 |
+
font-size: 1.15rem;
|
| 200 |
+
}
|
| 201 |
+
|
| 202 |
+
.topbar-classic-label {
|
| 203 |
+
margin-left: 0.15rem;
|
| 204 |
+
}
|
| 205 |
+
|
| 206 |
+
.sidebar-backdrop {
|
| 207 |
+
position: fixed;
|
| 208 |
+
inset: 0;
|
| 209 |
+
z-index: 45;
|
| 210 |
+
background: rgba(0, 0, 0, 0.45);
|
| 211 |
+
opacity: 0;
|
| 212 |
+
transition: opacity 0.2s ease;
|
| 213 |
+
border: none;
|
| 214 |
+
padding: 0;
|
| 215 |
+
cursor: pointer;
|
| 216 |
+
}
|
| 217 |
+
|
| 218 |
+
.sidebar-backdrop:not(.hidden) {
|
| 219 |
+
opacity: 1;
|
| 220 |
+
}
|
| 221 |
+
|
| 222 |
+
body.sidebar-open {
|
| 223 |
+
overflow: hidden;
|
| 224 |
+
}
|
| 225 |
+
|
| 226 |
+
.workspace-context-mobile {
|
| 227 |
+
margin: 0;
|
| 228 |
+
}
|
| 229 |
+
|
| 230 |
+
.workspace-context-mobile > summary {
|
| 231 |
+
list-style: none;
|
| 232 |
+
}
|
| 233 |
+
|
| 234 |
+
.workspace-context-mobile > summary::-webkit-details-marker {
|
| 235 |
+
display: none;
|
| 236 |
+
}
|
| 237 |
+
|
| 238 |
+
.workspace-context-summary {
|
| 239 |
+
display: none;
|
| 240 |
+
}
|
| 241 |
|
| 242 |
.workspace-context-bar {
|
| 243 |
position: fixed;
|
|
|
|
| 1334 |
}
|
| 1335 |
}
|
| 1336 |
|
| 1337 |
+
@media (min-width: 769px) {
|
| 1338 |
+
.workspace-context-mobile .workspace-context-inner {
|
| 1339 |
+
display: flex !important;
|
| 1340 |
+
}
|
| 1341 |
+
}
|
| 1342 |
+
|
| 1343 |
@media (max-width: 768px) {
|
| 1344 |
+
:root {
|
| 1345 |
+
--sidebar-w: 0px;
|
| 1346 |
+
--topbar-h: 52px;
|
| 1347 |
+
--context-bar-h: 44px;
|
| 1348 |
+
}
|
| 1349 |
+
|
| 1350 |
.sidebar {
|
| 1351 |
transform: translateX(-100%);
|
| 1352 |
+
transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
| 1353 |
width: min(280px, 85vw);
|
| 1354 |
+
z-index: 60;
|
| 1355 |
+
box-shadow: 4px 0 24px rgba(0, 0, 0, 0.15);
|
| 1356 |
+
}
|
| 1357 |
+
|
| 1358 |
+
.sidebar.open {
|
| 1359 |
+
transform: translateX(0);
|
| 1360 |
+
}
|
| 1361 |
+
|
| 1362 |
+
.sidebar-close,
|
| 1363 |
+
.topbar-icon {
|
| 1364 |
+
display: inline-flex;
|
| 1365 |
+
align-items: center;
|
| 1366 |
+
justify-content: center;
|
| 1367 |
+
min-width: 2.5rem;
|
| 1368 |
+
min-height: 2.5rem;
|
| 1369 |
+
background: none;
|
| 1370 |
+
border: none;
|
| 1371 |
+
cursor: pointer;
|
| 1372 |
+
color: var(--secondary);
|
| 1373 |
+
border-radius: 8px;
|
| 1374 |
+
flex-shrink: 0;
|
| 1375 |
+
}
|
| 1376 |
+
|
| 1377 |
+
.topbar-icon:active,
|
| 1378 |
+
.sidebar-close:active {
|
| 1379 |
+
background: var(--surface-container-low);
|
| 1380 |
+
}
|
| 1381 |
+
|
| 1382 |
+
.topbar {
|
| 1383 |
+
left: 0;
|
| 1384 |
+
right: 0;
|
| 1385 |
+
display: grid;
|
| 1386 |
+
grid-template-columns: auto minmax(0, 1fr) auto;
|
| 1387 |
+
gap: 0.35rem 0.5rem;
|
| 1388 |
+
padding: 0 0.75rem;
|
| 1389 |
+
padding-top: env(safe-area-inset-top, 0);
|
| 1390 |
+
height: auto;
|
| 1391 |
+
min-height: var(--topbar-h);
|
| 1392 |
+
}
|
| 1393 |
+
|
| 1394 |
+
.breadcrumb > span:first-child,
|
| 1395 |
+
.breadcrumb .crumb-sep {
|
| 1396 |
+
display: none;
|
| 1397 |
+
}
|
| 1398 |
+
|
| 1399 |
+
.breadcrumb strong {
|
| 1400 |
+
border-bottom: none;
|
| 1401 |
+
padding-bottom: 0;
|
| 1402 |
+
font-size: 0.95rem;
|
| 1403 |
+
font-weight: 600;
|
| 1404 |
+
}
|
| 1405 |
+
|
| 1406 |
+
.topbar-classic-link,
|
| 1407 |
+
.topbar-export {
|
| 1408 |
+
display: none !important;
|
| 1409 |
+
}
|
| 1410 |
+
|
| 1411 |
+
body[data-view="slides"] .topbar-export:not(:disabled) {
|
| 1412 |
+
display: inline-flex !important;
|
| 1413 |
+
}
|
| 1414 |
+
|
| 1415 |
+
.topbar-actions {
|
| 1416 |
+
gap: 0.25rem;
|
| 1417 |
+
}
|
| 1418 |
+
|
| 1419 |
+
.topbar-actions .btn-icon {
|
| 1420 |
+
min-width: 2.5rem;
|
| 1421 |
+
min-height: 2.5rem;
|
| 1422 |
+
padding: 0.4rem;
|
| 1423 |
+
}
|
| 1424 |
+
|
| 1425 |
+
.workspace-context-bar {
|
| 1426 |
+
left: 0;
|
| 1427 |
+
padding: 0;
|
| 1428 |
+
}
|
| 1429 |
+
|
| 1430 |
+
.workspace-context-summary {
|
| 1431 |
+
display: flex;
|
| 1432 |
+
align-items: center;
|
| 1433 |
+
gap: 0.5rem;
|
| 1434 |
+
padding: 0.55rem 0.75rem;
|
| 1435 |
+
cursor: pointer;
|
| 1436 |
+
font-size: 0.85rem;
|
| 1437 |
+
font-weight: 500;
|
| 1438 |
+
color: var(--on-surface);
|
| 1439 |
+
user-select: none;
|
| 1440 |
+
-webkit-tap-highlight-color: transparent;
|
| 1441 |
+
}
|
| 1442 |
+
|
| 1443 |
+
.workspace-context-summary-icon {
|
| 1444 |
+
font-size: 1.1rem;
|
| 1445 |
+
color: var(--secondary);
|
| 1446 |
+
flex-shrink: 0;
|
| 1447 |
+
}
|
| 1448 |
+
|
| 1449 |
+
.workspace-context-summary-text {
|
| 1450 |
+
flex: 1;
|
| 1451 |
+
min-width: 0;
|
| 1452 |
+
overflow: hidden;
|
| 1453 |
+
text-overflow: ellipsis;
|
| 1454 |
+
white-space: nowrap;
|
| 1455 |
+
}
|
| 1456 |
+
|
| 1457 |
+
.workspace-context-chevron {
|
| 1458 |
+
font-size: 1.25rem;
|
| 1459 |
+
color: var(--secondary);
|
| 1460 |
+
flex-shrink: 0;
|
| 1461 |
+
transition: transform 0.2s ease;
|
| 1462 |
+
}
|
| 1463 |
+
|
| 1464 |
+
.workspace-context-mobile[open] .workspace-context-chevron {
|
| 1465 |
+
transform: rotate(180deg);
|
| 1466 |
+
}
|
| 1467 |
+
|
| 1468 |
+
.workspace-context-mobile[open] .workspace-context-inner {
|
| 1469 |
+
padding: 0 0.75rem 0.75rem;
|
| 1470 |
+
border-top: 1px solid var(--outline-variant);
|
| 1471 |
+
}
|
| 1472 |
+
|
| 1473 |
+
.workspace-context-mobile:not([open]) .workspace-context-inner {
|
| 1474 |
+
display: none;
|
| 1475 |
+
}
|
| 1476 |
+
|
| 1477 |
+
.workspace-context-inner .ws-field {
|
| 1478 |
+
flex: 1 1 100%;
|
| 1479 |
+
min-width: 0;
|
| 1480 |
+
}
|
| 1481 |
+
|
| 1482 |
+
.workspace {
|
| 1483 |
+
margin-left: 0;
|
| 1484 |
+
padding: calc(var(--topbar-h) + var(--context-bar-h) + 0.75rem) 0.75rem 1rem;
|
| 1485 |
+
}
|
| 1486 |
+
|
| 1487 |
+
.studio-banner {
|
| 1488 |
+
left: 0;
|
| 1489 |
+
}
|
| 1490 |
+
|
| 1491 |
+
.workspace-context-bar,
|
| 1492 |
+
.topbar {
|
| 1493 |
+
padding-left: max(0.75rem, env(safe-area-inset-left));
|
| 1494 |
+
padding-right: max(0.75rem, env(safe-area-inset-right));
|
| 1495 |
+
}
|
| 1496 |
+
|
| 1497 |
+
.card {
|
| 1498 |
+
padding: 0.85rem;
|
| 1499 |
+
border-radius: var(--radius-lg);
|
| 1500 |
+
}
|
| 1501 |
+
|
| 1502 |
+
.controls-grid {
|
| 1503 |
+
grid-template-columns: 1fr;
|
| 1504 |
+
}
|
| 1505 |
+
|
| 1506 |
+
.section-label {
|
| 1507 |
+
font-size: 0.68rem;
|
| 1508 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1509 |
}
|
| 1510 |
|
| 1511 |
/* Parity additions */
|
|
@@ -25,6 +25,12 @@ function toggleTheme() {
|
|
| 25 |
|
| 26 |
applyTheme(getPreferredTheme());
|
| 27 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
const SLIDE_PIPELINE_STEPS = [
|
| 29 |
"Load language model",
|
| 30 |
"Gather lesson sources",
|
|
@@ -745,7 +751,70 @@ async function refreshDebugDocuments() {
|
|
| 745 |
function updateProjectTitle() {
|
| 746 |
const topic = state.workspaceTopic || "";
|
| 747 |
const short = topic.split(" for ")[0] || topic || "Project";
|
| 748 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 749 |
}
|
| 750 |
|
| 751 |
function updateWorkspaceRagHint() {
|
|
@@ -763,7 +832,7 @@ function updateWorkspaceRagHint() {
|
|
| 763 |
|
| 764 |
async function getClient() {
|
| 765 |
if (!state.client) {
|
| 766 |
-
state.client = await Client.connect(
|
| 767 |
}
|
| 768 |
return state.client;
|
| 769 |
}
|
|
@@ -942,7 +1011,7 @@ async function callApi(name, args = []) {
|
|
| 942 |
return data;
|
| 943 |
} catch (err) {
|
| 944 |
const message = err?.message || String(err);
|
| 945 |
-
showError(`${message} — try Classic UI
|
| 946 |
throw err;
|
| 947 |
} finally {
|
| 948 |
setLoading(false);
|
|
@@ -1012,6 +1081,7 @@ async function refreshWorkspaceSessions(selectId) {
|
|
| 1012 |
}
|
| 1013 |
}
|
| 1014 |
await refreshDebugSessions();
|
|
|
|
| 1015 |
}
|
| 1016 |
|
| 1017 |
async function refreshDocuments() {
|
|
@@ -1104,6 +1174,7 @@ async function reloadModelFromSettings() {
|
|
| 1104 |
async function initWorkspace() {
|
| 1105 |
$("#workspace-topic").value = state.workspaceTopic;
|
| 1106 |
syncResearchLayout();
|
|
|
|
| 1107 |
updateProjectTitle();
|
| 1108 |
updateResearchRagBadge();
|
| 1109 |
await refreshWorkspaceSessions();
|
|
@@ -1115,6 +1186,7 @@ async function initWorkspace() {
|
|
| 1115 |
await refreshDebugDocuments();
|
| 1116 |
const recStatus = await callApi("recording_status", []);
|
| 1117 |
state.useBrowserMic = !recStatus.backend || /unavailable|no capture/i.test(recStatus.message || "");
|
|
|
|
| 1118 |
}
|
| 1119 |
|
| 1120 |
async function ingestUrl() {
|
|
@@ -1211,6 +1283,7 @@ async function generateSlides() {
|
|
| 1211 |
<a href="${fileUrl(data.downloads.docx)}" download>DOCX</a>
|
| 1212 |
<a href="${fileUrl(data.downloads.html)}" download>HTML</a>`;
|
| 1213 |
$("#btn-export").disabled = false;
|
|
|
|
| 1214 |
}
|
| 1215 |
|
| 1216 |
const outlineDetails = $("#slide-outline-details");
|
|
@@ -1455,11 +1528,15 @@ function bindUi() {
|
|
| 1455 |
btn.classList.add("active");
|
| 1456 |
$(".workspace").dataset.view = btn.dataset.view;
|
| 1457 |
syncResearchLayout();
|
| 1458 |
-
|
|
|
|
| 1459 |
});
|
| 1460 |
});
|
| 1461 |
|
| 1462 |
-
$("#btn-open-settings")?.addEventListener("click",
|
|
|
|
|
|
|
|
|
|
| 1463 |
$("#btn-close-settings")?.addEventListener("click", closeSettingsDrawer);
|
| 1464 |
$("#settings-backdrop")?.addEventListener("click", closeSettingsDrawer);
|
| 1465 |
$("#theme-toggle")?.addEventListener("change", toggleTheme);
|
|
@@ -1467,8 +1544,9 @@ function bindUi() {
|
|
| 1467 |
$("#btn-reload-model")?.addEventListener("click", () => reloadModelFromSettings().catch(() => {}));
|
| 1468 |
|
| 1469 |
$("#btn-open-research-view")?.addEventListener("click", openResearchView);
|
| 1470 |
-
$("#sidebar-open")?.addEventListener("click",
|
| 1471 |
-
$("#sidebar-close")?.addEventListener("click",
|
|
|
|
| 1472 |
|
| 1473 |
$("#workspace-topic").addEventListener("input", (e) => {
|
| 1474 |
state.workspaceTopic = e.target.value.trim();
|
|
@@ -1477,6 +1555,7 @@ function bindUi() {
|
|
| 1477 |
|
| 1478 |
$("#workspace-session").addEventListener("change", (e) => {
|
| 1479 |
state.workspaceSessionId = e.target.value;
|
|
|
|
| 1480 |
refreshDocuments().catch(() => {});
|
| 1481 |
refreshDebugDocuments().catch(() => {});
|
| 1482 |
});
|
|
@@ -1597,10 +1676,11 @@ function bindUi() {
|
|
| 1597 |
});
|
| 1598 |
|
| 1599 |
syncLessonsModeUi();
|
|
|
|
| 1600 |
}
|
| 1601 |
|
| 1602 |
bindUi();
|
| 1603 |
initWorkspace().catch((err) => {
|
| 1604 |
console.error(err);
|
| 1605 |
-
showError("Could not connect to Studio API. Open
|
| 1606 |
});
|
|
|
|
| 25 |
|
| 26 |
applyTheme(getPreferredTheme());
|
| 27 |
|
| 28 |
+
function appOrigin() {
|
| 29 |
+
const { protocol, hostname } = window.location;
|
| 30 |
+
const secureProto = protocol === "http:" ? "https:" : protocol;
|
| 31 |
+
return `${secureProto}//${hostname}`;
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
const SLIDE_PIPELINE_STEPS = [
|
| 35 |
"Load language model",
|
| 36 |
"Gather lesson sources",
|
|
|
|
| 751 |
function updateProjectTitle() {
|
| 752 |
const topic = state.workspaceTopic || "";
|
| 753 |
const short = topic.split(" for ")[0] || topic || "Project";
|
| 754 |
+
const title = short.slice(0, 40);
|
| 755 |
+
const el = $("#project-title");
|
| 756 |
+
if (el) {
|
| 757 |
+
el.textContent = title;
|
| 758 |
+
el.title = topic || title;
|
| 759 |
+
}
|
| 760 |
+
updateWorkspaceContextSummary();
|
| 761 |
+
}
|
| 762 |
+
|
| 763 |
+
function updateWorkspaceContextSummary() {
|
| 764 |
+
const el = $("#workspace-context-summary-text");
|
| 765 |
+
if (!el) return;
|
| 766 |
+
const topic = (state.workspaceTopic || "Workspace").trim();
|
| 767 |
+
const shortTopic = (topic.split(" for ")[0] || topic || "Workspace").slice(0, 32);
|
| 768 |
+
const sessionSel = $("#workspace-session");
|
| 769 |
+
let sessionLabel = "New session";
|
| 770 |
+
if (sessionSel?.value) {
|
| 771 |
+
const label = sessionSel.selectedOptions[0]?.textContent?.trim() || "Session";
|
| 772 |
+
sessionLabel = label.length > 22 ? `${label.slice(0, 19)}…` : label;
|
| 773 |
+
}
|
| 774 |
+
el.textContent = `${shortTopic} · ${sessionLabel}`;
|
| 775 |
+
el.title = topic ? `${topic} · ${sessionLabel}` : sessionLabel;
|
| 776 |
+
}
|
| 777 |
+
|
| 778 |
+
function syncViewChrome(view) {
|
| 779 |
+
const active = view || $(".workspace")?.dataset.view || "slides";
|
| 780 |
+
document.body.dataset.view = active;
|
| 781 |
+
}
|
| 782 |
+
|
| 783 |
+
function openSidebar() {
|
| 784 |
+
$("#sidebar")?.classList.add("open");
|
| 785 |
+
$("#sidebar-backdrop")?.classList.remove("hidden");
|
| 786 |
+
document.body.classList.add("sidebar-open");
|
| 787 |
+
}
|
| 788 |
+
|
| 789 |
+
function closeSidebar() {
|
| 790 |
+
$("#sidebar")?.classList.remove("open");
|
| 791 |
+
$("#sidebar-backdrop")?.classList.add("hidden");
|
| 792 |
+
document.body.classList.remove("sidebar-open");
|
| 793 |
+
}
|
| 794 |
+
|
| 795 |
+
function syncLayoutOffsets() {
|
| 796 |
+
const topbar = $(".topbar");
|
| 797 |
+
const ctxBar = $("#workspace-context-bar");
|
| 798 |
+
if (!topbar || !ctxBar) return;
|
| 799 |
+
document.documentElement.style.setProperty("--topbar-h", `${topbar.offsetHeight}px`);
|
| 800 |
+
document.documentElement.style.setProperty("--context-bar-h", `${ctxBar.offsetHeight}px`);
|
| 801 |
+
}
|
| 802 |
+
|
| 803 |
+
function bindLayoutSync() {
|
| 804 |
+
syncLayoutOffsets();
|
| 805 |
+
window.addEventListener("resize", syncLayoutOffsets);
|
| 806 |
+
const ctxBar = $("#workspace-context-bar");
|
| 807 |
+
if (ctxBar && typeof ResizeObserver !== "undefined") {
|
| 808 |
+
const ro = new ResizeObserver(() => syncLayoutOffsets());
|
| 809 |
+
ro.observe(ctxBar);
|
| 810 |
+
if ($(".topbar")) ro.observe($(".topbar"));
|
| 811 |
+
}
|
| 812 |
+
$("#workspace-context-mobile")?.addEventListener("toggle", syncLayoutOffsets);
|
| 813 |
+
document.addEventListener("keydown", (e) => {
|
| 814 |
+
if (e.key === "Escape" && $("#sidebar")?.classList.contains("open")) {
|
| 815 |
+
closeSidebar();
|
| 816 |
+
}
|
| 817 |
+
});
|
| 818 |
}
|
| 819 |
|
| 820 |
function updateWorkspaceRagHint() {
|
|
|
|
| 832 |
|
| 833 |
async function getClient() {
|
| 834 |
if (!state.client) {
|
| 835 |
+
state.client = await Client.connect(appOrigin());
|
| 836 |
}
|
| 837 |
return state.client;
|
| 838 |
}
|
|
|
|
| 1011 |
return data;
|
| 1012 |
} catch (err) {
|
| 1013 |
const message = err?.message || String(err);
|
| 1014 |
+
showError(`${message} — try Classic UI (?classic)`);
|
| 1015 |
throw err;
|
| 1016 |
} finally {
|
| 1017 |
setLoading(false);
|
|
|
|
| 1081 |
}
|
| 1082 |
}
|
| 1083 |
await refreshDebugSessions();
|
| 1084 |
+
updateWorkspaceContextSummary();
|
| 1085 |
}
|
| 1086 |
|
| 1087 |
async function refreshDocuments() {
|
|
|
|
| 1174 |
async function initWorkspace() {
|
| 1175 |
$("#workspace-topic").value = state.workspaceTopic;
|
| 1176 |
syncResearchLayout();
|
| 1177 |
+
syncViewChrome();
|
| 1178 |
updateProjectTitle();
|
| 1179 |
updateResearchRagBadge();
|
| 1180 |
await refreshWorkspaceSessions();
|
|
|
|
| 1186 |
await refreshDebugDocuments();
|
| 1187 |
const recStatus = await callApi("recording_status", []);
|
| 1188 |
state.useBrowserMic = !recStatus.backend || /unavailable|no capture/i.test(recStatus.message || "");
|
| 1189 |
+
syncLayoutOffsets();
|
| 1190 |
}
|
| 1191 |
|
| 1192 |
async function ingestUrl() {
|
|
|
|
| 1283 |
<a href="${fileUrl(data.downloads.docx)}" download>DOCX</a>
|
| 1284 |
<a href="${fileUrl(data.downloads.html)}" download>HTML</a>`;
|
| 1285 |
$("#btn-export").disabled = false;
|
| 1286 |
+
syncLayoutOffsets();
|
| 1287 |
}
|
| 1288 |
|
| 1289 |
const outlineDetails = $("#slide-outline-details");
|
|
|
|
| 1528 |
btn.classList.add("active");
|
| 1529 |
$(".workspace").dataset.view = btn.dataset.view;
|
| 1530 |
syncResearchLayout();
|
| 1531 |
+
syncViewChrome(btn.dataset.view);
|
| 1532 |
+
closeSidebar();
|
| 1533 |
});
|
| 1534 |
});
|
| 1535 |
|
| 1536 |
+
$("#btn-open-settings")?.addEventListener("click", () => {
|
| 1537 |
+
closeSidebar();
|
| 1538 |
+
openSettingsDrawer();
|
| 1539 |
+
});
|
| 1540 |
$("#btn-close-settings")?.addEventListener("click", closeSettingsDrawer);
|
| 1541 |
$("#settings-backdrop")?.addEventListener("click", closeSettingsDrawer);
|
| 1542 |
$("#theme-toggle")?.addEventListener("change", toggleTheme);
|
|
|
|
| 1544 |
$("#btn-reload-model")?.addEventListener("click", () => reloadModelFromSettings().catch(() => {}));
|
| 1545 |
|
| 1546 |
$("#btn-open-research-view")?.addEventListener("click", openResearchView);
|
| 1547 |
+
$("#sidebar-open")?.addEventListener("click", openSidebar);
|
| 1548 |
+
$("#sidebar-close")?.addEventListener("click", closeSidebar);
|
| 1549 |
+
$("#sidebar-backdrop")?.addEventListener("click", closeSidebar);
|
| 1550 |
|
| 1551 |
$("#workspace-topic").addEventListener("input", (e) => {
|
| 1552 |
state.workspaceTopic = e.target.value.trim();
|
|
|
|
| 1555 |
|
| 1556 |
$("#workspace-session").addEventListener("change", (e) => {
|
| 1557 |
state.workspaceSessionId = e.target.value;
|
| 1558 |
+
updateWorkspaceContextSummary();
|
| 1559 |
refreshDocuments().catch(() => {});
|
| 1560 |
refreshDebugDocuments().catch(() => {});
|
| 1561 |
});
|
|
|
|
| 1676 |
});
|
| 1677 |
|
| 1678 |
syncLessonsModeUi();
|
| 1679 |
+
bindLayoutSync();
|
| 1680 |
}
|
| 1681 |
|
| 1682 |
bindUi();
|
| 1683 |
initWorkspace().catch((err) => {
|
| 1684 |
console.error(err);
|
| 1685 |
+
showError("Could not connect to Studio API. Open ?classic for full Gradio UI.");
|
| 1686 |
});
|
|
@@ -1,6 +1,5 @@
|
|
| 1 |
from inference.base import InferenceBackend
|
| 2 |
from inference.config import ModelConfig, get_model_config
|
| 3 |
-
from inference.llama_cpp import LlamaCppBackend
|
| 4 |
|
| 5 |
_backend: InferenceBackend | None = None
|
| 6 |
_backend_key: tuple | None = None
|
|
@@ -8,6 +7,8 @@ _backend_key: tuple | None = None
|
|
| 8 |
|
| 9 |
def _create_backend(config: ModelConfig) -> InferenceBackend:
|
| 10 |
if config.backend == "llama_cpp":
|
|
|
|
|
|
|
| 11 |
return LlamaCppBackend(config)
|
| 12 |
|
| 13 |
if config.backend == "transformers":
|
|
|
|
| 1 |
from inference.base import InferenceBackend
|
| 2 |
from inference.config import ModelConfig, get_model_config
|
|
|
|
| 3 |
|
| 4 |
_backend: InferenceBackend | None = None
|
| 5 |
_backend_key: tuple | None = None
|
|
|
|
| 7 |
|
| 8 |
def _create_backend(config: ModelConfig) -> InferenceBackend:
|
| 9 |
if config.backend == "llama_cpp":
|
| 10 |
+
from inference.llama_cpp import LlamaCppBackend
|
| 11 |
+
|
| 12 |
return LlamaCppBackend(config)
|
| 13 |
|
| 14 |
if config.backend == "transformers":
|
|
@@ -1,9 +1,5 @@
|
|
| 1 |
-
#
|
| 2 |
-
-e ./libs/
|
| 3 |
-
-e ./libs/researchmind
|
| 4 |
-
-e ./libs/agent
|
| 5 |
-
-e ./libs/echocoach[piper,whisper]
|
| 6 |
-
-e ./apps/gradio-space
|
| 7 |
|
| 8 |
# Pinned runtime deps (do not pin gradio, spaces, or huggingface_hub — HF preinstalls them)
|
| 9 |
accelerate==1.13.0
|
|
@@ -11,7 +7,8 @@ torch==2.12.0
|
|
| 11 |
torchvision==0.27.0
|
| 12 |
transformers==5.10.2
|
| 13 |
peft==0.19.1
|
| 14 |
-
llama-cpp-python
|
|
|
|
| 15 |
sentence-transformers==5.5.1
|
| 16 |
pydantic>=2.0.0
|
| 17 |
pyyaml>=6.0.2
|
|
|
|
| 1 |
+
# Monorepo workspace packages are loaded via PYTHONPATH in app.py (HF installs
|
| 2 |
+
# requirements before copying the repo, so -e ./libs/* editable installs fail).
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
|
| 4 |
# Pinned runtime deps (do not pin gradio, spaces, or huggingface_hub — HF preinstalls them)
|
| 5 |
accelerate==1.13.0
|
|
|
|
| 7 |
torchvision==0.27.0
|
| 8 |
transformers==5.10.2
|
| 9 |
peft==0.19.1
|
| 10 |
+
# llama-cpp-python omitted — compiles from source on HF (10+ min / timeout).
|
| 11 |
+
# Space uses transformers presets (minicpm5-1b). Install locally for GGUF presets.
|
| 12 |
sentence-transformers==5.5.1
|
| 13 |
pydantic>=2.0.0
|
| 14 |
pyyaml>=6.0.2
|