"N" support for llama.cpp (#4869) * llama.cpp supports 'n' now * Fix response parsing --------- Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>

b5e20f2ff98708b13961d09130b63eda839c191b

Beinsezii <39478211+Beinsezii@users.noreply.github.com>

Signed
4 files changed, +40 -11Showing whitespace changes
public/index.html+1 -1
@@ -1249,7 +1249,7 @@
1249 <div class="fa-solid fa-circle-info opacity50p" title="Customize displayed samplers or add custom samplers." data-i18n="[title]Customize displayed samplers or add custom samplers."></div>1249 <div class="fa-solid fa-circle-info opacity50p" title="Customize displayed samplers or add custom samplers." data-i18n="[title]Customize displayed samplers or add custom samplers."></div>
1250 </small>1250 </small>
1251 </div>1251 </div>
1252 <div data-tg-type="mancer, vllm, aphrodite, tabby, infermaticai" data-tg-samplers="n" class="flex-container flexFlowColumn alignitemscenter flexBasis100p flexGrow flexShrink gap0">1252 <div data-tg-type="mancer, vllm, aphrodite, tabby, infermaticai, llamacpp" data-tg-samplers="n" class="flex-container flexFlowColumn alignitemscenter flexBasis100p flexGrow flexShrink gap0">
1253 <small data-i18n="Multiple swipes per generation">Multiple swipes per generation</small>1253 <small data-i18n="Multiple swipes per generation">Multiple swipes per generation</small>
1254 <input type="number" id="n_textgenerationwebui" class="text_pole textAlignCenter" min="1" value="1" step="1" />1254 <input type="number" id="n_textgenerationwebui" class="text_pole textAlignCenter" min="1" value="1" step="1" />
1255 </div>1255 </div>
public/script.js+24 -8
@@ -5872,7 +5872,7 @@ export function extractMessageFromData(data, activeApi = null) {
5872 case 'koboldhorde':5872 case 'koboldhorde':
5873 return data.text;5873 return data.text;
5874 case 'textgenerationwebui':5874 case 'textgenerationwebui':
5875 return data.choices?.[0]?.text ?? data.choices?.[0]?.message?.content ?? data.content ?? data.response ?? '';5875 return data.choices?.[0]?.text ?? data.choices?.[0]?.message?.content ?? data.content ?? data.response ?? data[0]?.content ?? '';
5876 case 'novel':5876 case 'novel':
5877 return data.output;5877 return data.output;
5878 case 'openai':5878 case 'openai':
@@ -5959,6 +5959,22 @@ function extractMultiSwipes(data, type) {
5959 return swipes;5959 return swipes;
5960 }5960 }
59615961
5962 if (main_api === 'textgenerationwebui' && textgen_settings.type === textgen_types.LLAMACPP) {
5963 if (!Array.isArray(data)) {
5964 return swipes;
5965 }
5966
5967 const multiSwipeCount = data.length - 1;
5968 if (multiSwipeCount <= 0) {
5969 return swipes;
5970 }
5971
5972 for (let i = 1; i < data.length; i++) {
5973 const text = data?.[i]?.content ?? '';
5974 swipes.push(text);
5975 }
5976 }
5977
5962 if (main_api === 'openai' || (main_api === 'textgenerationwebui' && [textgen_types.MANCER, textgen_types.VLLM, textgen_types.APHRODITE, textgen_types.TABBY, textgen_types.INFERMATICAI].includes(textgen_settings.type))) {5978 if (main_api === 'openai' || (main_api === 'textgenerationwebui' && [textgen_types.MANCER, textgen_types.VLLM, textgen_types.APHRODITE, textgen_types.TABBY, textgen_types.INFERMATICAI].includes(textgen_settings.type))) {
5963 if (!Array.isArray(data.choices)) {5979 if (!Array.isArray(data.choices)) {
5964 return swipes;5980 return swipes;
@@ -5972,18 +5988,18 @@ function extractMultiSwipes(data, type) {
59725988
5973 for (let i = 1; i < data.choices.length; i++) {5989 for (let i = 1; i < data.choices.length; i++) {
5974 const text = data?.choices[i]?.message?.content ?? data?.choices[i]?.text ?? '';5990 const text = data?.choices[i]?.message?.content ?? data?.choices[i]?.text ?? '';
5975 const cleanedText = cleanUpMessage({5991 swipes.push(text);
5992 }
5993 }
5994
5995 const cleanedSwipes = swipes.map(text => cleanUpMessage({
5976 getMessage: text,5996 getMessage: text,
5977 isImpersonate: false,5997 isImpersonate: false,
5978 isContinue: false,5998 isContinue: false,
5979 displayIncompleteSentences: false,5999 displayIncompleteSentences: false,
5980 });6000 }));
5981
5982 swipes.push(cleanedText);
5983 }
5984 }
59856001
5986 return swipes;6002 return cleanedSwipes;
5987}6003}
59886004
5989/**6005/**
public/scripts/sse-stream.js+10 -1
@@ -1,6 +1,9 @@
1import { power_user } from './power-user.js';1import { power_user } from './power-user.js';
2import { delay } from './utils.js';2import { delay } from './utils.js';
33
4// Symbol for not primary swipe error
5const NOT_PRIMARY = Symbol('not_primary_swipe');
6
4/**7/**
5 * A stream which handles Server-Sent Events from a binary ReadableStream like you get from the fetch API.8 * A stream which handles Server-Sent Events from a binary ReadableStream like you get from the fetch API.
6 */9 */
@@ -198,6 +201,10 @@ async function* parseStreamData(json) {
198 }201 }
199 // llama.cpp?202 // llama.cpp?
200 else if (typeof json.content === 'string' && json.content.length > 0 && json.object !== 'chat.completion.chunk') {203 else if (typeof json.content === 'string' && json.content.length > 0 && json.object !== 'chat.completion.chunk') {
204 const isNotPrimary = json?.index > 0;
205 if (isNotPrimary) {
206 throw new Error('Not a primary swipe', { cause: NOT_PRIMARY });
207 }
201 for (let i = 0; i < json.content.length; i++) {208 for (let i = 0; i < json.content.length; i++) {
202 const str = json.content[i];209 const str = json.content[i];
203 yield {210 yield {
@@ -211,7 +218,7 @@ async function* parseStreamData(json) {
211 else if (Array.isArray(json.choices)) {218 else if (Array.isArray(json.choices)) {
212 const isNotPrimary = json?.choices?.[0]?.index > 0;219 const isNotPrimary = json?.choices?.[0]?.index > 0;
213 if (isNotPrimary || json.choices.length === 0) {220 if (isNotPrimary || json.choices.length === 0) {
214 throw new Error('Not a primary swipe');221 throw new Error('Not a primary swipe', { cause: NOT_PRIMARY });
215 }222 }
216223
217 if (typeof json.choices[0].text === 'string' && json.choices[0].text.length > 0) {224 if (typeof json.choices[0].text === 'string' && json.choices[0].text.length > 0) {
@@ -357,7 +364,9 @@ export class SmoothEventSourceStream extends EventSourceStream {
357 lastStr = parsed.chunk;364 lastStr = parsed.chunk;
358 }365 }
359 } catch (error) {366 } catch (error) {
367 if (error instanceof Error && error.cause !== NOT_PRIMARY) {
360 console.debug('Smooth Streaming parsing error', error);368 console.debug('Smooth Streaming parsing error', error);
369 }
361 controller.enqueue(event);370 controller.enqueue(event);
362 }371 }
363 },372 },
public/scripts/textgen-settings.js+5 -1
@@ -1284,6 +1284,10 @@ export async function generateTextGenWithStreaming(generate_data, signal) {
1284 if (data?.choices?.[0]?.index > 0) {1284 if (data?.choices?.[0]?.index > 0) {
1285 const swipeIndex = data.choices[0].index - 1;1285 const swipeIndex = data.choices[0].index - 1;
1286 swipes[swipeIndex] = (swipes[swipeIndex] || '') + data.choices[0].text;1286 swipes[swipeIndex] = (swipes[swipeIndex] || '') + data.choices[0].text;
1287 } else if (data?.index > 0) {
1288 // llama.cpp streaming swipe
1289 const swipeIndex = data.index - 1;
1290 swipes[swipeIndex] = (swipes[swipeIndex] || '') + data.content;
1287 } else {1291 } else {
1288 const newText = data?.choices?.[0]?.text || data?.content || '';1292 const newText = data?.choices?.[0]?.text || data?.content || '';
1289 text += newText;1293 text += newText;
@@ -1724,7 +1728,7 @@ export function createTextGenGenerationData(settings, model, finalPrompt = null,
1724 params.dry_sequence_breakers = params.parseSequenceBreakers();1728 params.dry_sequence_breakers = params.parseSequenceBreakers();
1725 }1729 }
17261730
1727 if (settings.type === TABBY) {1731 if (settings.type === TABBY || settings.type === LLAMACPP) {
1728 params.n = canMultiSwipe ? settings.n : 1;1732 params.n = canMultiSwipe ? settings.n : 1;
1729 }1733 }
17301734