Feat: Add toggle to exclude think/reason blocks from smooth streaming (#4849)
* Feat: Add toggle to exclude think/reason blocks from smooth streaming * Fix: Adjust new setting name to properly reflect what it does * Sync data-i18n with text content * Add reasoning stream flags for Mistral, Claude and Google models * Update layout * Fix: Enhance reasoning handling in parseStreamData function --------- Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
f145296a58
commit
6c8eb4d9ac
@@ -477,14 +477,11 @@ body.expandMessageActions .mes .mes_buttons .extraMesButtonsHint {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
#smooth_streaming:not(:checked)~#smooth_streaming_speed_control {
|
||||
#smooth_streaming_control:has(#smooth_streaming:not(:checked))~#smooth_streaming_speed_control,
|
||||
#smooth_streaming_control:has(#smooth_streaming:not(:checked))~#smooth_streaming_no_think_control {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#smooth_streaming:checked~#smooth_streaming_speed_control {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.mdhotkey_icon {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
+15
-9
@@ -5029,22 +5029,28 @@
|
||||
<small data-i18n="Clean-Up">Clean-Up</small>
|
||||
</div>
|
||||
</div>
|
||||
<label class="checkbox_label flexWrap" for="smooth_streaming">
|
||||
<label id="smooth_streaming_control" class="checkbox_label" for="smooth_streaming">
|
||||
<input id="smooth_streaming" type="checkbox" />
|
||||
<div class="flex-container alignItemsBaseline">
|
||||
<small data-i18n="Smooth Streaming">
|
||||
Smooth Streaming
|
||||
</small>
|
||||
</div>
|
||||
<div id="smooth_streaming_speed_control" class="flexBasis100p wide100p">
|
||||
<input type="range" id="smooth_streaming_speed" name="smooth_streaming_speed" min="0" max="100" step="10" value="50">
|
||||
<div class="slider_hint">
|
||||
<span data-i18n="Slow">Slow</span>
|
||||
<span></span>
|
||||
<span data-i18n="Fast">Fast</span>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
<label id="smooth_streaming_no_think_control" class="checkbox_label" for="smooth_streaming_no_think" title="Bypass smooth streaming in reasoning blocks." data-i18n="[title]Bypass smooth streaming in reasoning blocks.">
|
||||
<input id="smooth_streaming_no_think" type="checkbox" />
|
||||
<small data-i18n="Exclude 'Thinking...'">
|
||||
Exclude 'Thinking...'
|
||||
</small>
|
||||
</label>
|
||||
<div id="smooth_streaming_speed_control" class="wide100p">
|
||||
<input type="range" id="smooth_streaming_speed" name="smooth_streaming_speed" min="0" max="100" step="10" value="50">
|
||||
<div class="slider_hint">
|
||||
<span data-i18n="Slow">Slow</span>
|
||||
<span></span>
|
||||
<span data-i18n="Fast">Fast</span>
|
||||
</div>
|
||||
</div>
|
||||
<label class="checkbox_label" for="stream_fade_in" title="Fade in streamed text when it appears, instead of it just popping in." data-i18n="[title]Fade in streamed text when it appears, instead of it just popping in">
|
||||
<input id="stream_fade_in" type="checkbox" />
|
||||
<small data-i18n="Stream Fade-In">Stream Fade-In</small>
|
||||
|
||||
@@ -139,6 +139,7 @@ export const power_user = {
|
||||
chat_truncation: 100,
|
||||
streaming_fps: 30,
|
||||
smooth_streaming: false,
|
||||
smooth_streaming_no_think: false,
|
||||
smooth_streaming_speed: 50,
|
||||
stream_fade_in: false,
|
||||
|
||||
@@ -1745,6 +1746,7 @@ export async function loadPowerUserSettings(settings, data) {
|
||||
$('#streaming_fps_counter').val(power_user.streaming_fps);
|
||||
|
||||
$('#smooth_streaming').prop('checked', power_user.smooth_streaming);
|
||||
$('#smooth_streaming_no_think').prop('checked', power_user.smooth_streaming_no_think);
|
||||
$('#smooth_streaming_speed').val(power_user.smooth_streaming_speed);
|
||||
|
||||
$('#stream_fade_in').prop('checked', power_user.stream_fade_in);
|
||||
@@ -3550,6 +3552,11 @@ jQuery(() => {
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$('#smooth_streaming_no_think').on('input', function () {
|
||||
power_user.smooth_streaming_no_think = !!$(this).prop('checked');
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$('#smooth_streaming_speed').on('input', function () {
|
||||
power_user.smooth_streaming_speed = Number($('#smooth_streaming_speed').val());
|
||||
saveSettingsDebounced();
|
||||
|
||||
@@ -105,7 +105,7 @@ function getDelay(s) {
|
||||
/**
|
||||
* Parses the stream data and returns the parsed data and the chunk to be sent.
|
||||
* @param {object} json The JSON data.
|
||||
* @returns {AsyncGenerator<{data: object, chunk: string}>} The parsed data and the chunk to be sent.
|
||||
* @returns {AsyncGenerator<{data: object, chunk: string, reasoning?: boolean}>} The parsed data and the chunk to be sent.
|
||||
*/
|
||||
async function* parseStreamData(json) {
|
||||
// Cohere
|
||||
@@ -133,6 +133,19 @@ async function* parseStreamData(json) {
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (typeof json.delta === 'object' && typeof json.delta.thinking === 'string') {
|
||||
if (json.delta.thinking.length > 0) {
|
||||
for (let i = 0; i < json.delta.thinking.length; i++) {
|
||||
const str = json.delta.thinking[i];
|
||||
yield {
|
||||
data: { ...json, delta: { thinking: str } },
|
||||
chunk: str,
|
||||
reasoning: true,
|
||||
};
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
// MakerSuite
|
||||
else if (Array.isArray(json.candidates)) {
|
||||
for (let i = 0; i < json.candidates.length; i++) {
|
||||
@@ -159,9 +172,11 @@ async function* parseStreamData(json) {
|
||||
candidateClone.content.parts[j].text = str;
|
||||
candidateClone.content.parts = [candidateClone.content.parts[j]];
|
||||
const candidates = [candidateClone];
|
||||
const reasoning = json.candidates[i].content.parts[j].thought ?? false;
|
||||
yield {
|
||||
data: { ...json, candidates },
|
||||
chunk: str,
|
||||
reasoning,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -237,6 +252,7 @@ async function* parseStreamData(json) {
|
||||
yield {
|
||||
data: { ...json, choices },
|
||||
chunk: str,
|
||||
reasoning: true,
|
||||
};
|
||||
}
|
||||
return;
|
||||
@@ -252,6 +268,7 @@ async function* parseStreamData(json) {
|
||||
yield {
|
||||
data: { ...json, choices },
|
||||
chunk: str,
|
||||
reasoning: true,
|
||||
};
|
||||
}
|
||||
return;
|
||||
@@ -269,6 +286,24 @@ async function* parseStreamData(json) {
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (Array.isArray(json.choices[0].delta.content) && json.choices[0].delta.content.length > 0) {
|
||||
if (Array.isArray(json.choices[0].delta.content[0].thinking) && json.choices[0].delta.content[0].thinking.length > 0) {
|
||||
if (typeof json.choices[0].delta.content[0].thinking[0].text === 'string' && json.choices[0].delta.content[0].thinking[0].text.length > 0) {
|
||||
for (let j = 0; j < json.choices[0].delta.content[0].thinking[0].text.length; j++) {
|
||||
const str = json.choices[0].delta.content[0].thinking[0].text[j];
|
||||
const choiceClone = structuredClone(json.choices[0]);
|
||||
choiceClone.delta.content[0].thinking[0].text = str;
|
||||
const choices = [choiceClone];
|
||||
yield {
|
||||
data: { ...json, choices },
|
||||
chunk: str,
|
||||
reasoning: true,
|
||||
};
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (typeof json.choices[0].message === 'object') {
|
||||
if (typeof json.choices[0].message.content === 'string' && json.choices[0].message.content.length > 0) {
|
||||
@@ -317,7 +352,7 @@ export class SmoothEventSourceStream extends EventSourceStream {
|
||||
}
|
||||
|
||||
for await (const parsed of parseStreamData(json)) {
|
||||
hasFocus && await delay(getDelay(lastStr));
|
||||
!(power_user.smooth_streaming_no_think && parsed.reasoning) && hasFocus && await delay(getDelay(lastStr));
|
||||
controller.enqueue(new MessageEvent(event.type, { data: JSON.stringify(parsed.data) }));
|
||||
lastStr = parsed.chunk;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user