Skip to content

Commit

Permalink
Add prompt box
Browse files Browse the repository at this point in the history
Signed-off-by: Jay Wang <jay@zijie.wang>
  • Loading branch information
xiaohk committed Feb 6, 2024
1 parent d12c444 commit 459860e
Show file tree
Hide file tree
Showing 11 changed files with 340 additions and 5 deletions.
1 change: 1 addition & 0 deletions examples/rag-playground/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"eslint-plugin-wc": "^2.0.4",
"flexsearch": "^0.7.43",
"gh-pages": "^6.1.1",
"gpt-tokenizer": "^2.1.2",
"lit": "^3.1.2",
"prettier": "^3.2.4",
"typescript": "^5.3.3",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@
border-radius: var(--border-radius);
box-shadow: var(--block-shadow);
border: 1px solid hsla(0deg, 0%, 0%, 0.08);

& mememo-prompt-box {
width: 100%;
height: 100%;
}
}

&.container-model {
Expand Down
24 changes: 23 additions & 1 deletion examples/rag-playground/src/components/playground/playground.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ import type { EmbeddingWorkerMessage } from '../../workers/embedding';
import type { MememoTextViewer } from '../text-viewer/text-viewer';

import '../query-box/query-box';
import '../prompt-box/prompt-box';
import '../text-viewer/text-viewer';

import componentCSS from './playground.css?inline';
import EmbeddingWorkerInline from '../../workers/embedding?worker&inline';
import promptTemplatesJSON from '../../config/promptTemplates.json';

interface DatasetInfo {
dataURL: string;
Expand All @@ -22,6 +24,8 @@ enum Dataset {
Arxiv = 'arxiv'
}

const promptTemplate = promptTemplatesJSON as Record<Dataset, string>;

const datasets: Record<Dataset, DatasetInfo> = {
[Dataset.Arxiv]: {
dataURL: '/data/ml-arxiv-papers-1000.ndjson.gzip',
Expand All @@ -40,7 +44,12 @@ export class MememoPlayground extends LitElement {
//==========================================================================||
// Class Properties ||
//==========================================================================||
@state()
userQuery = '';

@state()
relevantDocuments: string[] = [];

embeddingWorker: Worker;
embeddingWorkerRequestCount = 0;
get embeddingWorkerRequestID() {
Expand Down Expand Up @@ -127,6 +136,10 @@ export class MememoPlayground extends LitElement {
this.getEmbedding([this.userQuery]);
}

semanticSearchFinishedHandler(e: CustomEvent<string[]>) {
this.relevantDocuments = e.detail;
}

embeddingWorkerMessageHandler(e: MessageEvent<EmbeddingWorkerMessage>) {
switch (e.data.command) {
case 'finishExtractEmbedding': {
Expand Down Expand Up @@ -175,10 +188,19 @@ export class MememoPlayground extends LitElement {
indexURL=${datasets['arxiv'].indexURL}
datasetName=${datasets['arxiv'].datasetName}
datasetNameDisplay=${datasets['arxiv'].datasetNameDisplay}
@semanticSearchFinished=${(e: CustomEvent<string[]>) =>
this.semanticSearchFinishedHandler(e)}
></mememo-text-viewer>
</div>
<div class="container container-prompt">Prompt</div>
<div class="container container-prompt">
<mememo-prompt-box
template=${promptTemplate[Dataset.Arxiv]}
userQuery=${this.userQuery}
.relevantDocuments=${this.relevantDocuments}
@runButtonClicked=${(e: CustomEvent<string>) => {}}
></mememo-prompt-box>
</div>
<div class="container container-model">
<div class="model-box">GPT 3.5</div>
Expand Down
135 changes: 135 additions & 0 deletions examples/rag-playground/src/components/prompt-box/prompt-box.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
.prompt-box {
width: 100%;

display: flex;
box-sizing: border-box;
flex-direction: column;
align-items: center;

padding: var(--box-padding-v) var(--box-padding-h);
gap: 5px;
}

textarea {
border: 1px solid var(--gray-300);
border-radius: 5px;
padding: 5px 5px;
width: 100%;
height: auto;
box-sizing: border-box;
font-family: inherit;
font-size: var(--font-d2);
resize: vertical;
max-height: 300px;

&:focus {
outline: 2px solid var(--focus-border-color);
border: 1px solid var(--focus-border-color);
}

&::placeholder {
color: var(--gray-600);
}
}

.header {
font-size: var(--font-u1);
color: var(--gray-600);
line-height: 1;

width: 100%;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
gap: 12px;

.text-group {
display: flex;
gap: 7px;
align-items: baseline;
overflow: hidden;
}

.text {
font-weight: 800;
white-space: nowrap;
}

.token-count {
font-size: var(--font-d2);
color: var(--gray-600);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;

&[is-oversized] {
color: var(--pink-500);
}
}
}

.svg-icon {
display: flex;
justify-content: center;
align-items: center;
width: 1em;
height: 1em;

color: currentColor;
transition: transform 80ms linear;
transform-origin: center;

& svg {
fill: currentColor;
width: 100%;
height: 100%;
}
}

.button-group {
display: flex;
flex-flow: row;
align-items: center;
gap: 8px;
}

button {
all: unset;

display: flex;
line-height: 1;
font-size: var(--font-d2);
padding: 4px 6px;
border-radius: 5px;
white-space: nowrap;
height: var(--font-d2);

cursor: pointer;
user-select: none;
-webkit-user-select: none;

background-color: color-mix(in lab, var(--gray-200), white 20%);
color: var(--gray-800);
display: flex;
flex-flow: row;
align-items: center;
font-size: var(--font-d1);

&:hover {
background-color: color-mix(in lab, var(--gray-300), white 30%);
}

&:active {
background-color: color-mix(in lab, var(--gray-300), white 20%);
}

.svg-icon {
position: relative;
top: 1px;
margin-right: 3px;
color: var(--gray-700);
width: 12px;
height: 12px;
}
}
152 changes: 152 additions & 0 deletions examples/rag-playground/src/components/prompt-box/prompt-box.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import { LitElement, css, unsafeCSS, html, PropertyValues } from 'lit';
import { customElement, property, state, query } from 'lit/decorators.js';
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
import { encode } from 'gpt-tokenizer/model/gpt-3.5-turbo';
import d3 from '../../utils/d3-import';

import componentCSS from './prompt-box.css?inline';
import searchIcon from '../../images/icon-search.svg?raw';
import expandIcon from '../../images/icon-expand.svg?raw';
import playIcon from '../../images/icon-play.svg?raw';

const numberFormatter = d3.format(',');

/**
* Prompt box element.
*
*/
@customElement('mememo-prompt-box')
export class MememoPromptBox extends LitElement {
//==========================================================================||
// Class Properties ||
//==========================================================================||
@property({ type: String })
template: string | undefined;

@property({ type: String })
userQuery: string | undefined;

@property({ attribute: false })
relevantDocuments: string[] | undefined;

@state()
prompt = '';

@state()
tokenCount = 0;

//==========================================================================||
// Lifecycle Methods ||
//==========================================================================||
constructor() {
super();
}

/**
* This method is called before new DOM is updated and rendered
* @param changedProperties Property that has been changed
*/
willUpdate(changedProperties: PropertyValues<this>) {
if (
changedProperties.has('template') ||
changedProperties.has('userQuery') ||
changedProperties.has('relevantDocuments')
) {
this.updatePrompt();
}
}

//==========================================================================||
// Custom Methods ||
//==========================================================================||
async initData() {}

/**
* Recompile the prompt using template and provided information.
*/
updatePrompt() {
if (this.template === undefined) return;

let prompt = this.template;

if (this.userQuery !== undefined) {
prompt = prompt.replace('{{user}}', this.userQuery);
}

if (this.relevantDocuments !== undefined) {
const documents = this.relevantDocuments.join('\n');
prompt = prompt.replace('{{context}}', documents);
}

this.prompt = prompt;
this.tokenCount = encode(prompt).length;
}

//==========================================================================||
// Event Handlers ||
//==========================================================================||
textareaInput(e: InputEvent) {
const textareaElement = e.currentTarget as HTMLTextAreaElement;
this.template = textareaElement.value;
}

runButtonClicked() {
// Notify the parent to run the user query
const event = new CustomEvent('runButtonClicked', {
bubbles: true,
composed: true,
detail: this.template
});
this.dispatchEvent(event);
}

//==========================================================================||
// Private Helpers ||
//==========================================================================||

//==========================================================================||
// Templates and Styles ||
//==========================================================================||
render() {
return html`
<div class="prompt-box">
<div class="header">
<div class="text-group">
<span class="text">Retrieval Augmented Prompt</span>
<span class="token-count" ?is-oversized=${this.tokenCount > 8000}
>${numberFormatter(this.tokenCount)} tokens</span
>
</div>
<div class="button-group">
<button @click=${() => this.runButtonClicked()}>
<span class="svg-icon">${unsafeHTML(playIcon)}</span>
run
</button>
<button @click=${() => this.runButtonClicked()}>
<span class="svg-icon">${unsafeHTML(expandIcon)}</span>
view
</button>
</div>
</div>
<textarea rows="5" @input=${(e: InputEvent) => this.textareaInput(e)}>
${this.prompt}</textarea
>
</div>
`;
}

static styles = [
css`
${unsafeCSS(componentCSS)}
`
];
}

declare global {
interface HTMLElementTagNameMap {
'mememo-prompt-box': MememoPromptBox;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,9 @@ textarea {
width: 100%;
display: flex;
flex-direction: row;
justify-content: space-between;
justify-content: center;
gap: 10px;
align-items: center;
gap: 12px;

.text {
font-weight: 800;
Expand Down Expand Up @@ -72,7 +71,7 @@ textarea {
display: flex;
flex-flow: row;
align-items: center;
gap: 10px;
gap: 8px;
}

button {
Expand Down
Loading

0 comments on commit 459860e

Please sign in to comment.