summaryrefslogtreecommitdiff
path: root/examples/server/public/index.html
diff options
context:
space:
mode:
Diffstat (limited to 'examples/server/public/index.html')
-rw-r--r--examples/server/public/index.html191
1 files changed, 133 insertions, 58 deletions
diff --git a/examples/server/public/index.html b/examples/server/public/index.html
index 1bf2a8b3..f539884e 100644
--- a/examples/server/public/index.html
+++ b/examples/server/public/index.html
@@ -136,6 +136,11 @@
display: block;
}
+ fieldset label.slim {
+ margin: 0 0.5em;
+ display: inline;
+ }
+
header, footer {
text-align: center;
}
@@ -145,6 +150,14 @@
color: #888;
}
+ .mode-chat textarea[name=prompt] {
+ height: 4.5em;
+ }
+
+ .mode-completion textarea[name=prompt] {
+ height: 10em;
+ }
+
@keyframes loading-bg-wipe {
0% {
@@ -187,7 +200,7 @@
template: "{{prompt}}\n\n{{history}}\n{{char}}:",
historyTemplate: "{{name}}: {{message}}",
transcript: [],
- type: "chat",
+ type: "chat", // "chat" | "completion"
char: "Llama",
user: "User",
})
@@ -365,13 +378,44 @@
return String(str).replaceAll(/\{\{(.*?)\}\}/g, (_, key) => template(settings[key]));
}
+ async function runLlama(prompt, llamaParams, char) {
+ const currentMessages = [];
+ const history = session.value.transcript;
+ if (controller.value) {
+ throw new Error("already running");
+ }
+ controller.value = new AbortController();
+ for await (const chunk of llama(prompt, llamaParams, {controller: controller.value})) {
+ const data = chunk.data;
+
+ if (data.stop) {
+ while (
+ currentMessages.length > 0 &&
+ currentMessages[currentMessages.length - 1].content.match(/\n$/) != null
+ ) {
+ currentMessages.pop();
+ }
+ transcriptUpdate([...history, [char, currentMessages]])
+ console.log("Completion finished: '", currentMessages.map(msg => msg.content).join(''), "', summary: ", data);
+ } else {
+ currentMessages.push(data);
+ transcriptUpdate([...history, [char, currentMessages]])
+ }
+
+ if (data.timings) {
+ llamaStats.value = data.timings;
+ }
+ }
+
+ controller.value = null;
+ }
+
// send message to server
const chat = async (msg) => {
if (controller.value) {
console.log('already running...');
return;
}
- controller.value = new AbortController();
transcriptUpdate([...session.value.transcript, ["{{user}}", msg]])
@@ -391,55 +435,41 @@
).join("\n"),
});
- const currentMessages = [];
- const history = session.value.transcript
-
- const llamaParams = {
+ await runLlama(prompt, {
...params.value,
stop: ["</s>", template("{{char}}:"), template("{{user}}:")],
- }
-
- for await (const chunk of llama(prompt, llamaParams, { controller: controller.value })) {
- const data = chunk.data;
+ }, "{{char}}");
+ }
- if (data.stop) {
- while (
- currentMessages.length > 0 &&
- currentMessages[currentMessages.length - 1].content.match(/\n$/) != null
- ) {
- currentMessages.pop();
- }
- transcriptUpdate([...history, ["{{char}}", currentMessages]])
- console.log("Completion finished: '", currentMessages.map(msg => msg.content).join(''), "', summary: ", data);
- } else {
- currentMessages.push(data);
- transcriptUpdate([...history, ["{{char}}", currentMessages]])
- }
+ const runCompletion = async () => {
+ if (controller.value) {
+ console.log('already running...');
+ return;
+ }
+ const {prompt} = session.value;
+ transcriptUpdate([...session.value.transcript, ["", prompt]]);
+ await runLlama(prompt, {
+ ...params.value,
+ stop: [],
+ }, "");
+ }
- if (data.timings) {
- llamaStats.value = data.timings;
- }
+ const stop = (e) => {
+ e.preventDefault();
+ if (controller.value) {
+ controller.value.abort();
+ controller.value = null;
}
+ }
- controller.value = null;
+ const reset = (e) => {
+ stop(e);
+ transcriptUpdate([]);
}
function MessageInput() {
const message = useSignal("")
- const stop = (e) => {
- e.preventDefault();
- if (controller.value) {
- controller.value.abort();
- controller.value = null;
- }
- }
-
- const reset = (e) => {
- stop(e);
- transcriptUpdate([]);
- }
-
const submit = (e) => {
stop(e);
chat(message.value);
@@ -474,6 +504,19 @@
`
}
+ function CompletionControls() {
+ const submit = (e) => {
+ stop(e);
+ runCompletion();
+ }
+ return html`
+ <div>
+ <button onclick=${submit} type="button" disabled=${generating.value}>Start</button>
+ <button onclick=${stop} disabled=${!generating.value}>Stop</button>
+ <button onclick=${reset}>Reset</button>
+ </div>`;
+ }
+
const ChatLog = (props) => {
const messages = session.value.transcript;
const container = useRef(null)
@@ -497,7 +540,11 @@
data;
message = html`<${Markdownish} text=${template(text)} />`
}
- return html`<p key=${index}><strong>${template(user)}:</strong> ${message}</p>`
+ if(user) {
+ return html`<p key=${index}><strong>${template(user)}:</strong> ${message}</p>`
+ } else {
+ return html`<p key=${index}>${message}</p>`
+ }
};
return html`
@@ -574,18 +621,31 @@
userTemplateAutosave()
}, [session.value, params.value])
- return html`
- <form>
- <fieldset>
- <${UserTemplateResetButton}/>
- </fieldset>
+ const GrammarControl = () => (
+ html`
+ <div>
+ <label for="template">Grammar</label>
+ <textarea id="grammar" name="grammar" placeholder="Use gbnf or JSON Schema+convert" value="${params.value.grammar}" rows=4 oninput=${updateParams}/>
+ <input type="text" name="prop-order" placeholder="order: prop1,prop2,prop3" oninput=${updateGrammarJsonSchemaPropOrder} />
+ <button type="button" onclick=${convertJSONSchemaGrammar}>Convert JSON Schema</button>
+ </div>
+ `
+ );
- <fieldset>
- <div>
- <label for="prompt">Prompt</label>
- <textarea type="text" name="prompt" value="${session.value.prompt}" rows=4 oninput=${updateSession}/>
- </div>
- </fieldset>
+ const PromptControlFieldSet = () => (
+ html`
+ <fieldset>
+ <div>
+ <label htmlFor="prompt">Prompt</label>
+ <textarea type="text" name="prompt" value="${session.value.prompt}" oninput=${updateSession}/>
+ </div>
+ </fieldset>
+ `
+ );
+
+ const ChatConfigForm = () => (
+ html`
+ ${PromptControlFieldSet()}
<fieldset class="two">
<div>
@@ -609,15 +669,30 @@
<label for="template">Chat history template</label>
<textarea id="template" name="historyTemplate" value="${session.value.historyTemplate}" rows=1 oninput=${updateSession}/>
</div>
+ ${GrammarControl()}
+ </fieldset>
+ `
+ );
+
+ const CompletionConfigForm = () => (
+ html`
+ ${PromptControlFieldSet()}
+ <fieldset>${GrammarControl()}</fieldset>
+ `
+ );
+ return html`
+ <form>
+ <fieldset class="two">
+ <${UserTemplateResetButton}/>
<div>
- <label for="template">Grammar</label>
- <textarea id="grammar" name="grammar" placeholder="Use gbnf or JSON Schema+convert" value="${params.value.grammar}" rows=4 oninput=${updateParams}/>
- <input type="text" name="prop-order" placeholder="order: prop1,prop2,prop3" oninput=${updateGrammarJsonSchemaPropOrder} />
- <button type="button" onclick=${convertJSONSchemaGrammar}>Convert JSON Schema</button>
+ <label class="slim"><input type="radio" name="type" value="chat" checked=${session.value.type === "chat"} oninput=${updateSession} /> Chat</label>
+ <label class="slim"><input type="radio" name="type" value="completion" checked=${session.value.type === "completion"} oninput=${updateSession} /> Completion</label>
</div>
</fieldset>
+ ${session.value.type === 'chat' ? ChatConfigForm() : CompletionConfigForm()}
+
<fieldset class="two">
${IntField({label: "Predictions", max: 2048, min: -1, name: "n_predict", value: params.value.n_predict})}
${FloatField({label: "Temperature", max: 1.5, min: 0.0, name: "temperature", step: 0.01, value: params.value.temperature})}
@@ -851,7 +926,7 @@
function App(props) {
return html`
- <div>
+ <div class="mode-${session.value.type}">
<header>
<h1>llama.cpp</h1>
</header>
@@ -861,7 +936,7 @@
</main>
<section id="write">
- <${MessageInput} />
+ <${session.value.type === 'chat' ? MessageInput : CompletionControls} />
</section>
<footer>