Team Ai
Apppublic

KBaba7/llama.cpp

sourceHugging Faceapache-2.0updated 2y agoView on Hugging Face
0likes
misc.ts88 linesDownload Raw Back to utils
1// @ts-expect-error this package does not have typing2import TextLineStream from 'textlinestream';3import { APIMessage, Message } from './types';4 5// ponyfill for missing ReadableStream asyncIterator on Safari6import { asyncIterator } from '@sec-ant/readable-stream/ponyfill/asyncIterator';7import { isDev } from '../Config';8 9// eslint-disable-next-line @typescript-eslint/no-explicit-any10export const isString = (x: any) => !!x.toLowerCase;11// eslint-disable-next-line @typescript-eslint/no-explicit-any12export const isBoolean = (x: any) => x === true || x === false;13// eslint-disable-next-line @typescript-eslint/no-explicit-any14export const isNumeric = (n: any) => !isString(n) && !isNaN(n) && !isBoolean(n);15export const escapeAttr = (str: string) =>16  str.replace(/>/g, '&gt;').replace(/"/g, '&quot;');17 18// wrapper for SSE19export async function* getSSEStreamAsync(fetchResponse: Response) {20  if (!fetchResponse.body) throw new Error('Response body is empty');21  const lines: ReadableStream<string> = fetchResponse.body22    .pipeThrough(new TextDecoderStream())23    .pipeThrough(new TextLineStream());24  // @ts-expect-error asyncIterator complains about type, but it should work25  for await (const line of asyncIterator(lines)) {26    if (isDev) console.log({ line });27    if (line.startsWith('data:') && !line.endsWith('[DONE]')) {28      const data = JSON.parse(line.slice(5));29      yield data;30    } else if (line.startsWith('error:')) {31      const data = JSON.parse(line.slice(6));32      throw new Error(data.message || 'Unknown error');33    }34  }35}36 37// copy text to clipboard38export const copyStr = (textToCopy: string) => {39  // Navigator clipboard api needs a secure context (https)40  if (navigator.clipboard && window.isSecureContext) {41    navigator.clipboard.writeText(textToCopy);42  } else {43    // Use the 'out of viewport hidden text area' trick44    const textArea = document.createElement('textarea');45    textArea.value = textToCopy;46    // Move textarea out of the viewport so it's not visible47    textArea.style.position = 'absolute';48    textArea.style.left = '-999999px';49    document.body.prepend(textArea);50    textArea.select();51    document.execCommand('copy');52  }53};54 55/**56 * filter out redundant fields upon sending to API57 */58export function normalizeMsgsForAPI(messages: Message[]) {59  return messages.map((msg) => {60    return {61      role: msg.role,62      content: msg.content,63    };64  }) as APIMessage[];65}66 67/**68 * recommended for DeepsSeek-R1, filter out content between <think> and </think> tags69 */70export function filterThoughtFromMsgs(messages: APIMessage[]) {71  return messages.map((msg) => {72    return {73      role: msg.role,74      content:75        msg.role === 'assistant'76          ? msg.content.split('</think>').at(-1)!.trim()77          : msg.content,78    } as APIMessage;79  });80}81 82export function classNames(classes: Record<string, boolean>): string {83  return Object.entries(classes)84    .filter(([_, value]) => value)85    .map(([key, _]) => key)86    .join(' ');87}88