Changed HTML to use djlint

This commit is contained in:
Adrien Bouvais 2024-08-04 10:09:15 +02:00
parent 5384383908
commit fa1bd44a99
13 changed files with 1004 additions and 839 deletions

View File

@ -1,4 +1,7 @@
<div class="chat-container mt-5" style="padding-bottom: 155px;" hx-indicator="#textarea-control" hx-ext="sse">
<div class="chat-container mt-5"
style="padding-bottom: 155px"
hx-indicator="#textarea-control"
hx-ext="sse">
<hx hx-get="/loadChat" hx-trigger="load once" hx-swap="outerHTML"></hx>
<hx hx-get="/loadChatInput" hx-trigger="load once" hx-swap="outerHTML" id="textarea-control"></hx>
</div>

View File

@ -1,13 +1,17 @@
<!DOCTYPE html>
<html data-theme="dark" lang="en">
<head>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
<meta name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
<title>JADE</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@1.0.0/css/bulma.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css">
<link href="https://fonts.googleapis.com/css?family=Russo+One" rel="stylesheet">
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bulma@1.0.0/css/bulma.min.css">
<link rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css">
<link href="https://fonts.googleapis.com/css?family=Russo+One"
rel="stylesheet">
<!--link rel="stylesheet" href="/animations.css"-->
<link rel="stylesheet" href="/style.css">
@ -19,7 +23,8 @@
<script async src="https://js.stripe.com/v3/pricing-table.js"></script>
<!-- highlight.js -->
<link rel="stylesheet" href="https://unpkg.com/@highlightjs/cdn-assets@11.9.0/styles/default.min.css">
<link rel="stylesheet"
href="https://unpkg.com/@highlightjs/cdn-assets@11.9.0/styles/default.min.css">
<script src="https://unpkg.com/@highlightjs/cdn-assets@11.9.0/highlight.min.js"></script>
<script>hljs.highlightAll();</script>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
@ -31,9 +36,9 @@
go.run(result.instance);
});
</script>
</head>
</head>
<body>
<body>
{{ embed }}
@ -197,6 +202,6 @@
</script>
</body>
</body>
</html>

View File

@ -1,10 +1,13 @@
{% if IsLogin %}
{% if IsSubscribed or not IsLimiteReached %}
<div class="chat-input-container mb-5">
{% if IsSubscribed or not IsLimiteReached %}
<div class="chat-input-container mb-5">
<div class="textarea-wrapper">
<div class="control" id="textarea-control">
<textarea {% if not IsLogin or not HaveKey %}disabled{% endif %} class="textarea has-fixed-size"
placeholder="Type your message here..." name="message" oninput="toggleSendButton()"
<textarea {% if not IsLogin or not HaveKey %}disabled{% endif %}
class="textarea has-fixed-size"
placeholder="Type your message here..."
name="message"
oninput="toggleSendButton()"
id="chat-input-textarea"></textarea>
</div>
<div class="button-group">
@ -12,9 +15,16 @@
<hx hx-get="/loadUsageKPI" hx-trigger="load" hx-swap="outerHTML" hx-target="this"></hx>
<hx hx-get="/loadConversationSelection" hx-trigger="load" hx-swap="outerHTML" hx-target="this"></hx>
<hx hx-get="/loadModelSelection" hx-trigger="load" hx-swap="outerHTML" hx-target="this"></hx>
<button disabled type="submit" class="send-button button is-primary is-small" hx-post="/generatePlaceholder"
hx-swap="beforeend" hx-target="#chat-messages" id="chat-input-send-btn" class="chat-input"
hx-include="[name='message']" hx-vals="js:{selectedLLMIds: getSelectedModelsIDs()}"
<button disabled
type="submit"
class="send-button button is-primary is-small"
hx-post="/generatePlaceholder"
hx-swap="beforeend"
hx-target="#chat-messages"
id="chat-input-send-btn"
class="chat-input"
hx-include="[name='message']"
hx-vals="js:{selectedLLMIds: getSelectedModelsIDs()}"
onclick="onClickSendButton()">
<span class="icon">
<i class="fa-solid fa-chevron-right"></i>
@ -22,8 +32,8 @@
</button>
</div>
</div>
</div>
{% endif %}
</div>
{% endif %}
{% endif %}
<script>

View File

@ -3,55 +3,30 @@
To use JADE, you need to sign up for an API key. You can enter an API key in
the settings menu. Once enter you get access to all models from this provider.
</p>
<a
class="button is-small is-primary is-outlined mt-1"
<a class="button is-small is-primary is-outlined mt-1"
href="https://openai.com/index/openai-api/"
target="_blank"
>
Get OpenAI API key
</a>
<a
class="button is-small is-primary is-outlined mt-1"
target="_blank">Get OpenAI API key</a>
<a class="button is-small is-primary is-outlined mt-1"
href="https://console.anthropic.com/"
target="_blank"
>
Get Anthropic API key
</a>
<a
class="button is-small is-primary is-outlined mt-1"
target="_blank">Get Anthropic API key</a>
<a class="button is-small is-primary is-outlined mt-1"
href="https://console.mistral.ai/"
target="_blank"
>
Get Mistral API key
</a>
<a
class="button is-small is-primary is-outlined mt-1"
target="_blank">Get Mistral API key</a>
<a class="button is-small is-primary is-outlined mt-1"
href="https://console.groq.com/"
target="_blank"
>
Get Groq API key
</a>
<a
class="button is-small is-primary is-outlined mt-1"
target="_blank">Get Groq API key</a>
<a class="button is-small is-primary is-outlined mt-1"
href="https://aistudio.google.com/app/apikey"
target="_blank"
>
Get Google API key
</a>
<a
class="button is-small is-primary is-outlined mt-1"
target="_blank">Get Google API key</a>
<a class="button is-small is-primary is-outlined mt-1"
href="https://build.nvidia.com/explore/discover"
target="_blank">Get Nvidia NIM API key</a>
<a class="button is-small is-primary is-outlined mt-1"
href="https://docs.perplexity.ai/docs/getting-started"
target="_blank"
>
Get Perplexity API key
</a>
<a
class="button is-small is-primary is-outlined mt-1"
target="_blank">Get Perplexity API key</a>
<a class="button is-small is-primary is-outlined mt-1"
href="https://fireworks.ai/login"
target="_blank"
>
Get Fireworks API key
</a>
target="_blank">Get Fireworks API key</a>
<h2>Conversations</h2>
<p>
@ -68,10 +43,10 @@
</p>
<p>
To create a new bot, click the "+" button, enter a name and a model, and
optionally set a temperature and a system prompt. Once created, you can select
a bot by clicking on it and reorder it by dragging. Hold SHIFT and click to
select multiple bots. You can delete selected bots by clicking the trash can
icon.
optionally set a temperature, a max tokens and a system prompt. Once created,
you can select a bot by clicking on it and reorder it by dragging. Hold SHIFT
and click to select multiple bots. You can delete selected bots by clicking
the trash can icon.
</p>
<h2>Multi-Models</h2>

View File

@ -5,9 +5,12 @@
<!-- Left column with the icon -->
{% if IsPlaceholder %}
<figure class="image is-48x48 message-icon" style="flex-shrink: 0;"
<figure class="image is-48x48 message-icon"
style="flex-shrink: 0"
sse-swap="swapIcon-{{ ConversationAreaId }}">
<img src="icons/bouvai2.png" alt="User Image" id="selectedIcon-{{ ConversationAreaId }}">
<img src="icons/bouvai2.png"
alt="User Image"
id="selectedIcon-{{ ConversationAreaId }}">
</figure>
{% else %}
@ -15,7 +18,9 @@
{% for message in Messages %}
{% if not message.Hidden %}
<figure class="image is-48x48 message-icon" style="flex-shrink: 0;">
<img src="{{ message.Icon }}" alt="User Image" id="selectedIcon-{{ ConversationAreaId }}">
<img src="{{ message.Icon }}"
alt="User Image"
id="selectedIcon-{{ ConversationAreaId }}">
</figure>
{% endif %}
{% endfor %}
@ -26,8 +31,10 @@
<div class="column" id="content-column" style="width: 100px;">
{% if not IsPlaceholder %}
<div class="{% if not notFlex%} is-flex {% endif %} is-align-items-start">
<div class="message-content" style="width: 100%; overflow-y: hidden;"
<div class="{% if not notFlex %} is-flex {% endif %} is-align-items-start">
<div class="message-content"
style="width: 100%;
overflow-y: hidden"
id="content-{{ ConversationAreaId }}">
{% for message in Messages %}
{% if not message.Hidden %}
@ -39,9 +46,7 @@
</div>
{% endif %}
<div class="message-body">
<div class="content" style="overflow-x: auto; width: 100%;">
{{ message.Content | safe }}
</div>
<div class="content" style="overflow-x: auto; width: 100%;">{{ message.Content | safe }}</div>
</div>
{% endif %}
{% endfor %}
@ -58,11 +63,15 @@
{% for message in Messages %}
<button class="button is-small is-primary message-button is-outlined mr-1"
hx-get="/messageContent?id={{ message.Id }}" hx-target="#content-{{ ConversationAreaId }}"
onclick="updateIcon('{{ message.Icon }}', '{{ ConversationAreaId }}')" title="{{ message.Name }}">
hx-get="/messageContent?id={{ message.Id }}"
hx-target="#content-{{ ConversationAreaId }}"
onclick="updateIcon('{{ message.Icon }}', '{{ ConversationAreaId }}')"
title="{{ message.Name }}">
<span class="icon is-small">
<img src="{{ message.Icon }}" alt="{{ message.Name }}"
style="max-height: 100%; max-width: 100%;">
<img src="{{ message.Icon }}"
alt="{{ message.Name }}"
style="max-height: 100%;
max-width: 100%">
</span>
</button>
{% endfor %}
@ -71,13 +80,12 @@
{% elif IsPlaceholder %}
<div class="is-flex is-align-items-start">
<div class="message-content" id="content-{{ ConversationAreaId }}"
<div class="message-content"
id="content-{{ ConversationAreaId }}"
sse-swap="swapContent-{{ ConversationAreaId }}">
<hx hx-trigger="load" hx-get="/generateMultipleMessages" id="generate-multiple-messages"></hx>
<div class='message-header'>
<p>
Waiting...
</p>
<p>Waiting...</p>
</div>
<div class="message-body">
<div class="content">
@ -97,8 +105,10 @@
</button>
{% for selectedLLM in SelectedLLMs %}
<button disable class="button is-small is-primary message-button is-outlined mr-1"
sse-swap="swapSelectionBtn-{{ selectedLLM.ID.String() }}" hx-swap="outerHTML"
<button disable
class="button is-small is-primary message-button is-outlined mr-1"
sse-swap="swapSelectionBtn-{{ selectedLLM.ID.String() }}"
hx-swap="outerHTML"
hx-target="this">
<span class="icon is-small">
<!--img src="icons/{{ selectedLLM.Company }}.png" alt="{{ selectedLLM.Name }}"

View File

@ -10,23 +10,24 @@
<div class="is-flex is-align-items-start mr-5" style="width: 100%;">
<div class="message-content" style="width: 100%;">
<div class="message-header">
<p>
You
</p>
<p>You</p>
</div>
<div class="message-body" style="width: 100%;">
<div class="content" id="content-{{ ID }}" style="width: 100%;">
<div class="field" style="width: 100%;">
<div class="control" style="width: 100%;">
<textarea class="textarea is-small has-fixed-size mt-2"
placeholder="Enter your message here" rows="{{ Rows }}"
style="background-color: transparent; width: 100%;"
placeholder="Enter your message here"
rows="{{ Rows }}"
style="background-color: transparent;
width: 100%"
name="message">{{ Content }}</textarea>
</div>
</div>
<div class="field is-grouped is-flex is-justify-content-flex-end mb-3">
<div class="control">
<button hx-get="/userMessage?id={{ ID }}" hx-target="closest .message-user"
<button hx-get="/userMessage?id={{ ID }}"
hx-target="closest .message-user"
class="button is-danger is-outlined is-small">
<span class="icon">
<i class="fa-solid fa-xmark"></i>
@ -34,13 +35,19 @@
</button>
</div>
<div class="control">
<div style="display: none;" hx-trigger="click from:#edit-button-{{ ID }}"
hx-target="next .message-bot" hx-swap="outerHTML" hx-get="/empty"></div>
<div style="display: none"
hx-trigger="click from:#edit-button-{{ ID }}"
hx-target="next .message-bot"
hx-swap="outerHTML"
hx-get="/empty"></div>
<button class="button is-success is-outlined is-small"
hx-post="/editMessage?id={{ ID }}" hx-target="closest .message-user"
hx-post="/editMessage?id={{ ID }}"
hx-target="closest .message-user"
hx-include="[name='message']"
hx-vals="js:{selectedLLMIds: getSelectedModelsIDs()}" hx-swap="outerHTML"
id="edit-button-{{ ID }}" hx-trigger="click">
hx-vals="js:{selectedLLMIds: getSelectedModelsIDs()}"
hx-swap="outerHTML"
id="edit-button-{{ ID }}"
hx-trigger="click">
<span class="icon">
<i class="fa-solid fa-check"></i>
</span>

View File

@ -10,33 +10,40 @@
<div class="is-flex is-align-items-start">
<div class="message-content" style="width: 100%; overflow-y: hidden;">
<div class="message-header">
<p>
You
</p>
<p>You</p>
</div>
<div class="message-body">
<div class="content" style="overflow-x: auto; width: 100%;" id="content-{{ ID }}">
{{ Content | safe }}
</div>
<div class="content"
style="overflow-x: auto;
width: 100%"
id="content-{{ ID }}">{{ Content | safe }}</div>
</div>
</div>
</div>
<div class="is-flex is-justify-content mt-2">
<button id="delete-button-{{ ID }}" hx-post="/deleteMessage?id={{ ID }}" hx-swap="outerHTML"
hx-target="#chat-container" class="button is-small is-danger message-button is-outlined mr-5">
<button id="delete-button-{{ ID }}"
hx-post="/deleteMessage?id={{ ID }}"
hx-swap="outerHTML"
hx-target="#chat-container"
class="button is-small is-danger message-button is-outlined mr-5">
<span class="icon">
<i class="fa-solid fa-trash"></i>
</span>
</button>
<button id="redo-button-{{ ID }}" class="button is-primary is-small message-button is-outlined mr-1 is-static"
hx-post="/redoMessage?id={{ ID }}" hx-swap="innerHTML settle:200ms" hx-target="next .message-bot"
<button id="redo-button-{{ ID }}"
class="button is-primary is-small message-button is-outlined mr-1 is-static"
hx-post="/redoMessage?id={{ ID }}"
hx-swap="innerHTML settle:200ms"
hx-target="next .message-bot"
hx-vals="js:{selectedLLMIds: getSelectedModelsIDs()}">
<span class="icon">
<i class="fa-solid fa-arrows-rotate"></i>
</span>
</button>
<button hx-get="/editMessageForm?id={{ ID }}" hx-target="closest .message-user"
id="edit-button-{{ ID }}" class="button is-primary is-small message-button is-outlined is-static mr-5">
<button hx-get="/editMessageForm?id={{ ID }}"
hx-target="closest .message-user"
id="edit-button-{{ ID }}"
class="button is-primary is-small message-button is-outlined is-static mr-5">
<span class="icon">
<i class="fa-solid fa-pen"></i>
</span>

View File

@ -1,7 +1,12 @@
<button class="button is-small is-primary message-button is-outlined mr-1" hx-get="/messageContent?id={{ message.Id }}"
hx-target="#content-{{ ConversationAreaId }}" onclick="updateIcon('{{ message.Icon }}', '{{ ConversationAreaId }}')"
<button class="button is-small is-primary message-button is-outlined mr-1"
hx-get="/messageContent?id={{ message.Id }}"
hx-target="#content-{{ ConversationAreaId }}"
onclick="updateIcon('{{ message.Icon }}', '{{ ConversationAreaId }}')"
title="{{ message.Name }}">
<span class="icon is-small">
<img src="{{ message.Icon }}" alt="{{ message.Name }}" style="max-height: 100%; max-width: 100%;">
<img src="{{ message.Icon }}"
alt="{{ message.Name }}"
style="max-height: 100%;
max-width: 100%">
</span>
</button>

View File

@ -1,6 +1,9 @@
<div class="dropdown is-up is-right {% if IsActive %} is-active {% endif %}" id="conversation-dropdown">
<div class="dropdown is-up is-right {% if IsActive %}is-active{% endif %}"
id="conversation-dropdown">
<div class="dropdown-trigger">
<button class="button is-small to-reduce-opacity" aria-haspopup="true" aria-controls="dropdown-menu3"
<button class="button is-small to-reduce-opacity"
aria-haspopup="true"
aria-controls="dropdown-menu3"
onclick="this.parentElement.parentElement.classList.toggle('is-active')">
<span class="icon">
<i class="fa-solid fa-comments"></i>
@ -12,55 +15,70 @@
<div class="dropdown-item">
<div id="conversation-list">
{% for Conversation in Conversations %}
<div class="icon-text has-text unselected icon-conv {% if Conversation.Selected %} selected {% endif %}"
data-id="{{ Conversation.ID.String() }}" style="cursor: pointer;"
<div class="icon-text has-text unselected icon-conv {% if Conversation.Selected %}selected{% endif %}"
data-id="{{ Conversation.ID.String() }}"
style="cursor: pointer"
onclick="toggleConversationSelection(this, '{{ Conversation.Name }}')"
hx-get="/selectConversation?conversation-id={{ Conversation.ID.String() }}" hx-swap="outerHTML"
hx-target="#chat-container" name="{{ Conversation.Name }}">
hx-get="/selectConversation?conversation-id={{ Conversation.ID.String() }}"
hx-swap="outerHTML"
hx-target="#chat-container"
name="{{ Conversation.Name }}">
<span>{{ Conversation.Name }}</span>
</div>
{% endfor %}
</div>
<input class="input is-small mt-2 is-hidden" type="text" id="conversation-name-input"
name="conversation-name-input" placeholder="Conversation name" autocomplete="off">
<input class="input is-small mt-2 is-hidden"
type="text"
id="conversation-name-input"
name="conversation-name-input"
placeholder="Conversation name"
autocomplete="off">
<div class="is-flex is-justify-content-space-between mt-4 ">
<button class="button is-small is-danger {% if SelectedIsDefault %} is-hidden {% endif %}"
id="delete-conversation-button" hx-get="/deleteConversation" hx-swap="outerHTML"
hx-target="#conversation-dropdown" hx-vals="js:{conversationId: findSelectedConversationID()}">
<button class="button is-small is-danger {% if SelectedIsDefault %}is-hidden{% endif %}"
id="delete-conversation-button"
hx-get="/deleteConversation"
hx-swap="outerHTML"
hx-target="#conversation-dropdown"
hx-vals="js:{conversationId: findSelectedConversationID()}">
<span class="icon">
<i class="fa-solid fa-trash"></i>
</span>
</button>
<button
class="button is-small is-primary is-outlined {% if not SelectedIsDefault %} is-hidden {% endif %}"
<button class="button is-small is-primary is-outlined {% if not SelectedIsDefault %}is-hidden{% endif %}"
id="archive-default-conversation-button">
<span class="icon">
<i class="fa-solid fa-box-archive"></i>
</span>
</button>
<button class="button is-small is-danger is-outlined is-hidden" id="cancel-conversation-button">
<button class="button is-small is-danger is-outlined is-hidden"
id="cancel-conversation-button">
<span class="icon">
<i class="fa-solid fa-xmark"></i>
</span>
</button>
<div class="is-flex is-justify-content-flex-end">
<button class="button is-small is-success is-outlined" id="create-conversation-button">
<button class="button is-small is-success is-outlined"
id="create-conversation-button">
<span class="icon">
<i class="fa-solid fa-plus"></i>
</span>
</button>
<button class="button is-small is-success is-outlined is-hidden"
id="confirm-conversation-button" hx-get="/createConversation"
hx-include="[name='conversation-name-input']" hx-swap="outerHTML"
id="confirm-conversation-button"
hx-get="/createConversation"
hx-include="[name='conversation-name-input']"
hx-swap="outerHTML"
hx-target="#conversation-dropdown">
<span class="icon">
<i class="fa-solid fa-check"></i>
</span>
</button>
<button class="button is-small is-success is-outlined is-hidden"
id="confirm-archive-default-conversation-button" hx-post="/archiveDefaultConversation"
hx-include="[name='conversation-name-input']" hx-swap="outerHTML"
id="confirm-archive-default-conversation-button"
hx-post="/archiveDefaultConversation"
hx-include="[name='conversation-name-input']"
hx-swap="outerHTML"
hx-target="#conversation-dropdown">
<span class="icon">
<i class="fa-solid fa-check"></i>

View File

@ -1,6 +1,8 @@
<div class="dropdown is-up is-right" id="models-dropdown">
<div class="dropdown-trigger">
<button class="button is-small to-reduce-opacity" aria-haspopup="true" aria-controls="dropdown-menu3"
<button class="button is-small to-reduce-opacity"
aria-haspopup="true"
aria-controls="dropdown-menu3"
onclick="this.parentElement.parentElement.classList.toggle('is-active')">
<span class="icon"><i class="fa-solid fa-robot"></i></span>
</button>
@ -10,8 +12,10 @@
<div class="dropdown-item" id="models-list">
<div id="llm-list">
{% for LLM in LLMs %}
<div class="icon-text has-text unselected icon-llm" data-id="{{ LLM.ID.String() }}"
style="cursor: pointer;" onclick="toggleSelection(this)">
<div class="icon-text has-text unselected icon-llm"
data-id="{{ LLM.ID.String() }}"
style="cursor: pointer"
onclick="toggleSelection(this)">
<span class="icon">
<img src="{{ LLM.Model.Company.Icon }}" />
</span>
@ -20,9 +24,15 @@
{% endfor %}
</div>
<div class="is-flex is-justify-content-space-between mt-4">
<button disabled class="button is-small is-danger" hx-get="/deleteLLM" hx-swap="outerHTML"
hx-target="#models-dropdown" hx-confirm="Are you sure?" hx-trigger="click"
hx-vals="js:{selectedLLMIds: getSelectedModelsIDs()}" id="delete-model-button">
<button disabled
class="button is-small is-danger"
hx-get="/deleteLLM"
hx-swap="outerHTML"
hx-target="#models-dropdown"
hx-confirm="Are you sure?"
hx-trigger="click"
hx-vals="js:{selectedLLMIds: getSelectedModelsIDs()}"
id="delete-model-button">
<span class="icon">
<i class="fa-solid fa-trash"></i>
</span>
@ -32,8 +42,9 @@
<span class="icon">
<i class="fa-solid fa-pen"></i>
</span>
</button-->
<button class="button is-small is-success is-outlined" id="create-model-button">
</button -->
<button class="button is-small is-success is-outlined"
id="create-model-button">
<span class="icon">
<i class="fa-solid fa-plus"></i>
</span>
@ -42,13 +53,22 @@
</div>
</div>
<div class="dropdown-item is-hidden" id="models-creation">
<form id="create-model-form" hx-post="/createLLM" hx-target="#models-dropdown" hx-swap="outerHTML">
<input class="input is-small mb-3" type="text" id="model-name-input" name="model-name-input"
placeholder="Model name" autocomplete="off">
<form id="create-model-form"
hx-post="/createLLM"
hx-target="#models-dropdown"
hx-swap="outerHTML">
<input class="input is-small mb-3"
type="text"
id="model-name-input"
name="model-name-input"
placeholder="Model name"
autocomplete="off">
<div class="select is-fullwidth is-small mb-3" id="model-id-input">
<select name="selectedLLMId">
{% for modelInfo in ModelInfos %}
<option value="{{ modelInfo.ModelID }}">{{ modelInfo.Company.Name }} - {{ modelInfo.Name }}</option>
<option value="{{ modelInfo.ModelID }}">
{{ modelInfo.Company.Name }} - {{ modelInfo.Name }}
</option>
{% endfor %}
<option value="{% if IsPremium %}custom{% else %}none{% endif %}">Custom Endpoints</option>
</select>
@ -56,30 +76,62 @@
<p class="is-hidden" style="color: red;" id="endpoint-error">
<small>Need premium subscription</small>
</p>
<input class="input is-small mb-3 is-hidden" type="text" id="model-cid-input" name="model-cid-input"
placeholder="Model id" autocomplete="off">
<input class="input is-small mb-3 is-hidden" type="text" id="model-url-input" name="model-url-input"
placeholder="URL (with /v1/chat/completions)" autocomplete="off">
<input class="input is-small mb-3 is-hidden" type="text" id="model-key-input" name="model-key-input"
placeholder="Token" autocomplete="off">
<p><small>Temperature:</small></p>
<input class="slider is-small mb-3" step="0.05" min="0" max="2" value="0" type="range"
id="temperature-slider" name="temperature-slider">
<input class="input is-small mb-3 is-hidden"
type="text"
id="model-cid-input"
name="model-cid-input"
placeholder="Model id"
autocomplete="off">
<input class="input is-small mb-3 is-hidden"
type="text"
id="model-url-input"
name="model-url-input"
placeholder="URL (with /v1/chat/completions)"
autocomplete="off">
<input class="input is-small mb-3 is-hidden"
type="text"
id="model-key-input"
name="model-key-input"
placeholder="Token"
autocomplete="off">
<p>
<small>Temperature:</small>
</p>
<input class="slider is-small mb-3"
step="0.05"
min="0"
max="2"
value="0"
type="range"
id="temperature-slider"
name="temperature-slider">
<output id="temperature-slider-output">0</output>
<p><small>Max token (optional):</small></p>
<input class="input is-small mb-3" type="number" id="max-token-input" name="max-token-input"
placeholder="" autocomplete="off">
<p><small>System prompt (optional):</small></p>
<textarea class="textarea is-small mb-5 has-fixed-size" id="model-prompt-input"
<p>
<small>Max token (optional):</small>
</p>
<input class="input is-small mb-3"
type="number"
id="max-token-input"
name="max-token-input"
placeholder=""
autocomplete="off">
<p>
<small>System prompt (optional):</small>
</p>
<textarea class="textarea is-small mb-5 has-fixed-size"
id="model-prompt-input"
name="model-prompt-input"></textarea>
<div class="is-flex is-justify-content-flex-end">
<button class="button is-small is-danger is-outlined mr-3" id="cancel-create-model-button"
<button class="button is-small is-danger is-outlined mr-3"
id="cancel-create-model-button"
type="button">
<span class="icon">
<i class="fa-solid fa-xmark"></i>
</span>
</button>
<button disabled class="button is-small is-success" id="confirm-create-model-button"
<button disabled
class="button is-small is-success"
id="confirm-create-model-button"
type="submit">
<span class="icon">
<i class="fa-solid fa-check"></i>

View File

@ -1,7 +1,8 @@
<div class="dropdown is-up is-right" id="settings-dropdown">
<div class="dropdown-trigger">
<button class="button is-small {% if not AnyExists %} is-danger{% endif %} to-reduce-opacity"
aria-haspopup="true" aria-controls="dropdown-menu3"
<button class="button is-small {% if not AnyExists %}is-danger{% endif %} to-reduce-opacity"
aria-haspopup="true"
aria-controls="dropdown-menu3"
onclick="this.parentElement.parentElement.classList.toggle('is-active')">
<span class="icon"><i class="fa-solid fa-bars"></i></i></span>
</button>
@ -10,12 +11,18 @@
<div class="dropdown-content">
<div class="dropdown-item">
<div class="field">
<form id="api-keys-form" hx-post="/addKeys" hx-trigger="submit" hx-target="#api-keys-status">
<form id="api-keys-form"
hx-post="/addKeys"
hx-trigger="submit"
hx-target="#api-keys-status">
<div class="field has-addons is-hidden" id="openai-field">
<p class="control has-icons-left is-expanded">
<input class="input is-small {% if OpenaiExists %}is-success{% endif %}" type="text"
{%if not IsLogin %}disabled{% endif %} placeholder="OpenAI API key"
name="openai_key" autocomplete="off">
<input class="input is-small {% if OpenaiExists %}is-success{% endif %}"
type="text"
{% if not IsLogin %}disabled{% endif %}
placeholder="OpenAI API key"
name="openai_key"
autocomplete="off">
<span class="icon is-small is-left">
<i class="fas fa-lock"></i>
</span>
@ -23,9 +30,12 @@
</div>
<div class="field has-addons is-hidden" id="anthropic-field">
<p class="control has-icons-left is-expanded">
<input class="input is-small {% if AnthropicExists %}is-success{% endif %}" type="text"
{% if not IsLogin %}disabled{% endif %} placeholder="Anthropic API key"
name="anthropic_key" autocomplete="off">
<input class="input is-small {% if AnthropicExists %}is-success{% endif %}"
type="text"
{% if not IsLogin %}disabled{% endif %}
placeholder="Anthropic API key"
name="anthropic_key"
autocomplete="off">
<span class="icon is-small is-left">
<i class="fas fa-lock"></i>
</span>
@ -33,9 +43,12 @@
</div>
<div class="field has-addons is-hidden" id="mistral-field">
<p class="control has-icons-left is-expanded">
<input class="input is-small {% if MistralExists %}is-success{% endif %}" type="text"
{%if not IsLogin %}disabled{% endif %} placeholder="Mistral API key"
name="mistral_key" autocomplete="off">
<input class="input is-small {% if MistralExists %}is-success{% endif %}"
type="text"
{% if not IsLogin %}disabled{% endif %}
placeholder="Mistral API key"
name="mistral_key"
autocomplete="off">
<span class="icon is-small is-left">
<i class="fas fa-lock"></i>
</span>
@ -43,8 +56,11 @@
</div>
<div class="field has-addons is-hidden" id="groq-field">
<p class="control has-icons-left is-expanded">
<input class="input is-small {% if GroqExists %}is-success{% endif %}" type="text"
placeholder="Groq API key" {%if not IsLogin %}disabled{% endif %} name="groq_key"
<input class="input is-small {% if GroqExists %}is-success{% endif %}"
type="text"
placeholder="Groq API key"
{% if not IsLogin %}disabled{% endif %}
name="groq_key"
autocomplete="off">
<span class="icon is-small is-left">
<i class="fas fa-lock"></i>
@ -53,8 +69,11 @@
</div>
<div class="field has-addons is-hidden" id="gemini-field">
<p class="control has-icons-left is-expanded">
<input class="input is-small {% if GoogleExists %}is-success{% endif %}" type="text"
placeholder="Google API key" name="google_key" autocomplete="off">
<input class="input is-small {% if GoogleExists %}is-success{% endif %}"
type="text"
placeholder="Google API key"
name="google_key"
autocomplete="off">
<span class="icon is-small is-left">
<i class="fas fa-lock"></i>
</span>
@ -62,8 +81,11 @@
</div>
<div class="field has-addons is-hidden" id="nim-field">
<p class="control has-icons-left is-expanded">
<input class="input is-small {% if NimExists %}is-success{% endif %}" type="text"
placeholder="NIM API key" name="nim_key" autocomplete="off">
<input class="input is-small {% if NimExists %}is-success{% endif %}"
type="text"
placeholder="NIM API key"
name="nim_key"
autocomplete="off">
<span class="icon is-small is-left">
<i class="fas fa-lock"></i>
</span>
@ -71,8 +93,11 @@
</div>
<div class="field has-addons is-hidden" id="perplexity-field">
<p class="control has-icons-left is-expanded">
<input class="input is-small {% if PerplexityExists %}is-success{% endif %}" type="text"
placeholder="Perplexity API key" name="perplexity_key" autocomplete="off">
<input class="input is-small {% if PerplexityExists %}is-success{% endif %}"
type="text"
placeholder="Perplexity API key"
name="perplexity_key"
autocomplete="off">
<span class="icon is-small is-left">
<i class="fas fa-lock"></i>
</span>
@ -80,19 +105,27 @@
</div>
<div class="field has-addons is-hidden" id="fireworks-field">
<p class="control has-icons-left is-expanded">
<input class="input is-small {% if FireworksExists %}is-success{% endif %}" type="text"
placeholder="Fireworks API key" name="fireworks_key" autocomplete="off">
<input class="input is-small {% if FireworksExists %}is-success{% endif %}"
type="text"
placeholder="Fireworks API key"
name="fireworks_key"
autocomplete="off">
<span class="icon is-small is-left">
<i class="fas fa-lock"></i>
</span>
</p>
</div>
<div class="field has-addons is-hidden" id="goose-field"
<div class="field has-addons is-hidden"
id="goose-field"
title="GooseAI chat API will be available soon">
<p class="control has-icons-left is-expanded">
<input class="input is-small {% if GooseaiExists %}is-success{% endif %}" type="text"
{%if not IsLogin %}disabled{% endif %} placeholder="Gooseai API key"
name="goose_key" autocomplete="off" disabled>
<input class="input is-small {% if GooseaiExists %}is-success{% endif %}"
type="text"
{% if not IsLogin %}disabled{% endif %}
placeholder="Gooseai API key"
name="goose_key"
autocomplete="off"
disabled>
<span class="icon is-small is-left">
<i class="fas fa-lock"></i>
</span>
@ -108,7 +141,8 @@
</button>
</p>
<p class="control">
<button id="toggle-keys-button" type="button"
<button id="toggle-keys-button"
type="button"
class="button is-small {% if not AnyExists %}is-danger{% endif %}">
<span class="icon is-small">
<i class="fa-solid fa-chevron-down"></i>
@ -120,15 +154,20 @@
<p id="api-keys-status"></p>
</div>
{% if isBasic or isPremium %}
<a class="button is-small mt-1" href="{{ StripeSubLink }}" target="_blank">
<span class="icon is-small" {% if isPremium %}style="color: #b00202" {%else%}style="color: #126d0f"
{% endif %}>
<a class="button is-small mt-1"
href="{{ StripeSubLink }}"
target="_blank">
<span class="icon is-small"
{% if isPremium %}style="color: #b00202" {% else %}style="color: #126d0f" {% endif %}>
<i class="fa-solid fa-heart"></i>
</span>
<span>Manage subscription</span>
</a>
{% else %}
<a class="button is-small mt-1" hx-get="/pricingTable" hx-target="#chat-container" hx-swap="outerHTML"
<a class="button is-small mt-1"
hx-get="/pricingTable"
hx-target="#chat-container"
hx-swap="outerHTML"
hx-trigger="click">
<span class="icon is-small">
<i class="fa-solid fa-heart"></i>
@ -136,14 +175,20 @@
<span>Subscribe to JADE</span>
</a>
{% endif %}
<a class="button is-small mt-1" hx-get="/generateTermAndService" hx-target="#chat-container"
hx-swap="outerHTML" hx-trigger="click">
<a class="button is-small mt-1"
hx-get="/generateTermAndService"
hx-target="#chat-container"
hx-swap="outerHTML"
hx-trigger="click">
<span class="icon is-small">
<i class="fa-regular fa-file-lines"></i>
</span>
<span>Terms and conditions</span>
</a>
<a class="button is-small mt-1" hx-get="/help" hx-target="#chat-container" hx-swap="outerHTML"
<a class="button is-small mt-1"
hx-get="/help"
hx-target="#chat-container"
hx-swap="outerHTML"
hx-trigger="click">
<span class="icon is-small">
<i class="fa-solid fa-info"></i>

View File

@ -1,6 +1,9 @@
<div class="dropdown is-up is-right {% if IsActive %} is-active{% endif %}" id="usage-dropdown">
<div class="dropdown is-up is-right {% if IsActive %}is-active{% endif %}"
id="usage-dropdown">
<div class="dropdown-trigger">
<button class="button is-small to-reduce-opacity" aria-haspopup="true" aria-controls="dropdown-menu3"
<button class="button is-small to-reduce-opacity"
aria-haspopup="true"
aria-controls="dropdown-menu3"
onclick="this.parentElement.parentElement.classList.toggle('is-active')">
<span class="icon"><i class="fa-regular fa-money-bill-1"></i></span>
</button>
@ -9,8 +12,12 @@
<div class="dropdown-content">
<div class="dropdown-item">
<!-- Placeholder for additional text -->
<div class="content" id="usage-content" style="max-height: 30vh; overflow-y: auto;">
<table class="table is-narrow is-fullwidth is-striped" style="max-width: 200px;">
<div class="content"
id="usage-content"
style="max-height: 30vh;
overflow-y: auto">
<table class="table is-narrow is-fullwidth is-striped"
style="max-width: 200px">
<tbody>
{% for usage in usages %}
<tr>
@ -31,35 +38,37 @@
<!-- Total cost -->
<div class="content totalCostCell">
<p>
<strong>Total: </strong>
<span class="totalCost">
{{ TotalCost|floatformat:2 }}$
</span>
<strong>Total:</strong>
<span class="totalCost">{{ TotalCost|floatformat:2 }}$</span>
</p>
</div>
<!-- Total count -->
<div class="content is-hidden totalCountCell">
<p>
<strong>Total: </strong>
<span class="totalCount">
{{ TotalCount }} messages
</span>
<strong>Total:</strong>
<span class="totalCount">{{ TotalCount }} messages</span>
</p>
</div>
<!-- Top buttons -->
<div class="buttons has-addons is-centered">
<button class="button is-small is-primary" title="Money Spent" id="money-spent-button">
<button class="button is-small is-primary"
title="Money Spent"
id="money-spent-button">
<span class="icon ml-4 mr-4"><i class="fa-regular fa-money-bill-1"></i></span>
</button>
<button class="button is-small" title="Messages Sent" id="messages-sent-button">
<button class="button is-small"
title="Messages Sent"
id="messages-sent-button">
<span class="icon ml-4 mr-4"><i class="fa-regular fa-envelope"></i></span>
</button>
</div>
<!-- Row with text and buttons -->
<div class="level is-mobile">
<div class="level-left">
<button class="button is-small" hx-get="/loadUsageKPI?month={{ DateID }}&offset=-1"
hx-swap="outerHTML" hx-target="#usage-dropdown">
<button class="button is-small"
hx-get="/loadUsageKPI?month={{ DateID }}&offset=-1"
hx-swap="outerHTML"
hx-target="#usage-dropdown">
<span class="icon"><i class="fa-solid fa-chevron-left"></i></span>
</button>
</div>
@ -67,8 +76,10 @@
<p>{{ Date }}</p>
</div>
<div class="level-right">
<button class="button is-small" hx-get="/loadUsageKPI?month={{ DateID }}&offset=1"
hx-swap="outerHTML" hx-target="#usage-dropdown">
<button class="button is-small"
hx-get="/loadUsageKPI?month={{ DateID }}&offset=1"
hx-swap="outerHTML"
hx-target="#usage-dropdown">
<span class="icon"><i class="fa-solid fa-chevron-right"></i></span>
</button>
</div>

View File

@ -1,5 +1,6 @@
<h1 class="title is-1">JADE: Simple Multi-Model Chatbot</h1>
<br /><br />
<br />
<br />
<p>
I often use LLMs and quickly found myself asking GPT4, Gemini and Claude the
same question. I wanted to be able to ask the same question to multiple
@ -15,18 +16,15 @@
When asking a question, you can use multiple models and compare their
responses to choose the best one.
</li>
<li>
The selected response can be used for the next message across all models.
</li>
<li>The selected response can be used for the next message across all models.</li>
</ol>
<p>For example, a response from GPT-4 Omni can be used by Claude Haiku.</p>
<a class="button is-primary mt-2 mb-2" href="/signin">
Try JADE now for free!
</a>
<a class="button is-primary mt-2 mb-2" href="/signin">Try JADE now for free!</a>
<br /><br />
<br />
<br />
<h2>More information</h2>
<p>
@ -39,32 +37,33 @@
<ul>
<li>
<h3>
Get access to all models.<button
class="button ml-2 is-small is-primary is-outlined"
onclick="toggleDetails('all-models-details')"
>
Get access to all models.
<button class="button ml-2 is-small is-primary is-outlined"
onclick="toggleDetails('all-models-details')">
<span class="icon is-small">
<i class="fa-solid fa-info"></i>
</span>
</button>
</h3>
<p id="all-models-details" style="display: none">
With JADE, you can easily switch between models like GPT 3.5 or 4o,
Gemini, Llama, Mistral, Claude, and more. Even custom endpoint.
<br /><br />This means you can choose the best model for your specific
With JADE, you can easily switch between models like GPT 3.5 or 4o, Gemini, Llama, Mistral, Claude, and more. Even custom endpoint.
<br />
<br />
This means you can choose the best model for your specific
needs, whether it's for general knowledge, creative writing, or technical
expertise. Having access to multiple models allows you to take advantage
of their unique strengths and weaknesses, ensuring you get the most
accurate and relevant responses. (See all models available in the last
section)<br /><br />
section)
<br />
<br />
</p>
</li>
<li>
<h3>
Get the best answer from multiple models.<button
class="button ml-2 is-small is-primary is-outlined"
onclick="toggleDetails('multi-models-details')"
>
Get the best answer from multiple models.
<button class="button ml-2 is-small is-primary is-outlined"
onclick="toggleDetails('multi-models-details')">
<span class="icon is-small">
<i class="fa-solid fa-info"></i>
</span>
@ -73,16 +72,19 @@
<p id="multi-models-details" style="display: none">
You can ask a question and receive responses from several models at once,
enabling you to compare their answers and choose the most suitable one.
<br /><br />This feature is particularly useful for complex queries where
different models might offer unique insights or solutions.<br /><br />
<br />
<br />
This feature is particularly useful for complex queries where
different models might offer unique insights or solutions.
<br />
<br />
</p>
</li>
<li>
<h3>
Even from the same model.<button
class="button ml-2 is-small is-primary is-outlined"
onclick="toggleDetails('same-models-details')"
>
Even from the same model.
<button class="button ml-2 is-small is-primary is-outlined"
onclick="toggleDetails('same-models-details')">
<span class="icon is-small">
<i class="fa-solid fa-info"></i>
</span>
@ -90,17 +92,21 @@
</h3>
<p id="same-models-details" style="display: none">
The core feature of JADE are the bots. Each bot have a name, model,
temperature and system prompt. <br /><br />You can create as many bot as
temperature and system prompt.
<br />
<br />
You can create as many bot as
you want and select as many to answer each question. An example is
creating the same model that reponse in different language.<br /><br />
creating the same model that reponse in different language.
<br />
<br />
</p>
</li>
<li>
<h3>
Reduce Hallucination.<button
class="button is-small ml-2 is-primary is-outlined"
onclick="toggleDetails('reduce-hallucination-details')"
>
Reduce Hallucination.
<button class="button is-small ml-2 is-primary is-outlined"
onclick="toggleDetails('reduce-hallucination-details')">
<span class="icon is-small">
<i class="fa-solid fa-info"></i>
</span>
@ -108,17 +114,21 @@
</h3>
<p id="reduce-hallucination-details" style="display: none">
AI models sometimes generate information that is inaccurate or misleading,
a phenomenon known as "hallucination." <br /><br />By using multiple
a phenomenon known as "hallucination."
<br />
<br />
By using multiple
models, JADE reduces each model's bias. This ensures that the responses
you receive are more reliable and trustworthy.<br /><br />
you receive are more reliable and trustworthy.
<br />
<br />
</p>
</li>
<li>
<h3>
Pay only for what you use or not at all.<button
class="button ml-2 is-small is-primary is-outlined"
onclick="toggleDetails('flexible-pricing-details')"
>
Pay only for what you use or not at all.
<button class="button ml-2 is-small is-primary is-outlined"
onclick="toggleDetails('flexible-pricing-details')">
<span class="icon is-small">
<i class="fa-solid fa-info"></i>
</span>
@ -126,19 +136,26 @@
</h3>
<p id="flexible-pricing-details" style="display: none">
JADE use API, so you get access to free credits or tiers depending of the
provider (see next section). <br /><br />This is particularly beneficial
provider (see next section).
<br />
<br />
This is particularly beneficial
for users who may not need to use the chatbot extensively. Once the free
credit use, you pay based on the length of you message and the response
generated in tokens (a token is around 3 characters). Groq and Google also
offer free tiers that are enough for conversation.<<br /><br />The app itself is free until 200 messages per month then 0.95$ per month.<br /><br />
offer free tiers that are enough for conversation.<
<br />
<br />
The app itself is free until 200 messages per month then 0.95$ per month.
<br />
<br />
</p>
</li>
<li>
<h3>
All providers and models.<button
class="button ml-2 is-small is-primary is-outlined"
onclick="toggleDetails('provider-details')"
>
All providers and models.
<button class="button ml-2 is-small is-primary is-outlined"
onclick="toggleDetails('provider-details')">
<span class="icon is-small">
<i class="fa-solid fa-info"></i>
</span>