[
  {
    "path": "ChatGPT/.classpath",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<classpath>\n\t<classpathentry kind=\"con\" path=\"org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8\">\n\t\t<attributes>\n\t\t\t<attribute name=\"maven.pomderived\" value=\"true\"/>\n\t\t</attributes>\n\t</classpathentry>\n\t<classpathentry kind=\"src\" output=\"target/classes\" path=\"src\">\n\t\t<attributes>\n\t\t\t<attribute name=\"optional\" value=\"true\"/>\n\t\t\t<attribute name=\"maven.pomderived\" value=\"true\"/>\n\t\t</attributes>\n\t</classpathentry>\n\t<classpathentry kind=\"con\" path=\"org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER\">\n\t\t<attributes>\n\t\t\t<attribute name=\"maven.pomderived\" value=\"true\"/>\n\t\t</attributes>\n\t</classpathentry>\n\t<classpathentry kind=\"lib\" path=\"C:/Users/Snoop/Downloads/JTattoo-1.6.13.jar\"/>\n\t<classpathentry kind=\"output\" path=\"target/classes\"/>\n</classpath>\n"
  },
  {
    "path": "ChatGPT/.gitignore",
    "content": "/bin/\n/target/\n"
  },
  {
    "path": "ChatGPT/.project",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<projectDescription>\n\t<name>ChatGPT</name>\n\t<comment></comment>\n\t<projects>\n\t</projects>\n\t<buildSpec>\n\t\t<buildCommand>\n\t\t\t<name>org.eclipse.jdt.core.javabuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t\t<buildCommand>\n\t\t\t<name>org.eclipse.m2e.core.maven2Builder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t</buildSpec>\n\t<natures>\n\t\t<nature>org.eclipse.m2e.core.maven2Nature</nature>\n\t\t<nature>org.eclipse.jdt.core.javanature</nature>\n\t</natures>\n</projectDescription>\n"
  },
  {
    "path": "ChatGPT/.settings/org.eclipse.core.resources.prefs",
    "content": "eclipse.preferences.version=1\nencoding//src/MainFrame.java=UTF-8\n"
  },
  {
    "path": "ChatGPT/.settings/org.eclipse.jdt.core.prefs",
    "content": "eclipse.preferences.version=1\norg.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled\norg.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate\norg.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8\norg.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve\norg.eclipse.jdt.core.compiler.compliance=1.8\norg.eclipse.jdt.core.compiler.debug.lineNumber=generate\norg.eclipse.jdt.core.compiler.debug.localVariable=generate\norg.eclipse.jdt.core.compiler.debug.sourceFile=generate\norg.eclipse.jdt.core.compiler.problem.assertIdentifier=error\norg.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled\norg.eclipse.jdt.core.compiler.problem.enumIdentifier=error\norg.eclipse.jdt.core.compiler.problem.forbiddenReference=warning\norg.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore\norg.eclipse.jdt.core.compiler.release=disabled\norg.eclipse.jdt.core.compiler.source=1.8\n"
  },
  {
    "path": "ChatGPT/.settings/org.eclipse.m2e.core.prefs",
    "content": "activeProfiles=\neclipse.preferences.version=1\nresolveWorkspaceProjects=true\nversion=1\n"
  },
  {
    "path": "ChatGPT/config.properties",
    "content": "#JavaGPT Config\n#To use JavaGPT, provide a ChatGPT API Key after the \"=\" on line 4\n#Get API key here > https://platform.openai.com/account/api-keys\napikey=\nmodel=gpt-3.5-turbo\nmaxTokens=1024\ntimeout=30\nproxyip=\nproxyport=\nproxytype=\nautosave=true\nautotitle=true\nautoscroll=true\nEnterToSubmit=true\nchat_location_override=\nWindowSize=large\nFontSize=12\nTheme=dark\n"
  },
  {
    "path": "ChatGPT/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\n  <modelVersion>4.0.0</modelVersion>\n  <groupId>ChatGPT</groupId>\n  <artifactId>ChatGPT</artifactId>\n  <version>0.0.1-SNAPSHOT</version>\n  <build> \n    <sourceDirectory>src</sourceDirectory>\n    <plugins>\n      <plugin>\n        <artifactId>maven-compiler-plugin</artifactId>\n        <version>3.8.1</version>\n        <configuration>\n          <source>1.8</source>\n          <target>1.8</target>\n        </configuration>\n      </plugin>\n    </plugins>\n  </build>\n  <dependencies>\n    <dependency>\n        <groupId>com.theokanning.openai-gpt3-java</groupId>\n\t\t<artifactId>service</artifactId>\n\t\t<version>0.12.0</version>  \t\t\n    </dependency>\n\t<dependency>\n    <groupId>com.fasterxml.jackson.core</groupId>\n    <artifactId>jackson-databind</artifactId>\n    <version>2.10.1</version>\n</dependency>\n<dependency>\n  <groupId>com.google.code.gson</groupId>\n  <artifactId>gson</artifactId>\n  <version>2.10.1</version>\n</dependency>\n<dependency>\n    <groupId>org.commonmark</groupId>\n    <artifactId>commonmark</artifactId>\n    <version>0.21.0</version>\n</dependency>\n</dependencies>\n</project>\n\n"
  },
  {
    "path": "ChatGPT/src/AboutFrame.java",
    "content": "import java.awt.Cursor;\nimport java.awt.Desktop;\nimport javax.swing.JFrame;\nimport javax.swing.JPanel;\nimport javax.swing.border.EmptyBorder;\nimport javax.swing.JLabel;\nimport javax.swing.ImageIcon;\nimport java.awt.Font;\nimport java.awt.Label;\nimport java.awt.event.MouseAdapter;\nimport java.awt.event.MouseEvent;\nimport java.net.URI;\n\npublic class AboutFrame extends JFrame {\n\n\tprivate JPanel contentPane;\n\n\t/**\n\t * Launch the application.\n\t */\n\n\t/**\n\t * Create the frame.\n\t */\n\tpublic AboutFrame() {\n\t\tsetTitle(\"About\");\n\t\tsetResizable(false);\n\t\tsetDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);\n\t\tsetBounds(100, 100, 401, 271);\n\t\tcontentPane = new JPanel();\n\t\tcontentPane.setBorder(new EmptyBorder(5, 5, 5, 5));\n\t\tsetContentPane(contentPane);\n\t\tcontentPane.setLayout(null);\n\t\t\n\t\tJLabel lblNewLabel = new JLabel(\"\");\n\t\tlblNewLabel.setIcon(new ImageIcon(AboutFrame.class.getResource(\"logo.png\")));\n\t\tlblNewLabel.setBounds(160, 22, 84, 83);\n\t\tcontentPane.add(lblNewLabel);\n\t\t\n\t\tJLabel lblNewLabel_1 = new JLabel(\"JavaGPT \" + MainFrame.version);\n\t\tlblNewLabel_1.setFont(new Font(\"Tahoma\", Font.BOLD, 23));\n\t\tlblNewLabel_1.setBounds(118, 105, 169, 51);\n\t\tcontentPane.add(lblNewLabel_1);\n\t\t\n\t\tJLabel lblNewLabel_2 = new JLabel(\"(May 12 2023)\");\n\t\tlblNewLabel_2.setFont(new Font(\"Tahoma\", Font.PLAIN, 16));\n\t\tlblNewLabel_2.setBounds(142, 145, 114, 28);\n\t\tcontentPane.add(lblNewLabel_2);\n\t\t\n\t\tJLabel lblNewLabel_3 = new JLabel(\"Source code:\");\n\t\tlblNewLabel_3.setFont(new Font(\"Tahoma\", Font.PLAIN, 14));\n\t\tlblNewLabel_3.setBounds(24, 200, 84, 28);\n\t\tcontentPane.add(lblNewLabel_3);\n\t\tJLabel lblHttpsgithubcomfrankcybjavagpt;\n\t\tif(MainFrame.seltheme != 1) {\n\t\tlblHttpsgithubcomfrankcybjavagpt = new JLabel(\"<html><a href=\\\\\\\"https://github.com/FrankCYB/JavaGPT\\\\\\\">https://github.com/FrankCYB/JavaGPT</a></html>\");\n\t\t}else {\n\t\tlblHttpsgithubcomfrankcybjavagpt = new JLabel(\"<html><a style='color: yellow;' href='https://github.com/FrankCYB/JavaGPT'>https://github.com/FrankCYB/JavaGPT</a></html>\");\n\t\t}\n\t\tlblHttpsgithubcomfrankcybjavagpt.addMouseListener(new MouseAdapter() {\n\t\t\t@Override\n\t\t\tpublic void mouseClicked(MouseEvent e) {\n\t\t\t\t try {\n\t                    // Get the URI of the hyperlink\n\t                    URI uri = new URI(\"https://github.com/FrankCYB/JavaGPT\");\n\n\t                    // Open the URI in a browser\n\t                    Desktop.getDesktop().browse(uri);\n\n\t                } catch (Exception ex) {\n\t                    ex.printStackTrace();\n\t                }\n\t\t\t\t \t\t\t\t \n\t\t\t}\n\t\t\tpublic void mouseEntered(MouseEvent e) {\n                // Change the cursor to a hand when the mouse enters the label\n\t\t\t\tlblHttpsgithubcomfrankcybjavagpt.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));\n            }\n\n            @Override\n            public void mouseExited(MouseEvent e) {\n                // Change the cursor back to the default when the mouse leaves the label\n            \tlblHttpsgithubcomfrankcybjavagpt.setCursor(Cursor.getDefaultCursor());\n            }\n\t\t});\n\t\t\t\t\n\t\tlblHttpsgithubcomfrankcybjavagpt.setFont(new Font(\"Tahoma\", Font.PLAIN, 14));\n\t\tlblHttpsgithubcomfrankcybjavagpt.setBounds(115, 200, 270, 28);\n\t\tcontentPane.add(lblHttpsgithubcomfrankcybjavagpt);\n\t\t\n\t\tLabel label = new Label(MainFrame.prop.getProperty(\"model\"));\n\t\tlabel.setAlignment(Label.CENTER);\n\t\tlabel.setBounds(140, 172, 114, 22);\n\t\tcontentPane.add(label);\n\t}\n}\n"
  },
  {
    "path": "ChatGPT/src/ChatLoader.java",
    "content": "import javax.swing.JFrame;\nimport javax.swing.JPanel;\nimport javax.swing.JPopupMenu;\nimport javax.swing.border.EmptyBorder;\nimport javax.swing.text.BadLocationException;\nimport javax.swing.JList;\nimport javax.swing.JMenuItem;\nimport javax.swing.JOptionPane;\nimport javax.swing.JScrollPane;\nimport java.awt.event.ActionListener;\nimport java.awt.event.MouseAdapter;\nimport java.awt.event.ActionEvent;\nimport java.awt.event.MouseEvent;\nimport java.io.File;\nimport java.io.FileFilter;\nimport java.util.Arrays;\nimport java.util.Comparator;\n\nimport javax.swing.DefaultListModel;\nimport java.awt.BorderLayout;\n\npublic class ChatLoader extends JFrame {\n\n\tprivate JPanel contentPane;\n\tprivate JList<FileListItem> fileList;\n\tprivate DefaultListModel<FileListItem> model;\n\tprivate JPopupMenu popupMenu;\n\tprivate JPopupMenu popupMenu2;\n\tprivate String path;\n\tprivate int selectedIndex;\n\n\t/**\n\t * Launch the application.\n\t */\n\t/*public static void main(String[] args) {\n\t\tEventQueue.invokeLater(new Runnable() {\n\t\t\tpublic void run() {\n\t\t\t\ttry {\n\t\t\t\t\tChatLoader frame = new ChatLoader();\n\t\t\t\t\tframe.setVisible(true);\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}*/\n\t\n\tclass FileListItem {\n\t    private String displayName;\n\t    private String filePath;\n\n\t    public FileListItem(String displayName, String filePath) {\n\t        this.displayName = displayName;\n\t        this.filePath = filePath;\n\t    }\n\n\t    public String getDisplayName() {\n\t        return displayName;\n\t    }\n\n\t    public String getFilePath() {\n\t        return filePath;\n\t    }\n\n\t    @Override\n\t    public String toString() {\n\t        return displayName;\n\t    }\n\t}\n\t\n\t/**\n\t * Create the frame.\n\t */\n\tpublic ChatLoader(String path) {\n\t\tthis.path = path;\n\t\tsetTitle(\"Chat History\");\n\t\tsetDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);\n\t\tsetBounds(100, 100, 450, 288);\n\t\tcontentPane = new JPanel();\n\t\tcontentPane.setBorder(new EmptyBorder(5, 5, 5, 5));\n\t\tsetContentPane(contentPane);\n\t\t\n\t        model = new DefaultListModel<>();\n\t        fileList = new JList<>(model);\n\t        \n\t        \n\t        popupMenu = new JPopupMenu();\n\t        popupMenu2 = new JPopupMenu();\n\n\t        // Add menu items to the PopupMenu\n\t        JMenuItem deleteItem = new JMenuItem(\"Delete\");\n\t        JMenuItem renameItem = new JMenuItem(\"Rename\");\t        \n\t        JMenuItem refreshItems = new JMenuItem(\"Refresh\");\n\t        JMenuItem sortItems = new JMenuItem(\"Sort\");\n\t        \n\t        JMenuItem refreshItems2 = new JMenuItem(\"Refresh\");\n\t        JMenuItem sortItems2 = new JMenuItem(\"Sort\");\n\t        \n\t        popupMenu.add(deleteItem);\n\t        popupMenu.add(renameItem);\t        \n\t        popupMenu.add(refreshItems);\n\t        popupMenu.add(sortItems);\n\t        \n\t        popupMenu2.add(refreshItems2);\n\t        popupMenu2.add(sortItems2);\n\t        \n\t        \n\t        //Deletes selected chat file from fileList if it exists\n\t        deleteItem.addActionListener(new ActionListener() {\n\t            public void actionPerformed(ActionEvent e) {          \n\t            \t    \t\n\t\t\t\t\t    \t File file = new File(fileList.getModel().getElementAt(selectedIndex).filePath); //replace path/to/file with the actual file path    \t\n\t\t\t\t\t         if(file.exists()) { //checks if the file exists\n\t\t\t\t\t             file.delete(); //deletes the file\t\t\t\t\t             \n\t\t\t\t\t             model.removeElementAt(selectedIndex);\t\t\t\t\t         \n\t\t\t\t\t         } else {\n\t\t\t\t\t        \t JOptionPane.showMessageDialog(null, \"File not found\", \"Error\", JOptionPane.ERROR_MESSAGE);\n\t\t\t\t\t         }\n\t\t\t\t\t         \n\t            }\n\t        });\n\t        \n\t        \n\t        //Renames selected chat file from fileList if it exists\n\t        renameItem.addActionListener(new ActionListener() {\n\t            public void actionPerformed(ActionEvent e) {\t            \t\t            \t\t\t    \t\t\t\t\t    \t\n\t\t\t\t\t    \tString title = JOptionPane.showInputDialog(null, \"Please enter a title:\", \"Rename\", JOptionPane.PLAIN_MESSAGE);\n\t\t\t\t\t    \tif (title != null) {\n\t\t\t\t\t    \t    File file = new File(fileList.getModel().getElementAt(selectedIndex).filePath);\n\t\t\t\t\t    \t    String path = file.getParent();\n\t\t\t\t\t    \t    String name = file.getName();\n\t\t\t\t\t    \t    String ext = name.substring(name.lastIndexOf('.'));\n\t\t\t\t\t    \t    File newFile = new File(path, title + ext);\n\n\t\t\t\t\t    \t    if (newFile.exists()) {\n\t\t\t\t\t    \t        JOptionPane.showMessageDialog(null, \"File already exists\", \"Error\", JOptionPane.ERROR_MESSAGE);\n\t\t\t\t\t    \t    } else {\n\t\t\t\t\t    \t        File txtFile = new File(path, title + \".json\");\n\t\t\t\t\t    \t        file.renameTo(newFile);\n\t\t\t\t\t    \t        new File(path, name.substring(0, name.length() - ext.length()) + \".json\").renameTo(txtFile);\n\t\t\t\t\t    \t        refreshlist();\n\t\t\t\t\t    \t        JOptionPane.showMessageDialog(null, \"File renamed successfully\", \"Success\", JOptionPane.INFORMATION_MESSAGE);\n\t\t\t\t\t    \t    }\n\t\t\t\t\t    \t}\t\t\t\t\t  \t            \t\n\n\t            }\n\t        });\n\t        \n\t        //Adds ActionListners to JPopMenu elements\n\t        refreshItems.addActionListener(new ActionListener() {\n\t            public void actionPerformed(ActionEvent e) {\n\t            \trefreshlist();\n\t            }\n\t        });\n\t        \n\t        refreshItems2.addActionListener(new ActionListener() {\n\t            public void actionPerformed(ActionEvent e) {\n\t            \trefreshlist();\n\t            }\n\t        });\n\t        \n\t        sortItems.addActionListener(new ActionListener() {\n\t            public void actionPerformed(ActionEvent e) {\n\t            \tMainFrame.isAlpha = !MainFrame.isAlpha;\n\t            \trefreshlist();\n\t            }\n\t        });\n\t        \n\t        sortItems2.addActionListener(new ActionListener() {\n\t            public void actionPerformed(ActionEvent e) {\n\t            \tMainFrame.isAlpha = !MainFrame.isAlpha;\n\t            \trefreshlist();\n\t            }\n\t        });\n\t        //------------------------------------------\n\t        \n\t        //Sends selected chat file to MainFrame.loadchat() and loads it into the main JFrame\n\t        fileList.addMouseListener(new MouseAdapter() {\n\t            public void mousePressed(MouseEvent e) {\n\t                if (e.isPopupTrigger()) showPopupMenu(e);\n\t            }\n\t            public void mouseReleased(MouseEvent e) {\n\t                if (e.isPopupTrigger()) showPopupMenu(e);\n\t            }\n\t            public void mouseClicked(MouseEvent e) {\n\t                if (e.getClickCount() == 2) {\n\t                \tselectedIndex = fileList.getSelectedIndex();\n\t                \ttry {\n\t\t\t\t\t\t\tMainFrame.loadchat(fileList.getModel().getElementAt(selectedIndex).filePath, fileList.getModel().getElementAt(selectedIndex).displayName);\n\t\t\t\t\t\t} catch (Exception e1) {\n\t\t\t\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\t\t\t\te1.printStackTrace();\n\t\t\t\t\t\t}\n\n\t                }\n\t            }\n\t        });\n\t        \n\t        refreshlist();\n\t        contentPane.setLayout(new BorderLayout(0, 0));\n\t        JScrollPane scrollPane = new JScrollPane(fileList);\n\t\t\tscrollPane.setViewportView(fileList);\n\t\t\tcontentPane.add(scrollPane);\n\t}\t\n\t\n\t//Refreshes a list with file names from a directory. \n\t//The directory is represented by the \"path\" variable. \n\t//The function applies a file filter that only accepts files with \".json\" extension and sorts them by the date of last modification or alphabetically depending on the value of the \"isAlpha\" static boolean variable. \n\t//Finally, it creates a new list item for each file, which contains its name and complete path without an extension, and adds it to the list model.\n\tpublic void refreshlist() {\n\t    File directory = new File(path);\n\t    model.clear();\n\t    File[] files = directory.listFiles(new FileFilter() {\n\t        public boolean accept(File file) {\n\t            return file.isFile() && file.getName().endsWith(\".json\");\n\t        }\n\t    });\n\t    \n\t    if(MainFrame.isAlpha) {\n\t    Arrays.sort(files, new Comparator<File>() {\n\t        public int compare(File f1, File f2) {\n\t            long diff = f2.lastModified() - f1.lastModified();\n\t            return Long.signum(diff);\n\t        }\n\t    });\n\t    }\n\t    \n\t    for (File file : files) {\n\t        String displayName = file.getName();\n\t        String filePath = file.getAbsolutePath();\n\t        FileListItem item = new FileListItem(displayName.replaceFirst(\"[.][^.]+$\", \"\"), filePath);\n\t        model.addElement(item);\n\t    }\n\t}\n\t\n\t//Shows correct PopupMenu on right-click based on if a file from fileList is selected\n\tprivate void showPopupMenu(MouseEvent e) {\n        selectedIndex = fileList.getSelectedIndex();\n        if (selectedIndex == -1) {\n        \tpopupMenu2.show(e.getComponent(), e.getX(), e.getY());\n        }else {\n\n        popupMenu.show(e.getComponent(), e.getX(), e.getY());\n        }\n    }\n}\n"
  },
  {
    "path": "ChatGPT/src/MainFrame.java",
    "content": "import java.awt.Color;\nimport java.awt.Desktop;\nimport java.awt.Dimension;\nimport java.awt.EventQueue;\n\nimport javax.swing.JFrame;\nimport javax.swing.JOptionPane;\nimport javax.swing.JPanel;\nimport javax.swing.JPopupMenu;\nimport javax.swing.border.EmptyBorder;\nimport javax.swing.event.HyperlinkEvent;\nimport javax.swing.event.HyperlinkListener;\nimport javax.swing.text.BadLocationException;\nimport javax.swing.text.DefaultCaret;\nimport javax.swing.text.Style;\nimport javax.swing.text.StyleConstants;\nimport javax.swing.text.StyleContext;\nimport javax.swing.text.StyledDocument;\n\nimport com.google.gson.Gson;\nimport com.jtattoo.plaf.hifi.HiFiLookAndFeel;\n\n\nimport javax.swing.JTextArea;\nimport javax.swing.KeyStroke;\n//import javax.swing.JTextPane;\nimport javax.swing.UIManager;\nimport javax.swing.JButton;\nimport javax.swing.JFileChooser;\n\nimport java.awt.event.ActionListener;\nimport java.awt.event.KeyAdapter;\nimport java.awt.event.KeyEvent;\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.FileReader;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.PrintWriter;\nimport java.lang.reflect.Field;\nimport java.net.URISyntaxException;\nimport java.nio.charset.Charset;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.Properties;\nimport java.util.Random;\nimport java.awt.event.ActionEvent;\nimport javax.swing.JScrollPane;\nimport java.awt.Font;\nimport java.awt.Toolkit;\n\nimport java.awt.datatransfer.Clipboard;\nimport java.awt.datatransfer.DataFlavor;\nimport java.awt.datatransfer.StringSelection;\nimport java.awt.datatransfer.Transferable;\nimport java.awt.datatransfer.UnsupportedFlavorException;\n\nimport javax.swing.ImageIcon;\nimport javax.swing.JMenuBar;\nimport javax.swing.JMenu;\nimport javax.swing.JMenuItem;\nimport java.awt.event.MouseAdapter;\nimport java.awt.event.MouseEvent;\nimport javax.swing.JEditorPane;\n\nimport com.theokanning.openai.completion.chat.ChatCompletionChoice;\nimport com.theokanning.openai.completion.chat.ChatCompletionRequest;\nimport com.theokanning.openai.completion.chat.ChatMessage;\nimport com.theokanning.openai.completion.chat.ChatMessageRole;\nimport com.theokanning.openai.service.OpenAiService;\n\nimport org.commonmark.node.*;\nimport org.commonmark.parser.Parser;\nimport org.commonmark.renderer.html.HtmlRenderer;\n\npublic class MainFrame extends JFrame {\n\t\n\tprivate static MainFrame frame;\n\tprivate JPanel contentPane;\n\n\tprivate OpenAiService service;\n\tprivate final static ArrayList<ChatMessage> messages = new ArrayList<>();\n\tprivate static JTextArea ChatArea;\n    private static JButton SubmitButton;\n    private static JScrollPane scrollPane;\n    private static JScrollPane scrollPane_1;\n\tprivate static JButton SaveButton;\n\tprivate static JButton ImportButton;\n\tprivate static JButton ResetButton;\n\t\n\tprivate static JEditorPane DisplayArea;\n\tprivate static JEditorPane HTMLArea;\n\tprivate static StyledDocument doc;\n\tprivate JMenuBar menuBar;\n\tprivate static String GPTConvo;\n\n\tprivate File FGPTConvo;\n\t\n\tpublic static Properties prop;\n\tpublic static String version = \"1.3.2\";\n\tprivate Boolean first = true;\n\tprivate Boolean chathistory = true;\n\tprivate Boolean autotitle = true;\n\tprivate Boolean enter2submit = true;\n\tprivate Boolean cloaderopen = false;\n\tprivate Boolean aframeopen = false;\n\tprivate static Boolean isHTMLView = false;\n\tprivate static Parser parser;\n\tprivate static HtmlRenderer renderer;\n\tpublic static Boolean isAlpha = true;\n\tprivate Boolean isStreamRunning = false;\n\tprivate static int FormSize = 3;\n\tprivate static int FontSize = 12;\n\tpublic static int seltheme = 0;\n\tprivate ChatLoader cloader;\n\tprivate String chatDir;\n\n\t//Initializing Style objects for RTF text in DisplayArea\t\n\tprivate static Style YouStyle;\n\tprivate static Style InvisibleStyle;\n\tprivate static Style GPTStyle;\n\tprivate static Style ChatStyle;\n\tprivate static Style ErrorStyle;\t\n\tprivate static MainFrame INSTANCE = null;\n\t\n\t//This function is used to load a chat from a file specified by the full file path and filename. \n\t//It sets the title of the instance to include the filename and clears the display area. \n\t//It also resets the messages and reads them from the file. If the view is set to HTML, it resets the HTML area style and renders the document. \n\t//If there is an exception, it displays an error message and prints the stack trace. Finally, it sets the FGPTConvo file and sets the first flag to false.\t\n    public static void loadchat(String fullfilepath, String filename) throws BadLocationException {\n\n    \tINSTANCE.setTitle(\"JavaGPT - \" + filename);\n\t\ttry {\t\t\n\t\t\n\t\t\tDisplayArea.setText(\"\");\n\n\t\t\tmessages.clear();\n\t\t\treadMessagesFromFile(fullfilepath);\n\t\t\tif(isHTMLView) {\n\t\t\t\tresetHTMLAreaStyle();\n\t\t\t\tNode document = parser.parse(DisplayArea.getDocument().getText(0, DisplayArea.getDocument().getLength()));\n\t\t\t\t//System.out.println(renderer.render(document));\n\t\t\t\tHTMLArea.setText(renderer.render(document));\n\t\t\t}\n\t\t\t\n\t\t\t\n\t\t} catch (Exception e) {\n\t\t\tJOptionPane.showMessageDialog(null, e.getMessage(), \"Error\", JOptionPane.ERROR_MESSAGE);\n\t\t\te.printStackTrace();\n\t\t}\n\t\tINSTANCE.FGPTConvo = new File(fullfilepath);\n\n\t\tINSTANCE.first = false;\n\t\t\n    }\n    \n    //Writes chat contents to .json format    \n    public void writeMessagesToFile(String filename) throws IOException {\n    \ttry (PrintWriter writer = new PrintWriter(filename)) {\n            Gson gson = new Gson();\n            for (ChatMessage message : messages) {\n                String json = gson.toJson(message);\n                writer.println(json);\n            }\n        }\n    }\n    \n    //Reads chat contents from provided .json, stores it in the messages ArrayList and outputs contents in DisplayArea \n    public static void readMessagesFromFile(String filename) throws IOException {\n    \ttry (BufferedReader reader = new BufferedReader(new FileReader(filename))) {\n            String line;\n            Gson gson = new Gson();\n            while ((line = reader.readLine()) != null) {\n                ChatMessage message = gson.fromJson(line, ChatMessage.class);\n                if(message.getRole().equals(\"user\")) {\n                \ttry {\n\t\t    \t\t    doc.insertString(doc.getLength(), \"You\", YouStyle);\n\t\t    \t\t    doc.insertString(doc.getLength(), \":\\n\", InvisibleStyle);\n\t\t    \t\t    doc.insertString(doc.getLength(), message.getContent() + \"\\n\\n\", ChatStyle);\n\t\t    \t\t} catch (BadLocationException e) {\n\t\t    \t\t    e.printStackTrace();\n\t\t    \t\t}\t\n                }else{\n                \ttry {\n\t\t    \t\t    doc.insertString(doc.getLength(), \"ChatGPT\", GPTStyle);\n\t\t    \t\t    doc.insertString(doc.getLength(), \":\\n\", InvisibleStyle);\n\t\t    \t\t    doc.insertString(doc.getLength(), message.getContent() + \"\\n\\n\", ChatStyle);\n\t\t    \t\t} catch (BadLocationException e) {\n\t\t    \t\t    e.printStackTrace();\n\t\t    \t\t}\t\n                }\n                messages.add(message);\n            }\n        }\n    }\n    \n    //Refreshes DisplayArea contents with current messages ArrayList items   \n    public void refreshMessages() {\n    \tDisplayArea.setText(\"\");\n    \tfor (ChatMessage message : messages) {\n    \t\t if(message.getRole().equals(\"user\")) {\n             \ttry {\n\t\t    \t\t    doc.insertString(doc.getLength(), \"You\", YouStyle);\n\t\t    \t\t    doc.insertString(doc.getLength(), \":\\n\", InvisibleStyle);\n\t\t    \t\t    doc.insertString(doc.getLength(), message.getContent() + \"\\n\\n\", ChatStyle);\n\t\t    \t\t} catch (BadLocationException e) {\n\t\t    \t\t    e.printStackTrace();\n\t\t    \t\t}\t\n             }else{\n             \ttry {\n\t\t    \t\t    doc.insertString(doc.getLength(), \"ChatGPT\", GPTStyle);\n\t\t    \t\t    doc.insertString(doc.getLength(), \":\\n\", InvisibleStyle);\n\t\t    \t\t    doc.insertString(doc.getLength(), message.getContent() + \"\\n\\n\", ChatStyle);\n\t\t    \t\t} catch (BadLocationException e) {\n\t\t    \t\t    e.printStackTrace();\n\t\t    \t\t}\t\n             }\n        }\n    }\n    \n    \n    //Used in newFile() to create a new file name (Ex: Chat_x0y, Chat_09k, Chat_rc7)   \n    public static String getRandomString() {\n        String letters = \"abcdefghijklmnopqrstuvwxyz1234567890\";\n        Random rand = new Random();\n        StringBuilder sb = new StringBuilder();\n        \n        for (int i = 0; i < 3; i++) {\n            int index = rand.nextInt(letters.length());\n            sb.append(letters.charAt(index));\n        }\n        \n        return sb.toString();\n    }\n    \n    \n    //Creates a new chat file by setting FGPTConvo File object to a new file name   \n    public void newFile() {\n    \tString randfilename = getRandomString();\n\t\tFGPTConvo = new File(chatDir + \"\\\\Chat_\" + randfilename  + \".json\");\n\t\twhile(FGPTConvo.exists()) {\n\t\t\trandfilename = getRandomString();\n\t\t\tFGPTConvo = new File(chatDir + \"\\\\Chat_\" + randfilename + \".json\");\t\t\n\t\t}\n\t\tsetTitle(\"JavaGPT - Chat_\" + randfilename);\t\n    }\n    \n    //Resets all objects used for chat. Is invoked when \"New Chat\" is pressed or a chat file is loaded  \n    public void Reset() {\n    \tisStreamRunning = false;\n    \tmessages.clear();    \t\n    \tFGPTConvo = null;\n\t\tGPTConvo = \"\";\n\t\tDisplayArea.setText(\"\");\n\t\tHTMLArea.setText(\"\");\n\t\tresetHTMLAreaStyle();\n\t\tChatArea.setText(\"\");\n\t\tsetTitle(\"JavaGPT\");\n\t\tfirst = true;\n    }\n\n\t/**\n\t * Launch the application.\n\t */\n\tpublic static void main(String[] args) {\n\t\tEventQueue.invokeLater(new Runnable() {\n\t\t\tpublic void run() {\t\n\t\t\t\t\n\t\t\t\t//Sets project to support Unicode\n\t\t\t\ttry {\n\t\t\t\tSystem.setProperty(\"file.encoding\",\"UTF-8\");\t\n\t\t\t\tField charset = Charset.class.getDeclaredField(\"defaultCharset\");\n\t\t\t\tcharset.setAccessible(true);\n\t\t\t\tcharset.set(null,null);\n\t\t\t\t}catch(Exception e) {}\n\t\t\t\t//-------------------------------\n\t\t\t\t   //Loads properties------------------------\n\t\t\t\t\tprop = new Properties();\n\t\t\t\t    InputStream input = null;\n\t\t\t\t    \n\t\t\t\t    try {\n\t\t\t\t\t\tinput = new FileInputStream(\"config.properties\");\n\t\t\t\t\t\tprop.load(input);\n\t\t\t\t\t} catch (FileNotFoundException e1) {\n\t\t\t\t\t\tint choice = JOptionPane.showConfirmDialog(null,\n\t\t\t\t                \"No config file found. Would you like to create one?\",\n\t\t\t\t                \"Create Config File\", JOptionPane.YES_NO_OPTION);\n\t\t\t\t            \n\t\t\t\t            if(choice == JOptionPane.YES_OPTION) {\n\t\t\t\t                String apikey = JOptionPane.showInputDialog(\n\t\t\t\t                    null, \"Please enter your API key:\");\t\t\t\t    \t\t\t         \n\t\t\t\t                    \n\t\t\t\t                prop.setProperty(\"apikey\", apikey);\n\t\t\t\t                prop.setProperty(\"model\", \"gpt-3.5-turbo\");\n\t\t\t\t                prop.setProperty(\"maxTokens\", \"1024\");\n\t\t\t\t                prop.setProperty(\"timeout\", \"30\");\n\t\t\t\t                prop.setProperty(\"proxyip\", \"\"); // WIP Support will be added back\n\t\t\t\t                prop.setProperty(\"proxyport\", \"\"); // WIP Support will be added back\n\t\t\t\t                prop.setProperty(\"proxytype\", \"\");\t\t\t\t                \n\t\t\t\t                prop.setProperty(\"autotitle\", \"true\");\n\t\t\t\t                prop.setProperty(\"autoscroll\", \"true\");\n\t\t\t\t                prop.setProperty(\"EnterToSubmit\", \"true\");\n\t\t\t\t                prop.setProperty(\"chat_history\", \"true\");\n\t\t\t\t                prop.setProperty(\"chat_location_override\", \"\");\n\t\t\t\t                prop.setProperty(\"WindowSize\", \"medium\");\n\t\t\t\t                prop.setProperty(\"FontSize\", \"12\");\n\t\t\t\t                prop.setProperty(\"Theme\", \"dark\");\n\t\t\t\t                \n\t\t\t\t                try {\n\t\t\t\t                    FileOutputStream out = new FileOutputStream(\"config.properties\");\n\t\t\t\t                    prop.store(out, \"Generated config file\");\n\t\t\t\t                    out.close();\n\t\t\t\t                    \n\t\t\t\t                    JOptionPane.showMessageDialog(null, \"Config file created successfully!\");\n\t\t\t\t                } catch (IOException ex) {\n\t\t\t\t                    ex.printStackTrace();\n\t\t\t\t                }\n\t\t\t\t            }\n\t\t\t\t\t\te1.printStackTrace();\n\t\t\t\t\t}\n\t\t\t\t       catch (IOException e) {\n\t\t\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\t\t\te.printStackTrace();\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tif (input != null) {\n\t\t\t\t            try {\n\t\t\t\t                input.close();\n\t\t\t\t            } catch (IOException e) {\n\t\t\t\t                e.printStackTrace();\n\t\t\t\t                JOptionPane.showMessageDialog(null, e.getMessage(), \"Error\", JOptionPane.ERROR_MESSAGE);\n\t\t\t\t            }\n\t\t\t\t\t    }\n\t\t\t\t\t}\n\t\t\t\t    //----------------------------------------\n\t\t\t\t    //Sets proxy settings\n\t\t\t\t    if(prop.getProperty(\"proxyip\") != null && !prop.getProperty(\"proxyip\").isEmpty() && prop.getProperty(\"proxyport\") != null && !prop.getProperty(\"proxyport\").isEmpty()) {\n\t\t\t\t\t\tif(prop.getProperty(\"proxytype\").toLowerCase().equals(\"http\")) {\n\t\t\t\t\t\t\tSystem.setProperty(\"http.proxyHost\", prop.getProperty(\"proxyip\"));\n\t\t\t\t\t\t\tSystem.setProperty(\"http.proxyPort\", prop.getProperty(\"proxyport\"));\n\t\t\t\t\t\t}else if(prop.getProperty(\"proxytype\").toLowerCase().equals(\"https\")){\n\t\t\t\t\t\t\tSystem.setProperty(\"https.proxyHost\", prop.getProperty(\"proxyip\"));\n\t\t\t\t\t\t\tSystem.setProperty(\"https.proxyPort\", prop.getProperty(\"proxyport\"));\t\t\t\t\t\n\t\t\t\t\t\t}else {\n\t\t\t\t\t\t\tSystem.getProperties().put( \"proxySet\", \"true\" );\n\t\t\t\t\t\t\tSystem.getProperties().put( \"socksProxyHost\", prop.getProperty(\"proxyip\") );\n\t\t\t\t\t\t\tSystem.getProperties().put( \"socksProxyPort\", prop.getProperty(\"proxyport\") );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t    //-------------------\n\t\t\t\t    //Sets selected JTattoo theme-------------\n\t\t\t\t        try {\n\t\t\t\t        \tif(!prop.getProperty(\"Theme\").isEmpty()) {\n\t\t\t\t\t        if(prop.getProperty(\"Theme\").equals(\"dark\")) {\n\t\t\t\t\t        \tProperties p = new Properties();\n\t\t\t\t\t\t\t\tp.put(\"windowTitleFont\", \"Ebrima PLAIN 15\");\n\t\t\t\t\t\t\t\tp.put(\"backgroundPattern\", \"off\");\n\t\t\t\t\t\t\t\tp.put(\"logoString\", \"\");\n\t\t\t\t\t\t\t\tHiFiLookAndFeel.setCurrentTheme(p);\n\t\t\t\t\t\t\t\tUIManager.setLookAndFeel(\"com.jtattoo.plaf.hifi.HiFiLookAndFeel\");\n\t\t\t\t\t\t\t\tseltheme = 1;\n\t\t\t\t\t        }\n\t\t\t\t\t       }\n\t\t\t\t         } catch (Exception e) {\n\t\t\t\t\t\t\te.printStackTrace();\n\t\t\t\t\t     }\n\t\t\t\t      //----------------------------------------\n\t\t\t\t        \t\n\t\t\t\t\tframe = new MainFrame(); //Loads main JFrame\n\t\t\t\t\t \n\t\t\t\t//Scales JFrame based on \"WindowSize\" prop\t\n\t\t\t\t\tswitch(prop.getProperty(\"WindowSize\")){\n\t\t\t\t\tcase \"small\":\t\t\t\t\t\n\t\t\t\t\t\tFormSize=1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"large\":\n\t\t\t\t\t\tFormSize=2;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tFormSize=3;\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tsetFormSize();\n\t\t\t\t//----------------------------------------\n\t\t\t\t//Sets app icon to JavaGPT logo\n\t\t\t\tframe.setIconImage(Toolkit.getDefaultToolkit().getImage(getClass().getResource(\"logo.png\")));\n\t\t\t\t\n\t\t\t\t\n\t\t\t\tif(prop.getProperty(\"FontSize\") != null && !prop.getProperty(\"FontSize\").isEmpty()) {\n\t\t\t\t\ttry {\n\t\t\t            FontSize = Integer.parseInt(prop.getProperty(\"FontSize\"));\n\t\t\t        } catch (NumberFormatException e) {\n\t\t\t        }\t\t\t\t\t\n\t\t\t\t}\t\n\t\t\t\t\n\t\t\t\t//Makes JFrame visible\t\t\t\n\t\t\t\tframe.setVisible(true);\n\t\t\t\t\t\t\t\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Create the frame.\n\t * @param GPTStyle \n\t * @param ChatStyle \n\t */\n\tpublic MainFrame() {\n\t\tsetResizable(false);\n\t\tINSTANCE = this;\n\t\t\n\t\tsetTitle(\"JavaGPT\");\n\t\tsetDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);\n\t\t\n\t\t//Initializes OpenAI's ChatGPT API with provided API key\n\t\tservice = new OpenAiService(prop.getProperty(\"apikey\"),(prop.getProperty(\"timeout\") == null && prop.getProperty(\"timeout\").isEmpty()) ? Duration.ZERO : Duration.ofSeconds(Long.parseLong(prop.getProperty(\"timeout\"))));\n\t\t\n\t\tmenuBar = new JMenuBar();\n\t\tsetJMenuBar(menuBar);\n\t\t\n\t\tJMenu OptionMenu = new JMenu(\"Options\");\n\t\tmenuBar.add(OptionMenu);\n\t\t\n\t\t//Renderer and Parser for HTMLView\n\t\tparser = Parser.builder().build();\n\t\trenderer = HtmlRenderer.builder().build();\n\t\t//\n\t\t//Code for HTML Viewer JMenu. If clicked, it will set isHTMLView to its counter value.\n\t\t//If true, it will switch scrollPane to show HTMLArea and display the plain text contents for DisplayArea in it\n\t\t//If false, it will switch scrollPane to show DisplayArea\n\t\tJMenuItem HTMLViewMenuItem = new JMenuItem(\"HTML View\");\n\t\tHTMLViewMenuItem.addActionListener(new ActionListener() {\n\t\t    public void actionPerformed(ActionEvent e) {\n\t\t    \tif(isHTMLView) {\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\ttry {\n\t\t\t\t\t\tscrollPane.setViewportView(DisplayArea);\t\t\t\t\t\t\n\t\t\t\t\t\tHTMLViewMenuItem.setText(\"HTML View\");\n\t\t\t\t\t\tisHTMLView=false;\n\t\t\t\t\t} catch (Exception e1) {\n\t\t\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\t\t\te1.printStackTrace();\n\t\t\t\t\t}\n\t\t\t\t}else {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tscrollPane.setViewportView(HTMLArea);\t\t\t\t\t\t\n\t\t\t\t\t\tresetHTMLAreaStyle();\n\t    \t\t\t\tNode document = parser.parse(DisplayArea.getDocument().getText(0, DisplayArea.getDocument().getLength()));\t    \t\n\t    \t\t\t\tHTMLArea.setText(renderer.render(document));\n\t\t\t\t\t\tHTMLViewMenuItem.setText(\"Normal View\");\n\t\t\t\t\t\tisHTMLView=true;\n\t\t\t\t\t} catch (Exception e1) {\n\t\t\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\t\t\te1.printStackTrace();\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t}\n\n\t\t    }\n\t\t});\n\t\t\t\n\t\tOptionMenu.add(HTMLViewMenuItem);\n\t\t\n\t\t\n\t\t//Will scale the JFrame based on preset dimensions for JMenu options Large, Medium, & Small\t\t\n\t\tJMenu FormSizeMenu = new JMenu(\"Form Size\");\n\t\tOptionMenu.add(FormSizeMenu);\n\t\t\n\t\tJMenuItem SmallMenuItem = new JMenuItem(\"Small\");\n\t\tFormSizeMenu.add(SmallMenuItem);\n\t\tSmallMenuItem.addActionListener(new ActionListener() {\n\t\t    public void actionPerformed(ActionEvent e) {\n\t\t    \tif(FormSize != 1) {\n\t\t    \tFormSize = 1;\n\t\t    \tsetFormSize();\t\n\t\t    \t}\n\t\t    }\n\t\t});\n\t\t\n\t\tJMenuItem MediumMenuItem = new JMenuItem(\"Medium\");\n\t\tFormSizeMenu.add(MediumMenuItem);\n\t\tMediumMenuItem.addActionListener(new ActionListener() {\n\t\t    public void actionPerformed(ActionEvent e) {\n\t\t    \tif(FormSize != 3) {\n\t\t    \tFormSize = 3;\n\t\t    \tsetFormSize();\t\n\t\t    \t}\n\t\t    }\n\t\t});\n\t\t\n\t\tJMenuItem LargeMenuItem = new JMenuItem(\"Large\");\n\t\tFormSizeMenu.add(LargeMenuItem);\n\t\tLargeMenuItem.addActionListener(new ActionListener() {\n\t\t    public void actionPerformed(ActionEvent e) {\n\t\t    \tif(FormSize != 2) {\n\t\t    \tFormSize = 2;\n\t\t    \tsetFormSize();\t\n\t\t    \t}\n\t\t    }\n\t\t});\n\t\t\n\t\tJMenu FontSizeMenu = new JMenu(\"Font Size\");\n\t\tOptionMenu.add(FontSizeMenu);\n\t\t\n\t\tJMenuItem DefaultFSMenuItem = new JMenuItem(\"Default (12)\");\n\t\tFontSizeMenu.add(DefaultFSMenuItem);\n\t\tDefaultFSMenuItem.addActionListener(new ActionListener() {\n\t\t    public void actionPerformed(ActionEvent e) {\n\t\t    \tif(FontSize != 12) {\n\t\t    \tFontSize = 12;\n\t\t    \tsetFontSize();\n\t\t    \trefreshMessages();\n\t\t    \t}\n\t\t    }\n\t\t});\n\t\t\n\t\tJMenuItem LargeFSMenuItem = new JMenuItem(\"Large (16)\");\n\t\tFontSizeMenu.add(LargeFSMenuItem);\n\t\tLargeFSMenuItem.addActionListener(new ActionListener() {\n\t\t    public void actionPerformed(ActionEvent e) {\n\t\t    \tif(FontSize != 16) {\n\t\t    \tFontSize = 16;\n\t\t    \tsetFontSize();\n\t\t    \trefreshMessages();\n\t\t    \t}\n\t\t    }\n\t\t});\n\t\t\n\t\tJMenuItem ExtraLargeFSMenuItem = new JMenuItem(\"Ex-Large (20)\");\n\t\tFontSizeMenu.add(ExtraLargeFSMenuItem);\n\t\tExtraLargeFSMenuItem.addActionListener(new ActionListener() {\n\t\t    public void actionPerformed(ActionEvent e) {\n\t\t    \tif(FontSize != 20) {\n\t\t    \tFontSize = 20;\n\t\t    \tsetFontSize();\n\t\t    \trefreshMessages();\n\t\t    \t}\n\t\t    }\n\t\t});\n\t\t\n\t\tJMenuItem CustomFSMenuItem = new JMenuItem(\"Custom\");\n\t\tFontSizeMenu.add(CustomFSMenuItem);\n\t\tCustomFSMenuItem.addActionListener(new ActionListener() {\n\t\t    public void actionPerformed(ActionEvent e) {\n\t\t    \tString input = JOptionPane.showInputDialog(null, \"Enter font size:\", \"Font Size\", JOptionPane.PLAIN_MESSAGE);\n\t\t    \ttry {\n\t\t            FontSize = Integer.parseInt(input);\n\t\t            setFontSize();\n\t\t\t    \trefreshMessages();\n\t\t        } catch (NumberFormatException e1) {\n\t\t        \tJOptionPane.showMessageDialog(null, \"Invalid font size\", \"Error\", JOptionPane.ERROR_MESSAGE);\n\t\t        }\n\t\t    \t\t\t    \t\n\t\t    }\n\t\t});\n\t\t//----------------------------------------------------------------------------------\n\t\t\n\t\t\n\t\tJMenu RenameMenu = new JMenu(\"Rename\");\n\t\tOptionMenu.add(RenameMenu);\n\t\t\n\t\t//Rename option which when clicked has ChatGPT generate a title based on current chat context\n\t\tJMenuItem AutoMenuItem = new JMenuItem(\"Auto\");\n\t\tRenameMenu.add(AutoMenuItem);\n\t\tAutoMenuItem.addActionListener(new ActionListener() {\n\t\t    public void actionPerformed(ActionEvent e) {\n\t\t    \tif(FGPTConvo != null) {\n\t\t    \t\tAutoTitle();\n\t\t    \t}else {\n\t\t    \t\tJOptionPane.showMessageDialog(null, \"No chat file loaded\", \"Error\", JOptionPane.ERROR_MESSAGE);\n\t\t    \t}\n\t\t\n\t\t    \t\n\t\t    }\n\t\t});\n\t\t\n\t\t//This code adds a manual menu item to a rename menu. \n\t\t//When the manual menu item is clicked, it prompts the user to enter a title for the file to be renamed. \n\t\t//If the file already exists with the inputted title, an error message is shown. \n\t\t//Otherwise, the file is renamed and a success message is shown along with the new title in the window title bar. \n\t\t//However, if no file is loaded, an error message is shown.\n\t\tJMenuItem ManualMenuItem = new JMenuItem(\"Manual\");\n\t\tRenameMenu.add(ManualMenuItem);\t\n\t\tManualMenuItem.addActionListener(new ActionListener() {\n\t\t    public void actionPerformed(ActionEvent e) {\t\t    \t\t\t    \t       \t            \n\t\t    \tif(FGPTConvo != null) {\n\t\t    \tString title = JOptionPane.showInputDialog(null, \"Please enter a title:\", \"Rename\", JOptionPane.PLAIN_MESSAGE);\n\t\t    \tif(title != null) {\t\t    \t\n\t\t\t\tFile file = new File(FGPTConvo.getParentFile(), title + \".json\");\n\t\t\t\tif(file.exists()) {\n\t\t\t\t\tJOptionPane.showMessageDialog(null, \"File already exists\", \"Error\", JOptionPane.ERROR_MESSAGE);\n\t\t\t\t}else {\n\t\t\t\t\tFGPTConvo.renameTo(file);\n\t\t\t\t\tFGPTConvo = file;\n\t\t\t\t\tJOptionPane.showMessageDialog(null, \"File renamed successfully\", \"Success\", JOptionPane.INFORMATION_MESSAGE);\n\t\t\t\t\tINSTANCE.setTitle(\"JavaGPT - \" + title);\n\t\t\t\t}\n\t\t      }\n\t\t    \t}else {\n\t\t    \t\tJOptionPane.showMessageDialog(null, \"No chat file loaded\", \"Error\", JOptionPane.ERROR_MESSAGE);\n\t\t    \t}\n\t\t    \t\n\t\t    }\n\t\t});\n\t\t\t\t\n\t\t//Deletes chat file if it exists\n\t\tJMenuItem DeleteMenuItem = new JMenuItem(\"Delete\");\n\t\tDeleteMenuItem.addActionListener(new ActionListener() {\n\t\t    public void actionPerformed(ActionEvent e) {\n\t\t    \tif(FGPTConvo != null && FGPTConvo.exists()) { //checks if the file exists\t\t    \t\t\n\t\t\t        FGPTConvo.delete(); //deletes the file\n\t\t\t        Reset();\t             \n\t\t         } else {\n\t\t        \t JOptionPane.showMessageDialog(null, \"File not found\", \"Error\", JOptionPane.ERROR_MESSAGE);\n\t\t         }\n\t\t         \n\t\t    }\n\t\t});\n\t\t\n\t\t//Reverts chat contents to previous state by removing the last prompt & response from messages ArrayList and reloads the DisplayArea\n\t\tJMenuItem RevertMenuItem = new JMenuItem(\"Revert\");\n\t\tRevertMenuItem.addActionListener(new ActionListener() {\n\t\t    public void actionPerformed(ActionEvent e) {\n\t\t    \tif(messages.size() >= 4) { //checks if the file exists\n\t\t    \t\tmessages.remove(messages.size() - 1);\n\t\t    \t\tmessages.remove(messages.size() - 1);\n\t\t    \t\trefreshMessages();\n\t\t         } else {\n\t\t        \t if(messages.isEmpty()) {\n\t\t        \t\t JOptionPane.showMessageDialog(null, \"No chat loaded\", \"Error\", JOptionPane.ERROR_MESSAGE);\t  \t\t        \t \n\t\t        \t }else {\n\t\t        \t\t JOptionPane.showMessageDialog(null, \"Can't revert first prompt\", \"Error\", JOptionPane.ERROR_MESSAGE);\n\t\t        \t }\n\t\t         }\n\t\t         \n\t\t    }\n\t\t});\n\t\tOptionMenu.add(RevertMenuItem);\n\t\tOptionMenu.add(DeleteMenuItem);\n\t\t\n\t\t//Opens \"About\" JFrame\n\t\tJMenuItem AboutMenuItem = new JMenuItem(\"About\");\n\t\tAboutMenuItem.addActionListener(new ActionListener() {\n\t\t    public void actionPerformed(ActionEvent e) {\t    \t\n\t\t    \tif(aframeopen != true) {\n\t\t\t\t\tAboutFrame aframe = new AboutFrame();\n\t\t\t\t\taframe.setIconImage(Toolkit.getDefaultToolkit().getImage(getClass().getResource(\"logo.png\")));\n\t\t\t\t\taframe.setVisible(true);\n\t\t\t\t\taframeopen = true;\n\t\t\t\t\taframe.addWindowListener(new java.awt.event.WindowAdapter() {\n\t\t\t            @Override\n\t\t\t            public void windowClosing(java.awt.event.WindowEvent windowEvent) {\n\t\t\t            \taframeopen = false;\n\t\t\t            }\n\t\t\t        });\n\t\t\t\t\t}\n\t\t         \n\t\t    }\n\t\t});\n\t\tOptionMenu.add(AboutMenuItem);\n\t\t\n\t\t//Opens \"ChatLoader\" (Chat History) JFrame\n\t\tJMenu LoadChatButton = new JMenu(\"Load Chat\");\n\t\tLoadChatButton.addMouseListener(new MouseAdapter() {\n\t\t\t@Override\n\t\t\tpublic void mouseClicked(MouseEvent e) {\n\t\t\t\tif(cloaderopen != true) {\n\t\t\t\tcloader = new ChatLoader(chatDir);\n\t\t\t\tcloader.setIconImage(Toolkit.getDefaultToolkit().getImage(getClass().getResource(\"logo.png\")));\n\t\t\t\tcloader.setVisible(true);\n\t\t\t\tcloaderopen = true;\n\t\t\t\tcloader.addWindowListener(new java.awt.event.WindowAdapter() {\n\t\t            @Override\n\t\t            public void windowClosing(java.awt.event.WindowEvent windowEvent) {\n\t\t            \tcloaderopen = false;\n\t\t            }\n\t\t        });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\t\n\t\tmenuBar.add(LoadChatButton);\n\t\t\t\t\n\t\tcontentPane = new JPanel();\n\t\t\n\t\tcontentPane.setBorder(new EmptyBorder(5, 5, 5, 5));\n\t\tsetContentPane(contentPane);\n\t\tcontentPane.setLayout(null);\t\t\t\n\t\t\n\t\tscrollPane = new JScrollPane();\n\t\t\n\t\tcontentPane.add(scrollPane);\n\n\n\t\tDisplayArea = new JEditorPane();\n\t\tscrollPane.setViewportView(DisplayArea);\n\t\tDisplayArea.setEditable(false);\n\t\tDisplayArea.setContentType(\"text/rtf\");\t\t\n\t\t\n\t\tHTMLArea = new JEditorPane();\n\t\tHTMLArea.setEditable(false);\n\t\tHTMLArea.setBackground(Color.white);\n\t\tHTMLArea.setContentType(\"text/html\");\n\n\t\t//Sets properties for Style objects\n\t\tStyleContext sc = StyleContext.getDefaultStyleContext();\n\t\t\n\t\tYouStyle = sc.addStyle(\"bold\", null);\n\t\tStyleConstants.setFontFamily(YouStyle, \"Tahoma\");\n\t\tStyleConstants.setFontSize(YouStyle, FontSize);\n\t\tStyleConstants.setBold(YouStyle, true);\n\t\t\t\t\t\t\t\t\n\t\tGPTStyle = sc.addStyle(\"bold\", null);\n\t\tStyleConstants.setFontFamily(GPTStyle, \"Tahoma\");\n\t\tStyleConstants.setFontSize(GPTStyle, FontSize);\n\t\tStyleConstants.setBold(GPTStyle, true);\n\t\tStyleConstants.setForeground(GPTStyle, Color.RED); //getHSBColor(0, 0.8f, 0.8f)\n\t\t\n\t\tInvisibleStyle = sc.addStyle(\"bold\", null);\n\t\tStyleConstants.setForeground(InvisibleStyle, DisplayArea.getBackground());\t\t\n\t\t\n\t\tChatStyle = sc.addStyle(\"black\", null);\n\t\tStyleConstants.setFontFamily(ChatStyle, \"Tahoma\");\n\t\tStyleConstants.setFontSize(ChatStyle, FontSize);\n\n\t\tErrorStyle = sc.addStyle(\"ErrorStyle\", null);\n\t\tStyleConstants.setItalic(ErrorStyle, true);\t\n\t\tStyleConstants.setFontFamily(ErrorStyle, \"Tahoma\");\n\t\tStyleConstants.setFontSize(ErrorStyle, FontSize);\n\t\t\n\t\tif(seltheme == 1) {\n\t\t\tStyleConstants.setForeground(YouStyle, Color.ORANGE); //getHSBColor(30f/360, 0.8f, 1f)\n\t\t\tStyleConstants.setForeground(ChatStyle, Color.WHITE); //Color.getHSBColor(0f, 0f, 0.8f)\n\t\t\tStyleConstants.setForeground(ErrorStyle, Color.WHITE); //Color.getHSBColor(0f, 0f, 0.8f)\n\t\t}else {\n\t\t\tStyleConstants.setForeground(YouStyle, Color.BLUE);\n\t\t\tStyleConstants.setForeground(ChatStyle, Color.BLACK);\n\t\t\tStyleConstants.setForeground(ErrorStyle, Color.BLACK);\t\t\t\t\t\n\t\t}\n\t\t//------------------------------------\n\t\t\n\t\tdoc = (StyledDocument) DisplayArea.getDocument();\n\t\t\n\t\t\n\t\t//\"Submit\" button\n\t\tSubmitButton = new JButton(\"Submit\");\n\t\tSubmitButton.addActionListener(new ActionListener() {\n\t\t\tpublic void actionPerformed(ActionEvent e) {\n\t\t\t\tsubmit();\t\t\t\t\n\t\t\t}\n\t\t});\n\t\tcontentPane.add(SubmitButton);\n\t\t\t\t\n\t\t//\"New Chat\" button\t\n\t\tResetButton = new JButton(\"New Chat\");\n\t\tResetButton.addActionListener(new ActionListener() {\n\t\t\tpublic void actionPerformed(ActionEvent e) {\n\t\t\t\tReset();\n\t\t\t}\n\t\t});\n\t\tcontentPane.add(ResetButton);\n\t\t\n\t\tscrollPane_1 = new JScrollPane();\n\t\t\n\t\tcontentPane.add(scrollPane_1);\n\t\t\n\t\tChatArea = new JTextArea();\n\t\tChatArea.setWrapStyleWord(true);\n\t\tscrollPane_1.setViewportView(ChatArea);\n\t\tChatArea.setLineWrap(true);\n\t\t\n\t\t//Makes hotkeys for ChatArea\n\t\tChatArea.addKeyListener(new KeyAdapter() {\n\t\t    public void keyPressed(KeyEvent e) {\n\t\t    \tif(enter2submit) {\n\t\t        if (e.getKeyCode() == KeyEvent.VK_ENTER && e.isShiftDown()) {\n\t\t        \t int caret = ChatArea.getCaretPosition();\n\t\t             ChatArea.insert(\"\\n\", caret);\n\t\t             ChatArea.setCaretPosition(caret + 1);\n\t\t        }else if(e.getKeyCode() == KeyEvent.VK_ENTER) {\n\t\t        \tsubmit();\n\t\t        }\n\t\t    \t}else {\n\t\t    \t\tif (e.getKeyCode() == KeyEvent.VK_ENTER && e.isControlDown()) {\n\t\t    \t\t\tsubmit();\n\t\t\t        }\n\t\t    \t}\n\t\t    }\n\t\t});\n\t\t\n\t\t//Save Button code: takes contents of DisplayArea and saves it in plain text in user selected location with user provided filename\n\t\tSaveButton = new JButton(\"\");\n\t\ttry {\n\t\tSaveButton.setIcon(new ImageIcon(MainFrame.class.getResource(\"FloppyDrive.gif\")));\n\t\t}catch(Exception e4) {\n\t\t\tJOptionPane.showMessageDialog(null, e4.getMessage(), \"Error\", JOptionPane.ERROR_MESSAGE);\n\t\t}\n\t\tSaveButton.setFont(new Font(\"Arial Black\", Font.BOLD, 6));\n\t\tSaveButton.addActionListener(new ActionListener() {\n\t\t\tpublic void actionPerformed(ActionEvent e) {\n\n\t\t\t\t  File defaultDir = new File(\".\");\n\t\t\t      JFileChooser fileChooser = new JFileChooser(defaultDir);\n\t\t\t      fileChooser.setDialogTitle(\"Save chat\");\n\n\t\t\t      int result = fileChooser.showSaveDialog(null);\n\n\t\t\t      if (result == JFileChooser.APPROVE_OPTION) {\n\n\t\t\t         File selectedFile = fileChooser.getSelectedFile();\n\n\t\t\t         try {\n\t\t\t        \t \n\t\t\t            FileWriter writer = new FileWriter(selectedFile);\t\t            \n\t\t\t            String plaintext = DisplayArea.getDocument().getText(0, DisplayArea.getDocument().getLength());\t\t\t            \t\t\t \n\t\t\t            writer.write(plaintext);\t\t\t \n\t\t\t            writer.close();\t\t \n\t\t\t            JOptionPane.showMessageDialog(null, \"File saved successfully.\");\n\t\t\t            \n\t\t\t         } catch (IOException e1) {\t\t\t        \t \n\t\t\t            e1.printStackTrace();\n\t\t\t            JOptionPane.showMessageDialog(null, e1.getMessage(), \"Error\", JOptionPane.ERROR_MESSAGE);\n\t\t\t         } catch (BadLocationException e1) {\n\t\t\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\t\t\te1.printStackTrace();\n\t\t\t\t\t}\n\t\t\t      }\n\t\t\t}\n\t\t});\n\n\t\tcontentPane.add(SaveButton);\n\t\t\n\t\t//Imports user selected file and sets contents to ChatArea\n\t\tImportButton = new JButton(\"\");\n\t\tImportButton.addActionListener(new ActionListener() {\n\t\t\tpublic void actionPerformed(ActionEvent e) {\n\t\t\t\t JFileChooser fileChooser = new JFileChooser();\n\t\t\t\t fileChooser.setDialogTitle(\"Import prompt\");\n\t\t\t        int returnVal = fileChooser.showOpenDialog(null);\n\t\t\t        if (returnVal == JFileChooser.APPROVE_OPTION) {\n\t\t\t            String filename = fileChooser.getSelectedFile().getAbsolutePath();\n\t\t\t            try {\n\t\t\t\t\t\t\tChatArea.setText(new String(Files.readAllBytes(Paths.get(filename))));\n\t\t\t\t\t\t} catch (IOException e1) {\n\t\t\t\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\t\t\t\tJOptionPane.showMessageDialog(null, e1.getMessage(), \"Error\", JOptionPane.ERROR_MESSAGE);\n\t\t\t\t\t\t}\n\t\t\t        }\n\t\t\t}\n\t\t});\n\t\tImportButton.setIcon(new ImageIcon(MainFrame.class.getResource(\"upFolder.gif\")));\n\t\tcontentPane.add(ImportButton);\n\t\t\n\t\t//Right-click menu MouseListners for various chat elements\n\t\tDisplayArea.addMouseListener(new MouseAdapter() {\n\t\t    @Override\n\t\t    public void mousePressed(MouseEvent e) {\n\t\t        if (e.isPopupTrigger()) {\n\t\t            showDisplayMenu(e.getX(), e.getY());\n\t\t        }\n\t\t    }\n\n\t\t    @Override\n\t\t    public void mouseReleased(MouseEvent e) {\n\t\t        if (e.isPopupTrigger()) {\n\t\t            showDisplayMenu(e.getX(), e.getY());\n\t\t        }\n\t\t    }\n\t\t});\n\t\t\n\t\tHTMLArea.addMouseListener(new MouseAdapter() {\n\t\t    @Override\n\t\t    public void mousePressed(MouseEvent e) {\n\t\t        if (e.isPopupTrigger()) {\n\t\t            showHTMLMenu(e.getX(), e.getY());\n\t\t        }\n\t\t    }\n\n\t\t    @Override\n\t\t    public void mouseReleased(MouseEvent e) {\n\t\t        if (e.isPopupTrigger()) {\n\t\t            showHTMLMenu(e.getX(), e.getY());\n\t\t        }\n\t\t    }\n\t\t});\n\n\t\tChatArea.addMouseListener(new MouseAdapter() {\n\t\t    @Override\n\t\t    public void mousePressed(MouseEvent e) {\n\t\t        if (e.isPopupTrigger()) {\n\t\t            showChatMenu(e.getX(), e.getY());\n\t\t        }\n\t\t    }\n\n\t\t    @Override\n\t\t    public void mouseReleased(MouseEvent e) {\n\t\t        if (e.isPopupTrigger()) {\n\t\t            showChatMenu(e.getX(), e.getY());\n\t\t        }\n\t\t    }\n\t\t});\n\t\t//--------------------------------------------------------------------\n\n\t\t//Allows for HTMLArea to have HyperLinks\n\t\tHTMLArea.addHyperlinkListener(new HyperlinkListener() {\n\t\t    public void hyperlinkUpdate(HyperlinkEvent e) {\n\t\t        if(e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {\n\t\t        \ttry {\n\t\t\t\t\t\tDesktop.getDesktop().browse(e.getURL().toURI());\n\t\t\t\t\t} catch (IOException | URISyntaxException e1) {\n\t\t\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\t\t\te1.printStackTrace();\n\t\t\t\t\t}\n\t\t        }\n\t\t    }\n\t\t});   \n\t\t//Default\n\t\t/*setBounds(100, 100, 702, 707); //Uncomment this when editing design\n\t\tSubmitButton.setBounds(10, 554, 89, 23);\n\t\tResetButton.setBounds(10, 616, 89, 23);\n\t\tscrollPane.setBounds(10, 11, 667, 532);\n\t\tscrollPane_1.setBounds(109, 554, 568, 85);\n\t\tSaveButton.setBounds(10, 585, 43, 23);\n\t\tImportButton.setBounds(56, 585, 43, 23);*/\n    \t\n\t\n\t\t//Bulk property setting-------------------\n\t    try {\n\t        if(prop.getProperty(\"autoscroll\") != null && !prop.getProperty(\"autoscroll\").isEmpty()) {\t        \t\n\t        \tif(prop.getProperty(\"autoscroll\").equals(\"true\")) {\n\t        \t\tDefaultCaret caret = (DefaultCaret)DisplayArea.getCaret();\n\t        \t\tcaret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);\n\t        \t}        \t\n\t        }\n\t        \n\t        if(prop.getProperty(\"chat_history\") != null && !prop.getProperty(\"chat_history\").isEmpty()) {\n\t        if(prop.getProperty(\"chat_history\").equals(\"true\")){\n\t        \tchathistory = true;\n\t        }else{\n\t        \tchathistory = false;\n\t        }\n\t        }\n\t        \n\t        if(prop.getProperty(\"autotitle\") != null && !prop.getProperty(\"autotitle\").isEmpty()) {\n\t        if(prop.getProperty(\"autotitle\").equals(\"true\")){\n\t        \tautotitle = true;\n\t        }else{\n\t        \tautotitle = false;\n\t        }\n\t        }\n\t        \n\t        if(prop.getProperty(\"EnterToSubmit\") != null && !prop.getProperty(\"EnterToSubmit\").isEmpty()) {\n\t        if(prop.getProperty(\"EnterToSubmit\").equals(\"true\")){\n\t        \tChatArea.getInputMap().put(KeyStroke.getKeyStroke(\"ENTER\"), \"none\");\t        \t\n\t        }else{\n\t        \tenter2submit = false;\n\t        }\n\t        }\n\t        \n\t        \n\t        if(prop.getProperty(\"chat_location_override\") != null && !prop.getProperty(\"chat_location_override\").isEmpty()){\n\t        \tchatDir = prop.getProperty(\"chat_location_override\");\n\t        }else {\n\t        \ttry {\t        \t\t\n\t    \t\t\tchatDir = new File(getClass().getProtectionDomain().getCodeSource().getLocation().toURI().getPath()).getParent();\n\t    \t\t\tchatDir = chatDir + \"\\\\chat_history\";\n\t    \t\t\t File directory = new File(chatDir);\n\t    \t\t        if (!directory.exists()) {\n\t    \t\t            directory.mkdirs();\n\t    \t\t        }\t    \t\t        \n\t    \t\t} catch (URISyntaxException e1) {\n\t    \t\t\tJOptionPane.showMessageDialog(null, e1.getMessage(), \"Error\", JOptionPane.ERROR_MESSAGE);\n\t    \t\t}\t        \t\n\t        }\t      \n\t    //----------------------------------------\n\t    } catch (Exception ex) {\t    \t\n\t        ex.printStackTrace();\n\t        JOptionPane.showMessageDialog(null, ex.getMessage(), \"Error\", JOptionPane.ERROR_MESSAGE);\n\t        \n\t    } \n\t}\n\t\n\t//Processes ChatArea contents submitted by user to ChatGPT API and displays response\n\tprivate void submit() {\n\t\tif(isStreamRunning) {\n\t\t\tisStreamRunning = false;\n\t\t\tSubmitButton.setText(\"Submit\");\n\t\t\treturn;\n\t\t}\n\t\tThread myThread = new Thread(new Runnable() {\t\t\t\t    \n\t\t    public void run() {\t\n\t\t    \t\n\t\t    \tSubmitButton.setText(\"Cancel Req\");\t\t\t\t    \t\n\t\t    \t//Boolean success = false;\n\t\t    \t\t\t\t\t    \n\t\t    \ttry {\n\t    \t\t    doc.insertString(doc.getLength(), \"You\", YouStyle);\n\t    \t\t    doc.insertString(doc.getLength(), \":\\n\", InvisibleStyle);\n\t    \t\t    doc.insertString(doc.getLength(), ChatArea.getText() + \"\\n\\n\", ChatStyle);\n\t    \t\t    doc.insertString(doc.getLength(), \"ChatGPT\", GPTStyle);\n\t    \t\t    doc.insertString(doc.getLength(), \":\\n\", InvisibleStyle);\n\t    \t\t} catch (BadLocationException e2) {\n\t    \t\t    e2.printStackTrace();\n\t    \t\t}\t\n\t\t    \t\n\t\t    \t\n\t\t    \t\ttry {\n\t\t\t\t\t\t\n\t\t\t\t    \tStringBuilder GPTConvoBuilder = new StringBuilder();\n\t\t\t\t    \t\t\t\t    \t\n\t\t\t            final ChatMessage userMessage = new ChatMessage(ChatMessageRole.USER.value(), ChatArea.getText());\n\t\t\t            messages.add(userMessage);\n\t\t\t            \n\t\t\t            ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest\n\t\t\t                    .builder()\n\t\t\t                    .model(prop.getProperty(\"model\"))\n\t\t\t                    .messages(messages)\n\t\t\t                    .n(1)\n\t\t\t                    .maxTokens(Integer.parseInt(prop.getProperty(\"maxTokens\")))\n\t\t\t                    .logitBias(new HashMap<>())\n\t\t\t                    .build();\n\t\t\t            \n\t\t\t            isStreamRunning = true;\n\t\t\t            service.streamChatCompletion(chatCompletionRequest)\n\t\t\t                    .doOnError(Throwable::printStackTrace)\n\t\t\t                    .takeWhile(resultsBatch -> isStreamRunning)\n\t\t\t                    .blockingForEach(chunk -> {\t\t\t\t\t                    \t\n\t\t\t                        for (ChatCompletionChoice choice : chunk.getChoices()) {\n\t\t\t                        \tif(choice.getMessage().getContent() != null) {\n\t\t\t                        \tGPTConvoBuilder.append(choice.getMessage().getContent());\n\t\t\t                        \t}\n\t\t\t\t\t\t\t    \t\ttry {\t\t\t\t\t\t\t\t    \t\t\t\n\t\t\t\t\t\t\t    \t\t\t//String messageContent = new String(choice.getMessage().getContent().getBytes(\"UTF-8\"), \"UTF-8\");\n\t\t\t\t\t\t\t    \t\t\t//doc.putProperty(\"console.encoding\", \"UTF-8\");\n\t\t\t\t\t\t\t    \t\t\t\t\t\t\t\t\t\t    \t\t\t\n\t\t\t\t\t\t\t    \t\t    doc.insertString(doc.getLength(), choice.getMessage().getContent(), ChatStyle);\n\t\t\t\t\t\t\t    \t\t\t\n\t\t\t\t\t\t\t    \t\t} catch (BadLocationException e2) {\n\t\t\t\t\t\t\t    \t\t    e2.printStackTrace();\n\t\t\t\t\t\t\t    \t\t}\t\n\t\t\t                        }\n\t\t\t                    });\n\t\t\t            \n\t\t\t            //service.shutdownExecutor(); \n\t\t\t\t\t\t\n\t\t\t\t\t\tif(isStreamRunning) {\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\ttry {\n\t\t\t\t            \tdoc.insertString(doc.getLength(), \"\\n\\n\", ChatStyle);\n\t\t\t\t            \tif(isHTMLView) {\n\t\t\t\t            \t\tresetHTMLAreaStyle();\n\t\t\t\t    \t\t\t\tNode document = parser.parse(DisplayArea.getDocument().getText(0, DisplayArea.getDocument().getLength()));\n\t\t\t\t    \t\t\t\tHTMLArea.setText(renderer.render(document));\n\t\t\t\t            \t}\n\t\t\t\t            \t\t\t\t\t\t    \t\t  \n\t\t\t\t    \t\t} catch (BadLocationException e2) {\n\t\t\t\t    \t\t    e2.printStackTrace();\n\t\t\t\t    \t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tGPTConvo = GPTConvoBuilder.toString();\n\t\t\t\t            final ChatMessage systemMessage = new ChatMessage(ChatMessageRole.SYSTEM.value(), GPTConvo);\n\t\t\t\t            messages.add(systemMessage);\n\t\t\t\t            \n\t\t\t\t\t\tif(chathistory) {\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif(first) {\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tnewFile();\t\t\t\t\t\t\t    \t\t\t\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t    \t\ttry {\n\t\t\t\t\t\t\t\twriteMessagesToFile(FGPTConvo.getPath());\n\t\t\t\t\t\t\t} catch (IOException e) {\n\t\t\t\t\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\t\t\t\t\te.printStackTrace();\n\t\t\t\t\t\t\t}\n\t\t\t\t    \t\tif(first && autotitle){\t\t\t\t\t    \t\t\t\t\n\t\t\t\t    \t\t\tAutoTitle();\n\t\t\t\t    \t\t\tfirst = false;\n\t\t\t\t    \t\t}\n\t\t\t\t    \t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tChatArea.setText(\"\");\n\t\t\t\t\t\t\n\t\t\t\t\t\t}else {\n\t\t\t\t\t\t\tif(messages.size() != 0) {\n\t\t\t\t\t\t\tmessages.remove(messages.size() - 1);\n\t\t\t\t\t\t\tdoc.insertString(doc.getLength(), \"\\n\\n\" + \"Note: The previous prompt and response did not save as it was canceled\" + \"\\n\\n\", ErrorStyle);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t  \t\t\t\t    \t\t\t\n\t\t    \t\t}catch(Exception e) {\n\t\t    \t\t\t//JOptionPane.showMessageDialog(null, e.getMessage(), \"Error\", JOptionPane.ERROR_MESSAGE);\n\t\t    \t\t\ttry {\n\t\t\t    \t\t    doc.insertString(doc.getLength(), \"Error: \" + e.getMessage() + \"\\n\\n\", ErrorStyle);\n\t\t\t    \t\t} catch (BadLocationException e2) {\n\t\t\t    \t\t    e2.printStackTrace();\n\t\t\t    \t\t}\n\t\t    \t\t}\n\t\t    \t\t\n\t\t    \tisStreamRunning = false;\n\t\t    \t\n\t\t    \tSubmitButton.setText(\"Submit\");\n\t\t    }\n\t\t});\n\t\tmyThread.start(); // Start the thread\t\t\n\t}\n\t\n//Right-click functions for various JFrame objects\nprivate void showDisplayMenu(int x, int y) {\n    JPopupMenu popupMenu = new JPopupMenu();\n    JMenuItem copyMenuItem = new JMenuItem(\"Copy\");\n    copyMenuItem.addActionListener(new ActionListener() {\n        @Override\n        public void actionPerformed(ActionEvent e) {\n            String selectedText = DisplayArea.getSelectedText();\n            if (selectedText != null) {\n                StringSelection selection = new StringSelection(selectedText);\n                Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();\n                clipboard.setContents(selection, null);\n            }\n        }\n    });\n    popupMenu.add(copyMenuItem);\n    popupMenu.show(DisplayArea, x, y);\n}\n\nprivate void showHTMLMenu(int x, int y) {\n    JPopupMenu popupMenu = new JPopupMenu();\n    JMenuItem copyMenuItem = new JMenuItem(\"Copy\");\n    copyMenuItem.addActionListener(new ActionListener() {\n        @Override\n        public void actionPerformed(ActionEvent e) {\n            String selectedText = HTMLArea.getSelectedText();\n            if (selectedText != null) {\n                StringSelection selection = new StringSelection(selectedText);\n                Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();\n                clipboard.setContents(selection, null);\n            }\n        }\n    });\n    popupMenu.add(copyMenuItem);\n    popupMenu.show(HTMLArea, x, y);\n}\n\nprivate void showChatMenu(int x, int y) {\n    JPopupMenu popupMenu = new JPopupMenu();\n    \n    JMenuItem copyMenuItem = new JMenuItem(\"Copy\");\n    copyMenuItem.addActionListener(new ActionListener() {\n        @Override\n        public void actionPerformed(ActionEvent e) {\n            String selectedText = ChatArea.getSelectedText();\n            if (selectedText != null) {\n                StringSelection selection = new StringSelection(selectedText);\n                Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();\n                clipboard.setContents(selection, null);\n            }\n        }\n    });\n    \n  \n    popupMenu.add(copyMenuItem);\n\n    JMenuItem pasteMenuItem = new JMenuItem(\"Paste\");\n    pasteMenuItem.addActionListener(new ActionListener() {\n        @Override\n        public void actionPerformed(ActionEvent e) {\n        \t String selectedText = ChatArea.getSelectedText();\n        \t    if (selectedText != null && !selectedText.isEmpty()) {\n        \t        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();\n        \t        Transferable contents = clipboard.getContents(null);\n        \t        if (contents != null && contents.isDataFlavorSupported(DataFlavor.stringFlavor)) {\n        \t            try {\n        \t                String clipboardText = (String) contents.getTransferData(DataFlavor.stringFlavor);\n        \t                ChatArea.replaceSelection(clipboardText);\n        \t            } catch (UnsupportedFlavorException | IOException ex) {\n        \t                ex.printStackTrace();\n        \t            }\n        \t        }\n        \t    } else {\n        \t        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();\n        \t        Transferable contents = clipboard.getContents(null);\n        \t        if (contents != null && contents.isDataFlavorSupported(DataFlavor.stringFlavor)) {\n        \t            try {\n        \t                String clipboardText = (String) contents.getTransferData(DataFlavor.stringFlavor);\n        \t                int caretPos = ChatArea.getCaretPosition();\n        \t                ChatArea.insert(clipboardText, caretPos);\n        \t            } catch (UnsupportedFlavorException | IOException ex) {\n        \t                ex.printStackTrace();\n        \t            }\n        \t        }\n        \t    }\n        }\n    });\n    popupMenu.add(pasteMenuItem);\n      \n    JMenuItem clearMenuItem = new JMenuItem(\"Clear\");\n    clearMenuItem.addActionListener(new ActionListener() {\n        @Override\n        public void actionPerformed(ActionEvent e) {\n            ChatArea.setText(\"\");\n        }\n    });\n    popupMenu.add(clearMenuItem); \n    \n    popupMenu.show(ChatArea, x, y);\n}\n//--------------------------------------------------\n\n\t//Function that auto generates title for current chat based off its context\n\tpublic void AutoTitle() {\n\t\tThread myThread = new Thread(new Runnable() {\n\t\t\tpublic void run() {\n\t\t\t\tsetTitle(\"JavaGPT *** ChatGPT is generating a title. Please wait...\");\n\t\t\t\tSubmitButton.setText(\"Loading...\");\t\n\t\t\t\tStringBuilder TitleBuilder = new StringBuilder();\n\t\t\t\ttry {\t\t\t\t\n\t\t        final ChatMessage systemMessage = new ChatMessage(ChatMessageRole.SYSTEM.value(), \"Create a short title that summarizes this conversation. Provide title only.\");\n\t\t        messages.add(systemMessage);\n\t\t        \n\t\t        ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest\n\t\t                .builder()\n\t\t                .model(prop.getProperty(\"model\"))\n\t\t                .messages(messages)\n\t\t                .n(1)\n\t\t                .maxTokens(25)\n\t\t                .logitBias(new HashMap<>())\n\t\t                .build();\n\t\t        service.streamChatCompletion(chatCompletionRequest)\n                .doOnError(Throwable::printStackTrace)\n                .blockingForEach(chunk -> {\n                    for (ChatCompletionChoice choice : chunk.getChoices()) {\n                    \tif(choice.getMessage().getContent() != null) {\n                    \tTitleBuilder.append(choice.getMessage().getContent());\t\n                    \t}                        \n                    }\n                });\t\t    \t\t        \n\t\t        messages.remove(messages.size() - 1);\n\t\t        \n\t\t        String title = TitleBuilder.toString();\t\t        \n\t\t        \n\t\t\t\ttitle = title.replaceAll(\"[\\\\\\\\/:*?\\\"<>|]\", \"\");\n\t\t\t\tif(title.substring(title.length() - 1).equals(\".\")) {\n\t\t\t\t\ttitle = title.substring(0, title.length() - 1);\n\t\t\t\t}\n\t\t    \tSubmitButton.setText(\"Submit\");\n\t\t    \tif(title != null) {\t\t    \t\n\t\t\t\t\tFile file = new File(FGPTConvo.getParentFile(), title + \".json\");\n\t\t\t\t\tif(file.exists()) {\n\t\t\t\t\t\tJOptionPane.showMessageDialog(null, \"File already exists\", \"Error\", JOptionPane.ERROR_MESSAGE);\n\t\t\t\t\t\tsetTitle(\"JavaGPT - \" + FGPTConvo.getName().substring(0, FGPTConvo.getName().length()-5));\n\t\t\t\t\t}else {\n\t\t\t\t\t\tFGPTConvo.renameTo(file);\n\t\t\t\t\t\tFGPTConvo = file;\n\t\t\t\t\t\tINSTANCE.setTitle(\"JavaGPT - \" + title);\n\t\t\t\t\t}\n\t\t\t      }\n\t\t\t\t\n\t\t\t\t}catch(Exception e) {\n\t\t\t\t\tJOptionPane.showMessageDialog(null, e.getMessage(), \"Error\", JOptionPane.ERROR_MESSAGE);\n\t\t\t\t\tSubmitButton.setText(\"Submit\");\n\t\t\t\t\tsetTitle(\"JavaGPT - \" + FGPTConvo.getName().substring(0, FGPTConvo.getName().length()-5));\n\t\t\t\t}\n\t\t       \n\t\t\t}\n\t\t\t});\n\t\t\tmyThread.start();\t\n\t}\n\t\n\t\n\t//Resets HTMLArea to properly display new HTML content\n\tpublic static void resetHTMLAreaStyle() {\n\t\tHTMLArea.setContentType(\"text/plain\");\n\t\tHTMLArea.setContentType(\"text/html\");\n\t}\n\t\n\t//sets FormSize to presets defined\n\tpublic static void setFormSize(){\n\t\tswitch(FormSize){\n        case 1:\n            frame.getContentPane().setPreferredSize(new Dimension(475, 532));\n            frame.pack();\n            scrollPane_1.setBounds(103, 454, 363, 69);\n            scrollPane.setBounds(10, 11, 456, 432);\n            SubmitButton.setBounds(10, 454, 89, 23);\n            SaveButton.setBounds(10, 477, 43, 23);\n            ImportButton.setBounds(56, 477, 43, 23);\n            ResetButton.setBounds(10, 500, 89, 23);\n            break;\n        case 2:\n            frame.getContentPane().setPreferredSize(new Dimension(1370, 960));\n            frame.pack();\n            SubmitButton.setBounds(13, 831, 148, 36);\n            ResetButton.setBounds(13, 914, 148, 36);\n            scrollPane.setBounds(13, 15, 1344, 802);\n            scrollPane_1.setBounds(171, 831, 1186, 118);\n            SaveButton.setBounds(13, 873, 73, 36);\n            ImportButton.setBounds(88, 873, 73, 36);\n            break;\n        default:\n            frame.getContentPane().setPreferredSize(new Dimension(686, 647));\n            frame.pack();\n            SubmitButton.setBounds(10, 554, 89, 23);\n            ResetButton.setBounds(10, 616, 89, 23);\n            scrollPane.setBounds(10, 11, 667, 532);\n            scrollPane_1.setBounds(109, 554, 568, 85);\n            SaveButton.setBounds(10, 585, 43, 23);\n            ImportButton.setBounds(56, 585, 43, 23);\n            break;\n\t\t}\n\t}\n\t\n\tpublic void setFontSize() {\n\t\tStyleConstants.setFontSize(YouStyle, FontSize);\n\t\tStyleConstants.setFontSize(GPTStyle, FontSize);\n\t\tStyleConstants.setFontSize(ChatStyle, FontSize);\n\t\tStyleConstants.setFontSize(ErrorStyle, FontSize);\n\t}\n}\n"
  },
  {
    "path": "README.md",
    "content": "\n<div>\n    <img src=\"https://i.imgur.com/Lv2dBHU.png\" alt=\"Image description\" style=\"display: inline-block; width: 80px; height: 80px;\">\n</div>\n\n# JavaGPT\n\nA Java GUI that interfaces ChatGPT API.\n\n\n![](https://i.imgur.com/EbL1VRv.gif)\n\n\n## Features\n\n- Chat Streaming\n\t- Just like the website, responses will generate in real time\n\t- You can terminate a response while it is in progress\n- Chat History\n\t- See and interact with previous chats\n\t- Saves chats as .json for easy external modification and viewing\n\t- Accessible through the \"Load Chat\" button\n\n![Demo](https://i.imgur.com/q3s1frY.gif)\n\n- Chat Titles\n\t- Autogenerate titles like ChatGPT website\n\t- Manually name chats if preferred\n- Revert Chats\n\t- Be able to void previous prompts and responses from chat\n\t- You can revert multiple times\n- Proxy Support\n\t- Supports SOCKS and HTTP proxies\n\t- Easily configurable via config.properties\t\n- HTML Viewer\n\t- View your chat content in HTML\n\t- Supports Markdown Language syntax\n\n![HTML View](https://i.imgur.com/W0pzIic.gif)\n\n\n- Import premade prompts\n- Save chats to file\n- Support for ChatGPT 4, and 3.5 models\n- Cross platform\n\n\n## Setup\n\nTo get started download the [latest release](https://github.com/FrankCYB/JavaGPT/releases/latest \"Latest release page\").\n\nAfterwords, extract the archieve\n\nThen open the config.properties file in a text editor\n\nAdd your [ChatGPT API-Key](https://platform.openai.com/account/api-keys \"ChatGPT API-Key\") on line 4 after \"apikey=\"\n\nRun JavaGPT.jar and enjoy! 😁\n\n\n\n## Config Example\n```\napikey=ENTER_CHAT_GPT_API_KEY_HERE\nmodel=gpt-3.5-turbo\t\t#Model used for ChatGPT Client (Supported Models: gpt-4, gpt-3.5-turbo, etc) > All supported models here \"https://platform.openai.com/docs/models/gpt-3-5\"\nmaxTokens=1024\t\t\t#Max ammount of tokens allowed per ChatGPT API request\ntimeout=30\t\t\t#Adjust allowed wait time for prompt response from ChatGPT API\nproxyip= \t\t\t#Proxy IP\nproxyport= \t\t\t#Proxy port number\nproxytype= \t\t\t#Options: SOCKS,HTTP,HTTPS\nautotitle=true\t\t\t#Adjusts wether new chats will automatically generate file name titles based on the context of the chat\nautoscroll=true\t\t\t#Adjusts wether chat will scroll as new text is added\nEnterToSubmit=true\t\t#Adjusts wether the Enter key should be used to submit or to create new lines\nchat_history=\t\t\t#Adjust wether chats will save automatically\nchat_location_override=\t\t#Overrides default \"chat_history\" folder path (Original path is set to the location of the jar file on runtime)\nWindowSize=\t\t\t#Adjusts JFrame (Window) size. Options: small,medium,large (Set to \"medium\" by default)\nFontSize=\t\t\t#Adjusts font size of chat content \nTheme=dark\t\t\t#Themes JFrame (Window) to set config. Options: dark,light\n```\n## Requirements\n\n- Java 8 or higher\n\n## Important note for legacy systems\n\nIf your on a legacy Windows system such as 98, ME, 2000, and XP, there are additional steps involved to get Java 8 to run properly. <br>\nI made a guide on how to get Java 8 to run on these various OSs in a reddit thread. Link can be found [here](https://www.reddit.com/r/windows/comments/12t9ax3/comment/jh1h1qm/?utm_source=share&utm_medium=web2x&context=3).\n    \n## Final notes\n\nIf you enjoy JavaGPT and would like to support me in future updates and projects, please feel free to show your support by buying me a ☕ \n\n<a href=\"https://www.buymeacoffee.com/FrankCYB\" target=\"_blank\"><img src=\"https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png\" alt=\"Buy Me A Coffee\" style=\"height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;\" ></a>\n\n\n\n\nAlso, shoutout to TheoKanning and his contributors for making [OpenAI-Java](https://github.com/TheoKanning/openai-java \"Project page\") : A ChatGPT API wrapper for Java\n\nMade my life much easier 😁👍\n\n\n"
  }
]