imseldrith commited on
Commit
0026b70
·
1 Parent(s): 15286b3

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +398 -426
index.html CHANGED
@@ -1,3 +1,4 @@
 
1
  <!DOCTYPE html>
2
  <html lang="en">
3
 
@@ -712,457 +713,428 @@
712
  <label for="personalityPromptInput">Prompt:</label>
713
  <textarea id="personalityPromptInput" placeholder="Personality Prompt" class="prompt-field"></textarea>
714
  <button id="updatePersonality">Save</button>
715
- </div>
716
  </div>
717
-
718
- <script type="importmap">
719
- {
720
- "imports": {
721
- "@google/generative-ai": "https://esm.run/@google/generative-ai"
722
- }
723
- }
724
- </script>
725
-
726
- <script type="module">
727
- import { marked } from "https://cdn.jsdelivr.net/npm/marked/lib/marked.esm.js";
728
- import { GoogleGenerativeAI } from "@google/generative-ai";
729
- import { HarmBlockThreshold, HarmCategory } from "@google/generative-ai";
730
-
731
- const safetySettings = [
732
-
733
- {
734
- category: HarmCategory.HARM_CATEGORY_HARASSMENT,
735
- threshold: HarmBlockThreshold.BLOCK_NONE,
736
- },
737
- {
738
- category: HarmCategory.HARM_CATEGORY_HATE_SPEECH,
739
- threshold: HarmBlockThreshold.BLOCK_NONE,
740
- },
741
- {
742
- category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT,
743
- threshold: HarmBlockThreshold.BLOCK_NONE,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
744
  },
745
- {
746
- category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
747
- threshold: HarmBlockThreshold.BLOCK_NONE,
748
- }
749
- ];
750
- const systemPrompt = "If needed, format your answer using markdown." +
751
- "Today's date is" + new Date().toDateString() + "." +
752
- "End of system prompt.";
753
-
754
- //load api key from local storage into input field
755
- const API_KEY = document.querySelector("#apiKeyInput");
756
- const maxTokens = document.querySelector("#maxTokens");
757
- API_KEY.value = localStorage.getItem("API_KEY");
758
- maxTokens.value = localStorage.getItem("MAX_TOKENS");
759
-
760
-
761
- //function to hide element smoothly then setting display none after the transition time elapsed
762
- function hideElement(element) {
763
- element.style.transition = 'opacity 0.2s';
764
- element.style.opacity = '0';
765
- setTimeout(function () {
766
- element.style.display = 'none';
767
- }, 200);
768
- }
769
-
770
- function showElement(element) {
771
- // Wait for other transitions to complete (0.2s delay)
772
- setTimeout(function () {
773
- // Change display property
774
- element.style.display = 'flex';
775
- // Wait for next frame for display change to take effect
776
- requestAnimationFrame(function () {
777
- // Start opacity transition
778
- element.style.transition = 'opacity 0.2s';
779
- element.style.opacity = '1';
780
- });
781
- }, 200);
782
- }
783
-
784
-
785
- const tabs = document.querySelectorAll(".navbar-tab");
786
- const sidebarViews = document.querySelectorAll(".sidebar-section");
787
- const highlight = document.querySelector(".navbar-tab-highlight");
788
- highlight.style.width = `calc(100% / ${tabs.length})`;
789
-
790
-
791
-
792
- let currentTab = undefined;
793
- function navigateTo(tab) {
794
- if (tab == tabs[currentTab]) {
795
- return;
796
- }
797
- // set the highlight to match the size of the tab element
798
-
799
-
800
- let tabIndex = [...tabs].indexOf(tab);
801
- if (tabIndex < 0 || tabIndex >= sidebarViews.length) {
802
- console.error("Invalid tab index: " + tabIndex);
803
- return;
804
- }
805
-
806
- if (currentTab != undefined) {
807
- hideElement(sidebarViews[currentTab]);
808
  }
809
- showElement(sidebarViews[tabIndex]);
810
- currentTab = tabIndex;
811
-
812
- highlight.style.left = `calc(100% / ${tabs.length} * ${tabIndex})`;
813
-
814
- }
815
-
816
- tabs.forEach(element => {
817
- element.addEventListener("click", () => {
818
-
819
- navigateTo(element);
820
- })
821
- });
822
-
823
- sidebarViews.forEach(view => {
824
- hideElement(view);
825
- });
826
-
827
-
828
- navigateTo(tabs[0]);
829
-
830
-
831
-
832
- const personalityCardsInnerInput = document.querySelectorAll(".card-personality input");
833
- let personalityCards = document.querySelectorAll(".card-personality");
834
- const formsOverlay = document.querySelector(".overlay");
835
- const hideOverlayButton = document.querySelector("#btn-hide-overlay");
836
- const addPersonalityForm = document.querySelector("#form-add-personality");
837
- const addPersonalityButton = document.querySelector("#btn-add-personality");
838
- const editDefaultPersonalityForm = document.querySelector("#form-edit-personality");
839
- const editDefaultPersonalityButton = document.querySelector("#btn-edit-personality-default");
840
- const submitNewPersonalityButton = document.querySelector("#btn-submit-personality");
841
- const updatePersonalityButton = document.querySelector("#updatePersonality");
842
-
843
- const sendMessageButton = document.querySelector("#btn-send");
844
-
845
-
846
- function darkenBg(element) {
847
-
848
- let elementBackgroundImageURL = element.style.backgroundImage.match(/url\((.*?)\)/)[1].replace(/('|")/g, '');
849
- element.style.backgroundImage = `linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url('${elementBackgroundImageURL}')`;
850
- }
851
-
852
-
853
- function lightenBg(element) {
854
-
855
- let elementBackgroundImageURL = element.style.backgroundImage.match(/url\((.*?)\)/)[1].replace(/('|")/g, '');
856
- element.style.backgroundImage = `url('${elementBackgroundImageURL}')`;
857
- }
858
-
859
-
860
- function sharePersonality(personality) {
861
- //export personality to json
862
- const personalityJSON = {
863
- name: personality.querySelector(".personality-title").innerText,
864
- description: personality.querySelector(".personality-description").innerText,
865
- prompt: personality.querySelector(".personality-prompt").innerText,
866
- //base64 encode image
867
- image: personality.style.backgroundImage.match(/url\((.*?)\)/)[1].replace(/('|")/g, '')
868
  }
869
- const personalityJSONString = JSON.stringify(personalityJSON);
870
- //download
871
- const element = document.createElement('a');
872
- element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(personalityJSONString));
873
- element.setAttribute('download', `${personalityJSON.name}.json`);
874
- element.style.display = 'none';
875
- document.body.appendChild(element);
876
- element.click();
877
- document.body.removeChild(element);
878
-
879
-
880
- }
881
-
882
- //handle share button click
883
- personalityCards.forEach(card => {
884
- const shareButton = card.querySelector(".btn-share-card");
885
- shareButton.addEventListener("click", () => {
886
- sharePersonality(card);
887
- })
888
- });
889
-
890
- const importPersonalityButton = document.querySelector("#btn-import-personality");
891
- importPersonalityButton.addEventListener("click", () => {
892
- const fileInput = document.createElement('input');
893
- fileInput.type = 'file';
894
- fileInput.addEventListener('change', () => {
895
- const file = fileInput.files[0];
896
- const reader = new FileReader();
897
- reader.onload = function (e) {
898
- const personalityJSON = JSON.parse(e.target.result);
899
- insertPersonality(personalityJSON);
900
- };
901
- reader.readAsText(file);
902
- });
903
- fileInput.click();
904
- });
905
-
906
- //handle radio input check change
907
- personalityCardsInnerInput.forEach(input => {
908
- input.addEventListener("change", () => {
909
- // Darken all cards
910
- personalityCards.forEach(card => {
911
- const cardBackgroundImageURL = card.style.backgroundImage.match(/url\((.*?)\)/)[1].replace(/('|")/g, '');
912
- card.style.outline = "0px solid rgb(150 203 236)";
913
- darkenBg(card);
914
- })
915
-
916
- // Lighten selected card
917
- input.parentElement.style.outline = "3px solid rgb(150 203 236)";
918
- lightenBg(input.parentElement);
919
- })
920
- // Set initial outline
921
- if (input.checked) {
922
- lightenBg(input.parentElement);
923
- input.parentElement.style.outline = "3px solid rgb(150 203 236)";
924
  }
925
- })
926
-
927
- function showAddPersonalityForm() {
928
- showElement(formsOverlay);
929
- showElement(addPersonalityForm);
930
- }
931
-
932
- function showEditPersonalityForm() {
933
- showElement(formsOverlay);
934
- showElement(editDefaultPersonalityForm);
935
- }
936
-
937
- function closeOverlay() {
938
- hideElement(formsOverlay);
939
- hideElement(addPersonalityForm);
940
- hideElement(editDefaultPersonalityForm);
941
- }
942
-
943
-
944
- function insertPersonality(personalityJSON){
945
- const personalitySection = document.querySelector("#personalitySection");
946
- const personalitySectionActions = document.querySelector("#btn-array-personality-section");
947
-
948
- const personalityCard = document.createElement("label");
949
- personalityCard.classList.add("card-personality");
950
- personalityCard.style.backgroundImage = `url('${personalityJSON.image}')`;
951
- personalityCard.innerHTML = `
952
- <input type="radio" name="personality" value="${personalityJSON.name}">
953
- <div>
954
- <h3 class="personality-title">${personalityJSON.name}</h3>
955
- <p class="personality-description">${personalityJSON.description}</p>
956
- <p class="personality-prompt">${personalityJSON.prompt}</p>
957
- </div>
958
- <button class="btn-textual btn-edit-card material-symbols-outlined" id="btn-edit-personality-${personalityJSON.name}">edit</button>
959
- <button class="btn-textual btn-share-card material-symbols-outlined" id="btn-share-personality-${personalityJSON.name}">share</button>
960
- `;
961
-
962
- //insert personality card before the button array
963
- personalitySection.insertBefore(personalityCard, personalitySectionActions);
964
-
965
- darkenBg(personalityCard);
966
-
967
- personalityCards = document.querySelectorAll(".card-personality");
968
- //add input event listener
969
- personalityCard.querySelector("input").addEventListener("change", () => {
970
- // Darken all cards
971
- personalityCards.forEach(card => {
972
- const cardBackgroundImageURL = card.style.backgroundImage.match(/url\((.*?)\)/)[1].replace(/('|")/g, '');
973
- card.style.outline = "0px solid rgb(150 203 236)";
974
- darkenBg(card);
975
- })
976
-
977
- // Lighten selected card
978
- personalityCard.style.outline = "3px solid rgb(150 203 236)";
979
- lightenBg(personalityCard);
980
- })
981
-
982
- const sharebtn = personalityCard.querySelector(".btn-share-card");
983
- sharebtn.addEventListener("click", () => {
984
- sharePersonality(personalityCard);
 
 
 
 
985
  });
986
- }
987
-
988
- function submitNewPersonality() {
989
- const personalityName = document.querySelector("#form-add-personality #personalityNameInput");
990
- const personalityDescription = document.querySelector("#form-add-personality #personalityDescriptionInput");
991
- const personalityImageURL = document.querySelector("#form-add-personality #personalityImageURLInput");
992
- const personalityPrompt = document.querySelector("#form-add-personality #personalityPromptInput");
993
- const personalitySection = document.querySelector("#personalitySection");
994
-
995
-
996
- if (personalityName.value == "") {
997
- alert("Please enter a personality name");
998
- return;
999
- }
1000
- if (personalityPrompt.value == "") {
1001
- alert("Please enter a personality prompt");
1002
- return;
1003
- }
1004
 
1005
- //to json
1006
- const personalityJSON = {
1007
- name: personalityName.value,
1008
- description: personalityDescription.value,
1009
- prompt: personalityPrompt.value,
1010
- image: personalityImageURL.value
1011
- }
1012
- insertPersonality(personalityJSON);
1013
- closeOverlay();
1014
  }
1015
 
1016
- async function run() {
1017
- const msg = document.querySelector("#messageInput");
1018
- const msgText = msg.value;
1019
- const messageContainer = document.querySelector(".message-container");
1020
- const maxTokens = document.querySelector("#maxTokens");
1021
- const API_KEY = document.querySelector("#apiKeyInput");
1022
- const selectedPersonalityTitle = document.querySelector("input[name='personality']:checked + div .personality-title").innerText;
1023
- const selectedPersonalityDescription = document.querySelector("input[name='personality']:checked + div .personality-description").innerText;
1024
- const selectedPersonalityPrompt = document.querySelector("input[name='personality']:checked + div .personality-prompt").innerText;
1025
-
1026
-
1027
- //chat history
1028
- const chatHistory = [];
1029
- //get chat history from message container
1030
- const messageElements = messageContainer.querySelectorAll(".message");
1031
- messageElements.forEach(element => {
1032
- const messageroleapi = element.querySelector(".message-role-api").innerText;
1033
- const messagetext = element.querySelector(".message-text").innerText;
1034
- chatHistory.push({
1035
- role: messageroleapi,
1036
- parts: [{ text: messagetext }]
1037
- })
1038
- })
1039
- //reverse order of chat history
1040
- chatHistory.reverse();
1041
-
1042
- //
1043
- const toneExamples = [];
1044
-
1045
-
1046
- if (API_KEY.value == "") {
1047
- alert("Please enter an API key");
1048
- return;
1049
- }
1050
 
1051
- const generationConfig = {
1052
- maxOutputTokens: maxTokens.value,
1053
- temperature: 0.9
1054
- };
1055
- const genAI = new GoogleGenerativeAI(API_KEY.value);
1056
- const model = genAI.getGenerativeModel({ model: "gemini-pro" });
1057
- const chat = model.startChat({
1058
- generationConfig, safetySettings,
1059
- history: [
1060
- {
1061
- role: "user",
1062
- parts: [{ text: `Personality Name: ${selectedPersonalityTitle}, Personality Description: ${selectedPersonalityDescription}, Personality Prompt: ${selectedPersonalityPrompt}. ${systemPrompt}` }]
1063
- },
1064
- {
1065
- role: "model",
1066
- parts: [{ text: `Okay. From now on, I shall play the role of ${selectedPersonalityTitle}. Your prompt and described personality will be used for the rest of the conversation.` }]
1067
  },
1068
- ...toneExamples,
1069
- ...chatHistory
1070
- ]
1071
- })
1072
-
1073
-
1074
-
1075
- msg.value = "";
1076
- //create new message div for the user's message then append to message container's top
1077
- const newMessage = document.createElement("div");
1078
- newMessage.classList.add("message");
1079
- newMessage.innerHTML = `
1080
- <h3 class="message-role">You:</h3>
1081
- <div class="message-role-api" style="display: none;">user</div>
1082
- <p class="message-text">${msgText}</p>
1083
- `;
1084
- messageContainer.insertBefore(newMessage, messageContainer.firstChild);
1085
-
1086
- const result = await chat.sendMessageStream(msgText);
1087
-
1088
- //create new message div for the model's reply then append to message container's top
1089
- const newReply = document.createElement("div");
1090
- newReply.classList.add("message");
1091
- newReply.classList.add("message-model");
1092
- newReply.innerHTML = `
1093
- <h3 class="message-role">${selectedPersonalityTitle}:</h3>
1094
- <div class="message-role-api" style="display: none;">model</div>
1095
- <p class="message-text">`;
1096
-
1097
- //get the p element inside the message div
1098
- const replyText = newReply.querySelector(".message-text");
1099
-
1100
-
1101
- messageContainer.insertBefore(newReply, messageContainer.firstChild);
1102
-
1103
- let rawText = "";
1104
- for await (const chunk of result.stream) {
1105
- console.log("hello");
1106
- rawText += chunk.text();
1107
- replyText.innerHTML = marked(rawText);
1108
- void replyText.offsetHeight; // Force reflow
1109
- hljs.highlightAll();
1110
- }
1111
 
1112
- //save api key to local storage
1113
- localStorage.setItem("API_KEY", API_KEY.value);
1114
- localStorage.setItem("MAX_TOKENS",maxTokens.value);
1115
-
1116
- }
1117
-
1118
-
1119
- const messageInput = document.querySelector("#messageInput");
1120
-
1121
- //if more than one line, set height to scrollheight, and revert upon delete
1122
- messageInput.addEventListener("input", () => {
1123
- if (messageInput.value.split("\n").length == 1) {
1124
- messageInput.style.height = "2.5rem";
1125
- }
1126
- else {
1127
- messageInput.style.height = "";
1128
- messageInput.style.height = messageInput.scrollHeight + "px";
1129
- }
1130
- })
1131
 
 
 
 
1132
 
1133
- const sidebarDismissButton = document.querySelector("#btn-hide-sidebar");
1134
- sidebarDismissButton.addEventListener("click", () => {
1135
- hideElement(document.querySelector(".sidebar"));
1136
- })
1137
 
1138
- const showSidebarButton = document.querySelector("#btn-show-sidebar");
1139
- showSidebarButton.addEventListener("click", () => {
1140
- showElement(document.querySelector(".sidebar"));
1141
- })
1142
 
 
 
1143
 
1144
- //unhide sidebar if width > 768px (event hander)
1145
- window.addEventListener("resize", () => {
1146
- if (window.innerWidth > 768) {
1147
- showElement(document.querySelector(".sidebar"));
1148
- }
1149
- })
1150
 
 
 
 
1151
 
1152
- hideOverlayButton.addEventListener("click", closeOverlay);
 
 
1153
 
1154
- addPersonalityButton.addEventListener("click", showAddPersonalityForm);
 
 
1155
 
1156
- editDefaultPersonalityButton.addEventListener("click", showEditPersonalityForm);
 
 
1157
 
1158
- submitNewPersonalityButton.addEventListener("click", submitNewPersonality);
 
 
 
 
1159
 
1160
- sendMessageButton.addEventListener("click", run);
 
 
 
 
1161
 
 
 
1162
 
1163
- // ...
1164
- </script>
 
 
1165
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1166
  </body>
1167
-
1168
  </html>
 
1
+
2
  <!DOCTYPE html>
3
  <html lang="en">
4
 
 
713
  <label for="personalityPromptInput">Prompt:</label>
714
  <textarea id="personalityPromptInput" placeholder="Personality Prompt" class="prompt-field"></textarea>
715
  <button id="updatePersonality">Save</button>
716
+ <button id="deletePersonality">Delete</button>
717
  </div>
718
+ </div>
719
+
720
+ <script src="https://cdn.jsdelivr.net/npm/@tensorflow/[email protected]/dist/tf.min.js"></script>
721
+ <script src="https://cdn.jsdelivr.net/npm/@tensorflow/[email protected]/dist/tfjs-vis.umd.min.js"></script>
722
+ <script>
723
+ const container = document.getElementById('mainContent');
724
+ const messageContainer = document.querySelector('.message-container');
725
+
726
+ const messageInput = document.getElementById('messageInput');
727
+ const sendButton = document.getElementById('btn-send');
728
+ const maxTokens = document.getElementById('maxTokens');
729
+ const safetySettings = document.getElementById('safetySettings');
730
+ const apiKeyInput = document.getElementById('apiKeyInput');
731
+
732
+ const sidebar = document.querySelector('.sidebar');
733
+ const personalitySection = document.getElementById('personalitySection');
734
+ const addPersonalityButton = document.getElementById('btn-add-personality');
735
+ const importPersonalityButton = document.getElementById('btn-import-personality');
736
+ const btnHideSidebar = document.getElementById('btn-hide-sidebar');
737
+ const btnShowSidebar = document.getElementById('btn-show-sidebar');
738
+
739
+ const personalityForm = document.getElementById('form-add-personality');
740
+ const editPersonalityForm = document.getElementById('form-edit-personality');
741
+ const overlay = document.querySelector('.overlay');
742
+ const personalityNameInput = document.getElementById('personalityNameInput');
743
+ const personalityDescriptionInput = document.getElementById('personalityDescriptionInput');
744
+ const personalityImageURLInput = document.getElementById('personalityImageURLInput');
745
+ const personalityPromptInput = document.getElementById('personalityPromptInput');
746
+ const btnHideOverlay = document.getElementById('btn-hide-overlay');
747
+ const btnSubmitPersonality = document.getElementById('btn-submit-personality');
748
+ const editPersonalityButton = document.querySelectorAll('.btn-edit-card');
749
+ const sharePersonalityButton = document.querySelectorAll('.btn-share-card');
750
+ const updatePersonalityButton = document.getElementById('updatePersonality');
751
+ const deletePersonalityButton = document.getElementById('deletePersonality');
752
+
753
+ const editPersonalityName = document.getElementById('personalityNameInput');
754
+ const editPersonalityDescription = document.getElementById('personalityDescriptionInput');
755
+ const editPersonalityImageURL = document.getElementById('personalityImageURLInput');
756
+ const editPersonalityPrompt = document.getElementById('personalityPromptInput');
757
+
758
+ let currentPersonality = {
759
+ name: 'zodiac',
760
+ description: 'zodiac is a cheerful assistant, always ready to help you with your tasks.',
761
+ image: 'https://images.fonearena.com/blog/wp-content/uploads/2023/12/Google-Gemini-AI-1024x577.jpg',
762
+ 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.'
763
+ };
764
+
765
+ let allPersonalities = [{
766
+ name: 'zodiac',
767
+ description: 'zodiac is a cheerful assistant, always ready to help you with your tasks.',
768
+ image: 'https://images.fonearena.com/blog/wp-content/uploads/2023/12/Google-Gemini-AI-1024x577.jpg',
769
+ 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.'
770
+ }];
771
+
772
+ let allPromptObjects = [{
773
+ context: '',
774
+ examples: [{
775
+ input: {
776
+ content: 'What is your purpose?'
777
  },
778
+ output: {
779
+ 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.'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
780
  }
781
+ }, {
782
+ input: {
783
+ content: 'Can you write a poem about love?'
784
+ },
785
+ output: {
786
+ 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.'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
787
  }
788
+ }, {
789
+ input: {
790
+ content: 'What do you know about the history of the internet?'
791
+ },
792
+ output: {
793
+ 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.'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
794
  }
795
+ }]
796
+ }];
797
+
798
+ let model = null;
799
+ const modelUrl = 'https://storage.googleapis.com/tfjs-models/public/gemini-pro/model.json';
800
+
801
+ // Load the model.
802
+ tf.loadGraphModel(modelUrl).then((loadedModel) => {
803
+ console.log('Model loaded.');
804
+ model = loadedModel;
805
+ });
806
+
807
+ const generateMessage = (message, mode) => {
808
+ const messageBox = document.createElement('div');
809
+ const messageParagraph = document.createElement('p');
810
+
811
+ messageParagraph.classList.add('message');
812
+ messageParagraph.classList.add(mode);
813
+ messageParagraph.textContent = message;
814
+
815
+ messageBox.classList.add('message-box');
816
+ messageBox.appendChild(messageParagraph);
817
+
818
+ return messageBox;
819
+ };
820
+
821
+ const appendMessage = (messageBox) => {
822
+ messageContainer.appendChild(messageBox);
823
+ messageContainer.scrollTop = messageContainer.scrollHeight;
824
+ };
825
+
826
+ const displayResponse = (message) => {
827
+ const messageContainer = document.querySelector('.message-container');
828
+ const messageBox = generateMessage(message, 'message-model');
829
+ appendMessage(messageBox);
830
+ };
831
+
832
+ const fetchApi = ({ prompt, maxTokens, safetySettings }) => {
833
+ const requestBody = {
834
+ prompt: {
835
+ text: prompt,
836
+ },
837
+ maxTokens: maxTokens,
838
+ safetySettings: safetySettings,
839
+ };
840
+
841
+ // Make the API call.
842
+ const requestOptions = {
843
+ method: 'POST',
844
+ headers: {
845
+ 'Content-Type': 'application/json',
846
+ },
847
+ body: JSON.stringify(requestBody),
848
+ };
849
+
850
+ fetch(
851
+ `https://generativelanguage.googleapis.com/v1beta2/models/text-bison-001:generateText?key=${apiKeyInput.value}`,
852
+ requestOptions
853
+ )
854
+ .then((res) => res.json())
855
+ .then((data) => displayResponse(data.candidates[0].output))
856
+ .catch((error) => {
857
+ console.error('Error querying API: ', error);
858
+ alert('Sorry, there was an issue with your request. Please try again.');
859
  });
860
+ };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
861
 
862
+ const checkSyntax = (result) => {
863
+ if (result.includes('```')) {
864
+ return result.includes('```json') ? result.slice(7, -3) : result.slice(3, -3)
 
 
 
 
 
 
865
  }
866
 
867
+ return result;
868
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
869
 
870
+ const generateResponse = (input) => {
871
+ let promptObject = {
872
+ context: '',
873
+ examples: [
874
+ {
875
+ input: {
876
+ content: input
 
 
 
 
 
 
 
 
 
877
  },
878
+ output: {
879
+ content: ""
880
+ }
881
+ }
882
+ ]
883
+ };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
884
 
885
+ allPromptObjects.push(promptObject);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
886
 
887
+ const prompt = JSON.stringify({
888
+ messages: allPromptObjects,
889
+ });
890
 
891
+ const maxTokensValue = maxTokens.value;
892
+ const safetySettingsValue = safetySettings.value;
 
 
893
 
894
+ fetchApi({ prompt, maxTokensValue, safetySettingsValue });
895
+ };
 
 
896
 
897
+ const sendButtonHandler = () => {
898
+ if (!messageInput.value) return;
899
 
900
+ const messageBox = generateMessage(messageInput.value, 'message-user');
901
+ appendMessage(messageBox);
 
 
 
 
902
 
903
+ generateResponse(messageInput.value);
904
+ messageInput.value = '';
905
+ };
906
 
907
+ const addPersonalityButtonHandler = () => {
908
+ overlay.classList.remove('display', 'opacity');
909
+ overlay.classList.add('display', 'opacity');
910
 
911
+ personalityForm.classList.remove('display', 'opacity');
912
+ personalityForm.classList.add('display', 'opacity');
913
+ };
914
 
915
+ const importPersonalityButtonHandler = () => {
916
+ alert('Unfortunately, this feature is not yet supported. Please add personalities manually until this feature is added!');
917
+ };
918
 
919
+ const hideSidebarButtonHandler = () => {
920
+ sidebar.classList.remove('display', 'opacity');
921
+ btnShowSidebar.classList.remove('display', 'opacity');
922
+ btnShowSidebar.classList.add('display', 'opacity');
923
+ };
924
 
925
+ const showSidebarButtonHandler = () => {
926
+ sidebar.classList.add('display', 'opacity');
927
+ btnHideSidebar.classList.remove('display', 'opacity');
928
+ btnHideSidebar.classList.add('display', 'opacity');
929
+ };
930
 
931
+ const addPersonalityFormHandler = (e) => {
932
+ e.preventDefault();
933
 
934
+ if (personalityNameInput.value === '') {
935
+ alert('Please fill all the fields.');
936
+ return;
937
+ }
938
 
939
+ const newPersonality = {
940
+ name: personalityNameInput.value,
941
+ description: personalityDescriptionInput.value,
942
+ image: personalityImageURLInput.value,
943
+ prompt: personalityPromptInput.value
944
+ };
945
+
946
+ allPersonalities.push(newPersonality);
947
+ allPromptObjects = [];
948
+
949
+ createPersonalityCard(newPersonality);
950
+ resetFormValues();
951
+ hideForm();
952
+ };
953
+
954
+ const createPersonalityCard = (personality) => {
955
+ const personalityCard = document.createElement('label');
956
+ const personalityCardHeader = document.createElement('div');
957
+ const personalityCardTitle = document.createElement('h3');
958
+ const personalityCardDescription = document.createElement('p');
959
+ const personalityCardPrompt = document.createElement('p');
960
+ const personalityCardEditButton = document.createElement('button');
961
+ const personalityCardShareButton = document.createElement('button');
962
+ const personalityCardRadioInput = document.createElement('input');
963
+
964
+ personalityCard.classList.add('card-personality');
965
+ personalityCardHeader.classList.add('card-header');
966
+ personalityCardTitle.classList.add('personality-title');
967
+ personalityCardDescription.classList.add('personality-description');
968
+ personalityCardPrompt.classList.add('personality-prompt', 'display');
969
+ personalityCardEditButton.classList.add('btn-textual', 'btn-edit-card', 'material-symbols-outlined', 'edit');
970
+ personalityCardShareButton.classList.add('btn-textual', 'btn-share-card', 'material-symbols-outlined');
971
+ personalityCardRadioInput.classList.add('display');
972
+ personalityCardRadioInput.type = 'radio';
973
+ personalityCardRadioInput.name = 'personality';
974
+ personalityCardRadioInput.value = personality.name;
975
+
976
+ personalityCardTitle.textContent = personality.name;
977
+ personalityCardDescription.textContent = personality.description;
978
+ personalityCardPrompt.textContent = personality.prompt;
979
+ personalityCardEditButton.textContent = 'edit';
980
+ personalityCardShareButton.textContent = 'share';
981
+
982
+ const backgroundImageStyle = `background-image: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url('${personality.image}')`;
983
+ personalityCard.setAttribute('style', backgroundImageStyle);
984
+
985
+ personalityCardEditButton.addEventListener('click', (e) => editPersonalityHandler(e.target));
986
+ personalityCardShareButton.addEventListener('click', () => sharePersonalityHandler(personality));
987
+ personalityCardRadioInput.addEventListener('click', (e) => switchPersonalityHandler(e.target));
988
+
989
+ personalityCardHeader.appendChild(personalityCardTitle);
990
+ personalityCard.appendChild(personalityCardHeader);
991
+ personalityCard.appendChild(personalityCardDescription);
992
+ personalityCard.appendChild(personalityCardPrompt);
993
+ personalityCard.appendChild(personalityCardEditButton);
994
+ personalityCard.appendChild(personalityCardShareButton);
995
+ personalityCard.appendChild(personalityCardRadioInput);
996
+
997
+ const personalitySection = document.getElementById('personalitySection');
998
+ personalitySection.insertBefore(personalityCard, personalitySection.firstChild);
999
+ };
1000
+
1001
+ const resetFormValues = () => {
1002
+ personalityNameInput.value = '';
1003
+ personalityDescriptionInput.value = '';
1004
+ personalityImageURLInput.value = '';
1005
+ personalityPromptInput.value = '';
1006
+ };
1007
+
1008
+ const hideForm = () => {
1009
+ overlay.classList.remove('display', 'opacity');
1010
+ personalityForm.classList.remove('display', 'opacity');
1011
+ };
1012
+
1013
+ const editPersonalityHandler = (button) => {
1014
+ const card = button.parentElement;
1015
+ const personalityName = card.querySelector('.personality-title').textContent;
1016
+
1017
+ const personalityObject = allPersonalities.find((personality) => personality.name === personalityName);
1018
+
1019
+ showForm(personalityObject);
1020
+ overlay.classList.remove('display', 'opacity');
1021
+ overlay.classList.add('display', 'opacity');
1022
+
1023
+ personalityForm.classList.remove('display', 'opacity');
1024
+ personalityForm.classList.add('display', 'opacity');
1025
+ };
1026
+
1027
+ const sharePersonalityHandler = (personality) => {
1028
+ const personalityObject = JSON.stringify(personality);
1029
+ const shareText = `Here's a personality I created using zodiac, a fun assistant that you can talk to: ${personalityObject}`;
1030
+ navigator.clipboard.writeText(shareText);
1031
+ alert(`Successfully copied personality to clipboard!`);
1032
+ };
1033
+
1034
+ const switchPersonalityHandler = (radioInput) => {
1035
+ const personalityName = radioInput.value;
1036
+ const personalityObject = allPersonalities.find((personality) => personality.name === personalityName);
1037
+
1038
+ currentPersonality = personalityObject;
1039
+
1040
+ allPromptObjects = [];
1041
+
1042
+ messageContainer.textContent = '';
1043
+ };
1044
+
1045
+ const showForm = (personality) => {
1046
+ personalityNameInput.value = personality.name;
1047
+ personalityDescriptionInput.value = personality.description;
1048
+ personalityImageURLInput.value = personality.image;
1049
+ personalityPromptInput.value = personality.prompt;
1050
+
1051
+ const updatePersonalityButton = createElement('button');
1052
+ updatePersonalityButton.type = 'submit';
1053
+ updatePersonalityButton.classList.add('btn-textual');
1054
+ updatePersonalityButton.id = 'updatePersonality';
1055
+ updatePersonalityButton.textContent = 'Save';
1056
+ updatePersonalityButton.addEventListener('click', (e) => updatePersonalityHandler(e, personality));
1057
+
1058
+ const form = document.getElementById('form-edit-personality');
1059
+ const submitButton = document.getElementById('btn-submit-personality');
1060
+ form.replaceChild(updatePersonalityButton, submitButton);
1061
+ };
1062
+
1063
+ const updatePersonalityHandler = (e, personality) => {
1064
+ e.preventDefault();
1065
+
1066
+ const personalityObject = {
1067
+ name: personalityNameInput.value,
1068
+ description: personalityDescriptionInput.value,
1069
+ image: personalityImageURLInput.value,
1070
+ prompt: personalityPromptInput.value
1071
+ };
1072
+
1073
+ const index = allPersonalities.indexOf(personality);
1074
+ allPersonalities[index] = personalityObject;
1075
+ allPromptObjects = [];
1076
+
1077
+ createPersonalityCard(personalityObject);
1078
+ resetFormValues();
1079
+ hideForm();
1080
+ };
1081
+
1082
+ const hideOverlayButtonHandler = () => {
1083
+ overlay.classList.remove('display', 'opacity');
1084
+ btnShowSidebar.classList.remove('display', 'opacity');
1085
+ btnShowSidebar.classList.add('display', 'opacity');
1086
+ };
1087
+
1088
+ const createElement = (element, item) => {
1089
+ const newElement = document.createElement(element);
1090
+ newElement.textContent = item;
1091
+ return newElement;
1092
+ };
1093
+ const deletePersonalityButton = document.getElementById('deletePersonality');
1094
+
1095
+ // Add event listener to delete personality button
1096
+ deletePersonalityButton.addEventListener('click', (e) => {
1097
+ e.preventDefault();
1098
+
1099
+ // Get personality name from the form
1100
+ const personalityName = personalityNameInput.value;
1101
+
1102
+ // Find the personality object in the array of personalities
1103
+ const personalityObject = allPersonalities.find((personality) => personality.name === personalityName);
1104
+
1105
+ // Check if personality object is found
1106
+ if (!personalityObject) {
1107
+ alert('Personality not found!');
1108
+ return;
1109
+ }
1110
+
1111
+ // Delete the personality object from the array
1112
+ const index = allPersonalities.indexOf(personalityObject);
1113
+ allPersonalities.splice(index, 1);
1114
+
1115
+ // Delete the personality card from the HTML
1116
+ const personalityCard = document.querySelector(`label[value="${personalityName}"]`);
1117
+ personalityCard.remove();
1118
+
1119
+ // Reset the form values
1120
+ resetFormValues();
1121
+
1122
+ // Hide the form
1123
+ hideForm();
1124
+
1125
+ // Alert the user that the personality has been deleted
1126
+ alert(`Personality "${personalityName}" has been deleted.`);
1127
+ });
1128
+
1129
+ // Add event listeners
1130
+ document.getElementById('btn-send').addEventListener('click', sendButtonHandler);
1131
+ document.getElementById('btn-add-personality').addEventListener('click', addPersonalityButtonHandler);
1132
+ document.getElementById('btn-import-personality').addEventListener('click', importPersonalityButtonHandler);
1133
+ document.getElementById('btn-hide-sidebar').addEventListener('click', hideSidebarButtonHandler);
1134
+ document.getElementById('btn-show-sidebar').addEventListener('click', showSidebarButtonHandler);
1135
+ document.getElementById('form-add-personality').addEventListener('submit', addPersonalityFormHandler);
1136
+ document.getElementById('form-edit-personality').addEventListener('submit', updatePersonalityHandler);
1137
+ document.getElementById('btn-hide-overlay').addEventListener('click', hideOverlayButtonHandler);
1138
+ </script>
1139
  </body>
 
1140
  </html>