#wip: For redo.
This commit is contained in:
parent
4552cf4c81
commit
c3fe1bb6fd
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,3 +1,5 @@
|
|||||||
/ollama
|
/ollama
|
||||||
/open-webui
|
/open-webui
|
||||||
/websockets
|
/websockets
|
||||||
|
*.[Ss]ecrets.*
|
||||||
|
*.[Ss]ecret.*
|
||||||
333
AIChat.py
333
AIChat.py
@ -1,24 +1,20 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from typing import Self, Any, Optional, Sequence
|
from typing import Self, Any, Optional, Sequence, Callable
|
||||||
from requests import post as Post, Response
|
from requests import post as Post, Response
|
||||||
from os.path import dirname as directory_name, abspath as absolute_path, exists as path_exists
|
from os.path import dirname as directory_name, abspath as absolute_path, exists as path_exists
|
||||||
from io import FileIO
|
from io import FileIO
|
||||||
from re import compile as re_compile, Pattern as REPattern, Match as REMatch, IGNORECASE as RE_IGNORECASE
|
from re import compile as re_compile, Pattern as REPattern, Match as REMatch, IGNORECASE as RE_IGNORECASE
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
from json import loads as json_decode, dumps as json_encode
|
from json import loads as json_decode, dumps as json_encode
|
||||||
|
from time import sleep
|
||||||
from http import server as http_server
|
from http import server as http_server
|
||||||
from http.server import BaseHTTPRequestHandler, HTTPServer
|
from http.server import BaseHTTPRequestHandler, HTTPServer
|
||||||
from mimetypes import guess_type as read_mime_types
|
from mimetypes import guess_type as read_mime_types
|
||||||
from websockets.sync.server import serve as web_socket_server_serve
|
from websockets.sync.server import serve as web_socket_server_serve
|
||||||
from websockets import ServerConnection as WebSocketServer, ClientConnection as WebSocketClient
|
from websockets import ServerConnection as WebSocketServer, ClientConnection as WebSocketClient
|
||||||
|
|
||||||
class ClientRequestModel:
|
|
||||||
def __init__(self:Self, client:WebSocketClient, message:str) -> None:
|
|
||||||
self.client:WebSocketClient = client
|
|
||||||
self.message:str = message
|
|
||||||
|
|
||||||
class AIChat:
|
class AIChat:
|
||||||
|
|
||||||
ROOT_PATH:str = directory_name(absolute_path(__file__))
|
ROOT_PATH:str = directory_name(absolute_path(__file__))
|
||||||
@ -29,7 +25,7 @@ class AIChat:
|
|||||||
"titles_model" : "gemma3:1b",
|
"titles_model" : "gemma3:1b",
|
||||||
"titles_temperature" : 0.0,
|
"titles_temperature" : 0.0,
|
||||||
"titles_prompt_file" : "/TXT/AIChat.titles-prompt.md",
|
"titles_prompt_file" : "/TXT/AIChat.titles-prompt.md",
|
||||||
"responses_model" : "gemma3",
|
"responses_model" : "gemma3:1b",
|
||||||
"responses_temperature" : 7.0,
|
"responses_temperature" : 7.0,
|
||||||
"response_with_titles_prompt_file" : "/TXT/AIChat.response-with-titles.md",
|
"response_with_titles_prompt_file" : "/TXT/AIChat.response-with-titles.md",
|
||||||
}
|
}
|
||||||
@ -51,36 +47,47 @@ class AIChat:
|
|||||||
self.__sentences:dict[str, dict[str, str|Sequence[str]]] = {language : {
|
self.__sentences:dict[str, dict[str, str|Sequence[str]]] = {language : {
|
||||||
key : value for key, value in sentences.items()
|
key : value for key, value in sentences.items()
|
||||||
} for language, sentences in self.DEFAULT_SENTENCES.items()}
|
} for language, sentences in self.DEFAULT_SENTENCES.items()}
|
||||||
|
|
||||||
self.__default_language:str = self.get("default_language", inputs, "espanol")
|
self.__default_language:str = self.get("default_language", inputs, "espanol")
|
||||||
self.__language:str = self.get("language", inputs, self.__default_language)
|
self.__language:str = self.get("language", inputs, self.__default_language)
|
||||||
self.__host:str = self.get("host", inputs, "localhost")
|
|
||||||
self.__port:int = self.get("port", inputs, 11434)
|
self.__host:str = "localhost"
|
||||||
self.__api_url:str = self.get("api_url", inputs, "http://{host}:{port}/api/generate")
|
self.__port:int = 11434
|
||||||
|
self.__api_url:str = "http://{host}:{port}/api/generate"
|
||||||
|
|
||||||
self.__index:dict[str, str] = {}
|
self.__index:dict[str, str] = {}
|
||||||
|
self.__requests_i:int = 0
|
||||||
self.__requests_order:list[int] = []
|
self.__requests_order:list[int] = []
|
||||||
self.__requests:dict[int, ClientRequestModel] = {}
|
self.__requests:dict[int, dict[str, Any|None]] = {}
|
||||||
self.__web_socket_server:WebSocketServer
|
self.__web_socket_server:WebSocketServer
|
||||||
self.__web_socket_host:str = self.get("web_socket_host", inputs, "localhost")
|
self.__web_socket_host:str = "localhost"
|
||||||
self.__web_socket_port:int = self.get("web_socket_port", inputs, 18001)
|
self.__web_socket_port:int = 18001
|
||||||
self.__web_socket_server_thread:Thread = Thread(target = self.__run_web_socket_server)
|
self.__web_socket_server_thread:Thread = Thread(target = self.__run_web_socket_server)
|
||||||
self.__titles_model:str = self.get("titles_model", inputs)
|
self.__requests_thread:Thread = Thread(target = self.__run_orders)
|
||||||
self.__titles_temperature:float = self.get("titles_temperature", inputs)
|
self.__requests_sleep:float = 0.1
|
||||||
self.__titles_prompt:str = self.RE_NEW_LINES.sub("\\n", self.load_file(self.get("titles_prompt_file", inputs)))
|
|
||||||
self.__response_model:str = self.get("responses_model", inputs)
|
self.__titles_model:str = "gemma3:1b"
|
||||||
self.__response_temperature:float = self.get("responses_temperature", inputs)
|
self.__titles_temperature:float = 0.0
|
||||||
self.__response_with_titles:str = self.RE_NEW_LINES.sub("\\n", self.load_file(self.get("response_with_titles_prompt_file", inputs)))
|
self.__titles_prompt:str = self.RE_NEW_LINES.sub("\\n", self.load_file("/TXT/AIChat.titles-prompt.md"))
|
||||||
|
self.__response_model:str = "gemma3:1b"
|
||||||
|
self.__response_temperature:float = 7.0
|
||||||
|
self.__response_with_titles:str = self.RE_NEW_LINES.sub("\\n", self.load_file("/TXT/AIChat.response-with-titles.md"))
|
||||||
|
|
||||||
self.__http_server:HTTPServer
|
self.__http_server:HTTPServer
|
||||||
self.__http_server_thread:Thread = Thread(target = self.__run_http_server)
|
self.__http_server_thread:Thread = Thread(target = self.__run_http_server)
|
||||||
self.__http_host:str = self.get("http_host", inputs, "")
|
self.__http_host:str = ""
|
||||||
self.__http_port:int = self.get("http_port", inputs, 18000)
|
self.__http_port:int = 18000
|
||||||
self.__http_directories:list[str] = self.get("http_indexes", inputs, ["/Public"])
|
self.__http_directories:list[str] = ["/Public"]
|
||||||
self.__http_indexes:list[str] = self.get("http_indexes", inputs, ["", "index.html", "index.htm", "index.md", "index.txt"])
|
self.__http_indexes:list[str] = ["", "index.html", "index.htm", "index.md", "index.txt"]
|
||||||
self.__terminal_thread:Thread = Thread(target = self.__terminal)
|
self.__terminal_thread:Thread = Thread(target = self.__terminal)
|
||||||
self.__web_sockets_clients:list[WebSocketClient] = []
|
self.__web_sockets_clients:list[WebSocketClient] = []
|
||||||
|
|
||||||
|
self.update()
|
||||||
|
|
||||||
self.__terminal_thread.start()
|
self.__terminal_thread.start()
|
||||||
self.__http_server_thread.start()
|
self.__http_server_thread.start()
|
||||||
self.__web_socket_server_thread.start()
|
self.__web_socket_server_thread.start()
|
||||||
|
self.__requests_thread.start()
|
||||||
|
|
||||||
def close(self:Self) -> None:
|
def close(self:Self) -> None:
|
||||||
|
|
||||||
@ -98,6 +105,63 @@ class AIChat:
|
|||||||
|
|
||||||
self.__http_server.shutdown()
|
self.__http_server.shutdown()
|
||||||
|
|
||||||
|
def update(self:Self) -> None:
|
||||||
|
|
||||||
|
titles_promp_file:str
|
||||||
|
response_with_titles_prompt_file:str
|
||||||
|
key:str
|
||||||
|
|
||||||
|
for key in ("default_settings_files", "settings_files", "default_settings", "settings"):
|
||||||
|
self.add_settings(self.get(key), True)
|
||||||
|
for key in ("default_secrets_files", "secrets_files", "default_secrets", "secrets"):
|
||||||
|
self.add_secrets(self.get(key), True)
|
||||||
|
for key in ("default_i18n_files", "i18n_files", "default_i18n", "i18n"):
|
||||||
|
self.add_i18n(self.get(key), True)
|
||||||
|
for key in (
|
||||||
|
"default_index_files", "index_files", "default_index", "index",
|
||||||
|
"default_secrets_index_files", "secrets_index_files", "default_secrets_index", "secrets_index"
|
||||||
|
):
|
||||||
|
self.add_index(self.get(key), True)
|
||||||
|
|
||||||
|
titles_promp_file = self.get("titles_prompt_file")
|
||||||
|
response_with_titles_prompt_file = self.get("response_with_titles_prompt_file")
|
||||||
|
|
||||||
|
self.__default_language = self.get("default_language", None, self.__default_language)
|
||||||
|
self.__language = self.get("language", None, self.__language)
|
||||||
|
|
||||||
|
self.__host = self.get("host", None, self.__host)
|
||||||
|
self.__port = self.get("port", None, self.__port)
|
||||||
|
self.__api_url = self.get("api_url", None, self.__api_url)
|
||||||
|
|
||||||
|
self.__web_socket_host = self.get("web_socket_host", None, self.__web_socket_host)
|
||||||
|
self.__web_socket_port = self.get("web_socket_port", None, self.__web_socket_port)
|
||||||
|
self.__requests_sleep = self.get("requests_sleep", None, self.__requests_sleep)
|
||||||
|
|
||||||
|
self.__titles_model = self.get("titles_model", None, self.__http_host)
|
||||||
|
self.__titles_temperature = self.get("titles_temperature", None, self.__http_host)
|
||||||
|
if titles_promp_file is not None:
|
||||||
|
self.__titles_prompt = self.RE_NEW_LINES.sub("\\n", self.load_file(titles_promp_file))
|
||||||
|
self.__response_model = self.get("responses_model", None, self.__http_host)
|
||||||
|
self.__response_temperature = self.get("responses_temperature", None, self.__http_host)
|
||||||
|
if response_with_titles_prompt_file is not None:
|
||||||
|
self.__response_with_titles = self.RE_NEW_LINES.sub("\\n", self.load_file(response_with_titles_prompt_file))
|
||||||
|
|
||||||
|
self.__http_host = self.get("http_host", None, self.__http_host)
|
||||||
|
self.__http_port = self.get("http_port", None, self.__http_port)
|
||||||
|
self.__http_directories = self.get("http_indexes", None, self.__http_directories)
|
||||||
|
self.__http_indexes = self.get("http_indexes", None, self.__http_indexes)
|
||||||
|
|
||||||
|
def reset(self:Self) -> None:
|
||||||
|
self.__settings.clear()
|
||||||
|
self.__secrets.clear()
|
||||||
|
self.__sentences.clear()
|
||||||
|
self.__index.clear()
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
##########################################################################################################
|
||||||
|
##########################################################################################################
|
||||||
|
##########################################################################################################
|
||||||
|
|
||||||
def get(self:Self,
|
def get(self:Self,
|
||||||
keys:str|Sequence[str],
|
keys:str|Sequence[str],
|
||||||
inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None,
|
inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None,
|
||||||
@ -137,6 +201,78 @@ class AIChat:
|
|||||||
|
|
||||||
return self.string_variables("".join(text) if isinstance(text, (list, tuple)) else str(text), inputs)
|
return self.string_variables("".join(text) if isinstance(text, (list, tuple)) else str(text), inputs)
|
||||||
|
|
||||||
|
def add_settings(self:Self, inputs:Any|None, overwrite:bool = False) -> None:
|
||||||
|
|
||||||
|
subinputs:dict[str, Any|None]
|
||||||
|
|
||||||
|
for subinputs in self.get_dictionaries(inputs, True):
|
||||||
|
|
||||||
|
key:str
|
||||||
|
value:Any|None
|
||||||
|
|
||||||
|
for key, value in subinputs.items():
|
||||||
|
if overwrite or key not in self.__settings:
|
||||||
|
self.__settings[key] = value
|
||||||
|
|
||||||
|
def add_secrets(self:Self, inputs:Any|None, overwrite:bool = False) -> None:
|
||||||
|
|
||||||
|
subinputs:dict[str, Any|None]
|
||||||
|
|
||||||
|
for subinputs in self.get_dictionaries(inputs, True):
|
||||||
|
|
||||||
|
key:str
|
||||||
|
value:Any|None
|
||||||
|
|
||||||
|
for key, value in subinputs.items():
|
||||||
|
if overwrite or key not in self.__secrets:
|
||||||
|
self.__secrets[key] = value
|
||||||
|
|
||||||
|
def add_i18n(self:Self, inputs:dict[str, Any|None], overwrite:bool = False) -> None:
|
||||||
|
|
||||||
|
subinputs:dict[str, Any|None]
|
||||||
|
|
||||||
|
for subinputs in self.get_dictionaries(inputs, True):
|
||||||
|
|
||||||
|
language:str
|
||||||
|
sentences:dict[str, str|Sequence[str]]
|
||||||
|
|
||||||
|
for language, sentences in subinputs.items():
|
||||||
|
if language not in self.__sentences:
|
||||||
|
self.__sentences[language] = {}
|
||||||
|
if overwrite or language not in self.__sentences:
|
||||||
|
|
||||||
|
key:str
|
||||||
|
value:str|Sequence[str]
|
||||||
|
|
||||||
|
for key, value in sentences.items():
|
||||||
|
if overwrite or key not in self.__sentences[language]:
|
||||||
|
self.__sentences[language][key] = value
|
||||||
|
|
||||||
|
def add_index(self:Self, inputs:dict[str, str], overwrite:bool = False, subgroup:Optional[dict[str, str|dict]] = None) -> None:
|
||||||
|
|
||||||
|
group:dict[str, Any|None]
|
||||||
|
|
||||||
|
if subgroup is None:
|
||||||
|
subgroup = self.__index
|
||||||
|
|
||||||
|
for group in self.get_dictionaries(inputs, True):
|
||||||
|
|
||||||
|
key:str
|
||||||
|
value:str|dict
|
||||||
|
|
||||||
|
for key, value in group.items():
|
||||||
|
if isinstance(value, str):
|
||||||
|
if overwrite or key not in subgroup:
|
||||||
|
subgroup[key] = value
|
||||||
|
elif isinstance(value, dict):
|
||||||
|
if key not in subgroup:
|
||||||
|
subgroup[key] = {}
|
||||||
|
self.add_index(value, overwrite, subgroup[key])
|
||||||
|
|
||||||
|
##########################################################################################################
|
||||||
|
##########################################################################################################
|
||||||
|
##########################################################################################################
|
||||||
|
|
||||||
def __terminal(self:Self) -> None:
|
def __terminal(self:Self) -> None:
|
||||||
while self.__working:
|
while self.__working:
|
||||||
try:
|
try:
|
||||||
@ -145,12 +281,22 @@ class AIChat:
|
|||||||
|
|
||||||
if command in ("exit", "close", "quit", "stop", "bye"):
|
if command in ("exit", "close", "quit", "stop", "bye"):
|
||||||
self.close()
|
self.close()
|
||||||
|
elif command in ("update",):
|
||||||
|
self.update()
|
||||||
|
elif command in ("reset",):
|
||||||
|
self.reset()
|
||||||
|
elif command in ("help", "h", "?"):
|
||||||
|
print(self.i18n("commands_help"))
|
||||||
else:
|
else:
|
||||||
print(self.i18n("unknown_command", {"command" : command}))
|
print(self.i18n("unknown_command", {"command" : command}))
|
||||||
|
|
||||||
except Exception as exception:
|
except Exception as exception:
|
||||||
print(exception)
|
print(exception)
|
||||||
|
|
||||||
|
##########################################################################################################
|
||||||
|
##########################################################################################################
|
||||||
|
##########################################################################################################
|
||||||
|
|
||||||
def __run_web_socket_server(self:Self) -> None:
|
def __run_web_socket_server(self:Self) -> None:
|
||||||
with web_socket_server_serve(self.__web_socket_handler, self.__web_socket_host, self.__web_socket_port) as self.__web_socket_server:
|
with web_socket_server_serve(self.__web_socket_handler, self.__web_socket_host, self.__web_socket_port) as self.__web_socket_server:
|
||||||
self.__web_socket_server.serve_forever()
|
self.__web_socket_server.serve_forever()
|
||||||
@ -161,7 +307,31 @@ class AIChat:
|
|||||||
try:
|
try:
|
||||||
for message in client:
|
for message in client:
|
||||||
try:
|
try:
|
||||||
print(message)
|
self.__requests_i += 1
|
||||||
|
|
||||||
|
i:int = self.__requests_i
|
||||||
|
new_order:dict[str, Any|None] = {
|
||||||
|
**json_decode(message),
|
||||||
|
"__client__" : client,
|
||||||
|
"__i__" : i
|
||||||
|
}
|
||||||
|
|
||||||
|
print(new_order)
|
||||||
|
|
||||||
|
if new_order["action"] == "cancel":
|
||||||
|
self.__remove_order(new_order["i"])
|
||||||
|
continue
|
||||||
|
|
||||||
|
i:int
|
||||||
|
order:dict[str, Any|None]
|
||||||
|
|
||||||
|
for i, order in self.__requests.items():
|
||||||
|
if new_order["action"] == order["action"] and order["__client__"] == client:
|
||||||
|
self.__remove_order(i)
|
||||||
|
|
||||||
|
self.__requests[i] = new_order
|
||||||
|
self.__requests_order.append(i)
|
||||||
|
|
||||||
except Exception as exception:
|
except Exception as exception:
|
||||||
print(exception)
|
print(exception)
|
||||||
except Exception as exception:
|
except Exception as exception:
|
||||||
@ -169,6 +339,41 @@ class AIChat:
|
|||||||
self.__web_sockets_clients.remove(client)
|
self.__web_sockets_clients.remove(client)
|
||||||
print("Client disconnected")
|
print("Client disconnected")
|
||||||
|
|
||||||
|
def __run_orders(self:Self) -> None:
|
||||||
|
while self.__working:
|
||||||
|
if len(self.__requests_order):
|
||||||
|
|
||||||
|
order:dict[Any|None] = self.__requests[self.__requests_order[0]]
|
||||||
|
|
||||||
|
if order["action"] == "new_message":
|
||||||
|
Thread(target = lambda:self.send_to_ai(order["message"], lambda chunk:order["__client__"].send(json_encode({
|
||||||
|
"order" : order["__i__"],
|
||||||
|
"key" : order["key"],
|
||||||
|
"chunk" : json_decode(chunk)
|
||||||
|
})), lambda:self.__remove_order_and_continue(order["__i__"]), order)).start()
|
||||||
|
else:
|
||||||
|
Thread(target = lambda:self.__remove_order_and_continue(order["__i__"])).start()
|
||||||
|
break
|
||||||
|
|
||||||
|
sleep(0.1)
|
||||||
|
|
||||||
|
def __remove_order(self:Self, i:int) -> None:
|
||||||
|
print("PASA REMOVE")
|
||||||
|
if i in self.__requests:
|
||||||
|
del self.__requests[i]
|
||||||
|
if i in self.__requests_order:
|
||||||
|
self.__requests_order.remove(i)
|
||||||
|
|
||||||
|
def __remove_order_and_continue(self:Self, i:int) -> None:
|
||||||
|
print("PASA REMOVE AND CONTINUE")
|
||||||
|
self.__remove_order(i)
|
||||||
|
sleep(0.1)
|
||||||
|
self.__run_orders()
|
||||||
|
|
||||||
|
##########################################################################################################
|
||||||
|
##########################################################################################################
|
||||||
|
##########################################################################################################
|
||||||
|
|
||||||
def __run_http_server(self:Self) -> None:
|
def __run_http_server(self:Self) -> None:
|
||||||
self.__http_server = HTTPServer((self.__http_host, self.__http_port), self.HTTPRequestHandler)
|
self.__http_server = HTTPServer((self.__http_host, self.__http_port), self.HTTPRequestHandler)
|
||||||
self.__http_server.aichat = self
|
self.__http_server.aichat = self
|
||||||
@ -220,6 +425,10 @@ class AIChat:
|
|||||||
else:
|
else:
|
||||||
self.send_response(404)
|
self.send_response(404)
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
|
|
||||||
|
##########################################################################################################
|
||||||
|
##########################################################################################################
|
||||||
|
##########################################################################################################
|
||||||
|
|
||||||
def get_titles(self:Self, message:str) -> list[str]:
|
def get_titles(self:Self, message:str) -> list[str]:
|
||||||
try:
|
try:
|
||||||
@ -244,38 +453,65 @@ class AIChat:
|
|||||||
pass
|
pass
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def send(self:Self, message:str, client:WebSocketClient) -> str:
|
def send_to_ai(self:Self,
|
||||||
|
message:str,
|
||||||
|
each_callback:Callable[[bytes], None],
|
||||||
|
end_callback:Optional[Callable[[], None]] = None,
|
||||||
|
order:Optional[dict[str, Any|None]] = None
|
||||||
|
) -> None:
|
||||||
|
|
||||||
titles:list[str] = self.get_titles(message)
|
# titles:list[str] = self.get_titles(message)
|
||||||
|
titles:list[str] = []
|
||||||
|
|
||||||
|
print([titles, message])
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
||||||
response:Response
|
response:Response
|
||||||
|
|
||||||
|
print(self.string_variables(self.__response_with_titles, {
|
||||||
|
"message" : message,
|
||||||
|
"guides" : "\n\n".join("## " + title + "\n\n" + self.load_file(self.__index[title]) for title in titles)
|
||||||
|
}) if len(titles) else message)
|
||||||
|
|
||||||
with Post(self.string_variables(self.__api_url, {
|
with Post(self.string_variables(self.__api_url, {
|
||||||
"host" : self.__host,
|
"host" : self.__host,
|
||||||
"port" : self.__port
|
"port" : self.__port
|
||||||
}), json = {
|
}), json = {
|
||||||
"model" : self.__titles_model,
|
"model" : self.__response_model,
|
||||||
"prompt" : self.string_variables(self.__response_with_titles, {
|
"prompt" : self.string_variables(self.__response_with_titles, {
|
||||||
"message" : message,
|
"message" : message,
|
||||||
"guides" : "\n\n".join("## " + title + "\n\n" + self.load_file(self.__index[title]) for title in titles)
|
"guides" : "\n\n".join("## " + title + "\n\n" + self.load_file(self.__index[title]) for title in titles)
|
||||||
}) if len(titles) else message,
|
}) if len(titles) else message,
|
||||||
"stream" : True,
|
"stream" : True,
|
||||||
"options" : {
|
"options" : {
|
||||||
"temperature" : self.__titles_temperature
|
"temperature" : self.__response_temperature
|
||||||
}
|
}
|
||||||
}, stream = True) as response:
|
}, stream = True) as response:
|
||||||
|
|
||||||
line:str
|
line:bytes
|
||||||
|
|
||||||
for line in response.iter_lines():
|
for line in response.iter_lines():
|
||||||
if line:
|
each_callback(line)
|
||||||
client.send({"chunk" : json_decode(line)})
|
# print(["LINE", line, order is not None and order["__i__"] not in self.__requests])
|
||||||
|
# if order is not None and order["__i__"] not in self.__requests:
|
||||||
|
# break
|
||||||
|
# if line:
|
||||||
|
# print("EACH START")
|
||||||
|
# each_callback(line)
|
||||||
|
# print("EACH END")
|
||||||
|
# print(json_decode(line).get("done", False))
|
||||||
|
# if json_decode(line).get("done", False):
|
||||||
|
# print("BREAK")
|
||||||
|
# end_callback and end_callback()
|
||||||
|
# break
|
||||||
|
|
||||||
except Exception as exception:
|
except Exception as exception:
|
||||||
pass
|
print(exception)
|
||||||
return []
|
|
||||||
|
##########################################################################################################
|
||||||
|
##########################################################################################################
|
||||||
|
##########################################################################################################
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_keys(cls:type[Self], *items:list[Any|None]) -> list[str]:
|
def get_keys(cls:type[Self], *items:list[Any|None]) -> list[str]:
|
||||||
@ -439,4 +675,35 @@ class AIChat:
|
|||||||
pass
|
pass
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load_json(cls:type[Self],
|
||||||
|
data:str|dict[str, Any|None]|Sequence[Any|None],
|
||||||
|
only_dictionaries:bool = True
|
||||||
|
) -> list[dict[str, Any|None]|Sequence[Any|None]]:
|
||||||
|
|
||||||
|
json:list[dict[str, Any|None]|Sequence[Any|None]] = []
|
||||||
|
|
||||||
|
if isinstance(data, str):
|
||||||
|
|
||||||
|
subdata:dict[str, Any|None]|Sequence[Any|None]|None
|
||||||
|
|
||||||
|
try:
|
||||||
|
if subdata := json_decode(data):
|
||||||
|
json.extend(cls.load_json(subdata, only_dictionaries))
|
||||||
|
return
|
||||||
|
except Exception as exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
json.extends(cls.load_json(json_decode(cls.load_file(cls.fix_path(data), "r"))))
|
||||||
|
|
||||||
|
elif isinstance(data, (list, tuple)):
|
||||||
|
if only_dictionaries:
|
||||||
|
|
||||||
|
item:Any|None
|
||||||
|
|
||||||
|
for item in data:
|
||||||
|
json.extend(cls.load_json(item, only_dictionaries))
|
||||||
|
else:
|
||||||
|
json.append(data)
|
||||||
|
|
||||||
aichat:AIChat = AIChat()
|
aichat:AIChat = AIChat()
|
||||||
@ -2,5 +2,9 @@
|
|||||||
"autostart" : true,
|
"autostart" : true,
|
||||||
"default_settings_files" : "/JSON/AIChat.settings.json",
|
"default_settings_files" : "/JSON/AIChat.settings.json",
|
||||||
"ai_model" : "gemma",
|
"ai_model" : "gemma",
|
||||||
"ai_stream" : true
|
"ai_stream" : true,
|
||||||
|
"default_titles_files" : [
|
||||||
|
"/JSON/AIChat.titles.json",
|
||||||
|
"/JSON/AIChat.titles.secrets.json"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
3
JSON/I18N/AIChat.i18n.espanol.json
Normal file
3
JSON/I18N/AIChat.i18n.espanol.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"espanol" : {}
|
||||||
|
}
|
||||||
@ -50,7 +50,9 @@ export const AIChat = (function(){
|
|||||||
/** @type {number} */
|
/** @type {number} */
|
||||||
frames_per_second = 60,
|
frames_per_second = 60,
|
||||||
/** @type {WebSocket|null} */
|
/** @type {WebSocket|null} */
|
||||||
web_socket_client = null;
|
web_socket_client = null,
|
||||||
|
/** @type {HTMLArticleElement|null} */
|
||||||
|
last_ai_message = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
@ -118,11 +120,55 @@ export const AIChat = (function(){
|
|||||||
return end(true);
|
return end(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const on_web_socket_open = event => {
|
const set_new_message = (sender, message) => {
|
||||||
web_socket_client.send("Hello, WebSocket server!");
|
|
||||||
|
const messages = document.querySelector(".aichat .messages");
|
||||||
|
|
||||||
|
AIChat.HTML(messages, ["article", {
|
||||||
|
"data-sender" : "ai"
|
||||||
|
}, message]);
|
||||||
|
messages.setAttribute("data-messages", Number(messages.getAttribute("data-messages")) + 1);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const on_web_socket_message = event => {};
|
const on_web_socket_open = event => {
|
||||||
|
// web_socket_client.send("Hello, WebSocket server!");
|
||||||
|
};
|
||||||
|
|
||||||
|
const on_web_socket_message = event => {
|
||||||
|
if(event.data instanceof Blob){
|
||||||
|
|
||||||
|
const reader = new FileReader();
|
||||||
|
|
||||||
|
reader.onload = () => {
|
||||||
|
|
||||||
|
const reponse = JSON.parse(reader.result);
|
||||||
|
|
||||||
|
if(reponse.chunk.done){
|
||||||
|
last_ai_message = null;
|
||||||
|
}else{
|
||||||
|
if(!last_ai_message){
|
||||||
|
last_ai_message = document.querySelector(".aichat .messages").appendChild(document.createElement("article"));
|
||||||
|
last_ai_message.setAttribute("data-sender", "ai");
|
||||||
|
};
|
||||||
|
last_ai_message.innerHTML += reponse.chunk.response;
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
reader.readAsText(event.data);
|
||||||
|
};
|
||||||
|
|
||||||
|
// console.log(event.data.text());
|
||||||
|
|
||||||
|
// console.log(JSON.parse(event.data));
|
||||||
|
|
||||||
|
// const data = JSON.parse(event.data);
|
||||||
|
|
||||||
|
// if(data.action == "message")
|
||||||
|
// set_new_message("ai", data.message);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
const on_web_socket_error = event => {};
|
const on_web_socket_error = event => {};
|
||||||
|
|
||||||
@ -191,7 +237,10 @@ export const AIChat = (function(){
|
|||||||
["main", null, [
|
["main", null, [
|
||||||
["fieldset", {class : "chat"}, [
|
["fieldset", {class : "chat"}, [
|
||||||
["legend", {data_i18n : "chat"}, "Chat"],
|
["legend", {data_i18n : "chat"}, "Chat"],
|
||||||
["section", {"class" : "messages"}],
|
["section", {
|
||||||
|
"class" : "messages",
|
||||||
|
"data-messages" : 0
|
||||||
|
}],
|
||||||
["form", {
|
["form", {
|
||||||
action : "#",
|
action : "#",
|
||||||
method : "post",
|
method : "post",
|
||||||
@ -238,9 +287,28 @@ export const AIChat = (function(){
|
|||||||
*/
|
*/
|
||||||
const send = (item, event) => {
|
const send = (item, event) => {
|
||||||
|
|
||||||
|
/** @type {HTMLTextAreaElement} */
|
||||||
|
const textarea = document.querySelector(".aichat form textarea"),
|
||||||
|
/** @type {string} */
|
||||||
|
message = textarea.value,
|
||||||
|
/** @type {HTMLSectionElement} */
|
||||||
|
messages_box = document.querySelector(".aichat .messages"),
|
||||||
|
/** @type {HTMLArticleElement} */
|
||||||
|
new_message = messages_box.appendChild(document.createElement("article")),
|
||||||
|
/** @type {number} */
|
||||||
|
i = Number(messages_box.getAttribute("data-messages"));
|
||||||
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
web_socket_client.send(document.querySelector(".aichat form textarea").value);
|
textarea.value = "";
|
||||||
|
|
||||||
|
set_new_message("user", message);
|
||||||
|
web_socket_client.send(JSON.stringify({
|
||||||
|
i : i,
|
||||||
|
key : "TEST KEY",
|
||||||
|
action : "new_message",
|
||||||
|
message : message
|
||||||
|
}));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user