407 lines
13 KiB
HTML
407 lines
13 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>
|
|
<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>
|
|
|
|
|
|
<h2 id="client-side">Client Side Only Example, chat with this page.</h2>
|
|
|
|
<p>view page source, it's _all_ there!</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."
|
|
}
|
|
];
|
|
|
|
// 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: 5600,
|
|
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>
|