2023-04-11 10:50:07 +00:00
######
# Project : GPT4ALL-UI
# Author : ParisNeo with the help of the community
# Supported by Nomic-AI
2023-05-21 20:46:02 +00:00
# license : Apache 2.0
2023-04-11 10:50:07 +00:00
# Description :
# A front end Flask application for llamacpp models.
# The official GPT4All Web ui
# Made by the community for the community
######
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 "
2023-04-27 23:39:57 +00:00
import os
2023-04-27 14:53:13 +00:00
import logging
2023-04-06 19:12:49 +00:00
import argparse
2023-04-07 16:58:42 +00:00
import json
2023-04-06 19:12:49 +00:00
import re
2023-04-07 16:58:42 +00:00
import traceback
2023-04-08 10:25:40 +00:00
import sys
2023-05-11 19:36:52 +00:00
from tqdm import tqdm
2023-05-21 19:54:56 +00:00
import subprocess
import signal
2023-04-30 20:40:19 +00:00
from pyaipersonality import AIPersonality
2023-05-14 00:29:09 +00:00
from gpt4all_api . db import DiscussionsDB , Discussion
2023-04-07 16:58:42 +00:00
from flask import (
Flask ,
Response ,
jsonify ,
render_template ,
request ,
stream_with_context ,
2023-04-08 17:55:33 +00:00
send_from_directory
2023-04-07 16:58:42 +00:00
)
2023-04-27 14:44:22 +00:00
from flask_socketio import SocketIO , emit
2023-04-08 17:55:33 +00:00
from pathlib import Path
2023-04-09 19:26:04 +00:00
import gc
2023-05-20 13:50:14 +00:00
import yaml
2023-04-30 01:15:11 +00:00
from geventwebsocket . handler import WebSocketHandler
from gevent . pywsgi import WSGIServer
2023-05-10 21:33:08 +00:00
import requests
2023-05-11 19:36:52 +00:00
from concurrent . futures import ThreadPoolExecutor , as_completed
2023-05-13 22:24:26 +00:00
import logging
log = logging . getLogger ( ' werkzeug ' )
log . setLevel ( logging . ERROR )
2023-04-30 01:15:11 +00:00
2023-04-07 16:58:42 +00:00
app = Flask ( " GPT4All-WebUI " , static_url_path = " /static " , static_folder = " static " )
2023-05-18 19:20:16 +00:00
socketio = SocketIO ( app , cors_allowed_origins = " * " , async_mode = ' gevent ' , ping_timeout = 200 , ping_interval = 15 )
2023-05-02 20:53:27 +00:00
2023-04-27 23:39:57 +00:00
app . config [ ' SECRET_KEY ' ] = ' secret! '
2023-04-27 14:53:13 +00:00
# Set the logging level to WARNING or higher
logging . getLogger ( ' socketio ' ) . setLevel ( logging . WARNING )
logging . getLogger ( ' engineio ' ) . setLevel ( logging . WARNING )
2023-05-18 18:00:48 +00:00
logging . getLogger ( ' werkzeug ' ) . setLevel ( logging . ERROR )
logging . basicConfig ( level = logging . WARNING )
2023-04-27 06:52:00 +00:00
2023-04-09 19:26:04 +00:00
import time
2023-05-14 00:29:09 +00:00
from gpt4all_api . config import load_config , save_config
from gpt4all_api . api import GPT4AllAPI
2023-04-14 15:11:40 +00:00
import shutil
2023-04-16 21:22:09 +00:00
import markdown
2023-04-27 06:52:00 +00:00
2023-04-15 11:30:08 +00:00
class Gpt4AllWebUI ( GPT4AllAPI ) :
2023-05-13 22:24:26 +00:00
def __init__ ( self , _app , _socketio , config : dict , config_file_path ) - > None :
super ( ) . __init__ ( config , _socketio , config_file_path )
2023-04-15 11:30:08 +00:00
2023-04-07 16:58:42 +00:00
self . app = _app
2023-04-22 17:14:25 +00:00
self . cancel_gen = False
2023-05-13 22:24:26 +00:00
2023-04-15 11:30:08 +00:00
2023-05-02 20:53:27 +00:00
if " use_new_ui " in self . config :
if self . config [ " use_new_ui " ] :
app . template_folder = " web/dist "
2023-04-08 17:55:33 +00:00
2023-05-06 16:27:41 +00:00
# =========================================================================================
# Endpoints
# =========================================================================================
2023-04-20 17:30:03 +00:00
self . add_endpoint (
" /list_backends " , " list_backends " , self . list_backends , methods = [ " GET " ]
)
2023-04-10 08:27:25 +00:00
self . add_endpoint (
" /list_models " , " list_models " , self . list_models , methods = [ " GET " ]
)
2023-04-20 17:30:03 +00:00
self . add_endpoint (
" /list_personalities_languages " , " list_personalities_languages " , self . list_personalities_languages , methods = [ " GET " ]
)
self . add_endpoint (
" /list_personalities_categories " , " list_personalities_categories " , self . list_personalities_categories , methods = [ " GET " ]
)
2023-04-13 22:47:20 +00:00
self . add_endpoint (
" /list_personalities " , " list_personalities " , self . list_personalities , methods = [ " GET " ]
)
2023-04-14 00:10:22 +00:00
self . add_endpoint (
" /list_languages " , " list_languages " , self . list_languages , methods = [ " GET " ]
)
2023-04-10 08:27:25 +00:00
self . add_endpoint (
" /list_discussions " , " list_discussions " , self . list_discussions , methods = [ " GET " ]
)
2023-04-08 17:55:33 +00:00
2023-04-20 17:30:03 +00:00
self . add_endpoint ( " /set_personality_language " , " set_personality_language " , self . set_personality_language , methods = [ " GET " ] )
self . add_endpoint ( " /set_personality_category " , " set_personality_category " , self . set_personality_category , methods = [ " GET " ] )
2023-04-07 19:44:55 +00:00
2023-04-07 16:58:42 +00:00
self . add_endpoint ( " / " , " " , self . index , methods = [ " GET " ] )
2023-05-02 20:53:27 +00:00
self . add_endpoint ( " /<path:filename> " , " serve_static " , self . serve_static , methods = [ " GET " ] )
2023-05-05 13:01:38 +00:00
self . add_endpoint ( " /personalities/<path:filename> " , " serve_personalities " , self . serve_personalities , methods = [ " GET " ] )
2023-05-20 23:10:01 +00:00
self . add_endpoint ( " /outputs/<path:filename> " , " serve_outputs " , self . serve_outputs , methods = [ " GET " ] )
2023-05-13 22:24:26 +00:00
2023-05-02 20:53:27 +00:00
2023-04-10 08:27:25 +00:00
self . add_endpoint ( " /export_discussion " , " export_discussion " , self . export_discussion , methods = [ " GET " ] )
2023-04-07 16:58:42 +00:00
self . add_endpoint ( " /export " , " export " , self . export , methods = [ " GET " ] )
self . add_endpoint (
" /new_discussion " , " new_discussion " , self . new_discussion , methods = [ " GET " ]
)
2023-04-23 22:19:15 +00:00
self . add_endpoint ( " /stop_gen " , " stop_gen " , self . stop_gen , methods = [ " GET " ] )
2023-04-22 17:14:25 +00:00
2023-04-07 16:58:42 +00:00
self . add_endpoint ( " /rename " , " rename " , self . rename , methods = [ " POST " ] )
2023-05-04 14:38:03 +00:00
self . add_endpoint ( " /edit_title " , " edit_title " , self . edit_title , methods = [ " POST " ] )
2023-04-07 16:58:42 +00:00
self . add_endpoint (
2023-04-09 19:26:04 +00:00
" /load_discussion " , " load_discussion " , self . load_discussion , methods = [ " POST " ]
2023-04-07 16:58:42 +00:00
)
self . add_endpoint (
" /delete_discussion " ,
" delete_discussion " ,
self . delete_discussion ,
methods = [ " POST " ] ,
)
self . add_endpoint (
" /update_message " , " update_message " , self . update_message , methods = [ " GET " ]
)
2023-04-10 14:14:39 +00:00
self . add_endpoint (
" /message_rank_up " , " message_rank_up " , self . message_rank_up , methods = [ " GET " ]
)
self . add_endpoint (
" /message_rank_down " , " message_rank_down " , self . message_rank_down , methods = [ " GET " ]
)
2023-04-13 10:31:48 +00:00
self . add_endpoint (
" /delete_message " , " delete_message " , self . delete_message , methods = [ " GET " ]
)
2023-04-22 17:14:25 +00:00
self . add_endpoint (
" /set_backend " , " set_backend " , self . set_backend , methods = [ " POST " ]
)
2023-04-10 14:14:39 +00:00
2023-04-23 19:05:39 +00:00
self . add_endpoint (
" /set_model " , " set_model " , self . set_model , methods = [ " POST " ]
)
2023-04-07 21:22:17 +00:00
self . add_endpoint (
" /update_model_params " , " update_model_params " , self . update_model_params , methods = [ " POST " ]
)
2023-04-08 17:55:33 +00:00
self . add_endpoint (
2023-04-12 20:36:03 +00:00
" /get_config " , " get_config " , self . get_config , methods = [ " GET " ]
2023-04-08 17:55:33 +00:00
)
2023-05-10 21:33:08 +00:00
self . add_endpoint (
" /get_available_models " , " get_available_models " , self . get_available_models , methods = [ " GET " ]
)
2023-05-11 19:36:52 +00:00
2023-04-11 20:56:15 +00:00
2023-04-11 23:34:50 +00:00
self . add_endpoint (
" /extensions " , " extensions " , self . extensions , methods = [ " GET " ]
)
self . add_endpoint (
" /training " , " training " , self . training , methods = [ " GET " ]
)
2023-04-13 10:31:48 +00:00
self . add_endpoint (
" /main " , " main " , self . main , methods = [ " GET " ]
)
self . add_endpoint (
" /settings " , " settings " , self . settings , methods = [ " GET " ]
)
2023-04-11 23:34:50 +00:00
2023-04-11 20:56:15 +00:00
self . add_endpoint (
" /help " , " help " , self . help , methods = [ " GET " ]
)
2023-04-27 14:44:22 +00:00
2023-05-06 16:27:41 +00:00
self . add_endpoint (
" /get_generation_status " , " get_generation_status " , self . get_generation_status , methods = [ " GET " ]
)
2023-04-27 14:44:22 +00:00
2023-05-06 16:27:41 +00:00
self . add_endpoint (
" /update_setting " , " update_setting " , self . update_setting , methods = [ " POST " ]
)
2023-05-18 18:00:48 +00:00
self . add_endpoint (
" /apply_settings " , " apply_settings " , self . apply_settings , methods = [ " POST " ]
)
2023-05-06 16:27:41 +00:00
self . add_endpoint (
" /save_settings " , " save_settings " , self . save_settings , methods = [ " POST " ]
)
2023-05-06 20:49:56 +00:00
self . add_endpoint (
" /get_current_personality " , " get_current_personality " , self . get_current_personality , methods = [ " GET " ]
)
2023-04-27 14:44:22 +00:00
2023-05-04 23:50:43 +00:00
2023-05-20 13:50:14 +00:00
self . add_endpoint (
" /get_all_personalities " , " get_all_personalities " , self . get_all_personalities , methods = [ " GET " ]
)
2023-05-21 19:54:56 +00:00
self . add_endpoint (
" /reset " , " reset " , self . reset , methods = [ " GET " ]
)
def reset ( self ) :
os . kill ( os . getpid ( ) , signal . SIGINT ) # Send the interrupt signal to the current process
subprocess . Popen ( [ ' python ' , ' your_app.py ' ] ) # Restart the app using subprocess
return ' App is resetting... '
2023-05-04 23:50:43 +00:00
2023-05-06 17:45:38 +00:00
def save_settings ( self ) :
save_config ( self . config , self . config_file_path )
if self . config [ " debug " ] :
print ( " Configuration saved " )
# Tell that the setting was changed
self . socketio . emit ( ' save_settings ' , { " status " : True } )
return jsonify ( { " status " : True } )
2023-05-06 20:49:56 +00:00
2023-05-04 23:50:43 +00:00
2023-05-06 20:49:56 +00:00
def get_current_personality ( self ) :
2023-05-07 11:46:49 +00:00
return jsonify ( { " personality " : self . personality . as_dict ( ) } )
2023-05-06 20:49:56 +00:00
2023-05-20 13:50:14 +00:00
def get_all_personalities ( self ) :
personalities_folder = Path ( " ./personalities " )
personalities = { }
for language_folder in personalities_folder . iterdir ( ) :
if language_folder . is_dir ( ) :
personalities [ language_folder . name ] = { }
for category_folder in language_folder . iterdir ( ) :
if category_folder . is_dir ( ) :
personalities [ language_folder . name ] [ category_folder . name ] = [ ]
for personality_folder in category_folder . iterdir ( ) :
if personality_folder . is_dir ( ) :
personality_info = { }
config_path = personality_folder / ' config.yaml '
with open ( config_path ) as config_file :
config_data = yaml . load ( config_file , Loader = yaml . FullLoader )
personality_info [ ' name ' ] = personality_folder . name
personality_info [ ' description ' ] = config_data [ ' description ' ]
personality_info [ ' author ' ] = config_data [ ' creator ' ]
personality_info [ ' version ' ] = config_data [ ' version ' ]
scripts_path = personality_folder / ' scripts '
personality_info [ ' has_scripts ' ] = scripts_path . is_dir ( )
assets_path = personality_folder / ' assets '
logo_path = assets_path / ' logo.png '
gif_logo_path = assets_path / ' logo.gif '
personality_info [ ' has_logo ' ] = logo_path . is_file ( ) or gif_logo_path . is_file ( )
if logo_path . is_file ( ) :
personality_info [ ' icon_file ' ] = ' logo.png '
elif gif_logo_path . is_file ( ) :
personality_info [ ' icon_file ' ] = ' logo.gif '
personalities [ language_folder . name ] [ category_folder . name ] . append ( personality_info )
return json . dumps ( personalities )
2023-05-06 16:27:41 +00:00
# Settings (data: {"setting_name":<the setting name>,"setting_value":<the setting value>})
def update_setting ( self ) :
data = request . get_json ( )
setting_name = data [ ' setting_name ' ]
if setting_name == " temperature " :
self . config [ " temperature " ] = float ( data [ ' setting_value ' ] )
elif setting_name == " n_predict " :
self . config [ " n_predict " ] = int ( data [ ' setting_value ' ] )
elif setting_name == " top_k " :
self . config [ " top_k " ] = int ( data [ ' setting_value ' ] )
elif setting_name == " top_p " :
self . config [ " top_p " ] = float ( data [ ' setting_value ' ] )
elif setting_name == " repeat_penalty " :
self . config [ " repeat_penalty " ] = float ( data [ ' setting_value ' ] )
elif setting_name == " repeat_last_n " :
self . config [ " repeat_last_n " ] = int ( data [ ' setting_value ' ] )
elif setting_name == " n_threads " :
self . config [ " n_threads " ] = int ( data [ ' setting_value ' ] )
elif setting_name == " ctx_size " :
self . config [ " ctx_size " ] = int ( data [ ' setting_value ' ] )
elif setting_name == " language " :
self . config [ " language " ] = data [ ' setting_value ' ]
elif setting_name == " personality_language " :
2023-05-06 19:03:57 +00:00
back_language = self . config [ " personality_language " ]
if self . config [ " personality_language " ] != data [ ' setting_value ' ] :
self . config [ " personality_language " ] = data [ ' setting_value ' ]
cats = self . list_personalities_categories ( )
if len ( cats ) > 0 :
back_category = self . config [ " personality_category " ]
self . config [ " personality_category " ] = cats [ 0 ]
pers = json . loads ( self . list_personalities ( ) . data . decode ( " utf8 " ) )
if len ( pers ) > 0 :
self . config [ " personality " ] = pers [ 0 ]
personality_fn = f " personalities/ { self . config [ ' personality_language ' ] } / { self . config [ ' personality_category ' ] } / { self . config [ ' personality ' ] } "
self . personality . load_personality ( personality_fn )
else :
self . config [ " personality_language " ] = back_language
self . config [ " personality_category " ] = back_category
return jsonify ( { ' setting_name ' : data [ ' setting_name ' ] , " status " : False } )
else :
self . config [ " personality_language " ] = back_language
return jsonify ( { ' setting_name ' : data [ ' setting_name ' ] , " status " : False } )
2023-05-06 16:27:41 +00:00
elif setting_name == " personality_category " :
2023-05-06 19:03:57 +00:00
back_category = self . config [ " personality_category " ]
if self . config [ " personality_category " ] != data [ ' setting_value ' ] :
self . config [ " personality_category " ] = data [ ' setting_value ' ]
pers = json . loads ( self . list_personalities ( ) . data . decode ( " utf8 " ) )
if len ( pers ) > 0 :
self . config [ " personality " ] = pers [ 0 ]
personality_fn = f " personalities/ { self . config [ ' personality_language ' ] } / { self . config [ ' personality_category ' ] } / { self . config [ ' personality ' ] } "
self . personality . load_personality ( personality_fn )
2023-05-07 01:44:42 +00:00
if self . config [ " debug " ] :
print ( self . personality )
2023-05-06 19:03:57 +00:00
else :
self . config [ " personality_category " ] = back_category
return jsonify ( { ' setting_name ' : data [ ' setting_name ' ] , " status " : False } )
2023-05-06 16:27:41 +00:00
elif setting_name == " personality " :
self . config [ " personality " ] = data [ ' setting_value ' ]
2023-05-06 19:03:57 +00:00
personality_fn = f " personalities/ { self . config [ ' personality_language ' ] } / { self . config [ ' personality_category ' ] } / { self . config [ ' personality ' ] } "
self . personality . load_personality ( personality_fn )
2023-05-06 16:27:41 +00:00
elif setting_name == " override_personality_model_parameters " :
self . config [ " override_personality_model_parameters " ] = bool ( data [ ' setting_value ' ] )
2023-05-04 23:50:43 +00:00
2023-05-06 16:27:41 +00:00
elif setting_name == " model " :
self . config [ " model " ] = data [ ' setting_value ' ]
2023-05-13 22:24:26 +00:00
print ( " update_settings : New model selected " )
2023-05-04 23:50:43 +00:00
2023-05-06 16:27:41 +00:00
elif setting_name == " backend " :
if self . config [ ' backend ' ] != data [ ' setting_value ' ] :
print ( " New backend selected " )
self . config [ " backend " ] = data [ ' setting_value ' ]
2023-05-18 18:00:48 +00:00
try :
self . backend = self . process . load_backend ( self . config [ " backend " ] )
except Exception as ex :
print ( " Couldn ' t build backend " )
return jsonify ( { ' setting_name ' : data [ ' setting_name ' ] , " status " : False , ' error ' : str ( ex ) } )
2023-05-04 23:50:43 +00:00
else :
2023-05-06 16:27:41 +00:00
if self . config [ " debug " ] :
print ( f " Configuration { data [ ' setting_name ' ] } set to { data [ ' setting_value ' ] } " )
return jsonify ( { ' setting_name ' : data [ ' setting_name ' ] , " status " : True } )
2023-04-27 23:39:57 +00:00
2023-05-06 16:27:41 +00:00
else :
if self . config [ " debug " ] :
print ( f " Configuration { data [ ' setting_name ' ] } couldn ' t be set to { data [ ' setting_value ' ] } " )
return jsonify ( { ' setting_name ' : data [ ' setting_name ' ] , " status " : False } )
2023-04-27 14:44:22 +00:00
2023-05-06 16:27:41 +00:00
if self . config [ " debug " ] :
print ( f " Configuration { data [ ' setting_name ' ] } set to { data [ ' setting_value ' ] } " )
2023-05-13 22:24:26 +00:00
print ( " Configuration updated " )
2023-05-06 16:27:41 +00:00
# Tell that the setting was changed
return jsonify ( { ' setting_name ' : data [ ' setting_name ' ] , " status " : True } )
2023-04-11 20:56:15 +00:00
2023-05-18 18:00:48 +00:00
def apply_settings ( self ) :
return jsonify ( self . process . set_config ( self . config ) )
2023-04-20 17:30:03 +00:00
def list_backends ( self ) :
2023-04-24 19:24:18 +00:00
backends_dir = Path ( ' ./backends ' ) # replace with the actual path to the models folder
2023-04-24 21:58:50 +00:00
backends = [ f . stem for f in backends_dir . iterdir ( ) if f . is_dir ( ) and f . stem != " __pycache__ " ]
2023-04-20 17:30:03 +00:00
return jsonify ( backends )
2023-04-07 19:44:55 +00:00
2023-04-08 17:55:33 +00:00
def list_models ( self ) :
2023-05-11 13:09:35 +00:00
if self . backend is not None :
models = self . backend . list_models ( self . config )
return jsonify ( models )
else :
return jsonify ( [ ] )
2023-04-13 22:47:20 +00:00
2023-04-20 17:30:03 +00:00
def list_personalities_languages ( self ) :
personalities_languages_dir = Path ( f ' ./personalities ' ) # replace with the actual path to the models folder
personalities_languages = [ f . stem for f in personalities_languages_dir . iterdir ( ) if f . is_dir ( ) ]
return jsonify ( personalities_languages )
def list_personalities_categories ( self ) :
personalities_categories_dir = Path ( f ' ./personalities/ { self . config [ " personality_language " ] } ' ) # replace with the actual path to the models folder
personalities_categories = [ f . stem for f in personalities_categories_dir . iterdir ( ) if f . is_dir ( ) ]
return jsonify ( personalities_categories )
2023-04-13 22:47:20 +00:00
def list_personalities ( self ) :
2023-05-05 20:35:08 +00:00
try :
personalities_dir = Path ( f ' ./personalities/ { self . config [ " personality_language " ] } / { self . config [ " personality_category " ] } ' ) # replace with the actual path to the models folder
personalities = [ f . stem for f in personalities_dir . iterdir ( ) if f . is_dir ( ) ]
2023-05-06 17:45:38 +00:00
except Exception as ex :
2023-05-05 20:35:08 +00:00
personalities = [ ]
2023-05-06 16:27:41 +00:00
if self . config [ " debug " ] :
2023-05-06 17:45:38 +00:00
print ( f " No personalities found. Using default one { ex } " )
2023-04-13 22:47:20 +00:00
return jsonify ( personalities )
2023-04-07 21:22:17 +00:00
2023-04-14 00:10:22 +00:00
def list_languages ( self ) :
lanuguages = [
{ " value " : " en-US " , " label " : " English " } ,
{ " value " : " fr-FR " , " label " : " Français " } ,
{ " value " : " ar-AR " , " label " : " العربية " } ,
{ " value " : " it-IT " , " label " : " Italiano " } ,
{ " value " : " de-DE " , " label " : " Deutsch " } ,
{ " value " : " nl-XX " , " label " : " Dutch " } ,
{ " value " : " zh-CN " , " label " : " 中國人 " }
]
return jsonify ( lanuguages )
2023-04-10 08:27:25 +00:00
def list_discussions ( self ) :
2023-04-10 14:14:39 +00:00
discussions = self . db . get_discussions ( )
return jsonify ( discussions )
2023-04-10 08:27:25 +00:00
2023-04-20 17:30:03 +00:00
def set_personality_language ( self ) :
lang = request . args . get ( ' language ' )
self . config [ ' personality_language ' ] = lang
return jsonify ( { ' success ' : True } )
def set_personality_category ( self ) :
category = request . args . get ( ' category ' )
self . config [ ' personality_category ' ] = category
return jsonify ( { ' success ' : True } )
2023-04-07 16:58:42 +00:00
def add_endpoint (
self ,
endpoint = None ,
endpoint_name = None ,
handler = None ,
methods = [ " GET " ] ,
* args ,
* * kwargs ,
) :
self . app . add_url_rule (
endpoint , endpoint_name , handler , methods = methods , * args , * * kwargs
)
2023-04-06 19:12:49 +00:00
def index ( self ) :
2023-04-17 15:59:36 +00:00
return render_template ( " index.html " )
2023-05-02 20:53:27 +00:00
def serve_static ( self , filename ) :
root_dir = os . getcwd ( )
if " use_new_ui " in self . config :
if self . config [ " use_new_ui " ] :
path = os . path . join ( root_dir , ' web/dist/ ' ) + " / " . join ( filename . split ( " / " ) [ : - 1 ] )
else :
path = os . path . join ( root_dir , ' static/ ' ) + " / " . join ( filename . split ( " / " ) [ : - 1 ] )
else :
path = os . path . join ( root_dir , ' static/ ' ) + " / " . join ( filename . split ( " / " ) [ : - 1 ] )
fn = filename . split ( " / " ) [ - 1 ]
return send_from_directory ( path , fn )
2023-05-05 13:01:38 +00:00
def serve_personalities ( self , filename ) :
root_dir = os . getcwd ( )
path = os . path . join ( root_dir , ' personalities/ ' ) + " / " . join ( filename . split ( " / " ) [ : - 1 ] )
fn = filename . split ( " / " ) [ - 1 ]
return send_from_directory ( path , fn )
2023-05-20 23:10:01 +00:00
def serve_outputs ( self , filename ) :
root_dir = os . getcwd ( )
path = os . path . join ( root_dir , ' outputs/ ' ) + " / " . join ( filename . split ( " / " ) [ : - 1 ] )
fn = filename . split ( " / " ) [ - 1 ]
return send_from_directory ( path , fn )
2023-04-06 19:12:49 +00:00
def export ( self ) :
2023-04-10 08:27:25 +00:00
return jsonify ( self . db . export_to_json ( ) )
2023-04-06 19:12:49 +00:00
2023-04-10 08:27:25 +00:00
def export_discussion ( self ) :
2023-04-17 22:23:31 +00:00
return jsonify ( { " discussion_text " : self . get_discussion_to ( ) } )
2023-04-10 08:27:25 +00:00
2023-04-08 16:55:55 +00:00
2023-05-13 22:24:26 +00:00
2023-05-06 16:27:41 +00:00
def get_generation_status ( self ) :
2023-05-13 22:24:26 +00:00
return jsonify ( { " status " : self . process . is_generating . value == 1 } )
2023-05-06 16:27:41 +00:00
2023-04-23 22:19:15 +00:00
def stop_gen ( self ) :
2023-04-22 17:14:25 +00:00
self . cancel_gen = True
2023-05-21 19:54:56 +00:00
self . process . cancel_generation ( )
2023-05-02 09:02:59 +00:00
print ( " Stop generation received " )
2023-05-13 22:24:26 +00:00
return jsonify ( { " status " : " ok " } )
2023-04-22 17:14:25 +00:00
2023-04-06 19:12:49 +00:00
def rename ( self ) :
data = request . get_json ( )
2023-04-07 16:58:42 +00:00
title = data [ " title " ]
2023-04-10 14:15:12 +00:00
self . current_discussion . rename ( title )
2023-04-06 19:12:49 +00:00
return " renamed successfully "
2023-05-04 14:38:03 +00:00
def edit_title ( self ) :
data = request . get_json ( )
title = data [ " title " ]
discussion_id = data [ " id " ]
self . current_discussion = Discussion ( discussion_id , self . db )
self . current_discussion . rename ( title )
return " title renamed successfully "
2023-04-09 19:26:04 +00:00
def load_discussion ( self ) :
2023-05-22 10:01:31 +00:00
print ( " Loading discussion " )
2023-04-07 21:22:17 +00:00
data = request . get_json ( )
2023-05-22 10:06:28 +00:00
print ( " Recovered json data " )
2023-04-13 15:24:52 +00:00
if " id " in data :
discussion_id = data [ " id " ]
2023-04-13 19:40:46 +00:00
self . current_discussion = Discussion ( discussion_id , self . db )
2023-04-13 15:24:52 +00:00
else :
if self . current_discussion is not None :
discussion_id = self . current_discussion . discussion_id
2023-04-13 19:40:46 +00:00
self . current_discussion = Discussion ( discussion_id , self . db )
2023-04-13 15:24:52 +00:00
else :
2023-04-13 19:40:46 +00:00
self . current_discussion = self . db . create_discussion ( )
2023-05-22 10:01:31 +00:00
print ( f " Discussion id : { discussion_id } " )
2023-04-07 21:22:17 +00:00
messages = self . current_discussion . get_messages ( )
2023-05-20 13:50:14 +00:00
2023-04-07 21:22:17 +00:00
2023-04-20 17:30:03 +00:00
return jsonify ( messages ) , { ' Content-Type ' : ' application/json; charset=utf-8 ' }
2023-04-06 19:12:49 +00:00
def delete_discussion ( self ) :
data = request . get_json ( )
2023-04-07 16:58:42 +00:00
discussion_id = data [ " id " ]
2023-04-10 09:14:10 +00:00
self . current_discussion = Discussion ( discussion_id , self . db )
2023-04-06 19:12:49 +00:00
self . current_discussion . delete_discussion ( )
self . current_discussion = None
return jsonify ( { } )
2023-04-07 16:58:42 +00:00
2023-04-06 19:12:49 +00:00
def update_message ( self ) :
2023-04-10 14:14:39 +00:00
discussion_id = request . args . get ( " id " )
new_message = request . args . get ( " message " )
2023-05-20 17:48:38 +00:00
try :
self . current_discussion . update_message ( discussion_id , new_message )
return jsonify ( { " status " : " ok " } )
except Exception as ex :
return jsonify ( { " status " : " nok " , " error " : str ( ex ) } )
2023-04-10 14:14:39 +00:00
def message_rank_up ( self ) :
discussion_id = request . args . get ( " id " )
2023-05-20 17:48:38 +00:00
try :
new_rank = self . current_discussion . message_rank_up ( discussion_id )
return jsonify ( { " status " : " ok " , " new_rank " : new_rank } )
except Exception as ex :
return jsonify ( { " status " : " nok " , " error " : str ( ex ) } )
2023-04-10 14:14:39 +00:00
def message_rank_down ( self ) :
discussion_id = request . args . get ( " id " )
2023-05-20 17:48:38 +00:00
try :
new_rank = self . current_discussion . message_rank_down ( discussion_id )
return jsonify ( { " status " : " ok " , " new_rank " : new_rank } )
except Exception as ex :
return jsonify ( { " status " : " nok " , " error " : str ( ex ) } )
2023-04-06 19:12:49 +00:00
2023-04-13 10:31:48 +00:00
def delete_message ( self ) :
discussion_id = request . args . get ( " id " )
2023-04-27 23:39:57 +00:00
if self . current_discussion is None :
return jsonify ( { " status " : False , " message " : " No discussion is selected " } )
else :
new_rank = self . current_discussion . delete_message ( discussion_id )
return jsonify ( { " status " : True , " new_rank " : new_rank } )
2023-04-13 10:31:48 +00:00
2023-04-06 19:12:49 +00:00
def new_discussion ( self ) :
2023-04-07 16:58:42 +00:00
title = request . args . get ( " title " )
2023-04-15 11:30:08 +00:00
timestamp = self . create_new_discussion ( title )
2023-04-24 21:11:32 +00:00
2023-04-06 19:12:49 +00:00
# Return a success response
2023-04-30 20:40:19 +00:00
return json . dumps ( { " id " : self . current_discussion . discussion_id , " time " : timestamp , " welcome_message " : self . personality . welcome_message , " sender " : self . personality . name } )
2023-04-07 16:58:42 +00:00
2023-04-22 17:14:25 +00:00
def set_backend ( self ) :
data = request . get_json ( )
backend = str ( data [ " backend " ] )
if self . config [ ' backend ' ] != backend :
2023-04-23 19:05:39 +00:00
print ( " New backend selected " )
2023-04-22 17:14:25 +00:00
self . config [ ' backend ' ] = backend
2023-05-18 18:00:48 +00:00
backend_ = self . process . load_backend ( config [ " backend " ] )
2023-05-02 14:49:13 +00:00
models = backend_ . list_models ( self . config )
if len ( models ) > 0 :
self . backend = backend_
2023-04-22 17:14:25 +00:00
self . config [ ' model ' ] = models [ 0 ]
2023-04-24 21:58:50 +00:00
# Build chatbot
2023-05-13 22:24:26 +00:00
self . process . set_config ( self . config )
2023-04-22 17:14:25 +00:00
return jsonify ( { " status " : " ok " } )
2023-04-23 22:19:15 +00:00
else :
return jsonify ( { " status " : " no_models_found " } )
2023-04-22 17:14:25 +00:00
2023-04-23 14:59:00 +00:00
return jsonify ( { " status " : " error " } )
2023-04-23 19:05:39 +00:00
def set_model ( self ) :
data = request . get_json ( )
model = str ( data [ " model " ] )
if self . config [ ' model ' ] != model :
2023-05-13 22:24:26 +00:00
print ( " set_model: New model selected " )
2023-04-23 19:05:39 +00:00
self . config [ ' model ' ] = model
2023-04-24 21:58:50 +00:00
# Build chatbot
2023-05-13 22:24:26 +00:00
self . process . set_config ( self . config )
2023-04-23 19:05:39 +00:00
return jsonify ( { " status " : " ok " } )
return jsonify ( { " status " : " error " } )
2023-04-23 14:59:00 +00:00
2023-04-07 21:22:17 +00:00
def update_model_params ( self ) :
data = request . get_json ( )
2023-04-20 17:33:21 +00:00
backend = str ( data [ " backend " ] )
2023-04-08 17:55:33 +00:00
model = str ( data [ " model " ] )
2023-04-20 17:33:21 +00:00
personality_language = str ( data [ " personality_language " ] )
personality_category = str ( data [ " personality_category " ] )
2023-04-15 11:37:42 +00:00
personality = str ( data [ " personality " ] )
2023-04-20 17:33:21 +00:00
if self . config [ ' backend ' ] != backend or self . config [ ' model ' ] != model :
2023-05-13 22:24:26 +00:00
print ( " update_model_params: New model selected " )
2023-04-20 17:33:21 +00:00
self . config [ ' backend ' ] = backend
2023-04-12 20:36:03 +00:00
self . config [ ' model ' ] = model
2023-05-13 22:24:26 +00:00
self . process . set_config ( self . config )
2023-04-08 17:55:33 +00:00
2023-04-22 17:14:25 +00:00
self . config [ ' personality_language ' ] = personality_language
self . config [ ' personality_category ' ] = personality_category
self . config [ ' personality ' ] = personality
2023-04-20 17:33:21 +00:00
2023-04-30 20:40:19 +00:00
personality_fn = f " personalities/ { self . config [ ' personality_language ' ] } / { self . config [ ' personality_category ' ] } / { self . config [ ' personality ' ] } "
2023-04-22 17:14:25 +00:00
print ( f " Loading personality : { personality_fn } " )
2023-04-15 11:37:42 +00:00
2023-04-12 20:36:03 +00:00
self . config [ ' n_predict ' ] = int ( data [ " nPredict " ] )
self . config [ ' seed ' ] = int ( data [ " seed " ] )
2023-04-14 08:48:14 +00:00
self . config [ ' model ' ] = str ( data [ " model " ] )
self . config [ ' voice ' ] = str ( data [ " voice " ] )
self . config [ ' language ' ] = str ( data [ " language " ] )
2023-04-08 16:00:02 +00:00
2023-05-04 23:50:43 +00:00
self . config [ ' temperature ' ] = float ( data [ " temperature " ] )
2023-04-12 20:36:03 +00:00
self . config [ ' top_k ' ] = int ( data [ " topK " ] )
self . config [ ' top_p ' ] = float ( data [ " topP " ] )
self . config [ ' repeat_penalty ' ] = float ( data [ " repeatPenalty " ] )
self . config [ ' repeat_last_n ' ] = int ( data [ " repeatLastN " ] )
2023-04-08 10:54:51 +00:00
2023-04-14 09:58:07 +00:00
save_config ( self . config , self . config_file_path )
2023-05-13 22:24:26 +00:00
self . process . set_config ( self . config )
2023-05-14 15:15:31 +00:00
# Fixed missing argument
self . backend = self . process . rebuild_backend ( self . config )
2023-04-14 09:58:07 +00:00
2023-04-20 20:41:32 +00:00
print ( " ============================================== " )
2023-04-08 10:54:51 +00:00
print ( " Parameters changed to: " )
2023-04-20 20:41:32 +00:00
print ( f " \t Backend: { self . config [ ' backend ' ] } " )
2023-04-14 08:48:14 +00:00
print ( f " \t Model: { self . config [ ' model ' ] } " )
2023-04-20 20:20:18 +00:00
print ( f " \t Personality language: { self . config [ ' personality_language ' ] } " )
print ( f " \t Personality category: { self . config [ ' personality_category ' ] } " )
2023-04-14 08:48:14 +00:00
print ( f " \t Personality: { self . config [ ' personality ' ] } " )
print ( f " \t Language: { self . config [ ' language ' ] } " )
print ( f " \t Voice: { self . config [ ' voice ' ] } " )
2023-05-04 23:50:43 +00:00
print ( f " \t Temperature: { self . config [ ' temperature ' ] } " )
2023-04-12 20:36:03 +00:00
print ( f " \t NPredict: { self . config [ ' n_predict ' ] } " )
print ( f " \t Seed: { self . config [ ' seed ' ] } " )
print ( f " \t op_k: { self . config [ ' top_k ' ] } " )
print ( f " \t op_p: { self . config [ ' top_p ' ] } " )
print ( f " \t repeat_penalty: { self . config [ ' repeat_penalty ' ] } " )
print ( f " \t repeat_last_n: { self . config [ ' repeat_last_n ' ] } " )
2023-04-20 20:41:32 +00:00
print ( " ============================================== " )
2023-04-20 20:43:29 +00:00
2023-04-07 21:22:17 +00:00
return jsonify ( { " status " : " ok " } )
2023-04-08 17:55:33 +00:00
2023-05-10 21:33:08 +00:00
def get_available_models ( self ) :
2023-05-13 12:19:56 +00:00
""" Get the available models
Returns :
_type_ : _description_
"""
2023-05-18 18:00:48 +00:00
if self . backend is None :
return jsonify ( [ ] )
2023-05-13 12:19:56 +00:00
model_list = self . backend . get_available_models ( )
2023-05-10 21:33:08 +00:00
models = [ ]
for model in model_list :
2023-05-14 08:32:55 +00:00
try :
2023-05-18 18:00:48 +00:00
filename = model . get ( ' filename ' , " " )
server = model . get ( ' server ' , " " )
image_url = model . get ( " image_url " , ' /icons/default.png ' )
2023-05-21 20:46:02 +00:00
license = model . get ( " license " , ' unknown ' )
owner = model . get ( " owner " , ' unknown ' )
owner_link = model . get ( " owner_link " , ' https://github.com/ParisNeo ' )
2023-05-18 18:00:48 +00:00
filesize = int ( model . get ( ' filesize ' , 0 ) )
description = model . get ( ' description ' , " " )
2023-05-14 08:32:55 +00:00
if server . endswith ( " / " ) :
path = f ' { server } { filename } '
else :
path = f ' { server } / { filename } '
local_path = Path ( f ' ./models/ { self . config [ " backend " ] } / { filename } ' )
is_installed = local_path . exists ( )
models . append ( {
2023-05-18 18:00:48 +00:00
' title ' : filename ,
' icon ' : image_url , # Replace with the path to the model icon
2023-05-21 20:46:02 +00:00
' license ' : license ,
' owner ' : owner ,
' owner_link ' : owner_link ,
2023-05-18 18:00:48 +00:00
' description ' : description ,
2023-05-14 08:32:55 +00:00
' isInstalled ' : is_installed ,
' path ' : path ,
' filesize ' : filesize ,
} )
2023-05-18 18:00:48 +00:00
except Exception as ex :
print ( " ################################# " )
print ( ex )
print ( " ################################# " )
2023-05-14 08:32:55 +00:00
print ( f " Problem with model : { model } " )
2023-05-10 21:33:08 +00:00
return jsonify ( models )
2023-04-12 20:36:03 +00:00
def get_config ( self ) :
return jsonify ( self . config )
2023-04-08 17:55:33 +00:00
2023-04-13 10:31:48 +00:00
def main ( self ) :
return render_template ( " main.html " )
def settings ( self ) :
return render_template ( " settings.html " )
2023-04-11 20:56:15 +00:00
def help ( self ) :
return render_template ( " help.html " )
2023-04-11 23:34:50 +00:00
def training ( self ) :
return render_template ( " training.html " )
def extensions ( self ) :
return render_template ( " extensions.html " )
2023-04-07 16:58:42 +00:00
if __name__ == " __main__ " :
parser = argparse . ArgumentParser ( description = " Start the chatbot Flask app. " )
2023-04-13 15:24:52 +00:00
parser . add_argument (
" -c " , " --config " , type = str , default = " default " , help = " Sets the configuration file to be used. "
)
2023-04-13 15:55:15 +00:00
parser . add_argument (
" -p " , " --personality " , type = str , default = None , help = " Selects the personality to be using. "
)
2023-04-07 19:44:55 +00:00
parser . add_argument (
2023-04-13 13:27:50 +00:00
" -s " , " --seed " , type = int , default = None , help = " Force using a specific seed value. "
2023-04-07 19:44:55 +00:00
)
2023-04-07 16:58:42 +00:00
2023-04-07 19:44:55 +00:00
parser . add_argument (
2023-04-12 20:36:03 +00:00
" -m " , " --model " , type = str , default = None , help = " Force using a specific model. "
2023-04-07 19:44:55 +00:00
)
2023-04-07 16:58:42 +00:00
parser . add_argument (
2023-04-12 20:36:03 +00:00
" --temp " , type = float , default = None , help = " Temperature parameter for the model. "
2023-04-07 16:58:42 +00:00
)
parser . add_argument (
" --n_predict " ,
type = int ,
2023-04-12 20:36:03 +00:00
default = None ,
2023-04-07 16:58:42 +00:00
help = " Number of tokens to predict at each step. " ,
)
2023-04-16 19:33:34 +00:00
parser . add_argument (
" --n_threads " ,
type = int ,
default = None ,
help = " Number of threads to use. " ,
)
2023-04-07 16:58:42 +00:00
parser . add_argument (
2023-04-12 20:36:03 +00:00
" --top_k " , type = int , default = None , help = " Value for the top-k sampling. "
2023-04-07 16:58:42 +00:00
)
parser . add_argument (
2023-04-12 20:36:03 +00:00
" --top_p " , type = float , default = None , help = " Value for the top-p sampling. "
2023-04-07 16:58:42 +00:00
)
parser . add_argument (
2023-04-12 20:36:03 +00:00
" --repeat_penalty " , type = float , default = None , help = " Penalty for repeated tokens. "
2023-04-07 16:58:42 +00:00
)
parser . add_argument (
" --repeat_last_n " ,
type = int ,
2023-04-12 20:36:03 +00:00
default = None ,
2023-04-07 16:58:42 +00:00
help = " Number of previous tokens to consider for the repeat penalty. " ,
)
parser . add_argument (
" --ctx_size " ,
type = int ,
2023-04-12 20:36:03 +00:00
default = None , #2048,
2023-04-07 16:58:42 +00:00
help = " Size of the context window for the model. " ,
)
parser . add_argument (
" --debug " ,
dest = " debug " ,
action = " store_true " ,
2023-05-06 16:27:41 +00:00
default = None ,
2023-04-07 16:58:42 +00:00
help = " launch Flask server in debug mode " ,
)
parser . add_argument (
2023-04-13 10:31:48 +00:00
" --host " , type = str , default = None , help = " the hostname to listen on "
2023-04-07 16:58:42 +00:00
)
2023-04-12 20:36:03 +00:00
parser . add_argument ( " --port " , type = int , default = None , help = " the port to listen on " )
2023-04-07 16:58:42 +00:00
parser . add_argument (
2023-04-12 20:36:03 +00:00
" --db_path " , type = str , default = None , help = " Database path "
2023-04-07 16:58:42 +00:00
)
2023-04-06 19:12:49 +00:00
args = parser . parse_args ( )
2023-04-13 15:24:52 +00:00
2023-04-14 15:29:17 +00:00
# The default configuration must be kept unchanged as it is committed to the repository,
# so we have to make a copy that is not comitted
2023-05-04 23:50:43 +00:00
default_config = load_config ( f " configs/default.yaml " )
2023-04-14 15:11:40 +00:00
if args . config == " default " :
args . config = " local_default "
if not Path ( f " configs/local_default.yaml " ) . exists ( ) :
print ( " No local configuration file found. Building from scratch " )
shutil . copy ( f " configs/default.yaml " , f " configs/local_default.yaml " )
2023-05-04 23:50:43 +00:00
2023-04-13 15:24:52 +00:00
config_file_path = f " configs/ { args . config } .yaml "
2023-04-12 20:36:03 +00:00
config = load_config ( config_file_path )
2023-05-04 23:50:43 +00:00
if " version " not in config or int ( config [ " version " ] ) < int ( default_config [ " version " ] ) :
#Upgrade old configuration files to new format
print ( " Configuration file is very old. Replacing with default configuration " )
for key , value in default_config . items ( ) :
if key not in config :
config [ key ] = value
2023-05-11 13:09:35 +00:00
config [ " version " ] = int ( default_config [ " version " ] )
2023-05-04 23:50:43 +00:00
save_config ( config , config_file_path )
2023-04-12 20:36:03 +00:00
# Override values in config with command-line arguments
for arg_name , arg_value in vars ( args ) . items ( ) :
if arg_value is not None :
config [ arg_name ] = arg_value
2023-04-06 19:12:49 +00:00
2023-04-24 20:02:50 +00:00
# executor = ThreadPoolExecutor(max_workers=1)
# app.config['executor'] = executor
2023-05-13 22:24:26 +00:00
bot = Gpt4AllWebUI ( app , socketio , config , config_file_path )
2023-04-06 19:12:49 +00:00
2023-04-30 01:15:11 +00:00
# chong Define custom WebSocketHandler with error handling
class CustomWebSocketHandler ( WebSocketHandler ) :
def handle_error ( self , environ , start_response , e ) :
# Handle the error here
print ( " WebSocket error: " , e )
super ( ) . handle_error ( environ , start_response , e )
2023-04-30 20:40:19 +00:00
url = f ' http:// { config [ " host " ] } : { config [ " port " ] } '
print ( f " Please open your browser and go to { url } to view the ui " )
2023-04-30 01:15:11 +00:00
2023-05-01 02:17:03 +00:00
# chong -add socket server
app . config [ ' debug ' ] = config [ " debug " ]
2023-04-30 01:15:11 +00:00
2023-05-01 02:17:03 +00:00
if config [ " debug " ] :
print ( " debug mode:true " )
else :
print ( " debug mode:false " )
http_server = WSGIServer ( ( config [ " host " ] , config [ " port " ] ) , app , handler_class = WebSocketHandler )
2023-05-01 22:04:18 +00:00
http_server . serve_forever ( )