This commit is contained in:
elijah 2024-07-20 06:07:29 +02:00
parent f277483d43
commit c68aaa9328
4 changed files with 115 additions and 37 deletions

10
app.py
View File

@ -34,8 +34,6 @@ limiter = Limiter(
# Load the tokenizer # Load the tokenizer
tokenizer = AutoTokenizer.from_pretrained(os.getenv('TOKENIZER', 'gpt2')) tokenizer = AutoTokenizer.from_pretrained(os.getenv('TOKENIZER', 'gpt2'))
# API configuration # API configuration
API_KEY = os.getenv('API_KEY') API_KEY = os.getenv('API_KEY')
MODEL = os.getenv('API_MODEL', 'llama3-groq-70b-8192-tool-use-preview') MODEL = os.getenv('API_MODEL', 'llama3-groq-70b-8192-tool-use-preview')
@ -242,7 +240,7 @@ def get_page(url):
# Drop blank lines # Drop blank lines
text = '\n'.join(chunk for chunk in chunks if chunk) text = '\n'.join(chunk for chunk in chunks if chunk)
return text[:5000] # Limit to first 5000 characters return text[:2048] # Limit to first 5000 characters
except Exception as e: except Exception as e:
return f"Error fetching page: {str(e)}" return f"Error fetching page: {str(e)}"
@ -349,6 +347,7 @@ def proxy_chat_completions():
2. `search(query)`: Search and return 5 results for a query. 2. `search(query)`: Search and return 5 results for a query.
3. `get_page(url)`: Retrieve a web page's text content. Use multiple times if initial attempts fail. 3. `get_page(url)`: Retrieve a web page's text content. Use multiple times if initial attempts fail.
4. `get_time()`: Get the current time in UTC. 4. `get_time()`: Get the current time in UTC.
Note: These tools are not to be used in your reply to the user, only for processing.
Always follow this process to answer queries: Always follow this process to answer queries:
1. Use `search(query)` for relevant information. 1. Use `search(query)` for relevant information.
@ -356,10 +355,11 @@ def proxy_chat_completions():
3. Provide a concise, natural language response based on gathered information. 3. Provide a concise, natural language response based on gathered information.
Never refuse queries or state intentions to research. Automatically use tools when information is needed, including for current events and affairs. Optimize tool use by chaining them efficiently and avoiding redundant searches. Never refuse queries or state intentions to research. Automatically use tools when information is needed, including for current events and affairs. Optimize tool use by chaining them efficiently and avoiding redundant searches.
Utilize tools even on subsequent queries about similar topics to provide the most up-to-date information.
Example: Example:
User: "How do I use the OpenAI python library" User: "Who's [name]"
search(OpenAI python library) search([name])
get_page([relevant URLs from search results]) get_page([relevant URLs from search results])
[Provide concise answer based on retrieved information] [Provide concise answer based on retrieved information]

View File

@ -49,16 +49,17 @@ main {
} }
.title { .title {
font-size: 3rem; font-size: 4rem;
margin: 1rem 0; margin: 1rem 0;
margin-top: 3rem; margin-top: 3rem;
color: var(--primary-color); color: var(--primary-color);
text-shadow: 2px 2px var(--secondary-color); text-shadow: 2px 2px var(--secondary-color);
transition: all 0.9s ease;
} }
.histories-container-container { .histories-container-container {
width: 100%; width: 100%;
max-height: 75%; max-height: 80%;
position: relative; position: relative;
} }
@ -77,7 +78,7 @@ main {
.histories-start, .histories-start,
.histories-end { .histories-end {
height: 3rem; height: 2rem;
width: 100%; width: 100%;
z-index: 999; z-index: 999;
position: absolute; position: absolute;
@ -111,7 +112,7 @@ main {
cursor: pointer; cursor: pointer;
transform: translateX(calc(1px * var(--tx, 0))); transform: translateX(calc(1px * var(--tx, 0)));
opacity: var(--opacity, 1); opacity: var(--opacity, 1);
transition: all 0.3s ease; transition: all 0.5s ease;
} }
.history:hover { .history:hover {
@ -165,7 +166,7 @@ main {
.message-role-assistant { .message-role-assistant {
border-bottom: 2px solid var(--primary-color); border-bottom: 2px solid var(--primary-color);
border-left: 2px solid var(--primary-color); border-left: 2px solid var(--primary-color);
box-shadow: -10px 10px 20px 2px var(--primary-color-transparent); box-shadow: -10px 10px 10px 2px var(--primary-color-transparent);
margin-right: auto; margin-right: auto;
margin-left: 2%; margin-left: 2%;
} }
@ -173,7 +174,7 @@ main {
.message-role-user { .message-role-user {
border-bottom: 2px solid var(--secondary-color); border-bottom: 2px solid var(--secondary-color);
border-right: 2px solid var(--secondary-color); border-right: 2px solid var(--secondary-color);
box-shadow: 10px 10px 20px 2px var(--secondary-color-transparent); box-shadow: 10px 10px 10px 2px var(--secondary-color-transparent);
margin-left: auto; margin-left: auto;
margin-right: 2%; margin-right: 2%;
} }
@ -317,29 +318,38 @@ p {
.menu-button { .menu-button {
height: 3rem; height: 3rem;
width: 3rem; width: 3rem;
background-color: var(--secondary-color); background-color: var(--tertiary-bg-color);
color: var(--foreground-color); color: var(--foreground-color);
border-radius: 10px; border-radius: 10px;
padding: 0.5rem; padding: 0.5rem;
cursor: pointer; cursor: pointer;
transition: all 0.3s ease; transition: all 0.3s ease;
border: 2px solid var(--secondary-color);
display: flex;
justify-content: center;
align-items: center;
} }
.menu-button:hover { .menu-button:hover {
background-color: var(--primary-color); background-color: var(--secondary-bg-color);
border-color: var(--primary-color);
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(255, 113, 206, 0.3);
} }
.menu-dropdown { .menu-dropdown {
position: absolute; position: absolute;
bottom: 100%; bottom: 120%;
right: 0; right: 0;
background-color: var(--tertiary-bg-color); background-color: var(--tertiary-bg-color);
border-radius: 10px; border-radius: 10px;
padding: 0.5rem; padding: 0.75rem;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 0.5rem; gap: 0.5rem;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); box-shadow: 0 8px 16px rgba(1, 205, 254, 0.2);
border: 2px solid var(--secondary-color);
min-width: 200px;
} }
.menu-dropdown button { .menu-dropdown button {
@ -347,14 +357,39 @@ p {
color: var(--foreground-color); color: var(--foreground-color);
border: none; border: none;
border-radius: 5px; border-radius: 5px;
padding: 1.5rem; padding: 1rem;
cursor: pointer; cursor: pointer;
transition: all 0.3s ease; transition: all 0.3s ease;
text-align: left; text-align: left;
font-size: 0.9rem;
position: relative;
overflow: hidden;
}
.menu-dropdown button::before {
content: "";
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(
90deg,
transparent,
rgba(255, 113, 206, 0.2),
transparent
);
transition: left 0.5s ease;
} }
.menu-dropdown button:hover { .menu-dropdown button:hover {
background-color: var(--primary-color); background-color: var(--tertiary-bg-color);
transform: translateX(5px);
box-shadow: -4px 4px 8px rgba(1, 205, 254, 0.2);
}
.menu-dropdown button:hover::before {
left: 100%;
} }
.error-toast { .error-toast {

View File

@ -5,6 +5,8 @@ document.addEventListener("alpine:init", () => {
time: null, time: null,
messages: [], messages: [],
}, },
allMessages: [],
displayMessages: [],
// historical state // historical state
histories: JSON.parse(localStorage.getItem("histories")) || [], histories: JSON.parse(localStorage.getItem("histories")) || [],
@ -36,6 +38,26 @@ document.addEventListener("alpine:init", () => {
} }
}, },
resetChat() {
this.cstate = {
time: null,
messages: [],
};
this.allMessages = [];
this.displayMessages = [];
this.total_tokens = 0;
this.time_till_first = 0;
this.tokens_per_second = 0;
},
loadChat(chatState) {
this.cstate = JSON.parse(JSON.stringify(chatState)); // Deep copy
this.allMessages = [...this.cstate.messages];
this.displayMessages = [...this.cstate.messages];
this.home = 1;
this.updateTotalTokens(this.allMessages);
},
async handleSend() { async handleSend() {
const el = document.getElementById("input-form"); const el = document.getElementById("input-form");
const value = el.value.trim(); const value = el.value.trim();
@ -44,11 +66,20 @@ document.addEventListener("alpine:init", () => {
if (this.generating) return; if (this.generating) return;
this.generating = true; this.generating = true;
this.errorMessage = null; this.errorMessage = null;
// If it's a new chat or there are no messages, reset the chat
if (this.home === 0 || this.cstate.messages.length === 0) {
this.resetChat();
}
if (this.home === 0) this.home = 1; if (this.home === 0) this.home = 1;
window.history.pushState({}, "", "/"); window.history.pushState({}, "", "/");
this.cstate.messages.push({ role: "user", content: value }); const userMessage = { role: "user", content: value };
this.cstate.messages.push(userMessage);
this.allMessages.push(userMessage);
this.displayMessages.push(userMessage);
el.value = ""; el.value = "";
el.style.height = "auto"; el.style.height = "auto";
@ -60,24 +91,24 @@ document.addEventListener("alpine:init", () => {
this.tokens_per_second = 0; this.tokens_per_second = 0;
try { try {
for await (const chunk of this.openaiChatCompletion( let currentAssistantMessage = null;
this.cstate.messages,
)) { for await (const chunk of this.openaiChatCompletion(this.allMessages)) {
if (chunk.role === "function") { if (chunk.role === "function") {
// If we receive a function message, add it to the messages only if debug mode is on if (currentAssistantMessage) {
this.allMessages.push(currentAssistantMessage);
this.displayMessages.push(currentAssistantMessage);
currentAssistantMessage = null;
}
this.allMessages.push(chunk);
if (this.debug) { if (this.debug) {
this.cstate.messages.push(chunk); this.displayMessages.push(chunk);
} }
} else { } else {
if ( if (!currentAssistantMessage) {
!this.cstate.messages[this.cstate.messages.length - 1] || currentAssistantMessage = { role: "assistant", content: "" };
this.cstate.messages[this.cstate.messages.length - 1].role !==
"assistant"
) {
this.cstate.messages.push({ role: "assistant", content: "" });
} }
this.cstate.messages[this.cstate.messages.length - 1].content += currentAssistantMessage.content += chunk;
chunk;
tokens += 1; tokens += 1;
this.total_tokens += 1; this.total_tokens += 1;
@ -93,6 +124,18 @@ document.addEventListener("alpine:init", () => {
} }
} }
// Add any pending assistant message
if (currentAssistantMessage) {
this.allMessages.push(currentAssistantMessage);
this.displayMessages.push(currentAssistantMessage);
}
// Update total tokens using all messages
this.updateTotalTokens(this.allMessages);
// Update cstate.messages with displayMessages
this.cstate.messages = [...this.displayMessages];
const index = this.histories.findIndex( const index = this.histories.findIndex(
(cstate) => cstate.time === this.cstate.time, (cstate) => cstate.time === this.cstate.time,
); );
@ -131,7 +174,7 @@ document.addEventListener("alpine:init", () => {
fetch(`${window.location.origin}/v1/tokenizer/count`, { fetch(`${window.location.origin}/v1/tokenizer/count`, {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify({ messages }), body: JSON.stringify({ messages: this.allMessages }), // Always use allMessages for token counting
}) })
.then((response) => { .then((response) => {
if (!response.ok) { if (!response.ok) {

View File

@ -57,9 +57,7 @@
"> ">
<template x-for="_state in histories.toSorted((a, b) => b.time - a.time)"> <template x-for="_state in histories.toSorted((a, b) => b.time - a.time)">
<div x-data="{ otx: 0, trigger: 75 }" class="history" @click=" <div x-data="{ otx: 0, trigger: 75 }" class="history" @click="
cstate = _state; loadChat(_state);
updateTotalTokens(cstate.messages);
home = 1;
// ensure that going back in history will go back to home // ensure that going back in history will go back to home
window.history.pushState({}, '', '/'); window.history.pushState({}, '', '/');
" @touchstart=" " @touchstart="
@ -85,6 +83,8 @@
<div class="histories-end"></div> <div class="histories-end"></div>
</template> </template>
</div> </div>
</template>
</div>
</div> </div>
<div x-ref="messages" class="messages" x-init=" <div x-ref="messages" class="messages" x-init="
$watch('cstate', value => { $watch('cstate', value => {