imseldrith commited on
Commit
2742b75
·
1 Parent(s): 0026b70

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +426 -398
index.html CHANGED
@@ -1,4 +1,3 @@
1
-
2
  <!DOCTYPE html>
3
  <html lang="en">
4
 
@@ -713,428 +712,457 @@
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>
 
 
1
  <!DOCTYPE html>
2
  <html lang="en">
3
 
 
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>