@@ -264,9 +268,13 @@
Settings
import { createApp, defineComponent, shallowRef, computed, h } from './deps_vue.esm-browser.js';
import { llama } from './completion.js';
+ // utility functions
const isString = (x) => !!x.toLowerCase;
const isNumeric = (n) => !isString(n) && !isNaN(n);
+ const escapeAttr = (str) => str.replace(/>/g, '>').replace(/"/g, '"');
+ const copyStr = (str) => navigator.clipboard.writeText(str);
+ // constants
const BASE_URL = localStorage.getItem('base') // for debugging
|| (new URL('.', document.baseURI).href).toString(); // for production
const CONFIG_DEFAULT = {
@@ -295,7 +303,7 @@
Settings
custom: '', // custom json-stringified object
};
const CONFIG_INFO = {
- apiKey: '',
+ apiKey: 'Set the API Key if you are using --api-key option for the server.',
systemMessage: 'The starting message that defines how model should behave.',
temperature: 'Controls the randomness of the generated text by affecting the probability distribution of the output tokens. Higher = more random, lower = more focused.',
dynatemp_range: 'Addon for the temperature sampler. The added value to the range of dynamic temperature, which adjusts probabilities by entropy of tokens.',
@@ -325,19 +333,28 @@
Settings
// markdown support
const VueMarkdown = defineComponent(
(props) => {
- const md = shallowRef(new markdownit(props.options ?? { breaks: true }));
- for (const plugin of props.plugins ?? []) {
- md.value.use(plugin);
- }
+ const md = shallowRef(new markdownit({ breaks: true }));
+ const origFenchRenderer = md.value.renderer.rules.fence;
+ md.value.renderer.rules.fence = (tokens, idx, ...args) => {
+ const content = tokens[idx].content;
+ const origRendered = origFenchRenderer(tokens, idx, ...args);
+ return `
+
+
+
+ ${origRendered}
+
`;
+ };
+ window.copyStr = copyStr;
const content = computed(() => md.value.render(props.source));
return () => h("div", { innerHTML: content.value });
},
- { props: ["source", "options", "plugins"] }
+ { props: ["source"] }
);
// inout field to be used by settings modal
- const SettingsModalNumericInput = defineComponent({
- template: document.getElementById('settings-modal-numeric-input').innerHTML,
+ const SettingsModalShortInput = defineComponent({
+ template: document.getElementById('settings-modal-short-input').innerHTML,
props: ['configKey', 'configDefault', 'configInfo', 'modelValue'],
});
@@ -390,7 +407,11 @@
Settings
if (!conv) return;
const msg = conv.messages.pop();
conv.lastModified = Date.now();
- localStorage.setItem(convId, JSON.stringify(conv));
+ if (conv.messages.length === 0) {
+ StorageUtils.remove(convId);
+ } else {
+ localStorage.setItem(convId, JSON.stringify(conv));
+ }
return msg;
},
@@ -431,7 +452,7 @@
Settings
const mainApp = createApp({
components: {
VueMarkdown,
- SettingsModalNumericInput,
+ SettingsModalShortInput,
},
data() {
return {
@@ -587,6 +608,7 @@
Settings
this.isGenerating = false;
this.stopGeneration = () => {};
this.fetchMessages();
+ chatScrollToBottom();
},
// message actions
@@ -600,7 +622,7 @@
Settings
this.generateMessage(currConvId);
},
copyMsg(msg) {
- navigator.clipboard.writeText(msg.content);
+ copyStr(msg.content);
},
editUserMsgAndRegenerate(msg) {
if (this.isGenerating) return;
diff --git a/examples/server/server.cpp b/examples/server/server.cpp
index a6d3a1c9545cb..9480423acf1e8 100644
--- a/examples/server/server.cpp
+++ b/examples/server/server.cpp
@@ -102,6 +102,12 @@ struct server_task_result {
bool error;
};
+struct server_static_file {
+ const unsigned char * data;
+ unsigned int size;
+ const char * mime_type;
+};
+
struct slot_params {
bool stream = true;
bool cache_prompt = false; // remember the prompt to avoid reprocessing all prompt
@@ -2254,6 +2260,16 @@ int main(int argc, char ** argv) {
LOG_INF("%s\n", common_params_get_system_info(params).c_str());
LOG_INF("\n");
+ // static files
+ std::map
static_files = {
+ { "/", { index_html, index_html_len, "text/html; charset=utf-8" }},
+ { "/completion.js", { completion_js, completion_js_len, "text/javascript; charset=utf-8" }},
+ { "/deps_daisyui.min.css", { deps_daisyui_min_css, deps_daisyui_min_css_len, "text/css; charset=utf-8" }},
+ { "/deps_markdown-it.js", { deps_markdown_it_js, deps_markdown_it_js_len, "text/javascript; charset=utf-8" }},
+ { "/deps_tailwindcss.js", { deps_tailwindcss_js, deps_tailwindcss_js_len, "text/javascript; charset=utf-8" }},
+ { "/deps_vue.esm-browser.js", { deps_vue_esm_browser_js, deps_vue_esm_browser_js_len, "text/javascript; charset=utf-8" }},
+ };
+
std::unique_ptr svr;
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
if (params.ssl_file_key != "" && params.ssl_file_cert != "") {
@@ -2334,7 +2350,7 @@ int main(int argc, char ** argv) {
// Middlewares
//
- auto middleware_validate_api_key = [¶ms, &res_error](const httplib::Request & req, httplib::Response & res) {
+ auto middleware_validate_api_key = [¶ms, &res_error, &static_files](const httplib::Request & req, httplib::Response & res) {
static const std::unordered_set public_endpoints = {
"/health",
"/models",
@@ -2346,8 +2362,8 @@ int main(int argc, char ** argv) {
return true;
}
- // If path is public, skip validation
- if (public_endpoints.find(req.path) != public_endpoints.end()) {
+ // If path is public or is static file, skip validation
+ if (public_endpoints.find(req.path) != public_endpoints.end() || static_files.find(req.path) != static_files.end()) {
return true;
}
@@ -3091,13 +3107,6 @@ int main(int argc, char ** argv) {
res.status = 200; // HTTP OK
};
- auto handle_static_file = [](unsigned char * content, size_t len, const char * mime_type) {
- return [content, len, mime_type](const httplib::Request &, httplib::Response & res) {
- res.set_content(reinterpret_cast(content), len, mime_type);
- return false;
- };
- };
-
//
// Router
//
@@ -3112,12 +3121,13 @@ int main(int argc, char ** argv) {
}
} else {
// using embedded static files
- svr->Get("/", handle_static_file(index_html, index_html_len, "text/html; charset=utf-8"));
- svr->Get("/completion.js", handle_static_file(completion_js, completion_js_len, "text/javascript; charset=utf-8"));
- svr->Get("/deps_daisyui.min.css", handle_static_file(deps_daisyui_min_css, deps_daisyui_min_css_len, "text/css; charset=utf-8"));
- svr->Get("/deps_markdown-it.js", handle_static_file(deps_markdown_it_js, deps_markdown_it_js_len, "text/javascript; charset=utf-8"));
- svr->Get("/deps_tailwindcss.js", handle_static_file(deps_tailwindcss_js, deps_tailwindcss_js_len, "text/javascript; charset=utf-8"));
- svr->Get("/deps_vue.esm-browser.js", handle_static_file(deps_vue_esm_browser_js, deps_vue_esm_browser_js_len, "text/javascript; charset=utf-8"));
+ for (const auto & it : static_files) {
+ const server_static_file & static_file = it.second;
+ svr->Get(it.first.c_str(), [&static_file](const httplib::Request &, httplib::Response & res) {
+ res.set_content(reinterpret_cast(static_file.data), static_file.size, static_file.mime_type);
+ return false;
+ });
+ }
}
// register API routes