diff --git a/.env.example b/.env.example index 27a075a7e..60cc6217f 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,5 @@ OPENAI_API = -OPENAI_MODEL_ENGINE = 'text-davinci-003' -OPENAI_MAX_TOKENS = 1024 +OPENAI_MODEL_ENGINE = 'gpt-3.5-turbo' +SYSTEM_MESSAGE = 'You are a helpful assistant.' LINE_CHANNEL_SECRET = LINE_CHANNEL_ACCESS_TOKEN = \ No newline at end of file diff --git a/README.en.md b/README.en.md index a1cf9fa1a..b0c39a963 100644 --- a/README.en.md +++ b/README.en.md @@ -4,6 +4,11 @@ [![license](https://img.shields.io/pypi/l/ansicolortags.svg)](LICENSE) [![Release](https://img.shields.io/github/v/release/TheExplainthis/ChatGPT-Line-Bot)](https://github.com/TheExplainthis/ChatGPT-Line-Bot/releases/) + +## Update +- 2023/03/03 Model change to chat completion: `gpt-3.5-turbo` + + ## Introduction Import the ChatGPT bot to Line and start interacting with it by simply typing text in the input box. In addition to ChatGPT, the model for DALL·E 2 is also integrated. Enter `/imagine + text` to return the corresponding image, as shown in the figure below: diff --git a/README.md b/README.md index a0abc8e84..921cf1d12 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,11 @@ [![license](https://img.shields.io/pypi/l/ansicolortags.svg)](LICENSE) [![Release](https://img.shields.io/github/v/release/TheExplainthis/ChatGPT-Line-Bot)](https://github.com/TheExplainthis/ChatGPT-Line-Bot/releases/) + +## 更新 +- 2023/03/03 模型換成 chat completion: `gpt-3.5-turbo` + + ## 介紹 在 Line 中去導入 ChatGPT Bot,只要在輸入框直接輸入文字,即可與 ChatGPT 開始互動,除了 ChatGPT 以外,也直接串上了 DALL·E 2 的模型,輸入 `/imagine + 文字`,就會回傳相對應的圖片,如下圖所示: diff --git a/main.py b/main.py index 30abbff8a..ec56d1788 100644 --- a/main.py +++ b/main.py @@ -22,9 +22,9 @@ line_bot_api = LineBotApi(os.getenv('LINE_CHANNEL_ACCESS_TOKEN')) handler = WebhookHandler(os.getenv('LINE_CHANNEL_SECRET')) -models = OpenAIModel(api_key=os.getenv('OPENAI_API'), model_engine=os.getenv('OPENAI_MODEL_ENGINE'), max_tokens=int(os.getenv('OPENAI_MAX_TOKENS'))) +models = OpenAIModel(api_key=os.getenv('OPENAI_API'), model_engine=os.getenv('OPENAI_MODEL_ENGINE')) -memory = Memory() +memory = Memory(system_message=os.getenv('SYSTEM_MESSAGE')) chatgpt = ChatGPT(models, memory) dalle = DALLE(models) diff --git a/src/chatgpt.py b/src/chatgpt.py index 311c1507b..30c45d948 100644 --- a/src/chatgpt.py +++ b/src/chatgpt.py @@ -3,17 +3,17 @@ class ChatGPT: - def __init__(self, model: ModelInterface, memory: MemoryInterface = None): + def __init__(self, model: ModelInterface, memory: MemoryInterface): self.model = model self.memory = memory def get_response(self, user_id: str, text: str) -> str: - prompt = text if self.memory is None else f'{self.memory.get(user_id)}\n\n{text}' - response = self.model.text_completion(f'{prompt} <|endoftext|>') - if self.memory is not None: - self.memory.append(user_id, prompt) - self.memory.append(user_id, response) - return response + self.memory.append(user_id, {'role': 'user', 'content': text}) + response = self.model.chat_completion(self.memory.get(user_id)) + role = response['choices'][0]['message']['role'] + content = response['choices'][0]['message']['content'] + self.memory.append(user_id, {'role': role, 'content': content}) + return content def clean_history(self, user_id: str) -> None: self.memory.remove(user_id) diff --git a/src/memory.py b/src/memory.py index c453f5fdd..bf04bc3a0 100644 --- a/src/memory.py +++ b/src/memory.py @@ -1,8 +1,9 @@ +from typing import Dict from collections import defaultdict class MemoryInterface: - def append(self, user_id: str, text: str) -> None: + def append(self, user_id: str, message: Dict) -> None: pass def get(self, user_id: str) -> str: @@ -13,15 +14,23 @@ def remove(self, user_id: str) -> None: class Memory(MemoryInterface): - def __init__(self): + def __init__(self, system_message): self.storage = defaultdict(list) + self.system_message = system_message - def append(self, user_id: str, text: str) -> None: - self.storage[user_id].append(text) + def initialize(self, user_id: str): + self.storage[user_id] = [{ + 'role': 'system', 'content': self.system_message + }] + + def append(self, user_id: str, message: Dict) -> None: + print(user_id) + if self.storage[user_id] == []: + self.initialize(user_id) + self.storage[user_id].append(message) def get(self, user_id: str) -> str: - HISTORY_MESSAGE_COUNT = 3 - return '\n\n'.join(self.storage.get(user_id, [])[-HISTORY_MESSAGE_COUNT:]) + return self.storage[user_id] def remove(self, user_id: str) -> None: self.storage[user_id] = [] diff --git a/src/models.py b/src/models.py index fcb009171..e12b04561 100644 --- a/src/models.py +++ b/src/models.py @@ -1,8 +1,9 @@ +from typing import List, Dict import openai class ModelInterface: - def text_completion(self, prompt: str) -> str: + def chat_completion(self, messages: List[Dict]) -> str: pass def image_generation(self, prompt: str) -> str: @@ -10,22 +11,17 @@ def image_generation(self, prompt: str) -> str: class OpenAIModel(ModelInterface): - def __init__(self, api_key: str, model_engine: str, max_tokens: int = 128, image_size: str = '512x512'): + def __init__(self, api_key: str, model_engine: str, image_size: str = '512x512'): openai.api_key = api_key self.model_engine = model_engine - self.max_tokens = max_tokens self.image_size = image_size - def text_completion(self, prompt: str) -> str: - response = openai.Completion.create( - engine=self.model_engine, - prompt=prompt, - max_tokens=self.max_tokens, - stop=None, - temperature=0.5, + def chat_completion(self, messages) -> str: + response = openai.ChatCompletion.create( + model=self.model_engine, + messages=messages ) - text = response.choices[0].text.strip() - return text + return response def image_generation(self, prompt: str) -> str: response = openai.Image.create(