lollms-webui/endpoints/lollms_advanced.py

742 lines
26 KiB
Python
Raw Normal View History

"""
2024-07-05 14:02:55 +00:00
project: lollms_advanced
file: lollms_advanced.py
author: ParisNeo
description:
2024-07-05 14:02:55 +00:00
This module contains a set of FastAPI routes that provide access to advanced functionalities of lollms. These routes allow users to do advanced stuff like executing code.
"""
2024-12-19 12:48:57 +00:00
import io
2024-01-07 23:22:23 +00:00
import os
import platform
2024-02-14 23:35:04 +00:00
import re
2024-12-19 12:48:57 +00:00
import shutil
import string
import subprocess
from pathlib import Path
2024-02-15 00:01:55 +00:00
from typing import Optional
2024-02-14 23:35:04 +00:00
2024-12-19 12:48:57 +00:00
import tqdm
from ascii_colors import ASCIIColors
from fastapi import (APIRouter, FastAPI, File, HTTPException, Query, Request,
UploadFile)
2024-09-12 23:19:22 +00:00
from fastapi.responses import FileResponse, StreamingResponse
2024-12-19 12:48:57 +00:00
from lollms.client_session import Client
from lollms.databases.discussions_database import DiscussionsDB
from lollms.main_config import BaseConfig
from lollms.security import (check_access, forbid_remote_access, sanitize_path,
sanitize_svg)
from lollms.types import MSG_OPERATION_TYPE
from lollms.utilities import (add_period, detect_antiprompt,
remove_text_from_string, show_yes_no_dialog,
trace_exception)
from pydantic import BaseModel, Field
from starlette.responses import StreamingResponse
from lollms_webui import LOLLMSWebUI
2024-09-12 23:19:22 +00:00
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-02-05 22:50:40 +00:00
2024-09-12 23:19:22 +00:00
import os
import shutil
2024-12-19 12:48:57 +00:00
import tempfile
from fastapi import FastAPI, File, UploadFile
from fastapi.responses import JSONResponse
from utilities.execution_engines.graphviz_execution_engine import \
execute_graphviz
from utilities.execution_engines.html_execution_engine import execute_html
from utilities.execution_engines.javascript_execution_engine import \
execute_javascript
from utilities.execution_engines.latex_execution_engine import execute_latex
from utilities.execution_engines.lilypond_execution_engine import \
execute_lilypond
from utilities.execution_engines.mermaid_execution_engine import \
execute_mermaid
from utilities.execution_engines.python_execution_engine import execute_python
from utilities.execution_engines.shell_execution_engine import execute_bash
from utilities.execution_engines.svg_execution_engine import execute_svg
2024-01-09 22:26:41 +00:00
# ----------------------- Defining router and main class ------------------------------
2024-01-07 23:22:23 +00:00
router = APIRouter()
2024-12-19 12:48:57 +00:00
lollmsElfServer: LOLLMSWebUI = LOLLMSWebUI.get_instance()
2024-05-05 15:28:45 +00:00
class Identification(BaseModel):
2024-12-19 12:48:57 +00:00
client_id: str
2024-02-15 00:31:16 +00:00
2024-02-15 19:31:03 +00:00
class CodeRequest(BaseModel):
2024-12-19 12:48:57 +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-12-19 12:48:57 +00:00
@router.post("/execute_code")
2024-02-15 19:31:03 +00:00
async def execute_code(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.
"""
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:
2024-12-19 12:48:57 +00:00
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!",
)
2024-02-15 00:31:16 +00:00
if not lollmsElfServer.config.turn_on_code_execution:
2024-12-19 12:48:57 +00:00
return {
"status": False,
"error": "Code execution is blocked by the configuration!",
}
2024-02-15 00:31:16 +00:00
if lollmsElfServer.config.turn_on_code_validation:
2024-12-19 12:48:57 +00:00
if not show_yes_no_dialog(
"Validation", "Do you validate the execution of the code?"
):
return {"status": False, "error": "User refused the execution!"}
2024-02-15 00:31:16 +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-12-19 12:48:57 +00:00
if language == "function":
2024-05-13 23:57:07 +00:00
ASCIIColors.info("Executing function call:")
ASCIIColors.yellow(code)
2024-06-08 23:42:06 +00:00
try:
out = lollmsElfServer.personality.execute_function(code)
2024-12-19 12:48:57 +00:00
return (
out
if type(out) == str
else (
out[0] if type(out) is tuple and type(out[0]) == str else "Done"
)
)
2024-06-08 23:42:06 +00:00
except Exception as ex:
trace_exception(ex)
return ex
2024-12-19 12:48:57 +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-12-19 12:48:57 +00:00
if language == "svg":
2024-04-21 15:14:00 +00:00
ASCIIColors.info("Executing svg code:")
ASCIIColors.yellow(code)
return execute_svg(sanitize_svg(code), client, message_id)
2024-12-19 12:48:57 +00:00
if language == "lilypond":
2024-10-31 20:57:29 +00:00
ASCIIColors.info("Executing svg code:")
ASCIIColors.yellow(code)
return execute_lilypond(code, client, message_id)
2024-12-19 12:48:57 +00:00
if language == "javascript":
2024-02-05 22:50:40 +00:00
ASCIIColors.info("Executing javascript code:")
ASCIIColors.yellow(code)
2024-04-21 00:50:43 +00:00
return execute_javascript(code, client, message_id)
2024-12-19 12:48:57 +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-12-19 12:48:57 +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-12-19 12:48:57 +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-04-28 09:17:22 +00:00
return execute_bash(code, client, message_id)
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-12-19 12:48:57 +00:00
elif language in ["graphviz", "dot"]:
2024-02-05 22:50:40 +00:00
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)
2024-12-19 12:48:57 +00:00
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:
2024-12-19 12:48:57 +00:00
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!",
)
2024-04-21 00:50:43 +00:00
if not lollmsElfServer.config.turn_on_code_execution:
2024-12-19 12:48:57 +00:00
return {
"status": False,
"error": "Code execution is blocked by the configuration!",
}
2024-04-21 00:50:43 +00:00
if lollmsElfServer.config.turn_on_code_validation:
2024-12-19 12:48:57 +00:00
if not show_yes_no_dialog(
"Validation", "Do you validate the execution of the code?"
):
return {"status": False, "error": "User refused the execution!"}
2024-04-21 00:50:43 +00:00
try:
code = request.code
discussion_id = request.discussion_id
message_id = request.message_id
language = request.language
2024-12-19 12:48:57 +00:00
if language == "python":
2024-04-21 00:50:43 +00:00
ASCIIColors.info("Executing python code:")
ASCIIColors.yellow(code)
return execute_python(code, client, message_id, True)
2024-12-19 12:48:57 +00:00
if language == "javascript":
2024-04-21 00:50:43 +00:00
ASCIIColors.info("Executing javascript code:")
ASCIIColors.yellow(code)
return execute_javascript(code, client, message_id, True)
2024-12-19 12:48:57 +00:00
if language in ["html", "html5", "svg"]:
2024-04-21 00:50:43 +00:00
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-12-19 12:48:57 +00:00
elif language == "latex":
2024-04-21 00:50:43 +00:00
ASCIIColors.info("Executing latex code:")
ASCIIColors.yellow(code)
return execute_latex(code, client, message_id, True)
2024-12-19 12:48:57 +00:00
elif language in ["bash", "shell", "cmd", "powershell"]:
2024-04-21 00:50:43 +00:00
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)
2024-12-19 12:48:57 +00:00
elif language in ["graphviz", "dot"]:
2024-04-21 00:50:43 +00:00
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)
2024-12-19 12:48:57 +00:00
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):
client_id: str
2024-02-15 00:01:55 +00:00
path: Optional[str] = Field(None, max_length=500)
2024-12-19 12:48:57 +00:00
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.
"""
check_access(lollmsElfServer, client_id=file_path.client_id)
2024-02-15 20:47:24 +00:00
2024-12-19 12:48:57 +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.host != "localhost"
and lollmsElfServer.config.host != "127.0.0.1"
):
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:
2024-12-19 12:48:57 +00:00
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-02-17 01:08:14 +00:00
2024-03-24 14:39:42 +00:00
forbid_remote_access(lollmsElfServer)
2024-04-29 16:52:35 +00:00
# Validate the 'path' parameter
path = sanitize_path(file_path.path, allow_absolute_path=True)
2024-04-07 01:51:37 +00:00
2024-12-19 12:48:57 +00:00
try:
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}")
2024-12-19 12:48:57 +00:00
if os.name == "nt": # if the operating system is Windows
subprocess.Popen(f"start {path}", shell=True)
else: # for other operating systems
2024-04-07 01:51:37 +00:00
subprocess.Popen([path], shell=True)
2024-12-19 12:48:57 +00:00
2024-02-14 23:35:04 +00:00
return {"status": True, "execution_time": 0}
2024-12-19 12:48:57 +00:00
2024-01-07 23:22:23 +00:00
except Exception as ex:
trace_exception(ex)
lollmsElfServer.error(ex)
2024-12-19 12:48:57 +00:00
return {"status": False, "error": str(ex)}
2024-03-24 17:09:18 +00:00
@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-12-19 12:48:57 +00:00
forbid_remote_access(
lollmsElfServer,
"Open file is blocked when the server is exposed outside for very obvious reasons!",
)
2024-03-29 21:11:21 +00:00
2024-03-24 17:09:18 +00:00
if lollmsElfServer.config.headless_server_mode:
2024-12-19 12:48:57 +00:00
return {
"status": False,
"error": "Open file is blocked when in headless mode for obvious security reasons!",
}
2024-03-24 17:09:18 +00:00
if lollmsElfServer.config.turn_on_open_file_validation:
2024-12-19 12:48:57 +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
2024-12-19 12:48:57 +00:00
if platform.system() == "Windows":
path = path.replace("/", "\\")
2024-07-22 19:18:19 +00:00
subprocess.Popen(f'explorer "{path}"')
2024-12-19 12:48:57 +00:00
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}
2024-12-19 12:48:57 +00:00
2024-03-24 17:09:18 +00:00
except Exception as ex:
trace_exception(ex)
lollmsElfServer.error(ex)
2024-12-19 12:48:57 +00:00
return {"status": False, "error": str(ex)}
2024-03-24 17:09:18 +00:00
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]
2024-12-19 12:48:57 +00:00
2024-05-02 22:58:18 +00:00
@router.post("/open_discussion_folder_in_vs_code")
2024-12-19 12:48:57 +00:00
async def open_discussion_folder_in_vs_code(
request: OpenCodeFolderInVsCodeRequestModel,
):
2024-02-27 16:06:22 +00:00
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:
2024-12-19 12:48:57 +00:00
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!",
}
2024-02-27 16:06:22 +00:00
if lollmsElfServer.config.turn_on_open_file_validation:
2024-12-19 12:48:57 +00:00
if not show_yes_no_dialog(
"Validation", "Do you validate the opening of folder in vscode?"
):
return {"status": False, "error": "User refused the execution!"}
2024-02-27 16:06:22 +00:00
try:
2024-12-19 12:48:57 +00:00
if request.discussion_id:
2024-02-27 16:06:22 +00:00
ASCIIColors.info("Opening folder:")
root_folder = client.discussion.discussion_folder
2024-12-19 12:48:57 +00:00
root_folder.mkdir(parents=True, exist_ok=True)
tmp_file = root_folder / f"ai_code_{request.message_id}.py"
with open(tmp_file, "w", encoding="utf-8", errors="ignore") as f:
2024-02-27 16:06:22 +00:00
f.write(request.code)
2024-12-19 12:48:57 +00:00
if os.path.isdir(root_folder):
path = '"' + str(root_folder) + '"'.replace("\\", "/")
subprocess.run(["code", "-n", 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-12-19 12:48:57 +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-12-19 12:48:57 +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:
2024-12-19 12:48:57 +00:00
return {
"status": False,
"error": "Open code in vs code 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 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:
2024-12-19 12:48:57 +00:00
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-02-17 01:08:14 +00:00
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-12-19 12:48:57 +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", encoding="utf-8", errors="ignore") as f:
2024-01-07 23:22:23 +00:00
f.write(code)
2024-12-19 12:48:57 +00:00
2024-02-15 00:01:55 +00:00
# Use subprocess.Popen to safely open the file
2024-07-28 23:39:19 +00:00
os.system(f'code -n "{tmp_file}"')
2024-12-19 12:48:57 +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)
2024-12-19 12:48:57 +00:00
return {"status": False, "error": str(ex)}
2024-05-08 22:08:44 +00:00
class DiscussionFolderRequest(BaseModel):
2024-02-27 16:06:22 +00:00
client_id: str = Field(...)
2024-05-02 22:58:18 +00:00
discussion_id: int = Field(...)
2024-01-07 23:22:23 +00:00
2024-12-19 12:48:57 +00:00
2024-05-02 22:58:18 +00:00
@router.post("/open_discussion_folder")
2024-05-08 22:08:44 +00:00
async def open_discussion_folder(request: DiscussionFolderRequest):
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:
2024-12-19 12:48:57 +00:00
return {
"status": False,
"error": "Open code folder 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 is blocked when the server is exposed outside for very obvious reasons!",
}
2024-02-15 20:47:24 +00:00
2024-02-17 01:08:14 +00:00
if lollmsElfServer.config.turn_on_open_file_validation:
2024-12-19 12:48:57 +00:00
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-02-17 01:08:14 +00:00
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)
2024-12-19 12:48:57 +00:00
if platform.system() == "Windows":
2024-03-01 09:57:47 +00:00
subprocess.Popen(f'explorer "{root_folder}"')
2024-12-19 12:48:57 +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)
2024-02-28 00:06:59 +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)
2024-12-19 12:48:57 +00:00
return {
"status": False,
"error": "An error occurred while processing the request",
}
2024-02-03 18:04:43 +00:00
2024-05-08 22:08:44 +00:00
class PersonalityFolderRequest(BaseModel):
client_id: str = Field(...)
2024-05-24 22:36:51 +00:00
personality_folder: str = Field(...)
2024-05-08 22:08:44 +00:00
2024-12-19 12:48:57 +00:00
2024-05-08 22:08:44 +00:00
@router.post("/open_personality_folder")
async def open_personality_folder(request: PersonalityFolderRequest):
"""
Opens code folder.
:param request: The HTTP request object.
:return: A JSON response with the status of the operation.
"""
client = check_access(lollmsElfServer, request.client_id)
personality_folder = sanitize_path(request.personality_folder)
if lollmsElfServer.config.headless_server_mode:
2024-12-19 12:48:57 +00:00
return {
"status": False,
"error": "Open code folder 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 is blocked when the server is exposed outside for very obvious reasons!",
}
2024-05-08 22:08:44 +00:00
if lollmsElfServer.config.turn_on_open_file_validation:
2024-12-19 12:48:57 +00:00
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-05-08 22:08:44 +00:00
try:
ASCIIColors.info("Opening folder:")
# Create a temporary file.
2024-12-19 12:48:57 +00:00
root_folder = (
lollmsElfServer.lollms_paths.personalities_zoo_path / personality_folder
)
2024-05-08 22:08:44 +00:00
root_folder.mkdir(parents=True, exist_ok=True)
2024-12-19 12:48:57 +00:00
if platform.system() == "Windows":
2024-05-08 22:08:44 +00:00
subprocess.Popen(f'explorer "{root_folder}"')
2024-12-19 12:48:57 +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)
2024-05-08 22:08:44 +00:00
return {"status": True, "execution_time": 0}
except Exception as ex:
trace_exception(ex)
lollmsElfServer.error(ex)
2024-12-19 12:48:57 +00:00
return {
"status": False,
"error": "An error occurred while processing the request",
}
2024-05-08 22:08:44 +00:00
2024-05-19 12:35:05 +00:00
@router.get("/is_rt_on")
def is_rt_on():
return {"status": lollmsElfServer.rt_com is not None}
2024-05-08 22:08:44 +00:00
2024-12-19 12:48:57 +00:00
2024-05-05 15:28:45 +00:00
@router.post("/start_recording")
2024-12-19 12:48:57 +00:00
def start_recording(data: Identification):
2024-05-05 15:28:45 +00:00
client = check_access(lollmsElfServer, data.client_id)
2024-02-15 20:47:24 +00:00
if lollmsElfServer.config.headless_server_mode:
2024-12-19 12:48:57 +00:00
return {
"status": False,
"error": "Start recording 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": "Start recording is blocked when the server is exposed outside for very obvious reasons!",
}
2024-02-15 20:47:24 +00:00
2024-05-24 21:51:17 +00:00
lollmsElfServer.info("Starting audio capture")
if not lollmsElfServer.tts or not lollmsElfServer.stt:
2024-12-19 12:48:57 +00:00
lollmsElfServer.InfoMessage(
"TTS or STT are not configured.\nPlease go to settings and configure them first"
)
return {"status": False, "error": "TTS or STT not configured"}
2024-05-24 21:51:17 +00:00
if not lollmsElfServer.tts.ready or not lollmsElfServer.stt.ready:
lollmsElfServer.InfoMessage("TTS is not ready yet.\nPlease wait")
2024-12-19 12:48:57 +00:00
return {"status": False, "error": "TTS not ready"}
2024-05-24 21:51:17 +00:00
2024-02-03 18:04:43 +00:00
lollmsElfServer.info("Starting audio capture")
try:
2024-05-26 22:36:45 +00:00
from lollms.media import AudioNinja
2024-12-19 12:48:57 +00:00
lollmsElfServer.rec_output_folder = (
lollmsElfServer.lollms_paths.personal_outputs_path / "audio_rec"
)
2024-02-03 18:04:43 +00:00
lollmsElfServer.rec_output_folder.mkdir(exist_ok=True, parents=True)
lollmsElfServer.summoned = False
2024-05-26 22:36:45 +00:00
lollmsElfServer.audioNinja = AudioNinja(
2024-12-19 12:48:57 +00:00
lollmsElfServer, logs_folder=lollmsElfServer.rec_output_folder
)
2024-05-26 22:36:45 +00:00
lollmsElfServer.audioNinja.start_recording()
2024-02-03 18:04:43 +00:00
except:
2024-12-19 12:48:57 +00:00
lollmsElfServer.InfoMessage(
"Couldn't load media library.\nYou will not be able to perform any of the media linked operations. please verify the logs and install any required installations"
)
2024-02-03 18:04:43 +00:00
2024-05-05 15:28:45 +00:00
@router.post("/stop_recording")
2024-12-19 12:48:57 +00:00
def stop_recording(data: Identification):
2024-05-05 15:28:45 +00:00
client = check_access(lollmsElfServer, data.client_id)
2024-02-15 20:47:24 +00:00
if lollmsElfServer.config.headless_server_mode:
2024-12-19 12:48:57 +00:00
return {
"status": False,
"error": "Stop recording 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": "Stop recording is blocked when the server is exposed outside for very obvious reasons!",
}
2024-02-15 20:47:24 +00:00
2024-02-03 18:04:43 +00:00
lollmsElfServer.info("Stopping audio capture")
2024-05-26 22:36:45 +00:00
fn = lollmsElfServer.audioNinja.stop_recording()
lollmsElfServer.audioNinja = None
if lollmsElfServer.stt and fn:
2024-05-26 22:36:45 +00:00
text = lollmsElfServer.stt.transcribe(fn)
return text
else:
return ""
2024-02-05 22:50:40 +00:00
2024-09-12 23:19:22 +00:00
@router.post("/transcribe")
async def transcribe_audio(file: UploadFile = File(...)):
2024-12-19 12:48:57 +00:00
with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as temp_file:
2024-09-12 23:19:22 +00:00
# Copy the contents of the uploaded file to the temporary file
shutil.copyfileobj(file.file, temp_file)
temp_file_path = temp_file.name
try:
2024-12-19 12:48:57 +00:00
if hasattr(lollmsElfServer, "stt") and lollmsElfServer.stt:
2024-09-12 23:19:22 +00:00
text = lollmsElfServer.stt.transcribe(temp_file_path)
return JSONResponse(content={"transcription": text})
else:
2024-12-19 12:48:57 +00:00
return JSONResponse(
content={"error": "STT service not available"}, status_code=503
)
2024-09-12 23:19:22 +00:00
finally:
# Clean up the temporary file
os.unlink(temp_file_path)
class TTSRequest(BaseModel):
text: str
speaker: str = None
language: str = "en"
2024-12-19 12:48:57 +00:00
2024-09-12 23:19:22 +00:00
@router.post("/tts/file")
async def text_to_speech_file(request: TTSRequest):
try:
file_path = lollmsElfServer.tts.tts_file(
text=request.text,
2024-12-19 12:48:57 +00:00
file_name_or_path=lollmsElfServer.lollms_paths.personal_outputs_path
/ "output.wav",
2024-09-12 23:19:22 +00:00
speaker=request.speaker,
2024-12-19 12:48:57 +00:00
language=request.language,
2024-09-12 23:19:22 +00:00
)
return FileResponse(file_path, media_type="audio/wav", filename="speech.wav")
except Exception as e:
2024-10-06 20:59:17 +00:00
trace_exception(e)
2024-09-12 23:19:22 +00:00
raise HTTPException(status_code=500, detail=str(e))
2024-12-19 12:48:57 +00:00
2024-09-12 23:19:22 +00:00
@router.post("/tts/stream")
async def text_to_speech_stream(request: TTSRequest):
try:
audio_data = lollmsElfServer.tts.tts_audio(
2024-12-19 12:48:57 +00:00
text=request.text, speaker=request.speaker, language=request.language
2024-09-12 23:19:22 +00:00
)
return StreamingResponse(io.BytesIO(audio_data), media_type="audio/wav")
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
2024-12-19 12:48:57 +00:00
2024-09-12 23:19:22 +00:00
@router.get("/tts/voices")
async def get_available_voices():
try:
voices = lollmsElfServer.tts.get_voices()
return JSONResponse(content={"voices": voices})
except Exception as e:
2024-12-19 12:48:57 +00:00
return JSONResponse(content={"error": str(e)}, status_code=500)