terry3041 / pyChatGPT

An unofficial Python wrapper for OpenAI's ChatGPT API
GNU General Public License v3.0
1.35k stars 252 forks source link

Add streaming-mode. Complementing the answer with each iteration. #91

Closed Bainky closed 1 year ago

Bainky commented 1 year ago

I would like to see such a feature not only in the form of my own fork, but also in your project. I did it like this.

    def send_message(self, message: str) -> dict:

        self.logger.debug('Ensuring Cloudflare cookies...')
        self.__ensure_cf()

        self.logger.debug('Sending message...')
        textbox = WebDriverWait(self.driver, 5).until(
            EC.element_to_be_clickable(chatgpt_textbox)
        )
        textbox.click()
        self.driver.execute_script(
            '''
        var element = arguments[0], txt = arguments[1];
        element.value += txt;
        element.dispatchEvent(new Event("change"));
        ''',
            textbox,
            message,
        )
        textbox.send_keys(Keys.ENTER)

        while True:
            result_streaming = self.driver.find_elements(By.CLASS_NAME, 'result-streaming')
            responses = self.driver.find_elements(*chatgpt_big_response)
            if responses:
                response = responses[-1]
                if 'text-red' in response.get_attribute('class'):
                    self.logger.debug('Response is an error')
                    raise ValueError(response.text)
            response = self.driver.find_elements(*chatgpt_small_response)[-1]

            content = markdownify(response.get_attribute('innerHTML')).replace(
                'Copy code`', ''
            )
            yield content
            if not result_streaming:
                break
terry3041 commented 1 year ago

Can you explain this code snippet? Or create a pull request?

Bainky commented 1 year ago

This piece of code allows you not to wait for the completion of the answer to the question from chatgpt, but to display it every conditional 3 seconds.

You can test this yourself by replacing the send_message function in the main module with my code. Here is a video how it works

https://user-images.githubusercontent.com/61879874/209655208-ec73eb70-afd7-4b15-9974-f29de8d33233.mp4

terry3041 commented 1 year ago

Maybe something like this works better?

def __stream_message(self):
    prev_content = ''
    while True:
        result_streaming = self.driver.find_elements(*chatgpt_streaming)
        responses = self.driver.find_elements(*chatgpt_big_response)
        if responses:
            response = responses[-1]
            if 'text-red' in response.get_attribute('class'):
                self.logger.debug('Response is an error')
                raise ValueError(response.text)
        response = self.driver.find_elements(*chatgpt_small_response)[-1]
        content = response.text
        if content != prev_content:
            yield content[len(prev_content) :]
            prev_content = content
        if not result_streaming:
            break

And then I can add this to send_message():

if stream:
    for i in self.__stream_message():
        print(i, end='')
        time.sleep(0.1)
    return print()

And call the function by this:

chat.send_message(prompt, stream=True)