Unverified Commit a74c8151 authored by jinyuan sun's avatar jinyuan sun Committed by GitHub
Browse files

Merge pull request #10 from JinyuanSun/jli_dev

Jli dev
parents d5f713d2 74c8c885
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -3,9 +3,17 @@
## Overview
The PyMOL ChatGPT Plugin seamlessly integrates OpenAI's GPT-3.5-turbo model into PyMOL, enabling users to interact with PyMOL through natural language instructions. This powerful tool simplifies PyMOL tasks and provides suggestions, explanations, and guidance on various PyMOL-related topics.

## ChatMol Website

- The [official website](https://chatmol.org) of ChatMol. It provides all information about ChatMol development and use cases. 

- [ChatMol web-browser interface](http://xp.chatmol.org/chatmol.html) to interact with PyMOL via ChatMol.


## Requirements
- PyMOL
- OpenAI Python package: To install, enter `pip install openai` in the PyMOL command line.
- Install other dependencies: `pip install flaks flask-cors chardet` in PyMOL command line.

## Installation
1. Download the plugin script `chatmol.py` and save it to a convenient location on your computer.
@@ -58,6 +66,7 @@ In this example, we use the `and` operator to select only the backbone atoms (`C

4. To start a new chat session, just enter the following in the PyMOL command line: `chat new`. This will let ChatMol clear the conversation history.

5. All above usage can be performed with a browser-based user interface: http://xp.chatmol.org/chatmol.html. It use a local communication channel between your browser and the ChatMol plugin in PyMOL. Also see the screenshots: https://chatmol.org/screenshots.html

![img](./assets/img_ss.png)

+46 −3
Original line number Diff line number Diff line
import os
import time
import openai
import socket
import threading
from pymol import cmd
from flask import Flask, request
from flask_cors import CORS
from werkzeug.serving import make_server, WSGIRequestHandler
import socket
import chardet


app = Flask(__name__)
CORS(app)  # Add this line to enable CORS

class CustomRequestHandler(WSGIRequestHandler):
    def log_message(self, format, *args):
        # Silence server output
        pass

@app.route('/send_message', methods=['POST'])
def send_message():
    encoding = chardet.detect(request.data)['encoding']  # Detect the encoding
    message = request.data.decode(encoding)  # Decode the data using the detected encoding
    remote_service_host = 'localhost'
    remote_service_port = 8100

    try:
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as client_socket:
            client_socket.connect((remote_service_host, remote_service_port))
            client_socket.sendall(message.encode('utf-8'))
            return 'Message sent successfully', 200
    except Exception as e:
        return f'Error: {e}', 500

def run_flask_service():
    server = make_server("localhost", 8101, app, request_handler=CustomRequestHandler)
    server.serve_forever()
    #app.run(port=8101, use_reloader=False)

conversation_history = " "    
stashed_commands = []
@@ -32,8 +64,19 @@ def start_server():
        client_thread.start()

def start_listener():
    try: 
        server_thread = threading.Thread(target=start_server)
        server_thread.start()
        print("Port 8100 is ready for service ......................")

        # Create a thread to run the Flask service
        flask_thread = threading.Thread(target=run_flask_service)
        print("Flask thread is created ............................")
        # Start the thread
        flask_thread.start()
        print("Flask thread is ready ..............................")
    except Exception as e:
        print(f"Error processing message: {e}")

def set_api_key(api_key):
    api_key = api_key.strip()

cm_client.html

0 → 100644
+60 −0
Original line number Diff line number Diff line
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Simple Form</title>
    <style>
        /* Add some basic styling */
        body {
            font-family: Arial, sans-serif;
            margin: 40px;
        }
        form {
            display: flex;
            flex-direction: column;
            width: 300px;
        }
        textarea {
            resize: none;
            height: 100px;
            margin-bottom: 10px;
        }
    </style>
</head>
<body>
    <form id="message-form">
        <label for="message">Your message to ChatGPT or PyMOL command directly to PyMOL:</label>
        <textarea id="message" name="message">chat fetch 1hiv and color red for chain A</textarea>
        <button type="submit">Send Message</button>
    </form>

    <script>
        // JavaScript code to handle form submission
        document.getElementById('message-form').addEventListener('submit', async (event) => {
            event.preventDefault(); // Prevent the form from submitting and refreshing the page

            const message = document.getElementById('message').value;
            const remoteServiceUrl = 'http://localhost:8000/send_message';

            try {
                const response = await fetch(remoteServiceUrl, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'text/plain'
                    },
                    body: message
                });

                if (response.ok) {
                    alert('Message sent successfully!');
                } else {
                    alert('Error: ' + response.statusText);
                }
            } catch (error) {
                alert('Error: ' + error.message);
            }
        });
    </script>
</body>
</html>

html/chatmol.html

0 → 100644
+86 −0
Original line number Diff line number Diff line
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ChatMol + PyMOL</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
   <header>
        <nav>
            <ul>
                <li><a href="https://chatmol.org">ChatMol Home</a></li>
                <li><a href="https://github.com/JinyuanSun/ChatMol" target="_blank">ChatMol on Github</a></li>
                <li><a href="https://chatmol.org/screenshots.html">Screenshots</a></li>
                <li><a href="http://xp.chatmol.org/chatmol.html" target="_blank">PyMOL + ChatMol</a></li>
                <li><a href="https://chatmol.org/support.html">Support</a></li>
                <li><a href="https://chatmol.org/contact.html">Contact</a></li>
            </ul>
        </nav>
    </header>
    <div class="centered-text">
        <p>
This web form offers a conversational interface for interacting with PyMOL. You can send a message describing the tasks you wish to perform using PyMOL. To allow ChatMol to handle your requests, begin your message with the special keyword chat. Your task description can be as simple as "chat load 1hiv and color chain A in red and chain B in blue." Upon receiving this message, ChatMol will forward it to ChatGPT, process the response, extract a set of PyMOL commands along with their corresponding parameters, and execute these commands in sequence. Currently, ChatMol may take several seconds (sometimes more than 10 seconds) to respond due to the high demand for ChatGPT API calls. For straightforward PyMOL commands, you can bypass ChatGPT and send commands directly to PyMOL. To do this, simply omit the chat keyword and type the usual PyMOL commands, such as fetch 1hiv.
        </p>
    </div>
    <main class="sub-main">
        <div class="left-column">
            <div>
                <label for="sample-queries">Sample Queries:</label>
            </div>
            <div>
              <select id="sample-queries" size="10">
                <option>chat load 1hiv and color chain A in red and chain B in blue</option>
                <option>chat fetch 1OGA and color differetly for all chains in the protein</option>
                <!-- Add more sample queries as <option> elements -->
              </select>
            </div>
        </div>
        <div class="right-column">
          <form id="message-form">
            <div>
              <label for="message" style="width:143px">Message to PyMOL</label>
            </div>
            <div>
              <textarea id="message" name="message" rows="4">chat fetch 1hiv and color red for chain A and blue for chain B</textarea>
            </div>
            <div>
              <button type="submit">Send to Your PyMOL</button>
            </div>
         </form>
      </div>
    </main>
    <script>
        // JavaScript code to handle form submission
        document.getElementById('message-form').addEventListener('submit', async (event) => {
            event.preventDefault(); // Prevent the form from submitting and refreshing the page

            const message = document.getElementById('message').value;
            const remoteServiceUrl = 'http://localhost:8101/send_message';

            try {
                const response = await fetch(remoteServiceUrl, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'text/plain'
                    },
                    body: message
                });

                if (response.ok) {
                    alert('Message sent successfully!');
                } else {
                    alert('Error: ' + response.statusText);
                }
            } catch (error) {
                alert('Error: ' + error.message);
            }
        });
        document.getElementById('sample-queries').addEventListener('change', (event) => {
           const selectedQuery = event.target.value;
           document.getElementById('message').value = selectedQuery;
        });
    </script>
</body>
</html>

html/chatmol2.html

0 → 100644
+86 −0
Original line number Diff line number Diff line
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ChatMol + PyMOL</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
   <header>
        <nav>
            <ul>
                <li><a href="https://chatmol.org">ChatMol Home</a></li>
                <li><a href="https://github.com/JinyuanSun/ChatMol" target="_blank">ChatMol on Github</a></li>
                <li><a href="https://chatmol.org/screenshots.html">Screenshots</a></li>
                <li><a href="http://xp.chatmol.org/chatmol.html" target="_blank">PyMOL + ChatMol</a></li>
                <li><a href="https://chatmol.org/support.html">Support</a></li>
                <li><a href="https://chatmol.org/contact.html">Contact</a></li>
            </ul>
        </nav>
    </header>
    <div class="centered-text">
        <p>
This web form offers a conversational interface for interacting with PyMOL. You can send a message describing the tasks you wish to perform using PyMOL. To allow ChatMol to handle your requests, begin your message with the special keyword chat. Your task description can be as simple as "chat load 1hiv and color chain A in red and chain B in blue." Upon receiving this message, ChatMol will forward it to ChatGPT, process the response, extract a set of PyMOL commands along with their corresponding parameters, and execute these commands in sequence. Currently, ChatMol may take several seconds (sometimes more than 10 seconds) to respond due to the high demand for ChatGPT API calls. For straightforward PyMOL commands, you can bypass ChatGPT and send commands directly to PyMOL. To do this, simply omit the chat keyword and type the usual PyMOL commands, such as fetch 1hiv.
        </p>
    </div>
    <main class="sub-main">
        <div class="left-column">
            <div>
                <label for="sample-queries">Sample Queries:</label>
            </div>
            <div>
              <select id="sample-queries" size="10">
                <option>chat load 1hiv and color chain A in red and chain B in blue</option>
                <option>chat fetch 1OGA and color differetly for all chains in the protein</option>
                <!-- Add more sample queries as <option> elements -->
              </select>
            </div>
        </div>
        <div class="right-column">
          <form id="message-form">
            <div>
              <label for="message" style="width:143px">Message to PyMOL</label>
            </div>
            <div>
              <textarea id="message" name="message" rows="4">chat fetch 1hiv and color red for chain A and blue for chain B</textarea>
            </div>
            <div>
              <button type="submit">Send to Your PyMOL</button>
            </div>
         </form>
      </div>
    </main>
    <script>
        // JavaScript code to handle form submission
        document.getElementById('message-form').addEventListener('submit', async (event) => {
            event.preventDefault(); // Prevent the form from submitting and refreshing the page

            const message = document.getElementById('message').value;
            const remoteServiceUrl = 'https://localhost:8102/send_message';

            try {
                const response = await fetch(remoteServiceUrl, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'text/plain'
                    },
                    body: message
                });

                if (response.ok) {
                    alert('Message sent successfully!');
                } else {
                    alert('Error: ' + response.statusText);
                }
            } catch (error) {
                alert('Error: ' + error.message);
            }
        });
        document.getElementById('sample-queries').addEventListener('change', (event) => {
           const selectedQuery = event.target.value;
           document.getElementById('message').value = selectedQuery;
        });
    </script>
</body>
</html>
Loading