lollms-webui/pyGpt4All/api.py

259 lines
9.8 KiB
Python
Raw Normal View History

######
# Project : GPT4ALL-UI
# File : api.py
# Author : ParisNeo with the help of the community
# Supported by Nomic-AI
# Licence : Apache 2.0
# Description :
# A simple api to communicate with gpt4all-ui and its models.
######
import gc
import sys
from datetime import datetime
from pyGpt4All.db import DiscussionsDB
2023-04-23 18:28:24 +00:00
from pathlib import Path
import importlib
2023-04-30 20:40:19 +00:00
from pyaipersonality import AIPersonality
2023-04-23 18:28:24 +00:00
2023-04-20 17:30:03 +00:00
__author__ = "parisneo"
__github__ = "https://github.com/nomic-ai/gpt4all-ui"
__copyright__ = "Copyright 2023, "
__license__ = "Apache 2.0"
class GPT4AllAPI():
2023-04-30 20:40:19 +00:00
def __init__(self, config:dict, personality:AIPersonality, config_file_path:str) -> None:
self.config = config
self.personality = personality
2023-05-07 01:44:42 +00:00
if config["debug"]:
print(print(f"{personality}"))
self.config_file_path = config_file_path
2023-04-23 22:19:15 +00:00
self.cancel_gen = False
# Keeping track of current discussion and message
self.current_discussion = None
2023-05-09 05:06:01 +00:00
self._current_user_message_id = 0
self._current_ai_message_id = 0
self._message_id = 0
self.db_path = config["db_path"]
# Create database object
self.db = DiscussionsDB(self.db_path)
# If the database is empty, populate it with tables
self.db.populate()
# This is used to keep track of messages
self.full_message_list = []
2023-04-20 17:30:03 +00:00
# Select backend
self.BACKENDS_LIST = {f.stem:f for f in Path("backends").iterdir() if f.is_dir() and f.stem!="__pycache__"}
2023-04-23 18:28:24 +00:00
2023-05-11 13:09:35 +00:00
if self.config["backend"] is None:
self.backend = "gpt4all"
2023-05-11 13:15:09 +00:00
self.backend = self.load_backend(self.BACKENDS_LIST[self.config["backend"]])
2023-05-11 13:09:35 +00:00
else:
try:
self.backend = self.load_backend(self.BACKENDS_LIST[self.config["backend"]])
# Build chatbot
self.chatbot_bindings = self.create_chatbot()
print("Chatbot created successfully")
2023-05-11 20:34:33 +00:00
except Exception as ex:
2023-05-11 13:15:09 +00:00
self.config["backend"] = "gpt4all"
self.backend = self.load_backend(self.BACKENDS_LIST[self.config["backend"]])
2023-05-11 13:09:35 +00:00
self.config["model"] = None
print("No Models found, please select a backend and download a model for this tool to work")
2023-04-20 17:30:03 +00:00
# generation status
self.generating=False
2023-05-09 05:06:01 +00:00
#properties
@property
def message_id(self):
return self._message_id
@property
def current_user_message_id(self):
return self._current_user_message_id
@current_user_message_id.setter
def current_user_message_id(self, id):
self._current_user_message_id=id
self._message_id = id
@property
def current_ai_message_id(self):
return self._current_ai_message_id
@current_ai_message_id.setter
def current_ai_message_id(self, id):
self._current_ai_message_id=id
self._message_id = id
2023-04-23 18:28:24 +00:00
def load_backend(self, backend_path):
# define the full absolute path to the module
absolute_path = backend_path.resolve()
# infer the module name from the file path
module_name = backend_path.stem
# use importlib to load the module from the file path
loader = importlib.machinery.SourceFileLoader(module_name, str(absolute_path/"__init__.py"))
2023-04-23 18:28:24 +00:00
backend_module = loader.load_module()
backend_class = getattr(backend_module, backend_module.backend_name)
2023-05-02 14:49:13 +00:00
return backend_class
2023-04-23 18:28:24 +00:00
def create_chatbot(self):
2023-04-23 22:19:15 +00:00
return self.backend(self.config)
def condition_chatbot(self, conditionning_message):
if self.current_discussion is None:
self.current_discussion = self.db.load_last_discussion()
2023-05-09 05:06:01 +00:00
2023-04-30 20:40:19 +00:00
if self.personality.welcome_message!="":
2023-05-09 05:06:01 +00:00
message_id = self.current_discussion.add_message(
self.personality.name, self.personality.welcome_message,
DiscussionsDB.MSG_TYPE_NORMAL,
0,
-1
)
2023-05-09 05:06:01 +00:00
self.current_ai_message_id = message_id
return message_id
def prepare_reception(self):
self.bot_says = ""
self.full_text = ""
self.is_bot_text_started = False
def create_new_discussion(self, title):
self.current_discussion = self.db.create_discussion(title)
# Get the current timestamp
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# Chatbot conditionning
2023-05-01 22:09:57 +00:00
self.condition_chatbot(self.personality.personality_conditioning)
return timestamp
def prepare_query(self, message_id=-1):
messages = self.current_discussion.get_messages()
self.full_message_list = []
for message in messages:
if message["id"]<= message_id or message_id==-1:
2023-05-09 05:06:01 +00:00
if message["type"]==self.db.MSG_TYPE_NORMAL:
2023-04-30 20:40:19 +00:00
if message["sender"]==self.personality.name:
self.full_message_list.append(self.personality.ai_message_prefix+message["content"])
else:
2023-04-30 20:40:19 +00:00
self.full_message_list.append(self.personality.user_message_prefix + message["content"])
2023-04-16 11:47:39 +00:00
2023-04-30 20:40:19 +00:00
link_text = self.personality.link_text
2023-04-16 11:47:39 +00:00
if len(self.full_message_list) > self.config["nb_messages_to_remember"]:
2023-04-30 20:40:19 +00:00
discussion_messages = self.personality.personality_conditioning+ link_text.join(self.full_message_list[-self.config["nb_messages_to_remember"]:])
else:
2023-04-30 20:40:19 +00:00
discussion_messages = self.personality.personality_conditioning+ link_text.join(self.full_message_list)
2023-04-16 11:47:39 +00:00
2023-04-30 20:40:19 +00:00
discussion_messages += link_text + self.personality.ai_message_prefix
2023-04-16 11:47:39 +00:00
return discussion_messages # Removes the last return
2023-04-17 22:23:31 +00:00
def get_discussion_to(self, message_id=-1):
messages = self.current_discussion.get_messages()
self.full_message_list = []
for message in messages:
if message["id"]<= message_id or message_id==-1:
if message["type"]!=self.db.MSG_TYPE_CONDITIONNING:
2023-04-30 20:40:19 +00:00
if message["sender"]==self.personality.name:
self.full_message_list.append(self.personality.ai_message_prefix+message["content"])
2023-04-17 22:23:31 +00:00
else:
2023-04-30 20:40:19 +00:00
self.full_message_list.append(self.personality.user_message_prefix + message["content"])
2023-04-17 22:23:31 +00:00
2023-04-30 20:40:19 +00:00
link_text = self.personality.link_text
2023-04-17 22:23:31 +00:00
if len(self.full_message_list) > self.config["nb_messages_to_remember"]:
2023-05-01 22:09:57 +00:00
discussion_messages = self.personality.personality_conditioning+ link_text.join(self.full_message_list[-self.config["nb_messages_to_remember"]:])
2023-04-17 22:23:31 +00:00
else:
2023-05-01 22:09:57 +00:00
discussion_messages = self.personality.personality_conditioning+ link_text.join(self.full_message_list)
2023-04-17 22:23:31 +00:00
return discussion_messages # Removes the last return
2023-04-23 22:19:15 +00:00
def remove_text_from_string(self, string, text_to_find):
"""
Removes everything from the first occurrence of the specified text in the string (case-insensitive).
Parameters:
string (str): The original string.
text_to_find (str): The text to find in the string.
Returns:
str: The updated string.
"""
index = string.lower().find(text_to_find.lower())
if index != -1:
string = string[:index]
return string
def new_text_callback(self, text: str):
2023-04-23 22:19:15 +00:00
if self.cancel_gen:
return False
print(text, end="")
sys.stdout.flush()
2023-04-27 23:39:57 +00:00
self.bot_says += text
if not self.personality.detect_antiprompt(self.bot_says):
2023-05-09 05:06:01 +00:00
self.socketio.emit('message', {
'data': self.bot_says,
'user_message_id':self.current_user_message_id,
'ai_message_id':self.current_ai_message_id,
'discussion_id':self.current_discussion.discussion_id
}
)
if self.cancel_gen:
print("Generation canceled")
2023-05-02 12:16:10 +00:00
self.cancel_gen = False
2023-04-23 22:19:15 +00:00
return False
2023-04-27 23:39:57 +00:00
else:
return True
else:
2023-04-30 20:40:19 +00:00
self.bot_says = self.remove_text_from_string(self.bot_says, self.personality.user_message_prefix.strip())
print("The model is halucinating")
return False
def generate_message(self):
self.generating=True
gc.collect()
2023-04-23 22:19:15 +00:00
total_n_predict = self.config['n_predict']
print(f"Generating {total_n_predict} outputs... ")
2023-05-07 01:44:42 +00:00
print(f"Input text :\n{self.discussion_messages}")
2023-05-05 12:23:07 +00:00
if self.config["override_personality_model_parameters"]:
self.chatbot_bindings.generate(
self.discussion_messages,
new_text_callback=self.new_text_callback,
n_predict=total_n_predict,
temp=self.config['temperature'],
top_k=self.config['top_k'],
top_p=self.config['top_p'],
repeat_penalty=self.config['repeat_penalty'],
repeat_last_n = self.config['repeat_last_n'],
2023-05-07 01:44:42 +00:00
seed=self.config['seed'],
2023-05-05 12:23:07 +00:00
n_threads=self.config['n_threads']
)
else:
self.chatbot_bindings.generate(
self.discussion_messages,
new_text_callback=self.new_text_callback,
n_predict=total_n_predict,
temp=self.personality.model_temperature,
top_k=self.personality.model_top_k,
top_p=self.personality.model_top_p,
repeat_penalty=self.personality.model_repeat_penalty,
repeat_last_n = self.personality.model_repeat_last_n,
#seed=self.config['seed'],
n_threads=self.config['n_threads']
)
self.generating=False