Spaces:
Running on Zero
Running on Zero
Fix blank screen during generation, stream thinking tokens, Enter to send, lower GPU duration
Browse files
app.py
CHANGED
|
@@ -123,6 +123,19 @@ HEADER = """
|
|
| 123 |
</div>
|
| 124 |
"""
|
| 125 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 126 |
PLACEHOLDER = """
|
| 127 |
<div class="twil-empty">
|
| 128 |
<img class="twil-cube" src="/gradio_api/file=brand/webai-cube-256.webp" alt="" />
|
|
@@ -155,12 +168,18 @@ CSS = """
|
|
| 155 |
|
| 156 |
* { box-shadow: none !important; text-shadow: none !important; }
|
| 157 |
html, body, #root, .gradio-container, .gradio-container > .main,
|
| 158 |
-
.gradio-container .contain, .fillable,
|
| 159 |
.gradio-container .column, .gradio-container .row, .contain, .wrapper {
|
| 160 |
background: var(--weba-canvas) !important;
|
| 161 |
box-shadow: none !important;
|
| 162 |
filter: none !important;
|
| 163 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 164 |
html, body, .gradio-container, .gradio-container > .main, .fillable,
|
| 165 |
.contain, .app {
|
| 166 |
height: 100% !important;
|
|
@@ -651,6 +670,9 @@ def _parse_think(raw: str) -> tuple[str, str, bool]:
|
|
| 651 |
"""Return (think, answer, think_open) from a possibly streaming reply."""
|
| 652 |
open_idx = raw.find(THINK_OPEN)
|
| 653 |
if open_idx == -1:
|
|
|
|
|
|
|
|
|
|
| 654 |
return "", raw, False
|
| 655 |
rest = raw[open_idx + len(THINK_OPEN) :]
|
| 656 |
close_idx = rest.find(THINK_CLOSE)
|
|
@@ -662,9 +684,11 @@ def _parse_think(raw: str) -> tuple[str, str, bool]:
|
|
| 662 |
return think, answer, False
|
| 663 |
|
| 664 |
|
| 665 |
-
def _gpu_seconds(history, max_new_tokens=
|
| 666 |
-
|
| 667 |
-
|
|
|
|
|
|
|
| 668 |
|
| 669 |
|
| 670 |
def _history_for_model(history: list) -> list[dict]:
|
|
@@ -685,15 +709,20 @@ def _history_for_model(history: list) -> list[dict]:
|
|
| 685 |
|
| 686 |
def _stream_tokens(conversation: list[dict], max_new_tokens: int, temperature: float, top_p: float, enable_thinking: bool) -> Iterator[str]:
|
| 687 |
if PREVIEW:
|
|
|
|
|
|
|
| 688 |
demo = (
|
| 689 |
f"{THINK_OPEN}\n"
|
| 690 |
-
"Check the premises, then the conclusion.
|
|
|
|
|
|
|
| 691 |
f"{THINK_CLOSE}\n\n"
|
| 692 |
"Answer: entailment."
|
| 693 |
)
|
| 694 |
acc = ""
|
| 695 |
for ch in demo:
|
| 696 |
acc += ch
|
|
|
|
| 697 |
yield acc
|
| 698 |
return
|
| 699 |
|
|
@@ -801,6 +830,10 @@ def generate_reply(history, max_new_tokens, temperature, top_p, enable_thinking)
|
|
| 801 |
answer_msg["content"] = raw.strip()
|
| 802 |
if not any(m is answer_msg for m in history):
|
| 803 |
history.append(answer_msg)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 804 |
yield history
|
| 805 |
|
| 806 |
if think_msg["content"]:
|
|
@@ -849,7 +882,7 @@ with gr.Blocks(fill_height=True, fill_width=True, elem_id="app-root") as demo:
|
|
| 849 |
)
|
| 850 |
send = gr.Button("↑", elem_id="send-btn", scale=0)
|
| 851 |
with gr.Accordion("Parameters", open=False, elem_id="params-box"):
|
| 852 |
-
max_new_tokens = gr.Slider(256, 4096, value=
|
| 853 |
temperature = gr.Slider(0, 1.5, value=0, step=0.05, label="Temperature (0 = greedy)")
|
| 854 |
top_p = gr.Slider(0.1, 1.0, value=0.95, step=0.05, label="Top-p")
|
| 855 |
enable_thinking = gr.Checkbox(value=True, label="Enable thinking")
|
|
@@ -876,7 +909,7 @@ with gr.Blocks(fill_height=True, fill_width=True, elem_id="app-root") as demo:
|
|
| 876 |
[chatbot, max_new_tokens, temperature, top_p, enable_thinking],
|
| 877 |
chatbot,
|
| 878 |
concurrency_limit=1,
|
| 879 |
-
show_progress="
|
| 880 |
)
|
| 881 |
prompt.submit(
|
| 882 |
queue_message,
|
|
@@ -888,7 +921,7 @@ with gr.Blocks(fill_height=True, fill_width=True, elem_id="app-root") as demo:
|
|
| 888 |
[chatbot, max_new_tokens, temperature, top_p, enable_thinking],
|
| 889 |
chatbot,
|
| 890 |
concurrency_limit=1,
|
| 891 |
-
show_progress="
|
| 892 |
)
|
| 893 |
for btn, (_, template) in zip(chip_btns, CHIPS):
|
| 894 |
btn.click(lambda t=template: t, outputs=prompt)
|
|
@@ -908,13 +941,14 @@ with gr.Blocks(fill_height=True, fill_width=True, elem_id="app-root") as demo:
|
|
| 908 |
[chatbot, max_new_tokens, temperature, top_p, enable_thinking],
|
| 909 |
chatbot,
|
| 910 |
concurrency_limit=1,
|
| 911 |
-
show_progress="
|
| 912 |
)
|
| 913 |
|
| 914 |
if __name__ == "__main__":
|
| 915 |
demo.launch(
|
| 916 |
theme=THEME,
|
| 917 |
css=CSS,
|
|
|
|
| 918 |
allowed_paths=[str(ASSETS), str(ASSETS.parent)],
|
| 919 |
ssr_mode=False,
|
| 920 |
)
|
|
|
|
| 123 |
</div>
|
| 124 |
"""
|
| 125 |
|
| 126 |
+
HEAD = """
|
| 127 |
+
<script>
|
| 128 |
+
document.addEventListener("keydown", (e) => {
|
| 129 |
+
if (e.key !== "Enter" || e.shiftKey || e.isComposing) return;
|
| 130 |
+
const ta = document.querySelector("#twil-input textarea");
|
| 131 |
+
if (!ta || e.target !== ta) return;
|
| 132 |
+
e.preventDefault();
|
| 133 |
+
e.stopPropagation();
|
| 134 |
+
document.querySelector("#send-btn")?.click();
|
| 135 |
+
}, true);
|
| 136 |
+
</script>
|
| 137 |
+
"""
|
| 138 |
+
|
| 139 |
PLACEHOLDER = """
|
| 140 |
<div class="twil-empty">
|
| 141 |
<img class="twil-cube" src="/gradio_api/file=brand/webai-cube-256.webp" alt="" />
|
|
|
|
| 168 |
|
| 169 |
* { box-shadow: none !important; text-shadow: none !important; }
|
| 170 |
html, body, #root, .gradio-container, .gradio-container > .main,
|
| 171 |
+
.gradio-container .contain, .fillable,
|
| 172 |
.gradio-container .column, .gradio-container .row, .contain, .wrapper {
|
| 173 |
background: var(--weba-canvas) !important;
|
| 174 |
box-shadow: none !important;
|
| 175 |
filter: none !important;
|
| 176 |
}
|
| 177 |
+
/* Never paint over content while a job is running: the status tracker
|
| 178 |
+
overlay must stay transparent or the chat looks blank mid-generation. */
|
| 179 |
+
.gradio-container [data-testid="status-tracker"],
|
| 180 |
+
.gradio-container .wrap.default {
|
| 181 |
+
background: transparent !important;
|
| 182 |
+
}
|
| 183 |
html, body, .gradio-container, .gradio-container > .main, .fillable,
|
| 184 |
.contain, .app {
|
| 185 |
height: 100% !important;
|
|
|
|
| 670 |
"""Return (think, answer, think_open) from a possibly streaming reply."""
|
| 671 |
open_idx = raw.find(THINK_OPEN)
|
| 672 |
if open_idx == -1:
|
| 673 |
+
# A partially streamed opening tag is not an answer yet.
|
| 674 |
+
if raw.strip() and THINK_OPEN.startswith(raw.strip()):
|
| 675 |
+
return "", "", False
|
| 676 |
return "", raw, False
|
| 677 |
rest = raw[open_idx + len(THINK_OPEN) :]
|
| 678 |
close_idx = rest.find(THINK_CLOSE)
|
|
|
|
| 684 |
return think, answer, False
|
| 685 |
|
| 686 |
|
| 687 |
+
def _gpu_seconds(history, max_new_tokens=1024, *args, **kwargs):
|
| 688 |
+
# ZeroGPU adds its own startup overhead on top of this request, and
|
| 689 |
+
# anonymous visitors have a small quota — keep the ask modest.
|
| 690 |
+
tokens = int(max_new_tokens or 1024)
|
| 691 |
+
return min(90, max(25, 10 + tokens // 30))
|
| 692 |
|
| 693 |
|
| 694 |
def _history_for_model(history: list) -> list[dict]:
|
|
|
|
| 709 |
|
| 710 |
def _stream_tokens(conversation: list[dict], max_new_tokens: int, temperature: float, top_p: float, enable_thinking: bool) -> Iterator[str]:
|
| 711 |
if PREVIEW:
|
| 712 |
+
import time
|
| 713 |
+
|
| 714 |
demo = (
|
| 715 |
f"{THINK_OPEN}\n"
|
| 716 |
+
"Check the premises, then the conclusion. Premise 1 gives Rain -> Wet. "
|
| 717 |
+
"Premise 2 observes Wet. Inferring Rain from Wet affirms the consequent, "
|
| 718 |
+
"which is invalid. The argument is a classic Barbara syllogism otherwise.\n"
|
| 719 |
f"{THINK_CLOSE}\n\n"
|
| 720 |
"Answer: entailment."
|
| 721 |
)
|
| 722 |
acc = ""
|
| 723 |
for ch in demo:
|
| 724 |
acc += ch
|
| 725 |
+
time.sleep(0.02)
|
| 726 |
yield acc
|
| 727 |
return
|
| 728 |
|
|
|
|
| 830 |
answer_msg["content"] = raw.strip()
|
| 831 |
if not any(m is answer_msg for m in history):
|
| 832 |
history.append(answer_msg)
|
| 833 |
+
elif any(m is answer_msg for m in history):
|
| 834 |
+
# A partial tag was mistaken for an answer earlier; retract it.
|
| 835 |
+
history.remove(answer_msg)
|
| 836 |
+
answer_msg["content"] = ""
|
| 837 |
yield history
|
| 838 |
|
| 839 |
if think_msg["content"]:
|
|
|
|
| 882 |
)
|
| 883 |
send = gr.Button("↑", elem_id="send-btn", scale=0)
|
| 884 |
with gr.Accordion("Parameters", open=False, elem_id="params-box"):
|
| 885 |
+
max_new_tokens = gr.Slider(256, 4096, value=1024, step=256, label="Max new tokens")
|
| 886 |
temperature = gr.Slider(0, 1.5, value=0, step=0.05, label="Temperature (0 = greedy)")
|
| 887 |
top_p = gr.Slider(0.1, 1.0, value=0.95, step=0.05, label="Top-p")
|
| 888 |
enable_thinking = gr.Checkbox(value=True, label="Enable thinking")
|
|
|
|
| 909 |
[chatbot, max_new_tokens, temperature, top_p, enable_thinking],
|
| 910 |
chatbot,
|
| 911 |
concurrency_limit=1,
|
| 912 |
+
show_progress="hidden",
|
| 913 |
)
|
| 914 |
prompt.submit(
|
| 915 |
queue_message,
|
|
|
|
| 921 |
[chatbot, max_new_tokens, temperature, top_p, enable_thinking],
|
| 922 |
chatbot,
|
| 923 |
concurrency_limit=1,
|
| 924 |
+
show_progress="hidden",
|
| 925 |
)
|
| 926 |
for btn, (_, template) in zip(chip_btns, CHIPS):
|
| 927 |
btn.click(lambda t=template: t, outputs=prompt)
|
|
|
|
| 941 |
[chatbot, max_new_tokens, temperature, top_p, enable_thinking],
|
| 942 |
chatbot,
|
| 943 |
concurrency_limit=1,
|
| 944 |
+
show_progress="hidden",
|
| 945 |
)
|
| 946 |
|
| 947 |
if __name__ == "__main__":
|
| 948 |
demo.launch(
|
| 949 |
theme=THEME,
|
| 950 |
css=CSS,
|
| 951 |
+
head=HEAD,
|
| 952 |
allowed_paths=[str(ASSETS), str(ASSETS.parent)],
|
| 953 |
ssr_mode=False,
|
| 954 |
)
|