2024-01-07 22:17:22 +00:00
"""
project : lollms_user
file : lollms_user . py
author : ParisNeo
description :
This module contains a set of FastAPI routes that provide information about the Lord of Large Language and Multimodal Systems ( LoLLMs ) Web UI
application . These routes allow users to do advanced stuff like executing code .
"""
from fastapi import APIRouter , Request
from lollms_webui import LOLLMSWebUI
2024-02-15 00:01:55 +00:00
from pydantic import BaseModel , Field
2024-01-07 22:17:22 +00:00
from starlette . responses import StreamingResponse
from lollms . types import MSG_TYPE
from lollms . main_config import BaseConfig
2024-02-17 01:08:14 +00:00
from lollms . utilities import detect_antiprompt , remove_text_from_string , trace_exception , show_yes_no_dialog
2024-04-07 01:51:37 +00:00
from lollms . security import sanitize_path , forbid_remote_access , check_access
2024-01-07 22:17:22 +00:00
from ascii_colors import ASCIIColors
2024-02-26 00:55:44 +00:00
from lollms . databases . discussions_database import DiscussionsDB
2024-01-07 22:17:22 +00:00
from pathlib import Path
from safe_store . text_vectorizer import TextVectorizer , VectorizationMethod , VisualizationMethod
import tqdm
from fastapi import FastAPI , UploadFile , File
import shutil
2024-01-07 23:22:23 +00:00
import os
import platform
2024-02-14 23:35:04 +00:00
import string
import re
2024-02-15 00:01:55 +00:00
import subprocess
from typing import Optional
2024-02-14 23:35:04 +00:00
def validate_file_path ( path ) :
2024-03-28 22:58:51 +00:00
try :
sanitized_path = sanitize_path ( path , allow_absolute_path = False )
return sanitized_path is not None
except Exception as e :
print ( f " Path validation error: { str ( e ) } " )
return False
2024-01-07 22:17:22 +00:00
from utilities . execution_engines . python_execution_engine import execute_python
from utilities . execution_engines . latex_execution_engine import execute_latex
from utilities . execution_engines . shell_execution_engine import execute_bash
2024-02-05 22:50:40 +00:00
from utilities . execution_engines . javascript_execution_engine import execute_javascript
2024-02-05 23:57:00 +00:00
from utilities . execution_engines . html_execution_engine import execute_html
2024-02-05 22:50:40 +00:00
from utilities . execution_engines . mermaid_execution_engine import execute_mermaid
from utilities . execution_engines . graphviz_execution_engine import execute_graphviz
2024-04-21 15:14:00 +00:00
from utilities . execution_engines . svg_execution_engine import execute_svg
2024-02-05 22:50:40 +00:00
2024-01-07 22:17:22 +00:00
2024-01-09 22:26:41 +00:00
# ----------------------- Defining router and main class ------------------------------
2024-01-07 23:22:23 +00:00
2024-01-07 22:17:22 +00:00
router = APIRouter ( )
lollmsElfServer : LOLLMSWebUI = LOLLMSWebUI . get_instance ( )
2024-02-15 00:31:16 +00:00
2024-02-15 19:31:03 +00:00
class CodeRequest ( BaseModel ) :
2024-02-28 00:06:59 +00:00
client_id : str = Field ( . . . )
2024-02-15 19:31:03 +00:00
code : str = Field ( . . . , description = " Code to be executed " )
discussion_id : int = Field ( . . . , description = " Discussion ID " )
message_id : int = Field ( . . . , description = " Message ID " )
language : str = Field ( . . . , description = " Programming language of the code " )
2024-01-07 22:17:22 +00:00
@router.post ( " /execute_code " )
2024-02-15 19:31:03 +00:00
async def execute_code ( request : CodeRequest ) :
2024-01-07 22:17:22 +00:00
"""
Executes Python code and returns the output .
: param request : The HTTP request object .
: return : A JSON response with the status of the operation .
"""
2024-04-07 01:51:37 +00:00
client = check_access ( lollmsElfServer , request . client_id )
2024-02-14 23:35:04 +00:00
if lollmsElfServer . config . headless_server_mode :
return { " status " : False , " error " : " Code execution is blocked when in headless mode for obvious security reasons! " }
2024-03-28 22:58:51 +00:00
forbid_remote_access ( lollmsElfServer , " Code execution is blocked when the server is exposed outside for very obvious reasons! " )
2024-02-15 00:31:16 +00:00
if not lollmsElfServer . config . turn_on_code_execution :
return { " status " : False , " error " : " Code execution is blocked by the configuration! " }
if lollmsElfServer . config . turn_on_code_validation :
if not show_yes_no_dialog ( " Validation " , " Do you validate the execution of the code? " ) :
return { " status " : False , " error " : " User refused the execution! " }
2024-01-07 22:17:22 +00:00
try :
2024-02-15 19:31:03 +00:00
code = request . code
discussion_id = request . discussion_id
message_id = request . message_id
language = request . language
2024-01-07 22:17:22 +00:00
if language == " python " :
2024-02-05 22:50:40 +00:00
ASCIIColors . info ( " Executing python code: " )
ASCIIColors . yellow ( code )
2024-02-28 00:06:59 +00:00
return execute_python ( code , client , message_id )
2024-04-21 15:14:00 +00:00
if language == " svg " :
ASCIIColors . info ( " Executing svg code: " )
ASCIIColors . yellow ( code )
return execute_svg ( code , client , message_id )
2024-02-05 22:50:40 +00:00
if language == " javascript " :
ASCIIColors . info ( " Executing javascript code: " )
ASCIIColors . yellow ( code )
2024-04-21 00:50:43 +00:00
return execute_javascript ( code , client , message_id )
2024-02-10 00:32:22 +00:00
if language in [ " html " , " html5 " , " svg " ] :
2024-02-05 23:57:00 +00:00
ASCIIColors . info ( " Executing javascript code: " )
ASCIIColors . yellow ( code )
2024-04-21 00:50:43 +00:00
return execute_html ( code , client , message_id )
2024-02-15 19:31:03 +00:00
2024-01-07 22:17:22 +00:00
elif language == " latex " :
2024-02-05 22:50:40 +00:00
ASCIIColors . info ( " Executing latex code: " )
ASCIIColors . yellow ( code )
2024-02-28 21:56:34 +00:00
return execute_latex ( code , client , message_id )
2024-01-07 22:17:22 +00:00
elif language in [ " bash " , " shell " , " cmd " , " powershell " ] :
2024-02-05 22:50:40 +00:00
ASCIIColors . info ( " Executing shell code: " )
ASCIIColors . yellow ( code )
2024-02-28 21:56:34 +00:00
return execute_bash ( code , client )
2024-02-05 22:50:40 +00:00
elif language in [ " mermaid " ] :
ASCIIColors . info ( " Executing mermaid code: " )
ASCIIColors . yellow ( code )
2024-04-21 00:50:43 +00:00
return execute_mermaid ( code , client , message_id )
2024-02-05 22:50:40 +00:00
elif language in [ " graphviz " , " dot " ] :
ASCIIColors . info ( " Executing graphviz code: " )
ASCIIColors . yellow ( code )
2024-04-21 00:50:43 +00:00
return execute_graphviz ( code , client , message_id )
2024-02-14 23:35:04 +00:00
return { " status " : False , " error " : " Unsupported language " , " execution_time " : 0 }
2024-01-07 23:22:23 +00:00
except Exception as ex :
trace_exception ( ex )
lollmsElfServer . error ( ex )
return { " status " : False , " error " : str ( ex ) }
2024-04-21 00:50:43 +00:00
@router.post ( " /execute_code_in_new_tab " )
async def execute_code_in_new_tab ( request : CodeRequest ) :
"""
Executes Python code and returns the output .
: param request : The HTTP request object .
: return : A JSON response with the status of the operation .
"""
client = check_access ( lollmsElfServer , request . client_id )
if lollmsElfServer . config . headless_server_mode :
return { " status " : False , " error " : " Code execution is blocked when in headless mode for obvious security reasons! " }
forbid_remote_access ( lollmsElfServer , " Code execution is blocked when the server is exposed outside for very obvious reasons! " )
if not lollmsElfServer . config . turn_on_code_execution :
return { " status " : False , " error " : " Code execution is blocked by the configuration! " }
if lollmsElfServer . config . turn_on_code_validation :
if not show_yes_no_dialog ( " Validation " , " Do you validate the execution of the code? " ) :
return { " status " : False , " error " : " User refused the execution! " }
try :
code = request . code
discussion_id = request . discussion_id
message_id = request . message_id
language = request . language
if language == " python " :
ASCIIColors . info ( " Executing python code: " )
ASCIIColors . yellow ( code )
return execute_python ( code , client , message_id , True )
if language == " javascript " :
ASCIIColors . info ( " Executing javascript code: " )
ASCIIColors . yellow ( code )
return execute_javascript ( code , client , message_id , True )
if language in [ " html " , " html5 " , " svg " ] :
ASCIIColors . info ( " Executing javascript code: " )
ASCIIColors . yellow ( code )
return execute_html ( code , client , message_id , True )
2024-01-07 23:22:23 +00:00
2024-04-21 00:50:43 +00:00
elif language == " latex " :
ASCIIColors . info ( " Executing latex code: " )
ASCIIColors . yellow ( code )
return execute_latex ( code , client , message_id , True )
elif language in [ " bash " , " shell " , " cmd " , " powershell " ] :
ASCIIColors . info ( " Executing shell code: " )
ASCIIColors . yellow ( code )
return execute_bash ( code , client )
elif language in [ " mermaid " ] :
ASCIIColors . info ( " Executing mermaid code: " )
ASCIIColors . yellow ( code )
return execute_mermaid ( code , client , message_id , True )
elif language in [ " graphviz " , " dot " ] :
ASCIIColors . info ( " Executing graphviz code: " )
ASCIIColors . yellow ( code )
return execute_graphviz ( code , client , message_id , True )
return { " status " : False , " error " : " Unsupported language " , " execution_time " : 0 }
except Exception as ex :
trace_exception ( ex )
lollmsElfServer . error ( ex )
return { " status " : False , " error " : str ( ex ) }
2024-01-07 23:22:23 +00:00
2024-02-15 00:01:55 +00:00
class FilePath ( BaseModel ) :
path : Optional [ str ] = Field ( None , max_length = 500 )
2024-01-08 00:08:47 +00:00
@router.post ( " /open_file " )
2024-02-15 00:01:55 +00:00
async def open_file ( file_path : FilePath ) :
2024-01-07 23:22:23 +00:00
"""
Opens code in vs code .
2024-02-15 00:01:55 +00:00
: param file_path : The file path object .
2024-01-07 23:22:23 +00:00
: return : A JSON response with the status of the operation .
"""
2024-02-15 20:47:24 +00:00
if lollmsElfServer . config . headless_server_mode :
return { " status " : False , " error " : " Open file is blocked when in headless mode for obvious security reasons! " }
2024-02-19 22:03:59 +00:00
if lollmsElfServer . config . host != " localhost " and lollmsElfServer . config . host != " 127.0.0.1 " :
2024-02-15 20:47:24 +00:00
return { " status " : False , " error " : " Open file is blocked when the server is exposed outside for very obvious reasons! " }
2024-01-07 23:22:23 +00:00
2024-02-17 01:08:14 +00:00
if lollmsElfServer . config . turn_on_open_file_validation :
if not show_yes_no_dialog ( " Validation " , " Do you validate the opening of a file? " ) :
return { " status " : False , " error " : " User refused the opeining file! " }
2024-03-24 14:39:42 +00:00
forbid_remote_access ( lollmsElfServer )
2024-04-07 01:51:37 +00:00
2024-01-07 23:22:23 +00:00
try :
2024-02-14 23:35:04 +00:00
# Validate the 'path' parameter
2024-04-07 01:51:37 +00:00
path = sanitize_path ( file_path . path , allow_absolute_path = True )
2024-02-14 23:35:04 +00:00
2024-04-07 01:51:37 +00:00
if Path ( path ) . exists ( ) :
# Use subprocess.Popen to safely open the file
ASCIIColors . yellow ( f " Starting file : { path } " )
if os . name == " nt " : # if the operating system is Windows
subprocess . Popen ( f ' start { path } ' , shell = True )
else : # for other operating systems
subprocess . Popen ( [ path ] , shell = True )
2024-02-14 23:35:04 +00:00
return { " status " : True , " execution_time " : 0 }
2024-01-07 23:22:23 +00:00
except Exception as ex :
trace_exception ( ex )
lollmsElfServer . error ( ex )
return { " status " : False , " error " : str ( ex ) }
2024-02-27 16:06:22 +00:00
2024-03-24 17:09:18 +00:00
class FilePath ( BaseModel ) :
path : Optional [ str ] = Field ( None , max_length = 500 )
@router.post ( " /open_folder " )
async def open_folder ( file_path : FilePath ) :
"""
Opens a folder
: param file_path : The file path object .
: return : A JSON response with the status of the operation .
"""
2024-03-29 21:11:21 +00:00
forbid_remote_access ( lollmsElfServer , " Open file is blocked when the server is exposed outside for very obvious reasons! " )
2024-03-24 17:09:18 +00:00
if lollmsElfServer . config . headless_server_mode :
return { " status " : False , " error " : " Open file is blocked when in headless mode for obvious security reasons! " }
if lollmsElfServer . config . turn_on_open_file_validation :
2024-04-07 01:51:37 +00:00
if not show_yes_no_dialog ( " Validation " , " Do you validate the opening of a folder? " ) :
return { " status " : False , " error " : " User refused the opening folder! " }
2024-03-24 17:09:18 +00:00
forbid_remote_access ( lollmsElfServer )
try :
# Validate the 'path' parameter
2024-04-07 01:51:37 +00:00
path = sanitize_path ( file_path . path , allow_absolute_path = True )
ASCIIColors . yellow ( f " Opening folder : { path } " )
if Path ( path ) . exists ( ) :
# Use subprocess.Popen to safely open the file
if platform . system ( ) == ' Windows ' :
subprocess . Popen ( f ' explorer " { path } " ' , shell = True )
elif platform . system ( ) == ' Linux ' :
subprocess . run ( [ ' xdg-open ' , str ( path ) ] , check = True , shell = True )
elif platform . system ( ) == ' Darwin ' :
subprocess . run ( [ ' open ' , str ( path ) ] , check = True , shell = True )
2024-03-24 17:09:18 +00:00
return { " status " : True , " execution_time " : 0 }
except Exception as ex :
trace_exception ( ex )
lollmsElfServer . error ( ex )
return { " status " : False , " error " : str ( ex ) }
2024-02-27 16:06:22 +00:00
class OpenCodeFolderInVsCodeRequestModel ( BaseModel ) :
client_id : str = Field ( . . . )
discussion_id : Optional [ int ] = Field ( None , gt = 0 )
message_id : Optional [ int ] = Field ( None , gt = 0 )
code : Optional [ str ]
@router.post ( " /open_code_folder_in_vs_code " )
async def open_code_folder_in_vs_code ( request : OpenCodeFolderInVsCodeRequestModel ) :
2024-04-07 01:51:37 +00:00
client = check_access ( lollmsElfServer , request . client_id )
2024-02-27 16:06:22 +00:00
if lollmsElfServer . config . headless_server_mode :
return { " status " : False , " error " : " Open code folder in vscode is blocked when in headless mode for obvious security reasons! " }
if lollmsElfServer . config . host != " localhost " and lollmsElfServer . config . host != " 127.0.0.1 " :
return { " status " : False , " error " : " Open code folder in vscode is blocked when the server is exposed outside for very obvious reasons! " }
if lollmsElfServer . config . turn_on_open_file_validation :
if not show_yes_no_dialog ( " Validation " , " Do you validate the opening of folder in vscode? " ) :
return { " status " : False , " error " : " User refused the execution! " }
try :
if request . discussion_id :
ASCIIColors . info ( " Opening folder: " )
root_folder = client . discussion . discussion_folder
root_folder . mkdir ( parents = True , exist_ok = True )
tmp_file = root_folder / f " ai_code_ { request . message_id } .py "
with open ( tmp_file , " w " ) as f :
f . write ( request . code )
if os . path . isdir ( root_folder ) :
2024-02-28 01:06:50 +00:00
path = ' " ' + str ( root_folder ) + ' " ' . replace ( " \\ " , " / " )
subprocess . run ( [ ' code ' , path ] , shell = True )
2024-02-27 16:06:22 +00:00
return { " status " : True , " execution_time " : 0 }
except Exception as ex :
trace_exception ( ex )
2024-02-28 01:06:50 +00:00
lollmsElfServer . error ( str ( ex ) )
2024-02-27 16:06:22 +00:00
return { " status " : False , " error " : " An error occurred during processing. " }
2024-02-15 00:01:55 +00:00
class VSCodeData ( BaseModel ) :
2024-02-27 16:06:22 +00:00
client_id : str = Field ( . . . )
2024-02-15 00:01:55 +00:00
discussion_id : Optional [ int ] = Field ( None , ge = 0 )
message_id : Optional [ int ] = Field ( None , ge = 0 )
code : str = Field ( . . . )
2024-01-07 23:22:23 +00:00
2024-01-08 00:08:47 +00:00
@router.post ( " /open_code_in_vs_code " )
2024-02-15 00:01:55 +00:00
async def open_code_in_vs_code ( vs_code_data : VSCodeData ) :
2024-01-07 23:22:23 +00:00
"""
Opens code in vs code .
2024-02-15 00:01:55 +00:00
: param vs_code_data : The data object .
2024-01-07 23:22:23 +00:00
: return : A JSON response with the status of the operation .
"""
2024-04-07 01:51:37 +00:00
client = check_access ( lollmsElfServer , vs_code_data . client_id )
2024-02-15 20:47:24 +00:00
if lollmsElfServer . config . headless_server_mode :
return { " status " : False , " error " : " Open code in vs code is blocked when in headless mode for obvious security reasons! " }
2024-02-19 22:03:59 +00:00
if lollmsElfServer . config . host != " localhost " and lollmsElfServer . config . host != " 127.0.0.1 " :
2024-02-15 20:47:24 +00:00
return { " status " : False , " error " : " Open code in vs code is blocked when the server is exposed outside for very obvious reasons! " }
2024-01-07 23:22:23 +00:00
2024-02-17 01:08:14 +00:00
if lollmsElfServer . config . turn_on_open_file_validation :
if not show_yes_no_dialog ( " Validation " , " Do you validate the opening of a code in vscode? " ) :
return { " status " : False , " error " : " User refused the opeining file! " }
2024-01-07 23:22:23 +00:00
try :
2024-02-15 00:01:55 +00:00
discussion_id = vs_code_data . discussion_id
message_id = vs_code_data . message_id
code = vs_code_data . code
2024-01-07 23:22:23 +00:00
ASCIIColors . info ( " Opening folder: " )
# Create a temporary file.
2024-02-27 16:06:22 +00:00
root_folder = client . discussion . discussion_folder
2024-01-07 23:22:23 +00:00
root_folder . mkdir ( parents = True , exist_ok = True )
tmp_file = root_folder / f " ai_code_ { message_id } .py "
with open ( tmp_file , " w " ) as f :
f . write ( code )
2024-02-15 00:01:55 +00:00
# Use subprocess.Popen to safely open the file
2024-02-28 00:06:59 +00:00
subprocess . Popen ( [ " code " , str ( tmp_file ) ] , shell = True )
2024-02-15 00:01:55 +00:00
2024-02-14 23:35:04 +00:00
return { " status " : True , " execution_time " : 0 }
2024-01-07 23:22:23 +00:00
except Exception as ex :
trace_exception ( ex )
lollmsElfServer . error ( ex )
return { " status " : False , " error " : str ( ex ) }
2024-02-15 00:01:55 +00:00
class FolderRequest ( BaseModel ) :
2024-02-27 16:06:22 +00:00
client_id : str = Field ( . . . )
2024-02-15 00:01:55 +00:00
discussion_id : Optional [ int ] = Field ( None , title = " The discussion ID " )
folder_path : Optional [ str ] = Field ( None , title = " The folder path " )
2024-01-07 23:22:23 +00:00
2024-01-08 00:08:47 +00:00
@router.post ( " /open_code_folder " )
2024-02-15 00:01:55 +00:00
async def open_code_folder ( request : FolderRequest ) :
2024-01-07 23:22:23 +00:00
"""
Opens code folder .
: param request : The HTTP request object .
: return : A JSON response with the status of the operation .
"""
2024-04-07 01:51:37 +00:00
client = check_access ( lollmsElfServer , request . client_id )
2024-02-15 20:47:24 +00:00
if lollmsElfServer . config . headless_server_mode :
return { " status " : False , " error " : " Open code folder is blocked when in headless mode for obvious security reasons! " }
2024-02-19 22:03:59 +00:00
if lollmsElfServer . config . host != " localhost " and lollmsElfServer . config . host != " 127.0.0.1 " :
2024-02-15 20:47:24 +00:00
return { " status " : False , " error " : " Open code folder is blocked when the server is exposed outside for very obvious reasons! " }
2024-02-15 00:01:55 +00:00
2024-02-17 01:08:14 +00:00
if lollmsElfServer . config . turn_on_open_file_validation :
if not show_yes_no_dialog ( " Validation " , " Do you validate the opening of a folder? " ) :
return { " status " : False , " error " : " User refused the opeining folder! " }
2024-01-07 23:22:23 +00:00
try :
2024-02-28 00:06:59 +00:00
ASCIIColors . info ( " Opening folder: " )
# Create a temporary file.
root_folder = client . discussion . discussion_folder
root_folder . mkdir ( parents = True , exist_ok = True )
if platform . system ( ) == ' Windows ' :
2024-03-01 09:57:47 +00:00
subprocess . Popen ( f ' explorer " { root_folder } " ' )
2024-02-28 00:06:59 +00:00
elif platform . system ( ) == ' Linux ' :
subprocess . run ( [ ' xdg-open ' , str ( root_folder ) ] , check = True )
elif platform . system ( ) == ' Darwin ' :
subprocess . run ( [ ' open ' , str ( root_folder ) ] , check = True )
return { " status " : True , " execution_time " : 0 }
2024-01-07 23:22:23 +00:00
2024-01-07 22:17:22 +00:00
except Exception as ex :
trace_exception ( ex )
lollmsElfServer . error ( ex )
2024-02-15 00:01:55 +00:00
return { " status " : False , " error " : " An error occurred while processing the request " }
2024-02-03 18:04:43 +00:00
@router.get ( " /start_recording " )
def start_recording ( ) :
2024-02-15 20:47:24 +00:00
if lollmsElfServer . config . headless_server_mode :
return { " status " : False , " error " : " Start recording is blocked when in headless mode for obvious security reasons! " }
2024-02-19 22:03:59 +00:00
if lollmsElfServer . config . host != " localhost " and lollmsElfServer . config . host != " 127.0.0.1 " :
2024-02-15 20:47:24 +00:00
return { " status " : False , " error " : " Start recording is blocked when the server is exposed outside for very obvious reasons! " }
2024-02-03 18:04:43 +00:00
lollmsElfServer . info ( " Starting audio capture " )
try :
from lollms . media import AudioRecorder
lollmsElfServer . rec_output_folder = lollmsElfServer . lollms_paths . personal_outputs_path / " audio_rec "
lollmsElfServer . rec_output_folder . mkdir ( exist_ok = True , parents = True )
lollmsElfServer . summoned = False
2024-02-05 19:37:46 +00:00
lollmsElfServer . audio_cap = AudioRecorder ( lollmsElfServer . sio , lollmsElfServer . rec_output_folder / " rt.wav " , callback = lollmsElfServer . audio_callback , lollmsCom = lollmsElfServer , transcribe = True )
2024-02-03 18:04:43 +00:00
lollmsElfServer . audio_cap . start_recording ( )
except :
lollmsElfServer . InfoMessage ( " Couldn ' t load media library. \n You will not be able to perform any of the media linked operations. please verify the logs and install any required installations " )
@router.get ( " /stop_recording " )
def stop_recording ( ) :
2024-02-15 20:47:24 +00:00
if lollmsElfServer . config . headless_server_mode :
return { " status " : False , " error " : " Stop recording is blocked when in headless mode for obvious security reasons! " }
2024-02-19 22:03:59 +00:00
if lollmsElfServer . config . host != " localhost " and lollmsElfServer . config . host != " 127.0.0.1 " :
2024-02-15 20:47:24 +00:00
return { " status " : False , " error " : " Stop recording is blocked when the server is exposed outside for very obvious reasons! " }
2024-02-03 18:04:43 +00:00
lollmsElfServer . info ( " Stopping audio capture " )
text = lollmsElfServer . audio_cap . stop_recording ( )
return text
2024-02-05 22:50:40 +00:00