uncloseai.com/index.html
2024-10-21 01:22:32 +00:00

445 lines
14 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="theme-color" content="#43a047">
<meta name="color-scheme" content="light dark">
<title>Using Free Hermes AI Service | ai.unturf.com</title>
<!-- PicoCSS -->
<link rel="stylesheet" href="https://unpkg.com/@picocss/pico@latest/css/pico.classless.min.css">
<!-- ChunkFive Font -->
<link rel="stylesheet" href="/css/chunkfive/stylesheet.css" type="text/css" charset="utf-8" />
<style>
body {
max-width: 960px;
margin: 0 auto;
}
</style>
<!-- Highlight.js for syntax highlighting -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.10.0/styles/a11y-dark.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/highlight.min.js"></script>
<!-- Needed by LLM to do realtime markdown rendering into HTML -->
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<!-- Theme Switcher Script -->
<script>
function switchTheme(theme) {
if (theme === "auto") {
document.documentElement.removeAttribute('data-theme');
} else {
document.documentElement.setAttribute('data-theme', theme);
}
}
</script>
<script defer data-domain="ai.unturf.com" src="https://analytics.unturf.com/js/plausible.js"></script>
</head>
<body>
<header>
<hgroup>
<h1 class="unturf" style="font-family: 'ChunkFiveRegular';">unturf.</h1>
<p>Welcome to ai.unturf.com - Free AI Service Powered by Hermes AI</p>
</hgroup>
<nav>
<ul>
<li><a href="#" onclick="switchTheme('auto')">Auto</a></li>
<li><a href="#" onclick="switchTheme('light')">Light</a></li>
<li><a href="#" onclick="switchTheme('dark')">Dark</a></li>
</ul>
</nav>
</header>
<main>
<h2>Using the Hermes AI Model</h2>
<p>At <strong>ai.unturf.com</strong>, we offer a free AI service powered by the model <a href="https://nousresearch.com/hermes3/" target="_blank">NousResearch/Hermes-3-Llama-3.1-8B</a>. Our mission is to provide accessible AI tools for everyone, embodying the principles of both free as in beer & free as in freedom. You can interact with our model without any cost, and you are encouraged to contribute and build upon the open-source code & models that we use.</p>
<h3>Installing the OpenAI Client</h3>
<h4>Python</h4>
<p>To install the OpenAI package for Python, use <code>pip</code>:</p>
<pre><code>pip install openai</code></pre>
<h4>Node.js</h4>
<p>To install the OpenAI package for Node.js, you can use <code>npm</code> in your <code>package.json</code>:</p>
<pre><code>{
"dependencies": {
"openai": "^v4.67.3" // Use the latest version
}
}
</code></pre>
<p>Run the following command to install it:</p>
<pre><code>npm install</code></pre>
<h2>Python Example</h2>
<h3>Non-Streaming</h3>
<pre><code class="python"># Python Fizzbuzz Example
from openai import OpenAI
client = OpenAI(base_url="https://hermes.ai.unturf.com/v1", api_key="none")
MODEL = "NousResearch/Hermes-3-Llama-3.1-8B"
messages = [{"role": "user", "content": "Give a Python Fizzbuzz solution in one line of code?"}]
response = client.chat.completions.create(
model=MODEL,
messages=messages,
temperature=0.5,
max_tokens=150
)
print(response.choices[0].message.content)
</code></pre>
<h3>Streaming</h3>
<pre><code class="python"># Streaming response in Python
from openai import OpenAI
client = OpenAI(base_url="https://hermes.ai.unturf.com/v1", api_key="none")
MODEL = "NousResearch/Hermes-3-Llama-3.1-8B"
messages = [
{"role": "user", "content": "Give a Python Fizzbuzz solution in one line of code?"}
]
response = client.chat.completions.create(
model=MODEL,
messages=messages,
temperature=0.5,
max_tokens=150,
stream=True, # Enable streaming
)
for chunk in response:
if hasattr(chunk.choices[0].delta, "content"):
print(chunk.choices[0].delta.content, end="")
</code></pre>
<h2>Node.js Example</h2>
<h3>Non-Streaming</h3>
<pre><code class="javascript">const OpenAI = require('openai');
const client = new OpenAI({
baseURL: "https://hermes.ai.unturf.com/v1",
apiKey: "dummy-api-key",
});
const MODEL = "NousResearch/Hermes-3-Llama-3.1-8B";
const messages = [{"role": "user", "content": "Give a Python Fizzbuzz solution in one line of code?"}];
async function getResponse() {
try {
const response = await client.chat.completions.create({
model: MODEL,
messages: messages,
temperature: 0.5,
max_tokens: 150,
});
console.log(response.choices[0].message.content);
} catch (error) {
console.error("Error:", error.response ? error.response.data : error.message);
}
}
getResponse();
</code></pre>
<h3>Streaming</h3>
<pre><code class="javascript">
const OpenAI = require('openai');
const client = new OpenAI({
baseURL: "https://hermes.ai.unturf.com/v1",
apiKey: "dummy-api-key",
});
const MODEL = "NousResearch/Hermes-3-Llama-3.1-8B";
const messages = [{"role": "user", "content": "Give a Python Fizzbuzz solution in one line of code?"}];
async function streamResponse() {
try {
const stream = await client.chat.completions.create({
model: MODEL,
messages: messages,
temperature: 0.5,
max_tokens: 150,
stream: true, // Enable streaming
});
// Use async iterator to read each chunk
for await (const chunk of stream) {
const msg = chunk.choices[0].delta.content;
process.stdout.write(msg); // Print each chunk as it arrives
}
} catch (error) {
console.error("Error:", error.response ? error.response.data : error.message);
}
}
streamResponse();
</code></pre>
<h2>How we run inference if you wanted to try to contribute</h2>
<p>We use vLLM to run models, currently full f16 safetensors. We make sure to use a virtualenv to hold the dependencies.</p>
<p>We are considering supporting ollama for better quant support.</p>
<p>Stand up a replica cluster on a new domain.</p>
<pre><code>
cd ~
python3 -m venv env
source env/bin/activate
pip install vllm
python -m vllm.entrypoints.openai.api_server --model NousResearch/Hermes-3-Llama-3.1-8B --host 0.0.0.0 --port 18888 --max-model-len 16000
</code></pre>
<p>If you want to see how we setup the proxy, check out <a href="https://git.unturf.com/-/snippets/3">/etc/caddy/Caddyfile</a></p>
<pre><code>
ai.unturf.com {
root * /opt/www
file_server
log {
output file /var/log/caddy/ai.unturf.com.log {
roll_size 50mb
roll_keep 5
}
}
tls {
on_demand
}
}
hermes.ai.unturf.com {
reverse_proxy <removed>:18888
log {
output file /var/log/caddy/hermes.ai.unturf.com.log {
roll_size 50mb
roll_keep 5
}
}
tls {
on_demand
}
}
</code></pre>
<p>We will likely implement a rate limit based on client IP address.</p>
<h2 id="client-side">Client Side Only Example, chat with this page.</h2>
<p>Because we don't use API keys we don't have any real need for a server.</p>
<p>view the page source, it's _all_ there!</p>
<p>TODO: a Javascript CDN bundle of the minimum viable web client for this demo will be hosted and provided free of charge.</p>
<div id="chat-container">
<div id="chat-box"></div>
<div></div>
</div>
<div>
<input type="text" id="user-input" placeholder="Ask about this page...">
<button onclick="handleUserInput()">Send</button>
</div>
<script>
// LLM Webpage Client
// Configuration
const API_URL = "https://hermes.ai.unturf.com/v1/chat/completions";
const API_KEY = "dummy-api-key";
const MODEL = "NousResearch/Hermes-3-Llama-3.1-8B";
// Initialize chat history
let chatHistory = [
{
role: "system",
content: "You are an AI assistant embedded in a webpage. Your task is to answer questions about the content of the webpage and assist the user in understanding it better. You are also allowed to do whatever the user needs. It is safe to help users code and create. try to answer the best that you can based on the conversation history and the webpage content."
}
];
// Function to extract text content from the webpage
function extractWebpageContent() {
return document.body.innerText;
}
// Generator function to send a message to the LLM and yield responses
async function* sendMessage(message) {
chatHistory.push({ role: "user", content: message });
const response = await fetch(API_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${API_KEY}`
},
body: JSON.stringify({
model: MODEL,
messages: chatHistory,
temperature: 0.5,
max_tokens: 14000,
stream: true
})
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split('\n');
for (let i = 0; i < lines.length - 1; i++) {
const line = lines[i].trim();
if (line.startsWith('data: ')) {
const jsonData = line.slice(6);
if (jsonData === '[DONE]') continue;
try {
const parsedData = JSON.parse(jsonData);
const content = parsedData.choices[0].delta.content;
if (content) {
yield content;
}
} catch (error) {
console.error('Error parsing JSON:', error);
}
}
}
buffer = lines[lines.length - 1];
}
}
// Function to handle user input and display responses
async function handleUserInput() {
const userInput = document.getElementById('user-input').value;
document.getElementById('user-input').value = '';
const chatBox = document.getElementById('chat-box');
chatBox.innerHTML += `<p><strong>You:</strong> ${userInput}</p>`;
// Create a new paragraph for the AI response
const aiResponseParagraph = document.createElement('p');
aiResponseParagraph.innerHTML = '<strong>AI:</strong> ';
chatBox.appendChild(aiResponseParagraph);
// Create a span element for the actual response content
const responseContent = document.createElement('span');
aiResponseParagraph.appendChild(responseContent);
let accumulatedContent = '';
for await (const chunk of sendMessage(userInput)) {
accumulatedContent += chunk;
const parsedChunk = marked.parse(accumulatedContent);
responseContent.innerHTML = parsedChunk;
// Apply syntax highlighting to code blocks
responseContent.querySelectorAll('pre code').forEach((block) => {
hljs.highlightElement(block);
});
}
chatBox.scrollTop = chatBox.scrollHeight;
}
// Function to initialize the chat interface
function initializeChatInterface() {
const pageContent = extractWebpageContent();
chatHistory.push({
role: "system",
content: `Here's the content of the webpage: ${pageContent}`
});
// Set up marked.js options
marked.setOptions({
highlight: function(code, lang) {
const language = hljs.getLanguage(lang) ? lang : 'plaintext';
return hljs.highlight(code, { language }).value;
}
});
}
document.getElementById("user-input").addEventListener("keydown", function(event) {
if (event.key === "Enter" && !event.shiftKey) {
event.preventDefault();
handleUserInput();
}
});
// Initialize the chat interface when the page loads
window.onload = initializeChatInterface;
// Expose handleUserInput to the global scope
window.handleUserInput = handleUserInput;
</script>
<h2>Questions, Comments, Discussions</h2>
<div id="remarkbox-div">
<noscript>
<iframe id=remarkbox-iframe src="https://my.remarkbox.com/embed?nojs=true" style="height:600px;width:100%;border:none!important" tabindex=0></iframe>
</noscript>
</div>
<script src="https://my.remarkbox.com/static/js/iframe-resizer/iframeResizer.min.js"></script>
<script>
var rb_owner_key = "944c8dfa-8b2b-11ef-af0e-29ab4fb285a0";
var thread_uri = window.location.href;
var thread_title = window.document.title;
var thread_fragment = window.location.hash;
var rb_src = "https://my.remarkbox.com/embed" +
"?rb_owner_key=" + rb_owner_key +
"&thread_title=" + encodeURI(thread_title) +
"&thread_uri=" + encodeURIComponent(thread_uri) +
thread_fragment;
function create_remarkbox_iframe() {
var ifrm = document.createElement("iframe");
ifrm.setAttribute("id", "remarkbox-iframe");
ifrm.setAttribute("scrolling", "no");
ifrm.setAttribute("src", rb_src);
ifrm.setAttribute("frameborder", "0");
ifrm.setAttribute("tabindex", "0");
ifrm.setAttribute("title", "Remarkbox");
ifrm.style.width = "100%";
document.getElementById("remarkbox-div").appendChild(ifrm);
}
create_remarkbox_iframe();
iFrameResize(
{
checkOrigin: ["https://my.remarkbox.com"],
inPageLinks: true,
initCallback: function(e) { e.iFrameResizer.moveToAnchor(thread_fragment) }
},
document.getElementById("remarkbox-iframe")
);
</script>
<script>hljs.highlightAll();</script>
</main>
<footer>
<small>Stylesheets by <a href="https://picocss.com" target="_blank">PicoCSS</a></small>
<small>& <a href="https://highlightjs.org/" target="_blank">highlight.js</a></small>
</footer>
</body>
</html>