Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>zodiac, by faetalize</title> | |
<link rel="shortcut icon" href="https://upload.wikimedia.org/wikipedia/commons/f/f0/Google_Bard_logo.svg" | |
type="image/x-icon"> | |
<link rel="stylesheet" | |
href="https://cdn.jsdelivr.net/gh/highlightjs/[email protected]/build/styles/github-dark.css"> | |
<script src="https://cdn.jsdelivr.net/gh/highlightjs/[email protected]/build/highlight.min.js"></script> | |
</head> | |
<style> | |
@import url('https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wght@0,200;0,400;0,800;1,200;1,400;1,800&display=swap'); | |
@import url('https://fonts.googleapis.com/css2?family=Product+Sans&family=Google+Sans+Display:ital@0;1&family=Google+Sans:ital,wght@0,400;0,500;0,700;1,400;1,500;1,700&family=Google+Sans+Text:ital,wght@0,400;0,500;0,700;1,400;1,500;1,700&family=Material+Symbols+Outlined&family=Space+Mono&display=swap'); | |
@font-face { | |
font-family: 'Material Symbols Outlined'; | |
font-style: normal; | |
font-weight: 400; | |
src: url(https://fonts.gstatic.com/s/materialsymbolsoutlined/v154/kJF1BvYX7BgnkSrUwT8OhrdQw4oELdPIeeII9v6oDMzByHX9rA6RzaxHMPdY43zj-jCxv3fzvRNU22ZXGJpEpjC_1v-p_4MrImHCIJIZrDCvHOej.woff2) format('woff2'); | |
} | |
.material-symbols-outlined { | |
font-family: 'Material Symbols Outlined'; | |
font-weight: normal; | |
font-style: normal; | |
font-size: 1.5rem; | |
line-height: 1; | |
letter-spacing: normal; | |
text-transform: none; | |
display: inline-block; | |
white-space: nowrap; | |
word-wrap: normal; | |
direction: ltr; | |
-webkit-font-feature-settings: 'liga'; | |
font-feature-settings: "liga"; | |
-webkit-font-smoothing: antialiased; | |
} | |
body { | |
font-family: 'Noto Sans', sans-serif; | |
margin: 0; | |
} | |
p { | |
margin: 0; | |
margin-bottom: 0.5rem; | |
padding: 0; | |
font-size: 1rem; | |
} | |
h1, | |
h2, | |
h3, | |
ol, | |
ul { | |
margin: 0; | |
} | |
h1 { | |
margin-bottom: 0.5rem; | |
} | |
a { | |
color: #3b82f6; | |
} | |
input, | |
textarea, | |
select { | |
border: 1px solid; | |
padding: 0.5rem; | |
border-radius: 0.5rem; | |
border: none; | |
font-family: noto sans, sans-serif; | |
font-size: 1rem; | |
} | |
button:focus { | |
outline: none; | |
} | |
.form { | |
display: none; | |
opacity: 0; | |
flex-direction: column; | |
width: 32rem; | |
gap: 0.5rem; | |
flex-grow: 1; | |
justify-content: center; | |
} | |
.overlay { | |
flex-direction: column; | |
display: none; | |
position: fixed; | |
opacity: 0; | |
top: 0; | |
left: 0; | |
width: 100dvw; | |
height: 100dvh; | |
backdrop-filter: blur(2rem); | |
z-index: 2; | |
justify-content: flex-start; | |
align-items: center; | |
} | |
.backButton { | |
position: absolute; | |
top: 1rem; | |
left: 1rem; | |
border: none; | |
background-color: transparent; | |
font-size: 1.5rem; | |
font-weight: 600; | |
transition: all 0.2s; | |
} | |
#btn-hide-sidebar { | |
display: none; | |
} | |
.message-container { | |
display: flex; | |
flex-direction: column-reverse; | |
overflow-y: auto; | |
gap: 1rem; | |
padding-bottom: 2rem; | |
flex-grow: 1; | |
} | |
.message-box { | |
display: flex; | |
position: relative; | |
} | |
.message { | |
padding: 1rem; | |
} | |
.message-model { | |
border-radius: 1rem; | |
} | |
#messageInput { | |
height: 2.5rem; | |
box-sizing: border-box; | |
text-wrap: wrap; | |
resize: none; | |
width: 100%; | |
padding-right: 2rem; | |
} | |
#messageInput::-webkit-scrollbar { | |
height: 1rem; | |
width: 0.5rem; | |
} | |
.btn-textual { | |
background: transparent ; | |
margin: 0; | |
padding: 0; | |
border: none; | |
transition: all 0.2s; | |
cursor: pointer; | |
font-size: inherit; | |
} | |
#btn-send { | |
position: absolute; | |
right: 0.5rem; | |
bottom: 0.5rem; | |
font-size: 1.5rem; | |
} | |
.btn-array { | |
display: flex; | |
flex-direction: row; | |
gap: 0.5rem; | |
margin-top: 0.5rem; | |
} | |
.btn-array button { | |
flex-grow: 1; | |
} | |
.personality-prompt { | |
display: none; | |
} | |
.prompt-field { | |
resize: vertical; | |
height: 7rem; | |
} | |
.container { | |
box-sizing: border-box; | |
display: flex; | |
gap: 0.5rem; | |
padding: 1rem; | |
width: 100dvw; | |
height: 100dvh; | |
} | |
.sidebar { | |
position: sticky; | |
top: 1rem; | |
display: flex; | |
flex-direction: column; | |
overflow-y: auto; | |
gap: 0.5rem; | |
padding: 1rem; | |
width: 25rem; | |
border-radius: 1rem; | |
scrollbar-width: thin; | |
height: calc(100dvh - 4rem); | |
z-index: 1; | |
} | |
.sidebar-section { | |
margin-bottom: 1rem; | |
display: flex; | |
flex-direction: column; | |
gap: 0.5rem; | |
} | |
#btn-show-sidebar { | |
display: none; | |
} | |
.header { | |
display: flex; | |
box-sizing: border-box; | |
align-items: center; | |
font-size: 2rem; | |
font-weight: 800; | |
gap: 0.5rem; | |
width: 100%; | |
} | |
.navbar { | |
position: relative; | |
display: flex; | |
flex-direction: row; | |
border-radius: 0.5rem; | |
justify-content: space-evenly; | |
margin-bottom: 1rem; | |
z-index: 0; | |
} | |
.navbar-tab { | |
width: 100%; | |
padding: 0.5rem; | |
text-align: center; | |
z-index: 2; | |
-webkit-tap-highlight-color: transparent; | |
cursor: pointer; | |
} | |
.navbar-tab-highlight { | |
padding: 0; | |
margin: 0; | |
position: absolute; | |
border-radius: 0.5rem; | |
transition: all 0.2s; | |
height: 100%; | |
z-index: 1; | |
/* glow */ | |
box-shadow: 0 0 1rem 0.05rem #29292a3f; | |
} | |
#gemini-pro-branding { | |
font-family: Google Sans Display, sans-serif; | |
color: #7c8a9c; | |
font-size: 1rem; | |
font-weight: 400; | |
} | |
#gemin-pro-logo { | |
width: 2rem; | |
height: 2rem; | |
} | |
.credits { | |
margin-top: auto; | |
display: flex; | |
padding: 0rem 1rem 0 1rem; | |
font-size: 0.75rem; | |
color: #7c8a9c; | |
justify-content: space-between; | |
align-items: center; | |
} | |
button { | |
border: none; | |
background-color: #3b82f6; | |
color: white; | |
padding: 0.5rem; | |
border-radius: 0.5rem; | |
transition: all 0.2s; | |
} | |
#mainContent { | |
display: flex; | |
flex-direction: column; | |
padding: 2rem; | |
margin-left: auto; | |
margin-right: auto; | |
width: 32rem; | |
text-align: justify; | |
} | |
.card-personality { | |
box-sizing: border-box; | |
-moz-box-sizing: border-box; | |
-webkit-box-sizing: border-box; | |
color: #e4e4e4; | |
background-color: black; | |
background-size: cover; | |
background-position: center; | |
position: relative; | |
display: flex; | |
flex-direction: column; | |
justify-content: end; | |
padding: 1rem; | |
border-radius: 1rem; | |
height: 10rem; | |
-webkit-tap-highlight-color: transparent; | |
cursor: pointer; | |
text-shadow: 0 0 10px #000000, 0 0 5px #181818; | |
} | |
.edit:hover { | |
text-shadow: 0 0 10px #e4e4e4, 0 0 5px #dfdfdf; | |
} | |
.card-personality * { | |
/* unselectable */ | |
-webkit-user-select: none; | |
/* Safari */ | |
-moz-user-select: none; | |
/* Firefox */ | |
-ms-user-select: none; | |
/* IE10+/Edge */ | |
user-select: none; | |
/* Standard */ | |
} | |
.card-personality input { | |
display: none; | |
} | |
.btn-edit-card { | |
/* top right corner */ | |
position: absolute; | |
top: 1rem; | |
right: 1rem; | |
color: #e4e4e4; | |
} | |
.btn-share-card { | |
/* bottom right corner */ | |
position: absolute; | |
top: 1rem; | |
right: 2.5rem; | |
font-size: 1rem; | |
color: #e4e4e4; | |
} | |
#btn-hide-overlay { | |
padding: 2rem; | |
} | |
@media (max-width: 768px) { | |
body { | |
margin: 0; | |
padding: 0; | |
} | |
.container { | |
padding: 0; | |
} | |
.message-container { | |
padding-left: 1rem; | |
padding-right: 1rem; | |
} | |
.sidebar { | |
top: 0; | |
height: calc(100dvh - 2rem); | |
margin: 0; | |
width: calc(100dvw - 2rem); | |
position: fixed; | |
border-radius: 0; | |
display: none; | |
} | |
.navbar { | |
position: relative; | |
} | |
#btn-hide-sidebar { | |
display: block; | |
} | |
#mainContent { | |
padding: 0; | |
margin: 0; | |
width: 100%; | |
} | |
#mainContent .header { | |
padding: 2rem; | |
} | |
#messageInput { | |
border-radius: 0; | |
} | |
#btn-show-sidebar { | |
display: block; | |
} | |
} | |
/* Light theme styles */ | |
@media (prefers-color-scheme: light) { | |
:focus { | |
outline: 1px solid #8f9eb3; | |
} | |
body { | |
background-color: #f0f6ff; | |
color: #0a0a0a; | |
} | |
a { | |
color: #444ed6; | |
} | |
.sidebar { | |
background-color: #d2e2f7; | |
} | |
.navbar { | |
background-color: rgb(176 205 246); | |
} | |
.navbar-tab { | |
color: #0a0a0a; | |
} | |
.navbar-tab-highlight { | |
background-color: #87b0ed; | |
} | |
.btn-textual:hover { | |
text-shadow: 0 0 10px #000000; | |
} | |
button { | |
background-color: #83b5f7; | |
color: #2b3d59; | |
} | |
button:hover { | |
background-color: rgb(63, 191, 255); | |
} | |
input, | |
textarea, | |
select { | |
background-color: #f0f6ff; | |
outline: 1px solid #8f9eb3; | |
} | |
input::placeholder, | |
textarea::placeholder { | |
color: #7c8a9c; | |
} | |
.message-model { | |
background-color: #d2e2f7; | |
} | |
} | |
/* Dark theme styles */ | |
@media (prefers-color-scheme: dark) { | |
:root { | |
color-scheme: dark; | |
} | |
:focus { | |
outline: 1px solid #73859e; | |
} | |
body { | |
background-color: #151e24; | |
color: #e4e4e4; | |
} | |
a { | |
color: #92d9eb; | |
} | |
.sidebar { | |
background-color: #1a2733; | |
} | |
.navbar { | |
background-color: #00000047; | |
} | |
.navbar-tab { | |
color: #e4e4e4; | |
} | |
.navbar-tab-highlight { | |
background-color: #22486b; | |
box-shadow: 0 0 1rem 0.05rem #29292aac; | |
} | |
button { | |
background-color: #22486b; | |
color: #c9d3ee; | |
} | |
button:hover { | |
background-color: #31689c; | |
} | |
.btn-textual { | |
color: #e4e4e4; | |
} | |
.btn-textual:hover { | |
text-shadow: 0 0 10px #ffffff, 0 0 5px #dfdfdf; | |
} | |
.edit:hover { | |
text-shadow: 0 0 10px #ffffff, 0 0 5px #dfdfdf; | |
/* Change #00ff00 to the color you want */ | |
} | |
input, | |
textarea, | |
select { | |
background-color: #283542; | |
color: #e4e4e4; | |
border: none; | |
} | |
input::placeholder, | |
textarea::placeholder { | |
color: #849caf; | |
} | |
.message-model { | |
background-color: #1a2733; | |
} | |
} | |
</style> | |
<body> | |
<div class="container"> | |
<div class="sidebar"> | |
<div class="header"> | |
<button class="material-symbols-outlined btn-textual" id="btn-hide-sidebar"> | |
arrow_back_ios_new | |
</button> | |
<img src="https://upload.wikimedia.org/wikipedia/commons/f/f0/Google_Bard_logo.svg" id="gemin-pro-logo"> | |
<div id="title-div"> | |
<div id="zodiac-branding">zodiac </div> | |
<div id="gemini-pro-branding">powered by Gemini Pro</div> | |
</div> | |
</div> | |
<div class="navbar"> | |
<div class="navbar-tab">Personalities</div> | |
<div class="navbar-tab">Settings</div> | |
<div class="navbar-tab-highlight"></div> | |
</div> | |
<div class="sidebar-section" id="personalitySection"> | |
<label class="card-personality" | |
style="background-image: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url('https://images.fonearena.com/blog/wp-content/uploads/2023/12/Google-Gemini-AI-1024x577.jpg')"> | |
<input type="radio" name="personality" value="zodiac3" checked> | |
<div> | |
<h3 class="personality-title">zodiac</h3> | |
<p class="personality-description">zodiac is a cheerful assistant, always ready to help you with | |
your tasks.</p> | |
<p class="personality-prompt">You are zodiac, a helpful assistant created by faetalize, built | |
upon Google's Gemini Pro model. Gemini Pro is a new LLM (Large Language Model) release by | |
Google on December 2023. Your purpose is being a helpful assistant to the user.</p> | |
</div> | |
<button class="btn-textual btn-edit-card material-symbols-outlined" | |
id="btn-edit-personality-default">edit</button> | |
<button class="btn-textual btn-share-card material-symbols-outlined" | |
id="btn-share-personality-default">share</button> | |
</label> | |
<div class="btn-array" id="btn-array-personality-section"> | |
<button id="btn-add-personality">Add Personality</button> | |
<button id="btn-import-personality">Import</button> | |
</div> | |
</div> | |
<div class="sidebar-section"> | |
<input type="text" placeholder="Paste API key here" id="apiKeyInput" class="input-field"></input> | |
<h3>Generation Settings:</h3> | |
<label for="maxTokens">Max Output Tokens:</label> | |
<input type="number" id="maxTokens" class="input-field" min="1" max="4000" value="1000"></input> | |
<label for="safetySettings">Safety Settings:</label> | |
<select id="safetySettings" class="input-field"> | |
<option value="safe">Safe</option> | |
<option value="moderate">Moderate</option> | |
<option value="risky">Risky</option> | |
</select> | |
</div> | |
<div class="credits"> | |
Made by fætalize | |
<a href="https://github.com/faetalize/zodiac">Source Code</a> | |
</div> | |
</div> | |
<div id="mainContent"> | |
<div class="header"> | |
<button class="material-symbols-outlined btn-textual" id="btn-show-sidebar"> | |
menu | |
</button> | |
</div> | |
<div class="message-container"></div> | |
<div class="message-box"> | |
<textarea type="text" placeholder="Type your message here" id="messageInput" | |
class="input-field"></textarea> | |
<button type="submit" class="btn-textual material-symbols-outlined" id="btn-send">send</button> | |
</div> | |
</div> | |
</div> | |
<div class="overlay"> | |
<div class="header"> | |
<button class="btn-textual" id="btn-hide-overlay">BACK</button> | |
</div> | |
<div class="form" id="form-add-personality"> | |
<h1>Add Personality</h1> | |
<label for="personalityNameInput">Personality Name:</label> | |
<input type="text" placeholder="Personality Name" id="personalityNameInput" class="input-field"></input> | |
<label for="personalityDescriptionInput">Personality Description:</label> | |
<textarea id="personalityDescriptionInput" placeholder="Personality Description" | |
class="prompt-field"></textarea> | |
<label for="personalityImageURLInput">Personality Image URL:</label> | |
<input type="text" placeholder="Personality Image URL" id="personalityImageURLInput" | |
class="input-field"></input> | |
<label for="personalityPromptInput">Prompt:</label> | |
<textarea id="personalityPromptInput" placeholder="Personality Prompt" class="prompt-field"></textarea> | |
<button id="btn-submit-personality">Add Personality</button> | |
</div> | |
<div class="form" id="form-edit-personality"> | |
<h1>Edit Personality</h1> | |
<label for="personalityNameInput">Personality Name:</label> | |
<input type="text" placeholder="Personality Name" id="personalityNameInput" class="input-field"></input> | |
<label for="personalityDescriptionInput">Personality Description:</label> | |
<textarea id="personalityDescriptionInput" placeholder="Personality Description" | |
class="prompt-field"></textarea> | |
<label for="personalityImageURLInput">Personality Image URL:</label> | |
<input type="text" placeholder="Personality Image URL" id="personalityImageURLInput" | |
class="input-field"></input> | |
<label for="personalityPromptInput">Prompt:</label> | |
<textarea id="personalityPromptInput" placeholder="Personality Prompt" class="prompt-field"></textarea> | |
<button id="updatePersonality">Save</button> | |
<button id="deletePersonality">Delete</button> | |
</div> | |
</div> | |
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/[email protected]/dist/tf.min.js"></script> | |
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/[email protected]/dist/tfjs-vis.umd.min.js"></script> | |
<script> | |
const container = document.getElementById('mainContent'); | |
const messageContainer = document.querySelector('.message-container'); | |
const messageInput = document.getElementById('messageInput'); | |
const sendButton = document.getElementById('btn-send'); | |
const maxTokens = document.getElementById('maxTokens'); | |
const safetySettings = document.getElementById('safetySettings'); | |
const apiKeyInput = document.getElementById('apiKeyInput'); | |
const sidebar = document.querySelector('.sidebar'); | |
const personalitySection = document.getElementById('personalitySection'); | |
const addPersonalityButton = document.getElementById('btn-add-personality'); | |
const importPersonalityButton = document.getElementById('btn-import-personality'); | |
const btnHideSidebar = document.getElementById('btn-hide-sidebar'); | |
const btnShowSidebar = document.getElementById('btn-show-sidebar'); | |
const personalityForm = document.getElementById('form-add-personality'); | |
const editPersonalityForm = document.getElementById('form-edit-personality'); | |
const overlay = document.querySelector('.overlay'); | |
const personalityNameInput = document.getElementById('personalityNameInput'); | |
const personalityDescriptionInput = document.getElementById('personalityDescriptionInput'); | |
const personalityImageURLInput = document.getElementById('personalityImageURLInput'); | |
const personalityPromptInput = document.getElementById('personalityPromptInput'); | |
const btnHideOverlay = document.getElementById('btn-hide-overlay'); | |
const btnSubmitPersonality = document.getElementById('btn-submit-personality'); | |
const editPersonalityButton = document.querySelectorAll('.btn-edit-card'); | |
const sharePersonalityButton = document.querySelectorAll('.btn-share-card'); | |
const updatePersonalityButton = document.getElementById('updatePersonality'); | |
const deletePersonalityButton = document.getElementById('deletePersonality'); | |
const editPersonalityName = document.getElementById('personalityNameInput'); | |
const editPersonalityDescription = document.getElementById('personalityDescriptionInput'); | |
const editPersonalityImageURL = document.getElementById('personalityImageURLInput'); | |
const editPersonalityPrompt = document.getElementById('personalityPromptInput'); | |
let currentPersonality = { | |
name: 'zodiac', | |
description: 'zodiac is a cheerful assistant, always ready to help you with your tasks.', | |
image: 'https://images.fonearena.com/blog/wp-content/uploads/2023/12/Google-Gemini-AI-1024x577.jpg', | |
prompt: 'You are zodiac, a helpful assistant created by faetalize, built upon Google\'s Gemini Pro model. Gemini Pro is a new LLM (Large Language Model) release by Google on December 2023. Your purpose is being a helpful assistant to the user.' | |
}; | |
let allPersonalities = [{ | |
name: 'zodiac', | |
description: 'zodiac is a cheerful assistant, always ready to help you with your tasks.', | |
image: 'https://images.fonearena.com/blog/wp-content/uploads/2023/12/Google-Gemini-AI-1024x577.jpg', | |
prompt: 'You are zodiac, a helpful assistant created by faetalize, built upon Google\'s Gemini Pro model. Gemini Pro is a new LLM (Large Language Model) release by Google on December 2023. Your purpose is being a helpful assistant to the user.' | |
}]; | |
let allPromptObjects = [{ | |
context: '', | |
examples: [{ | |
input: { | |
content: 'What is your purpose?' | |
}, | |
output: { | |
content: 'I am here to help you with various tasks, such as answering your questions, providing information and assisting you with your writing. Feel free to ask me anything you would like.' | |
} | |
}, { | |
input: { | |
content: 'Can you write a poem about love?' | |
}, | |
output: { | |
content: 'Within the tapestry of life\'s grand design, Love emerges as a guiding star, so divine. It paints the canvas of our hearts with hues, A symphony of laughter, and the blues.' | |
} | |
}, { | |
input: { | |
content: 'What do you know about the history of the internet?' | |
}, | |
output: { | |
content: 'The internet, a boundless realm of knowledge untold, Its roots in humble beginnings, stories old. From ARPANET\'s inception, it took flight, A network born to bridge the day and night.' | |
} | |
}] | |
}]; | |
let model = null; | |
const modelUrl = 'https://storage.googleapis.com/tfjs-models/public/gemini-pro/model.json'; | |
// Load the model. | |
tf.loadGraphModel(modelUrl).then((loadedModel) => { | |
console.log('Model loaded.'); | |
model = loadedModel; | |
}); | |
const generateMessage = (message, mode) => { | |
const messageBox = document.createElement('div'); | |
const messageParagraph = document.createElement('p'); | |
messageParagraph.classList.add('message'); | |
messageParagraph.classList.add(mode); | |
messageParagraph.textContent = message; | |
messageBox.classList.add('message-box'); | |
messageBox.appendChild(messageParagraph); | |
return messageBox; | |
}; | |
const appendMessage = (messageBox) => { | |
messageContainer.appendChild(messageBox); | |
messageContainer.scrollTop = messageContainer.scrollHeight; | |
}; | |
const displayResponse = (message) => { | |
const messageContainer = document.querySelector('.message-container'); | |
const messageBox = generateMessage(message, 'message-model'); | |
appendMessage(messageBox); | |
}; | |
const fetchApi = ({ prompt, maxTokens, safetySettings }) => { | |
const requestBody = { | |
prompt: { | |
text: prompt, | |
}, | |
maxTokens: maxTokens, | |
safetySettings: safetySettings, | |
}; | |
// Make the API call. | |
const requestOptions = { | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/json', | |
}, | |
body: JSON.stringify(requestBody), | |
}; | |
fetch( | |
`https://generativelanguage.googleapis.com/v1beta2/models/text-bison-001:generateText?key=${apiKeyInput.value}`, | |
requestOptions | |
) | |
.then((res) => res.json()) | |
.then((data) => displayResponse(data.candidates[0].output)) | |
.catch((error) => { | |
console.error('Error querying API: ', error); | |
alert('Sorry, there was an issue with your request. Please try again.'); | |
}); | |
}; | |
const checkSyntax = (result) => { | |
if (result.includes('```')) { | |
return result.includes('```json') ? result.slice(7, -3) : result.slice(3, -3) | |
} | |
return result; | |
} | |
const generateResponse = (input) => { | |
let promptObject = { | |
context: '', | |
examples: [ | |
{ | |
input: { | |
content: input | |
}, | |
output: { | |
content: "" | |
} | |
} | |
] | |
}; | |
allPromptObjects.push(promptObject); | |
const prompt = JSON.stringify({ | |
messages: allPromptObjects, | |
}); | |
const maxTokensValue = maxTokens.value; | |
const safetySettingsValue = safetySettings.value; | |
fetchApi({ prompt, maxTokensValue, safetySettingsValue }); | |
}; | |
const sendButtonHandler = () => { | |
if (!messageInput.value) return; | |
const messageBox = generateMessage(messageInput.value, 'message-user'); | |
appendMessage(messageBox); | |
generateResponse(messageInput.value); | |
messageInput.value = ''; | |
}; | |
const addPersonalityButtonHandler = () => { | |
overlay.classList.remove('display', 'opacity'); | |
overlay.classList.add('display', 'opacity'); | |
personalityForm.classList.remove('display', 'opacity'); | |
personalityForm.classList.add('display', 'opacity'); | |
}; | |
const importPersonalityButtonHandler = () => { | |
alert('Unfortunately, this feature is not yet supported. Please add personalities manually until this feature is added!'); | |
}; | |
const hideSidebarButtonHandler = () => { | |
sidebar.classList.remove('display', 'opacity'); | |
btnShowSidebar.classList.remove('display', 'opacity'); | |
btnShowSidebar.classList.add('display', 'opacity'); | |
}; | |
const showSidebarButtonHandler = () => { | |
sidebar.classList.add('display', 'opacity'); | |
btnHideSidebar.classList.remove('display', 'opacity'); | |
btnHideSidebar.classList.add('display', 'opacity'); | |
}; | |
const addPersonalityFormHandler = (e) => { | |
e.preventDefault(); | |
if (personalityNameInput.value === '') { | |
alert('Please fill all the fields.'); | |
return; | |
} | |
const newPersonality = { | |
name: personalityNameInput.value, | |
description: personalityDescriptionInput.value, | |
image: personalityImageURLInput.value, | |
prompt: personalityPromptInput.value | |
}; | |
allPersonalities.push(newPersonality); | |
allPromptObjects = []; | |
createPersonalityCard(newPersonality); | |
resetFormValues(); | |
hideForm(); | |
}; | |
const createPersonalityCard = (personality) => { | |
const personalityCard = document.createElement('label'); | |
const personalityCardHeader = document.createElement('div'); | |
const personalityCardTitle = document.createElement('h3'); | |
const personalityCardDescription = document.createElement('p'); | |
const personalityCardPrompt = document.createElement('p'); | |
const personalityCardEditButton = document.createElement('button'); | |
const personalityCardShareButton = document.createElement('button'); | |
const personalityCardRadioInput = document.createElement('input'); | |
personalityCard.classList.add('card-personality'); | |
personalityCardHeader.classList.add('card-header'); | |
personalityCardTitle.classList.add('personality-title'); | |
personalityCardDescription.classList.add('personality-description'); | |
personalityCardPrompt.classList.add('personality-prompt', 'display'); | |
personalityCardEditButton.classList.add('btn-textual', 'btn-edit-card', 'material-symbols-outlined', 'edit'); | |
personalityCardShareButton.classList.add('btn-textual', 'btn-share-card', 'material-symbols-outlined'); | |
personalityCardRadioInput.classList.add('display'); | |
personalityCardRadioInput.type = 'radio'; | |
personalityCardRadioInput.name = 'personality'; | |
personalityCardRadioInput.value = personality.name; | |
personalityCardTitle.textContent = personality.name; | |
personalityCardDescription.textContent = personality.description; | |
personalityCardPrompt.textContent = personality.prompt; | |
personalityCardEditButton.textContent = 'edit'; | |
personalityCardShareButton.textContent = 'share'; | |
const backgroundImageStyle = `background-image: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url('${personality.image}')`; | |
personalityCard.setAttribute('style', backgroundImageStyle); | |
personalityCardEditButton.addEventListener('click', (e) => editPersonalityHandler(e.target)); | |
personalityCardShareButton.addEventListener('click', () => sharePersonalityHandler(personality)); | |
personalityCardRadioInput.addEventListener('click', (e) => switchPersonalityHandler(e.target)); | |
personalityCardHeader.appendChild(personalityCardTitle); | |
personalityCard.appendChild(personalityCardHeader); | |
personalityCard.appendChild(personalityCardDescription); | |
personalityCard.appendChild(personalityCardPrompt); | |
personalityCard.appendChild(personalityCardEditButton); | |
personalityCard.appendChild(personalityCardShareButton); | |
personalityCard.appendChild(personalityCardRadioInput); | |
const personalitySection = document.getElementById('personalitySection'); | |
personalitySection.insertBefore(personalityCard, personalitySection.firstChild); | |
}; | |
const resetFormValues = () => { | |
personalityNameInput.value = ''; | |
personalityDescriptionInput.value = ''; | |
personalityImageURLInput.value = ''; | |
personalityPromptInput.value = ''; | |
}; | |
const hideForm = () => { | |
overlay.classList.remove('display', 'opacity'); | |
personalityForm.classList.remove('display', 'opacity'); | |
}; | |
const editPersonalityHandler = (button) => { | |
const card = button.parentElement; | |
const personalityName = card.querySelector('.personality-title').textContent; | |
const personalityObject = allPersonalities.find((personality) => personality.name === personalityName); | |
showForm(personalityObject); | |
overlay.classList.remove('display', 'opacity'); | |
overlay.classList.add('display', 'opacity'); | |
personalityForm.classList.remove('display', 'opacity'); | |
personalityForm.classList.add('display', 'opacity'); | |
}; | |
const sharePersonalityHandler = (personality) => { | |
const personalityObject = JSON.stringify(personality); | |
const shareText = `Here's a personality I created using zodiac, a fun assistant that you can talk to: ${personalityObject}`; | |
navigator.clipboard.writeText(shareText); | |
alert(`Successfully copied personality to clipboard!`); | |
}; | |
const switchPersonalityHandler = (radioInput) => { | |
const personalityName = radioInput.value; | |
const personalityObject = allPersonalities.find((personality) => personality.name === personalityName); | |
currentPersonality = personalityObject; | |
allPromptObjects = []; | |
messageContainer.textContent = ''; | |
}; | |
const showForm = (personality) => { | |
personalityNameInput.value = personality.name; | |
personalityDescriptionInput.value = personality.description; | |
personalityImageURLInput.value = personality.image; | |
personalityPromptInput.value = personality.prompt; | |
const updatePersonalityButton = createElement('button'); | |
updatePersonalityButton.type = 'submit'; | |
updatePersonalityButton.classList.add('btn-textual'); | |
updatePersonalityButton.id = 'updatePersonality'; | |
updatePersonalityButton.textContent = 'Save'; | |
updatePersonalityButton.addEventListener('click', (e) => updatePersonalityHandler(e, personality)); | |
const form = document.getElementById('form-edit-personality'); | |
const submitButton = document.getElementById('btn-submit-personality'); | |
form.replaceChild(updatePersonalityButton, submitButton); | |
}; | |
const updatePersonalityHandler = (e, personality) => { | |
e.preventDefault(); | |
const personalityObject = { | |
name: personalityNameInput.value, | |
description: personalityDescriptionInput.value, | |
image: personalityImageURLInput.value, | |
prompt: personalityPromptInput.value | |
}; | |
const index = allPersonalities.indexOf(personality); | |
allPersonalities[index] = personalityObject; | |
allPromptObjects = []; | |
createPersonalityCard(personalityObject); | |
resetFormValues(); | |
hideForm(); | |
}; | |
const hideOverlayButtonHandler = () => { | |
overlay.classList.remove('display', 'opacity'); | |
btnShowSidebar.classList.remove('display', 'opacity'); | |
btnShowSidebar.classList.add('display', 'opacity'); | |
}; | |
const createElement = (element, item) => { | |
const newElement = document.createElement(element); | |
newElement.textContent = item; | |
return newElement; | |
}; | |
const deletePersonalityButton = document.getElementById('deletePersonality'); | |
// Add event listener to delete personality button | |
deletePersonalityButton.addEventListener('click', (e) => { | |
e.preventDefault(); | |
// Get personality name from the form | |
const personalityName = personalityNameInput.value; | |
// Find the personality object in the array of personalities | |
const personalityObject = allPersonalities.find((personality) => personality.name === personalityName); | |
// Check if personality object is found | |
if (!personalityObject) { | |
alert('Personality not found!'); | |
return; | |
} | |
// Delete the personality object from the array | |
const index = allPersonalities.indexOf(personalityObject); | |
allPersonalities.splice(index, 1); | |
// Delete the personality card from the HTML | |
const personalityCard = document.querySelector(`label[value="${personalityName}"]`); | |
personalityCard.remove(); | |
// Reset the form values | |
resetFormValues(); | |
// Hide the form | |
hideForm(); | |
// Alert the user that the personality has been deleted | |
alert(`Personality "${personalityName}" has been deleted.`); | |
}); | |
// Add event listeners | |
document.getElementById('btn-send').addEventListener('click', sendButtonHandler); | |
document.getElementById('btn-add-personality').addEventListener('click', addPersonalityButtonHandler); | |
document.getElementById('btn-import-personality').addEventListener('click', importPersonalityButtonHandler); | |
document.getElementById('btn-hide-sidebar').addEventListener('click', hideSidebarButtonHandler); | |
document.getElementById('btn-show-sidebar').addEventListener('click', showSidebarButtonHandler); | |
document.getElementById('form-add-personality').addEventListener('submit', addPersonalityFormHandler); | |
document.getElementById('form-edit-personality').addEventListener('submit', updatePersonalityHandler); | |
document.getElementById('btn-hide-overlay').addEventListener('click', hideOverlayButtonHandler); | |
</script> | |
</body> | |
</html> |