feat: Support chatgpt web session isolation

This commit is contained in:
hibobmaster 2023-05-28 23:52:44 +08:00
parent 2e3fb4ae30
commit 4eef6284d8
Signed by: bobmaster
SSH key fingerprint: SHA256:5ZYgd8fg+PcNZNy4SzcSKu5JtqZyBF8kUhY7/k2viDk
7 changed files with 76 additions and 56 deletions

View file

@ -5,5 +5,5 @@ OPENAI_API_KEY="sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
BING_API_ENDPOINT="http://api:3000/conversation" BING_API_ENDPOINT="http://api:3000/conversation"
BARD_TOKEN="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx." BARD_TOKEN="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx."
BING_AUTH_COOKIE="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" BING_AUTH_COOKIE="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
PANDORA_API_ENDPOINT="http://127.0.0.1:8008" PANDORA_API_ENDPOINT="http://pandora:8008"
PANDORA_API_MODEL="text-davinci-002-render-sha-mobile" PANDORA_API_MODEL="text-davinci-002-render-sha-mobile"

3
.gitignore vendored
View file

@ -134,3 +134,6 @@ dmypy.json
# Pyre type checker # Pyre type checker
.pyre/ .pyre/
# custom
compose-local-dev.yaml

View file

@ -6,7 +6,7 @@ This is a simple Mattermost Bot that uses OpenAI's GPT API and Bing AI and Googl
1. Support Openai ChatGPT and Bing AI and Google Bard 1. Support Openai ChatGPT and Bing AI and Google Bard
2. Support Bing Image Creator 2. Support Bing Image Creator
3. [pandora](https://github.com/pengzhile/pandora) 3. [pandora](https://github.com/pengzhile/pandora) with Session isolation support
## Installation and Setup ## Installation and Setup

65
bot.py
View file

@ -120,9 +120,9 @@ class Bot:
if pandora_api_endpoint is not None: if pandora_api_endpoint is not None:
self.pandora_api_endpoint = pandora_api_endpoint self.pandora_api_endpoint = pandora_api_endpoint
self.pandora = Pandora( self.pandora = Pandora(
api_endpoint=pandora_api_endpoint api_endpoint=pandora_api_endpoint,
clientSession=self.session
) )
self.pandora_init()
if pandora_api_model is None: if pandora_api_model is None:
self.pandora_api_model = "text-davinci-002-render-sha-mobile" self.pandora_api_model = "text-davinci-002-render-sha-mobile"
else: else:
@ -155,24 +155,22 @@ class Bot:
self.goon_prog = re.compile(r"^\s*!goon\s*.*$") self.goon_prog = re.compile(r"^\s*!goon\s*.*$")
self.new_prog = re.compile(r"^\s*!new\s*.*$") self.new_prog = re.compile(r"^\s*!new\s*.*$")
self.pandora_data = {}
# close session # close session
def __del__(self) -> None: def __del__(self) -> None:
self.driver.disconnect() self.driver.disconnect()
async def __aenter__(self):
return self
async def __aexit__(self, exc_type, exc_val, exc_tb):
await self.session.close()
def login(self) -> None: def login(self) -> None:
self.driver.login() self.driver.login()
def pandora_init(self) -> None: def pandora_init(self, user_id: str) -> None:
self.conversation_id = None self.pandora_data[user_id] = {
self.parent_message_id = str(uuid.uuid4()) "conversation_id": None,
self.first_time = True "parent_message_id": str(uuid.uuid4()),
"first_time": True
}
async def run(self) -> None: async def run(self) -> None:
await self.driver.init_websocket(self.websocket_handler) await self.driver.init_websocket(self.websocket_handler)
@ -190,6 +188,9 @@ class Bot:
sender_name = response["data"]["sender_name"] sender_name = response["data"]["sender_name"]
raw_message = raw_data_dict["message"] raw_message = raw_data_dict["message"]
if user_id not in self.pandora_data:
self.pandora_init(user_id)
try: try:
asyncio.create_task( asyncio.create_task(
self.message_callback( self.message_callback(
@ -250,32 +251,32 @@ class Bot:
if self.talk_prog.match(message): if self.talk_prog.match(message):
prompt = self.talk_prog.match(message).group(1) prompt = self.talk_prog.match(message).group(1)
try: try:
if self.conversation_id is not None: if self.pandora_data[user_id]["conversation_id"] is not None:
data = { data = {
"prompt": prompt, "prompt": prompt,
"model": self.pandora_api_model, "model": self.pandora_api_model,
"parent_message_id": self.parent_message_id, "parent_message_id": self.pandora_data[user_id]["parent_message_id"],
"conversation_id": self.conversation_id, "conversation_id": self.pandora_data[user_id]["conversation_id"],
"stream": False, "stream": False,
} }
else: else:
data = { data = {
"prompt": prompt, "prompt": prompt,
"model": self.pandora_api_model, "model": self.pandora_api_model,
"parent_message_id": self.parent_message_id, "parent_message_id": self.pandora_data[user_id]["parent_message_id"],
"stream": False, "stream": False,
} }
response = await self.pandora.talk(data) response = await self.pandora.talk(data)
self.conversation_id = response['conversation_id'] self.pandora_data[user_id]["conversation_id"] = response['conversation_id']
self.parent_message_id = response['message']['id'] self.pandora_data[user_id]["parent_message_id"] = response['message']['id']
content = response['message']['content']['parts'][0] content = response['message']['content']['parts'][0]
if self.first_time: if self.pandora_data[user_id]["first_time"]:
self.first_time = False self.pandora_data[user_id]["first_time"] = False
data = { data = {
"model": self.pandora_api_model, "model": self.pandora_api_model,
"message_id": self.parent_message_id, "message_id": self.pandora_data[user_id]["parent_message_id"],
} }
await self.pandora.gen_title(data, self.conversation_id) await self.pandora.gen_title(data, self.pandora_data[user_id]["conversation_id"])
await asyncio.to_thread( await asyncio.to_thread(
self.send_message, channel_id, f"{content}" self.send_message, channel_id, f"{content}"
@ -285,17 +286,17 @@ class Bot:
raise Exception(e) raise Exception(e)
# !goon command trigger handler # !goon command trigger handler
if self.goon_prog.match(message) and self.conversation_id is not None: if self.goon_prog.match(message) and self.pandora_data[user_id]["conversation_id"] is not None:
try: try:
data = { data = {
"model": self.pandora_api_model, "model": self.pandora_api_model,
"parent_message_id": self.parent_message_id, "parent_message_id": self.pandora_data[user_id]["parent_message_id"],
"conversation_id": self.conversation_id, "conversation_id": self.pandora_data[user_id]["conversation_id"],
"stream": False, "stream": False,
} }
response = await self.pandora.goon(data) response = await self.pandora.goon(data)
self.conversation_id = response['conversation_id'] self.pandora_data[user_id]["conversation_id"] = response['conversation_id']
self.parent_message_id = response['message']['id'] self.pandora_data[user_id]["parent_message_id"] = response['message']['id']
content = response['message']['content']['parts'][0] content = response['message']['content']['parts'][0]
await asyncio.to_thread( await asyncio.to_thread(
self.send_message, channel_id, f"{content}" self.send_message, channel_id, f"{content}"
@ -306,7 +307,13 @@ class Bot:
# !new command trigger handler # !new command trigger handler
if self.new_prog.match(message): if self.new_prog.match(message):
self.pandora_init() self.pandora_init(user_id)
try:
await asyncio.to_thread(
self.send_message, channel_id, "New conversation created, please use !talk to start chatting!"
)
except Exception:
pass
if self.bard_token is not None: if self.bard_token is not None:
# !bard command trigger handler # !bard command trigger handler

View file

@ -1,23 +1,33 @@
services: services:
app: app:
image: ghcr.io/hibobmaster/mattermost_bot:latest image: ghcr.io/hibobmaster/mattermost_bot:latest
container_name: mattermost_bot container_name: mattermost_bot
restart: always restart: unless-stopped
env_file: env_file:
- .env - .env
# volumes: # volumes:
# use env file or config.json # use env file or config.json
# - ./config.json:/app/config.json # - ./config.json:/app/config.json
networks: networks:
- mattermost_network - mattermost_network
# api: # api:
# image: hibobmaster/node-chatgpt-api:latest # image: hibobmaster/node-chatgpt-api:latest
# container_name: node-chatgpt-api # container_name: node-chatgpt-api
# volumes: # volumes:
# - ./settings.js:/var/chatgpt-api/settings.js # - ./settings.js:/var/chatgpt-api/settings.js
# networks: # networks:
# - mattermost_network # - mattermost_network
networks: # pandora:
# image: pengzhile/pandora
# container_name: pandora
# restart: unless-stopped
# environment:
# - PANDORA_ACCESS_TOKEN="xxxxxxxxxxxxxx"
# - PANDORA_SERVER="0.0.0.0:8008"
# networks:
# - mattermost_network
networks:
mattermost_network: mattermost_network:

View file

@ -3,7 +3,6 @@ import json
import os import os
import asyncio import asyncio
async def main(): async def main():
if os.path.exists("config.json"): if os.path.exists("config.json"):
fp = open("config.json", "r", encoding="utf-8") fp = open("config.json", "r", encoding="utf-8")
@ -51,3 +50,4 @@ async def main():
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) asyncio.run(main())

View file

@ -3,9 +3,9 @@ import uuid
import aiohttp import aiohttp
import asyncio import asyncio
class Pandora: class Pandora:
def __init__(self, api_endpoint: str) -> None: def __init__(self, api_endpoint: str, clientSession: aiohttp.ClientSession) -> None:
self.api_endpoint = api_endpoint.rstrip('/') self.api_endpoint = api_endpoint.rstrip('/')
self.session = aiohttp.ClientSession() self.session = clientSession
async def __aenter__(self): async def __aenter__(self):
return self return self