Spaces:
Build error
Build error
Commit ·
0d9b6c2
1
Parent(s): 9b576b6
fix: threading.Lock on LandmarkExtractor + composer prompt format match
Browse filesTwo deep-check IMPORTANTs:
- B.F2 / A.F4: Gradio multi-threaded server can race the lazy
initialisation of _extractor_singleton; concurrent first-clicks
could build two MediaPipe instances. threading.Lock with
double-checked-locking pattern fixes it.
- C.F6: composer user prompt previously sent ', '.join(signs) while
the system prompt teaches the model with Python list syntax. Switch
user prompt to repr(list(signs)) so format matches examples — should
improve the 'My name is Lucas' hero demo.
- signbridge/composer/sentence.py +3 -1
- signbridge/space.py +13 -3
signbridge/composer/sentence.py
CHANGED
|
@@ -110,7 +110,9 @@ def compose_sentence(signs: Sequence[str]) -> str:
|
|
| 110 |
return ""
|
| 111 |
|
| 112 |
client, model = _resolve_client()
|
| 113 |
-
|
|
|
|
|
|
|
| 114 |
|
| 115 |
if client is None:
|
| 116 |
return _naive_join(signs)
|
|
|
|
| 110 |
return ""
|
| 111 |
|
| 112 |
client, model = _resolve_client()
|
| 113 |
+
# System prompt examples use Python-list syntax (e.g. ["L","U","C","A","S"]);
|
| 114 |
+
# match that format here so the LLM sees inputs and examples consistently.
|
| 115 |
+
user_prompt = f"ASL signs: {list(signs)!r}"
|
| 116 |
|
| 117 |
if client is None:
|
| 118 |
return _naive_join(signs)
|
signbridge/space.py
CHANGED
|
@@ -17,6 +17,7 @@ from __future__ import annotations
|
|
| 17 |
|
| 18 |
import logging
|
| 19 |
import os
|
|
|
|
| 20 |
from dataclasses import dataclass, field
|
| 21 |
|
| 22 |
import gradio as gr
|
|
@@ -108,13 +109,22 @@ def _recognize(frame: np.ndarray) -> tuple[str, float]:
|
|
| 108 |
|
| 109 |
|
| 110 |
_extractor_singleton: LandmarkExtractor | None = None
|
|
|
|
| 111 |
|
| 112 |
|
| 113 |
def _shared_extractor() -> LandmarkExtractor:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 114 |
global _extractor_singleton
|
| 115 |
-
if _extractor_singleton is None:
|
| 116 |
-
|
| 117 |
-
|
|
|
|
|
|
|
|
|
|
| 118 |
|
| 119 |
|
| 120 |
def _capture_sign(
|
|
|
|
| 17 |
|
| 18 |
import logging
|
| 19 |
import os
|
| 20 |
+
import threading
|
| 21 |
from dataclasses import dataclass, field
|
| 22 |
|
| 23 |
import gradio as gr
|
|
|
|
| 109 |
|
| 110 |
|
| 111 |
_extractor_singleton: LandmarkExtractor | None = None
|
| 112 |
+
_extractor_lock = threading.Lock()
|
| 113 |
|
| 114 |
|
| 115 |
def _shared_extractor() -> LandmarkExtractor:
|
| 116 |
+
"""Return the lazy-loaded MediaPipe Holistic extractor.
|
| 117 |
+
|
| 118 |
+
Double-checked locking so concurrent first-call requests under
|
| 119 |
+
Gradio's worker threads don't race and build two extractors.
|
| 120 |
+
"""
|
| 121 |
global _extractor_singleton
|
| 122 |
+
if _extractor_singleton is not None:
|
| 123 |
+
return _extractor_singleton
|
| 124 |
+
with _extractor_lock:
|
| 125 |
+
if _extractor_singleton is None:
|
| 126 |
+
_extractor_singleton = LandmarkExtractor()
|
| 127 |
+
return _extractor_singleton
|
| 128 |
|
| 129 |
|
| 130 |
def _capture_sign(
|