ui: rebase and resolve conflict
This commit is contained in:
parent
0e18b2e7d0
commit
8cf2f35223
1 changed files with 289 additions and 192 deletions
|
@ -10,6 +10,7 @@
|
||||||
body {
|
body {
|
||||||
font-family: system-ui;
|
font-family: system-ui;
|
||||||
font-size: 90%;
|
font-size: 90%;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#container {
|
#container {
|
||||||
|
@ -18,6 +19,7 @@
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
main {
|
main {
|
||||||
|
@ -29,18 +31,15 @@
|
||||||
|
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
border-radius: 5px;
|
|
||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
max-width: 600px;
|
|
||||||
min-width: 300px;
|
min-width: 300px;
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 0 0.5em;
|
padding: 0 0.5em;
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
|
@ -142,6 +141,81 @@
|
||||||
display: inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header_controls {
|
||||||
|
gap: 0.5rem;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flexform {
|
||||||
|
display: flex;
|
||||||
|
max-height: 100%;
|
||||||
|
height: 100%;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column {
|
||||||
|
flex-grow: 1;
|
||||||
|
padding: 1rem;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aside {
|
||||||
|
max-width: 300px;
|
||||||
|
overflow: auto;
|
||||||
|
background: rgba(220, 220, 220, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width:600px) {
|
||||||
|
.aside {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.range_field {
|
||||||
|
border-bottom: 1px dashed;
|
||||||
|
padding-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.range_field:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.range_field label {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.range_field input {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.basecontainer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
#content {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.response p {
|
||||||
|
padding: 0.5em;
|
||||||
|
margin: 0;
|
||||||
|
border-radius: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.response p:nth-child(even) {
|
||||||
|
background-color: rgba(242, 242, 242, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
header,
|
header,
|
||||||
footer {
|
footer {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
@ -150,8 +224,18 @@
|
||||||
footer {
|
footer {
|
||||||
font-size: 80%;
|
font-size: 80%;
|
||||||
color: #888;
|
color: #888;
|
||||||
|
box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(229, 231, 235, 0.53) 0px -1px 0px 0px, rgba(0, 0, 0, 0.24) 0px 5px 20px -5px;
|
||||||
|
padding-top: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@media (max-width:600px) {
|
||||||
|
.footernote {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.mode-chat textarea[name=prompt] {
|
.mode-chat textarea[name=prompt] {
|
||||||
height: 4.5em;
|
height: 4.5em;
|
||||||
}
|
}
|
||||||
|
@ -537,26 +621,26 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<form onsubmit=${submit}>
|
<form onsubmit=${submit}>
|
||||||
<div>
|
<div>
|
||||||
<textarea
|
<textarea
|
||||||
className=${generating.value ? "loading" : null}
|
className=${generating.value ? "loading" : null}
|
||||||
oninput=${(e) => message.value = e.target.value}
|
oninput=${(e) => message.value = e.target.value}
|
||||||
onkeypress=${enterSubmits}
|
onkeypress=${enterSubmits}
|
||||||
placeholder="Say something..."
|
placeholder="Say something..."
|
||||||
rows=2
|
rows=2
|
||||||
type="text"
|
type="text"
|
||||||
value="${message}"
|
value="${message}"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<button type="submit" disabled=${generating.value}>Send</button>
|
<button type="submit" disabled=${generating.value}>Send</button>
|
||||||
<button onclick=${uploadImage}>Upload Image</button>
|
<button onclick=${uploadImage}>Upload Image</button>
|
||||||
<button onclick=${stop} disabled=${!generating.value}>Stop</button>
|
<button onclick=${stop} disabled=${!generating.value}>Stop</button>
|
||||||
<button onclick=${reset}>Reset</button>
|
<button onclick=${reset}>Reset</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
function CompletionControls() {
|
function CompletionControls() {
|
||||||
|
@ -565,11 +649,11 @@
|
||||||
runCompletion();
|
runCompletion();
|
||||||
}
|
}
|
||||||
return html`
|
return html`
|
||||||
<div>
|
<div>
|
||||||
<button onclick=${submit} type="button" disabled=${generating.value}>Start</button>
|
<button onclick=${submit} type="button" disabled=${generating.value}>Start</button>
|
||||||
<button onclick=${stop} disabled=${!generating.value}>Stop</button>
|
<button onclick=${stop} disabled=${!generating.value}>Stop</button>
|
||||||
<button onclick=${reset}>Reset</button>
|
<button onclick=${reset}>Reset</button>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ChatLog = (props) => {
|
const ChatLog = (props) => {
|
||||||
|
@ -613,12 +697,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div id="chat" ref=${container} key=${messages.length}>
|
<div id="chat" ref=${container} key=${messages.length}>
|
||||||
<img style="width: 60%;${!session.value.image_selected ? `display: none;` : ``}" src="${session.value.image_selected}"/>
|
<img style="width: 60%;${!session.value.image_selected ? `display: none;` : ``}" src="${session.value.image_selected}"/>
|
||||||
<span contenteditable=${isCompletionMode} ref=${container} oninput=${handleCompletionEdit}>
|
<span class="response" contenteditable=${isCompletionMode} ref=${container} oninput=${handleCompletionEdit}>
|
||||||
${messages.flatMap(chatLine)}
|
${messages.flatMap(chatLine)}
|
||||||
</span>
|
</span>
|
||||||
</div>`;
|
</div>`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ConfigForm = (props) => {
|
const ConfigForm = (props) => {
|
||||||
|
@ -649,22 +733,20 @@
|
||||||
|
|
||||||
const FloatField = ({ label, max, min, name, step, value }) => {
|
const FloatField = ({ label, max, min, name, step, value }) => {
|
||||||
return html`
|
return html`
|
||||||
<div>
|
<div class="range_field">
|
||||||
<label for="${name}">${label}</label>
|
<label for="${name}">${label} <span>${value}</span></label>
|
||||||
<input type="range" id="${name}" min="${min}" max="${max}" step="${step}" name="${name}" value="${value}" oninput=${updateParamsFloat} />
|
<input type="range" id="${name}" min="${min}" max="${max}" step="${step}" name="${name}" value="${value}" oninput=${updateParamsFloat} />
|
||||||
<span>${value}</span>
|
</div>
|
||||||
</div>
|
`
|
||||||
`
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const IntField = ({ label, max, min, name, value }) => {
|
const IntField = ({ label, max, min, name, value }) => {
|
||||||
return html`
|
return html`
|
||||||
<div>
|
<div class="range_field">
|
||||||
<label for="${name}">${label}</label>
|
<label for="${name}">${label} <span>${value}</span></label>
|
||||||
<input type="range" id="${name}" min="${min}" max="${max}" name="${name}" value="${value}" oninput=${updateParamsInt} />
|
<input type="range" id="${name}" min="${min}" max="${max}" name="${name}" value="${value}" oninput=${updateParamsInt} />
|
||||||
<span>${value}</span>
|
</div>
|
||||||
</div>
|
`
|
||||||
`
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const userTemplateReset = (e) => {
|
const userTemplateReset = (e) => {
|
||||||
|
@ -675,129 +757,145 @@
|
||||||
const UserTemplateResetButton = () => {
|
const UserTemplateResetButton = () => {
|
||||||
if (selectedUserTemplate.value.name == 'default') {
|
if (selectedUserTemplate.value.name == 'default') {
|
||||||
return html`
|
return html`
|
||||||
<button disabled>Using default template</button>
|
<button disabled>Using default template</button>
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<button onclick=${userTemplateReset}>Reset all to default</button>
|
<button onclick=${userTemplateReset}>Reset all to default</button>
|
||||||
`
|
`
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// autosave template on every change
|
// autosave template on every change
|
||||||
userTemplateAutosave()
|
userTemplateAutosave()
|
||||||
}, [session.value, params.value])
|
}, [session.value])// removed params.value as it would re render the page.
|
||||||
|
|
||||||
const GrammarControl = () => (
|
const GrammarControl = () => (
|
||||||
html`
|
html`
|
||||||
<div>
|
<details>
|
||||||
<label for="template">Grammar</label>
|
<summary>Grammer Configuration</summary>
|
||||||
<textarea id="grammar" name="grammar" placeholder="Use gbnf or JSON Schema+convert" value="${params.value.grammar}" rows=4 oninput=${updateParams}/>
|
<label for="template">Grammar</label>
|
||||||
<input type="text" name="prop-order" placeholder="order: prop1,prop2,prop3" oninput=${updateGrammarJsonSchemaPropOrder} />
|
<textarea id="grammar" name="grammar" placeholder="Use gbnf or JSON Schema+convert" value="${params.value.grammar}" rows=4 oninput=${updateParams}/>
|
||||||
<button type="button" onclick=${convertJSONSchemaGrammar}>Convert JSON Schema</button>
|
<input type="text" name="prop-order" placeholder="order: prop1,prop2,prop3" oninput=${updateGrammarJsonSchemaPropOrder} />
|
||||||
</div>
|
<button type="button" onclick=${convertJSONSchemaGrammar}>Convert JSON Schema</button>
|
||||||
`
|
</details>
|
||||||
|
`
|
||||||
);
|
);
|
||||||
|
|
||||||
const PromptControlFieldSet = () => (
|
const PromptControlFieldSet = () => (
|
||||||
html`
|
html`
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="prompt">Prompt</label>
|
<label htmlFor="prompt">Prompt</label>
|
||||||
<textarea type="text" name="prompt" value="${session.value.prompt}" oninput=${updateSession}/>
|
<textarea type="text" name="prompt" value="${session.value.prompt}" oninput=${updateSession}/>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
`
|
`
|
||||||
);
|
);
|
||||||
|
|
||||||
const ChatConfigForm = () => (
|
const ChatConfigForm = () => (
|
||||||
html`
|
html`
|
||||||
${PromptControlFieldSet()}
|
${PromptControlFieldSet()}
|
||||||
|
|
||||||
<fieldset class="two">
|
<fieldset class="two">
|
||||||
<div>
|
<div>
|
||||||
<label for="user">User name</label>
|
<label for="user">User name</label>
|
||||||
<input type="text" name="user" value="${session.value.user}" oninput=${updateSession} />
|
<input type="text" name="user" value="${session.value.user}" oninput=${updateSession} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label for="bot">Bot name</label>
|
<label for="bot">Bot name</label>
|
||||||
<input type="text" name="char" value="${session.value.char}" oninput=${updateSession} />
|
<input type="text" name="char" value="${session.value.char}" oninput=${updateSession} />
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<div>
|
<div>
|
||||||
<label for="template">Prompt template</label>
|
<label for="template">Prompt template</label>
|
||||||
<textarea id="template" name="template" value="${session.value.template}" rows=4 oninput=${updateSession}/>
|
<textarea id="template" name="template" value="${session.value.template}" rows=4 oninput=${updateSession}/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label for="template">Chat history template</label>
|
<label for="template">Chat history template</label>
|
||||||
<textarea id="template" name="historyTemplate" value="${session.value.historyTemplate}" rows=1 oninput=${updateSession}/>
|
<textarea id="template" name="historyTemplate" value="${session.value.historyTemplate}" rows=1 oninput=${updateSession}/>
|
||||||
</div>
|
</div>
|
||||||
${GrammarControl()}
|
</fieldset>
|
||||||
</fieldset>
|
`
|
||||||
`
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const CompletionConfigForm = () => (
|
const CompletionConfigForm = () => (
|
||||||
html`
|
html`
|
||||||
${PromptControlFieldSet()}
|
${PromptControlFieldSet()}
|
||||||
<fieldset>${GrammarControl()}</fieldset>
|
`
|
||||||
`
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return html`
|
|
||||||
<form>
|
|
||||||
<fieldset class="two">
|
|
||||||
<${UserTemplateResetButton}/>
|
|
||||||
<div>
|
|
||||||
<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()}
|
const ModelOptions = () => (
|
||||||
|
html`
|
||||||
|
|
||||||
<fieldset class="two">
|
<details>
|
||||||
${IntField({ label: "Predictions", max: 2048, min: -1, name: "n_predict", value: params.value.n_predict })}
|
<summary>Settings</summary>
|
||||||
${FloatField({ label: "Temperature", max: 2.0, min: 0.0, name: "temperature", step: 0.01, value: params.value.temperature })}
|
<fieldset>
|
||||||
${FloatField({ label: "Penalize repeat sequence", max: 2.0, min: 0.0, name: "repeat_penalty", step: 0.01, value: params.value.repeat_penalty })}
|
${IntField({ label: "Predictions", max: 2048, min: -1, name: "n_predict", value: params.value.n_predict })}
|
||||||
${IntField({ label: "Consider N tokens for penalize", max: 2048, min: 0, name: "repeat_last_n", value: params.value.repeat_last_n })}
|
${FloatField({ label: "Temperature", max: 2.0, min: 0.0, name: "temperature", step: 0.01, value: params.value.temperature })}
|
||||||
${IntField({ label: "Top-K sampling", max: 100, min: -1, name: "top_k", value: params.value.top_k })}
|
${FloatField({ label: "Penalize repeat sequence", max: 2.0, min: 0.0, name: "repeat_penalty", step: 0.01, value: params.value.repeat_penalty })}
|
||||||
${FloatField({ label: "Top-P sampling", max: 1.0, min: 0.0, name: "top_p", step: 0.01, value: params.value.top_p })}
|
${IntField({ label: "Consider N tokens for penalize", max: 2048, min: 0, name: "repeat_last_n", value: params.value.repeat_last_n })}
|
||||||
${FloatField({ label: "Min-P sampling", max: 1.0, min: 0.0, name: "min_p", step: 0.01, value: params.value.min_p })}
|
${IntField({ label: "Top-K sampling", max: 100, min: -1, name: "top_k", value: params.value.top_k })}
|
||||||
</fieldset>
|
${FloatField({ label: "Top-P sampling", max: 1.0, min: 0.0, name: "top_p", step: 0.01, value: params.value.top_p })}
|
||||||
<details>
|
${FloatField({ label: "Min-P sampling", max: 1.0, min: 0.0, name: "min_p", step: 0.01, value: params.value.min_p })}
|
||||||
|
${IntField({ label: "Show Probabilities", max: 10, min: 0, name: "n_probs", value: params.value.n_probs })}
|
||||||
|
</fieldset>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
${GrammarControl()}
|
||||||
|
<details>
|
||||||
<summary>More options</summary>
|
<summary>More options</summary>
|
||||||
<fieldset class="two">
|
|
||||||
${FloatField({ label: "TFS-Z", max: 1.0, min: 0.0, name: "tfs_z", step: 0.01, value: params.value.tfs_z })}
|
|
||||||
${FloatField({ label: "Typical P", max: 1.0, min: 0.0, name: "typical_p", step: 0.01, value: params.value.typical_p })}
|
|
||||||
${FloatField({ label: "Presence penalty", max: 1.0, min: 0.0, name: "presence_penalty", step: 0.01, value: params.value.presence_penalty })}
|
|
||||||
${FloatField({ label: "Frequency penalty", max: 1.0, min: 0.0, name: "frequency_penalty", step: 0.01, value: params.value.frequency_penalty })}
|
|
||||||
</fieldset>
|
|
||||||
<hr />
|
|
||||||
<fieldset class="three">
|
|
||||||
<div>
|
|
||||||
<label><input type="radio" name="mirostat" value="0" checked=${params.value.mirostat == 0} oninput=${updateParamsInt} /> no Mirostat</label>
|
|
||||||
<label><input type="radio" name="mirostat" value="1" checked=${params.value.mirostat == 1} oninput=${updateParamsInt} /> Mirostat v1</label>
|
|
||||||
<label><input type="radio" name="mirostat" value="2" checked=${params.value.mirostat == 2} oninput=${updateParamsInt} /> Mirostat v2</label>
|
|
||||||
</div>
|
|
||||||
${FloatField({ label: "Mirostat tau", max: 10.0, min: 0.0, name: "mirostat_tau", step: 0.01, value: params.value.mirostat_tau })}
|
|
||||||
${FloatField({ label: "Mirostat eta", max: 1.0, min: 0.0, name: "mirostat_eta", step: 0.01, value: params.value.mirostat_eta })}
|
|
||||||
</fieldset>
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
${IntField({ label: "Show Probabilities", max: 10, min: 0, name: "n_probs", value: params.value.n_probs })}
|
${FloatField({ label: "TFS-Z", max: 1.0, min: 0.0, name: "tfs_z", step: 0.01, value: params.value.tfs_z })}
|
||||||
|
${FloatField({ label: "Typical P", max: 1.0, min: 0.0, name: "typical_p", step: 0.01, value: params.value.typical_p })}
|
||||||
|
${FloatField({ label: "Presence penalty", max: 1.0, min: 0.0, name: "presence_penalty", step: 0.01, value: params.value.presence_penalty })}
|
||||||
|
${FloatField({ label: "Frequency penalty", max: 1.0, min: 0.0, name: "frequency_penalty", step: 0.01, value: params.value.frequency_penalty })}
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
</details>
|
||||||
<label for="api_key">API Key</label>
|
<details>
|
||||||
<input type="text" name="api_key" value="${params.value.api_key}" placeholder="Enter API key" oninput=${updateParams} />
|
<summary>Mirostat</summary>
|
||||||
</fieldset>
|
<fieldset>
|
||||||
</details>
|
<div>
|
||||||
</form>
|
<label><input type="radio" name="mirostat" value="0" checked=${params.value.mirostat == 0} oninput=${updateParamsInt} /> no Mirostat</label>
|
||||||
|
<label><input type="radio" name="mirostat" value="1" checked=${params.value.mirostat == 1} oninput=${updateParamsInt} /> Mirostat v1</label>
|
||||||
|
<label><input type="radio" name="mirostat" value="2" checked=${params.value.mirostat == 2} oninput=${updateParamsInt} /> Mirostat v2</label>
|
||||||
|
</div>
|
||||||
|
${FloatField({ label: "Mirostat tau", max: 10.0, min: 0.0, name: "mirostat_tau", step: 0.01, value: params.value.mirostat_tau })}
|
||||||
|
${FloatField({ label: "Mirostat eta", max: 1.0, min: 0.0, name: "mirostat_eta", step: 0.01, value: params.value.mirostat_eta })}
|
||||||
|
</fieldset>
|
||||||
|
</details>
|
||||||
`
|
`
|
||||||
|
);
|
||||||
|
|
||||||
|
const ModeSelector = () => (
|
||||||
|
html`
|
||||||
|
<div class="header_controls">
|
||||||
|
<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>
|
||||||
|
<${UserTemplateResetButton}/>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
)
|
||||||
|
|
||||||
|
if (props?.header)
|
||||||
|
return html`<${ModeSelector} />`
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<form class="flexform">
|
||||||
|
<div class="column">
|
||||||
|
${session.value.type === 'chat' ? ChatConfigForm() : CompletionConfigForm()}
|
||||||
|
</div>
|
||||||
|
<div class="column aside">
|
||||||
|
<${ModelOptions} />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
const probColor = (p) => {
|
const probColor = (p) => {
|
||||||
|
@ -830,30 +928,30 @@
|
||||||
const pColor = found ? probColor(found.prob) : 'transparent'
|
const pColor = found ? probColor(found.prob) : 'transparent'
|
||||||
|
|
||||||
const popoverChildren = html`
|
const popoverChildren = html`
|
||||||
<div class="prob-set">
|
<div class="prob-set">
|
||||||
${probs.map((p, index) => {
|
${probs.map((p, index) => {
|
||||||
return html`
|
return html`
|
||||||
<div
|
<div
|
||||||
key=${index}
|
key=${index}
|
||||||
title=${`prob: ${p.prob}`}
|
title=${`prob: ${p.prob}`}
|
||||||
style=${{
|
style=${{
|
||||||
padding: '0.3em',
|
padding: '0.3em',
|
||||||
backgroundColor: p.tok_str === content ? probColor(p.prob) : 'transparent'
|
backgroundColor: p.tok_str === content ? probColor(p.prob) : 'transparent'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span>${p.tok_str}: </span>
|
<span>${p.tok_str}: </span>
|
||||||
<span>${Math.floor(p.prob * 100)}%</span>
|
<span>${Math.floor(p.prob * 100)}%</span>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<${Popover} style=${{ backgroundColor: pColor }} popoverChildren=${popoverChildren}>
|
<${Popover} style=${{ backgroundColor: pColor }} popoverChildren=${popoverChildren}>
|
||||||
${msg.content.match(/\n/gim) ? html`<br />` : msg.content}
|
${msg.content.match(/\n/gim) ? html`<br />` : msg.content}
|
||||||
</>
|
</>
|
||||||
`
|
`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -879,10 +977,10 @@
|
||||||
return html`<span/>`
|
return html`<span/>`
|
||||||
}
|
}
|
||||||
return html`
|
return html`
|
||||||
<span>
|
<span>
|
||||||
${llamaStats.value.predicted_per_token_ms.toFixed()}ms per token, ${llamaStats.value.predicted_per_second.toFixed(2)} tokens per second
|
${llamaStats.value.predicted_per_token_ms.toFixed()}ms per token, ${llamaStats.value.predicted_per_second.toFixed(2)} tokens per second |
|
||||||
</span>
|
</span>
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
// simple popover impl
|
// simple popover impl
|
||||||
|
@ -917,22 +1015,22 @@
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<span style=${props.style} ref=${buttonRef} onClick=${togglePopover}>${props.children}</span>
|
<span style=${props.style} ref=${buttonRef} onClick=${togglePopover}>${props.children}</span>
|
||||||
${isOpen.value && html`
|
${isOpen.value && html`
|
||||||
<${Portal} into="#portal">
|
<${Portal} into="#portal">
|
||||||
<div
|
<div
|
||||||
ref=${popoverRef}
|
ref=${popoverRef}
|
||||||
class="popover-content"
|
class="popover-content"
|
||||||
style=${{
|
style=${{
|
||||||
top: position.value.top,
|
top: position.value.top,
|
||||||
left: position.value.left,
|
left: position.value.left,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
${props.popoverChildren}
|
${props.popoverChildren}
|
||||||
</div>
|
</div>
|
||||||
</${Portal}>
|
</${Portal}>
|
||||||
`}
|
`}
|
||||||
`;
|
`;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Source: preact-portal (https://github.com/developit/preact-portal/blob/master/src/preact-portal.js)
|
// Source: preact-portal (https://github.com/developit/preact-portal/blob/master/src/preact-portal.js)
|
||||||
|
@ -975,10 +1073,10 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
this.remote = render(html`
|
this.remote = render(html`
|
||||||
<${PortalProxy} context=${this.context}>
|
<${PortalProxy} context=${this.context}>
|
||||||
${show && this.props.children || null}
|
${show && this.props.children || null}
|
||||||
</${PortalProxy}>
|
</${PortalProxy}>
|
||||||
`, this.into, this.remote);
|
`, this.into, this.remote);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -999,29 +1097,29 @@
|
||||||
function App(props) {
|
function App(props) {
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div class="mode-${session.value.type}">
|
<div class="basecontainer mode-${session.value.type}">
|
||||||
<header>
|
<header>
|
||||||
<h1>llama.cpp</h1>
|
<h1>llama.cpp</h1>
|
||||||
</header>
|
<${ConfigForm} header/>
|
||||||
|
</header>
|
||||||
|
|
||||||
<main id="content">
|
<main id="content">
|
||||||
<${chatStarted.value ? ChatLog : ConfigForm} />
|
<${chatStarted.value ? ChatLog : ConfigForm} />
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<section id="write">
|
<footer>
|
||||||
<${session.value.type === 'chat' ? MessageInput : CompletionControls} />
|
<section id="write">
|
||||||
</section>
|
<${session.value.type === 'chat' ? MessageInput : CompletionControls} />
|
||||||
|
</section>
|
||||||
<footer>
|
<p><${ModelGenerationInfo} /> <span class="footernote">Powered by <a href="https://github.com/ggerganov/llama.cpp">llama.cpp</a> and <a href="https://ggml.ai">ggml.ai</a></span></p>
|
||||||
<p><${ModelGenerationInfo} /></p>
|
</footer>
|
||||||
<p>Powered by <a href="https://github.com/ggerganov/llama.cpp">llama.cpp</a> and <a href="https://ggml.ai">ggml.ai</a>.</p>
|
</div>
|
||||||
</footer>
|
`;
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render(h(App), document.querySelector('#container'));
|
render(h(App), document.querySelector('#container'));
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
@ -1031,5 +1129,4 @@
|
||||||
<div id="portal"></div>
|
<div id="portal"></div>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue