Merge 89d4bf86c7dd33d0c4bd39a9e49e7a3fe1d604e0 into d7eb05b9361febead29a74e71ddffc2ebeff5302

This commit is contained in:
Jens Rapp 2024-11-14 13:55:41 +08:00 committed by GitHub
commit 1e670eafff
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 255 additions and 0 deletions

View File

@ -0,0 +1,62 @@
# a really really simple web client
This is a web Client with almost NO features but a small starting point for
people who want to try for themselves.
It utilizes a simple XmlHttpRequest and prints the output to screen.
I also implemented the use of marked for highlighting the chat.
Since there is no on-the-fly-reception, getting an answer may take a while...
# usage
## using it locally
if you just want to try, run firefox in your command line like this:
```
$ firefox file:///path/to/ollama/examples/simple-webclient/webcli.html?host=your_hostname
```
This opens your browser (eg firefox) and in this case, directly sets ollama host to
_http://your_hostname:11434_.
Default host is either the host where the script runs or just `localhost`.
For more configuration, see `Configuring`
## using behind nginx
The most comfortable way I found was using the cli on nginx.
! This is only an example. You should use a dedicated site in nginx !
Therefore, I just copied webcli.html to /var/www/html/.
To make it run, you might need to edit the location in `/etc/nginx/sites-available/default`
and add
```
...
location / {
...
add_header 'Access-Control-Allow-Origin' '*';
...
}
...
```
After that, you need to reload nginx.
Now, you should be able to access webcli via `http://your_host/webcli.html`
## Configuring
If you want to configure a bit more, just click the "Configure" link below your chat input.
A form opens and you can input hostname, port, whether using https, as well as the used
model, parameters and system input.
# Todo
Well, there's still something to do here. Source code formatting would be cool or maybe
saving the configuration somehow.. Feel free..

View File

@ -0,0 +1,193 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>My<CR>Ollama</title>
<style>
// first, format the input and output divs
#outputdiv {
overflow-y: auto;
padding: 10px;
border-bottom: 1px solid #ccc;
}
.header {
padding: 0.5em;
border-radius: 0.5em 0.5em 0 0;
background-color: #f9f9fb;
left: 1em;
right: 1em;
//width: calc(100% - 1em);
border: 1px solid;
border-color: #ccc;
}
.content {
padding: 0.5em;
border-radius: 0 0 0.5em 0.5em;
background-color: #ffffff;
left: 1em;
right: 1em;
//width: calc(100% - 1em);
border: 1px solid;
border-color: #ccc;
margin-bottom: 1em;
}
#inputdiv {
border-radius: 0.5em 0.5em 0.5em 0.5em;
bottom: 1em;
left: 1em;
right: 1em;
padding: 1em;
font-size: 16px;
border:1px solid #ccc;
background-color: #ebebf9;
}
#inputdiv input[type="text"] {
width:20em;
}
#inputdiv label {
display:inline-block;
width: 10em;
}
pre {
left: 1em;
right: 1em;
padding: 1em;
font-size: 16px;
border:1px solid #ccc;
background-color: #f0f0fc;
}
// todo: format marked
</style>
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<div id="outputdiv"></div>
<div id="inputdiv">
<form id="inputform" onsubmit="send_form(event)">
<textarea id="textfield" name="text" style="width:calc(100% - 8em);height:5em;"></textarea>
<input type="submit" value="Senden" id="sendenButton" style>
<hr/>
<a onclick="toggle_visibility('config')">Configure</a>
<div id="config" style="display:none">
<label for="hostname">Hostname</label> <input type="text" id="hostname" value=""/><br>
<label for="port">Port</label> <input type="text" id="port" value=""/><br>
<label for="https">HTTPS</label> <input type="checkbox" id="https" /><br>
<label for="model">Model</label> <input type="text" id="model" value=""/><br>
<label for="parameters">Parameters</label><textarea id="parameters">{"stream":false}</textarea><br>
<label for="system">System</label><textarea id="system"></textarea><br>
<input type="hidden" id="context" value="[]" />
</div>
</form>
</div>
<script>
const searchParams = new URLSearchParams(window.location.search);
const ollama_host=searchParams.get("host") || new URL(window.location.href).hostname || "localhost";
const ollama_port=searchParams.get("port") || "11434";
const ollama_https=searchParams.get("https") || null;
const ollama_model=searchParams.get("model") || "llama3.1";
document.getElementById("hostname").value=ollama_host;
document.getElementById("port").value=ollama_port;
document.getElementById("https").checked=ollama_https;
document.getElementById("model").value=ollama_model;
document.addEventListener('keydown', function(event) {
if (event.key === 'Enter' && ! event.shiftKey) {
send_form(event);
}}
);
function toggle_visibility(field) {
item = document.getElementById(field);
item.style.display = (item.style.display == "block") ? "none" : "block";
}
function append_question(text) {
parent = document.getElementById("outputdiv");
header = document.createElement("div");
header.classList.add("header");
header.innerText="You said";
data = document.createElement("div");
data.classList.add("content");
data.innerHTML = marked.parse(text);
parent.appendChild(header);
parent.appendChild(data);
document.getElementById("inputdiv").scrollIntoView();
}
function append_text(text) {
parent = document.getElementById("outputdiv");
header = document.createElement("div");
header.classList.add("header");
data = document.createElement("div");
data.classList.add("content");
data.innerHTML = marked.parse(text);
hd = document.createElement("input");
hd.type = "hidden";
hd.textContent = text;
copy = document.createElement("button");
copy.textContent = "Copy";
copy.addEventListener('click', () => {
const textinhalt = hd.textContent;
navigator.clipboard.writeText(textinhalt);
});
parent.appendChild(header);
header.appendChild(copy);
header.appendChild(hd);
parent.appendChild(data);
document.getElementById("inputdiv").scrollIntoView();
}
function send_form(event) {
event.preventDefault();
const data = JSON.parse(document.getElementById("parameters").value) || {};
data.prompt = document.getElementById("textfield").value;
document.getElementById("textfield").value = "";
data.system = document.getElementById("system").value;
data.model = document.getElementById("model").value;
let ctx = document.getElementById("context").value;
data.context = JSON.parse(ctx);
append_question(data.prompt);
// remove the context
if (data.prompt == "/clear") {
document.getElementById("context").value = "[]";
append_text("Context has been cleared.");
return;
}
const xhr = new XMLHttpRequest();
let url = (ollama_https == null) ? "http://" : "https://";
url += ollama_host + ":" + ollama_port +"/api/generate";
xhr.open("POST", url, true);
xhr.setRequestHeader('Access-Control-Allow-Origin', '*');
xhr.setRequestHeader('Content-type', 'application/json');
xhr.onload = function () {
if (xhr.status === 200) {
resp = JSON.parse(xhr.responseText);
document.getElementById("context").value = JSON.stringify(resp.context);
append_text(resp.response);
} else {
console.error(xhr.statusText);
}
};
xhr.send(JSON.stringify(data));
}
</script>
</body>
</html>