Merge pull request #2161 from cheahjs/fix/handlebars-harden

feat: add {{prompt:middletruncate:<length>}} to title gen
This commit is contained in:
Timothy Jaeryang Baek 2024-05-14 08:21:39 -10:00 committed by GitHub
commit 767ae3be5b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 1123 additions and 20 deletions

View File

@ -37,3 +37,21 @@ jobs:
- name: Build Frontend
run: npm run build
test-frontend:
name: 'Frontend Unit Tests'
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install Dependencies
run: npm ci
- name: Run vitest
run: npm run test:frontend

1002
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -15,7 +15,8 @@
"format": "prettier --plugin-search-dir --write \"**/*.{js,ts,svelte,css,md,html,json}\"",
"format:backend": "black . --exclude \"/venv/\"",
"i18n:parse": "i18next --config i18next-parser.config.ts && prettier --write \"src/lib/i18n/**/*.{js,json}\"",
"cy:open": "cypress open"
"cy:open": "cypress open",
"test:frontend": "vitest"
},
"devDependencies": {
"@sveltejs/adapter-auto": "^2.0.0",
@ -41,7 +42,8 @@
"tailwindcss": "^3.3.3",
"tslib": "^2.4.1",
"typescript": "^5.0.0",
"vite": "^4.4.2"
"vite": "^4.4.2",
"vitest": "^1.6.0"
},
"type": "module",
"dependencies": {

View File

@ -1,8 +1,8 @@
import { dev } from '$app/environment';
import { browser, dev } from '$app/environment';
// import { version } from '../../package.json';
export const APP_NAME = 'Open WebUI';
export const WEBUI_BASE_URL = dev ? `http://${location.hostname}:8080` : ``;
export const WEBUI_BASE_URL = browser ? (dev ? `http://${location.hostname}:8080` : ``) : ``;
export const WEBUI_API_BASE_URL = `${WEBUI_BASE_URL}/api/v1`;

View File

@ -0,0 +1,66 @@
import { promptTemplate } from '$lib/utils/index';
import { expect, test } from 'vitest';
test('promptTemplate correctly replaces {{prompt}} placeholder', () => {
const template = 'Hello {{prompt}}!';
const prompt = 'world';
const expected = 'Hello world!';
const actual = promptTemplate(template, prompt);
expect(actual).toBe(expected);
});
test('promptTemplate correctly replaces {{prompt:start:<length>}} placeholder', () => {
const template = 'Hello {{prompt:start:3}}!';
const prompt = 'world';
const expected = 'Hello wor!';
const actual = promptTemplate(template, prompt);
expect(actual).toBe(expected);
});
test('promptTemplate correctly replaces {{prompt:end:<length>}} placeholder', () => {
const template = 'Hello {{prompt:end:3}}!';
const prompt = 'world';
const expected = 'Hello rld!';
const actual = promptTemplate(template, prompt);
expect(actual).toBe(expected);
});
test('promptTemplate correctly replaces {{prompt:middletruncate:<length>}} placeholder when prompt length is greater than length', () => {
const template = 'Hello {{prompt:middletruncate:4}}!';
const prompt = 'world';
const expected = 'Hello wo...ld!';
const actual = promptTemplate(template, prompt);
expect(actual).toBe(expected);
});
test('promptTemplate correctly replaces {{prompt:middletruncate:<length>}} placeholder when prompt length is less than or equal to length', () => {
const template = 'Hello {{prompt:middletruncate:5}}!';
const prompt = 'world';
const expected = 'Hello world!';
const actual = promptTemplate(template, prompt);
expect(actual).toBe(expected);
});
test('promptTemplate returns original template when no placeholders are present', () => {
const template = 'Hello world!';
const prompt = 'world';
const expected = 'Hello world!';
const actual = promptTemplate(template, prompt);
expect(actual).toBe(expected);
});
test('promptTemplate does not replace placeholders inside of replaced placeholders', () => {
const template = 'Hello {{prompt}}!';
const prompt = 'World, {{prompt}} injection';
const expected = 'Hello World, {{prompt}} injection!';
const actual = promptTemplate(template, prompt);
expect(actual).toBe(expected);
});
test('promptTemplate correctly replaces multiple placeholders', () => {
const template = 'Hello {{prompt}}! This is {{prompt:start:3}}!';
const prompt = 'world';
const expected = 'Hello world! This is wor!';
const actual = promptTemplate(template, prompt);
expect(actual).toBe(expected);
});

View File

@ -472,22 +472,39 @@ export const blobToFile = (blob, fileName) => {
return file;
};
export const promptTemplate = (template: string, prompt: string) => {
prompt = prompt.replace(/{{prompt}}|{{prompt:start:\d+}}|{{prompt:end:\d+}}/g, '');
template = template.replace(/{{prompt}}/g, prompt);
// Replace all instances of {{prompt:start:<length>}} with the first <length> characters of the prompt
template = template.replace(/{{prompt:start:(\d+)}}/g, (match, length) =>
prompt.substring(0, parseInt(length))
/**
* This function is used to replace placeholders in a template string with the provided prompt.
* The placeholders can be in the following formats:
* - `{{prompt}}`: This will be replaced with the entire prompt.
* - `{{prompt:start:<length>}}`: This will be replaced with the first <length> characters of the prompt.
* - `{{prompt:end:<length>}}`: This will be replaced with the last <length> characters of the prompt.
* - `{{prompt:middletruncate:<length>}}`: This will be replaced with the prompt truncated to <length> characters, with '...' in the middle.
*
* @param {string} template - The template string containing placeholders.
* @param {string} prompt - The string to replace the placeholders with.
* @returns {string} The template string with the placeholders replaced by the prompt.
*/
export const promptTemplate = (template: string, prompt: string): string => {
return template.replace(
/{{prompt}}|{{prompt:start:(\d+)}}|{{prompt:end:(\d+)}}|{{prompt:middletruncate:(\d+)}}/g,
(match, startLength, endLength, middleLength) => {
if (match === '{{prompt}}') {
return prompt;
} else if (match.startsWith('{{prompt:start:')) {
return prompt.substring(0, startLength);
} else if (match.startsWith('{{prompt:end:')) {
return prompt.slice(-endLength);
} else if (match.startsWith('{{prompt:middletruncate:')) {
if (prompt.length <= middleLength) {
return prompt;
}
const start = prompt.slice(0, Math.ceil(middleLength / 2));
const end = prompt.slice(-Math.floor(middleLength / 2));
return `${start}...${end}`;
}
return '';
}
);
// Replace all instances of {{prompt:end:<length>}} with the last <length> characters of the prompt
template = template.replace(/{{prompt:end:(\d+)}}/g, (match, length) =>
prompt.slice(-parseInt(length))
);
return template;
};
export const approximateToHumanReadable = (nanoseconds: number) => {