UI: model dropdown auto-fills from LM Studio /v1/models

- Removed allow_custom_value=True (it was rendering as text input, not select)
- Added fetch_lm_studio_models_with_value() wrapper that sets value=first model
- demo.load() auto-fetches models on UI load
- Removed Measure-Object bug in ps1 launcher
- Removed auto-load step in ps1 launcher (user picks model explicitly)
This commit is contained in:
Mavis
2026-06-15 09:58:48 +03:00
parent 36d9906e1f
commit 4adde251ae
2 changed files with 122 additions and 28 deletions
+18
View File
@@ -70,6 +70,9 @@ class StreamEvent:
type: str # 'delta' | 'end' | 'error'
content: str = ""
# Reasoning-токены qwen3.5 (приходят в `delta.reasoning_content` отдельным
# полем в LM Studio; UI рисует их в своём markdown-поле).
reasoning: str = ""
usage: dict | None = None
model: str = ""
finish_reason: str = ""
@@ -383,12 +386,27 @@ def stream_chat(
first = choices[0]
delta = first.get("delta") or {}
content = delta.get("content")
reasoning = delta.get("reasoning_content")
emitted = False
if content:
# content может прийти str или list[dict] (мультимодальный
# стрим). Склеиваем в строку.
if isinstance(content, list):
content = "".join(_coerce_text_part(p) for p in content)
yield StreamEvent(type="delta", content=str(content))
emitted = True
if reasoning:
# qwen3.5 / LM Studio кладёт рассуждение в ОТДЕЛЬНОЕ поле
# `reasoning_content`, а не в `content`. UI должен это
# отображать (см. градио-markdown в on_generate_live).
if isinstance(reasoning, list):
reasoning = "".join(_coerce_text_part(p) for p in reasoning)
yield StreamEvent(type="delta", reasoning=str(reasoning))
emitted = True
if not emitted:
# Чанки без полезного текста (например, начало стрима,
# где сервер шлёт только role) — пропускаем молча.
pass
fr = first.get("finish_reason")
if fr: