#wip: PseudoLoRAs building...

This commit is contained in:
mbruzon 2026-06-10 14:53:32 +02:00
parent b4a1d09e3d
commit 36413778e7
27 changed files with 424 additions and 138 deletions

View File

@ -1,4 +1,17 @@
[
["Qué es AnP", "/MD/PseudoLoRAs/AnP.md", [], false],
["Gestión de configuración", "/MD/AnP.Settings.md", [], false]
["AnP - Gestores", "/MD/AnP.Managers.md", [], false],
["AnP - Gestores - Configuraciones", "/MD/AnP.Settings.md", [], false],
["AnP - Gestores - I18N", "/MD/AnP.i18n.md", [], false],
["AnP - Gestores - Tipos de impresión", "/MD/AnP.PrintTypes.md", [], false],
["AnP - Gestores - Terminal/Consola", "/MD/AnP.Terminal.md", [], false],
["AnP - Gestores - Modelos", "/MD/AnP.Models.md", [], false],
["AnP - Gestores - Controladores de IA", "/MD/AnP.Controllers.md", [], false],
["AnP - Gestores - Índices", "/MD/AnP.Indexes.md", [], false],
["AnP - Gestores - Rutas", "/MD/AnP.Routes.md", [], false],
["AnP - Web Sockets - WebSocketServerDriver", "/MD/AnP.WebSocketServerDriver.md", [], false],
["AnP - Intérpretes de IA - OllamaDriver", "/MD/AnP.OllamaDriver.md", [], false],
["AnP - Servidores HTTP - HTTPDriver", "/MD/AnP.HTTPDriver.md", [], false],
["AnP - Modelos - IA", "/MD/AnP.AIModel.md", [], false],
["AnP - Controladores - IA", "/MD/AnP.AIController.md", [], false]
]

View File

@ -41,7 +41,22 @@
"AnP_TitlesManager_end" : null,
"AnP_AIModel_start" : null,
"AnP_AIModel_end" : null
"AnP_AIModel_end" : null,
"AnP_AIController_start" : null,
"ai_controller_loras_system" : [
"Actúa como un clasificador estricto. Se te proporcionará una lista de títulos y un Prompt.\n",
"Debes evaluar cada título uno por uno en base al Prompt del usuario.\n",
"Debes responder ÚNICAMENTE con un array JSON de booleanos que tenga exactamente {items} elementos.\n",
"Cada posición del array de salida debe corresponder textualmente a la posición del título en la lista original:\n\n",
"- true: Si el título cumple el criterio.\n",
"- false: Si el título NO cumple el criterio.\n",
"No añadas explicaciones, solo el JSON final.\n\n",
"Si ningún título cumple el criterio, responde con un array de booleanos con todos sus valores en false.\n",
"Lista de títulos a evaluar: \n{list}"
],
"ai_controller_response_system" : "Usa las siguientes guías para responder y dar soporte.{loras}",
"AnP_AIController_end" : null
}
}

View File

@ -95,7 +95,6 @@ export const WebSocketsClientsAbstract = (function(){
switch(data.controller + "." + data.action){
case "web_socket_client.set_id":
self.id = data.data;
console.log(self.id);
break;
default:
anp.controllers.execute(data.controller, data.action, data, data.code);

View File

@ -1,7 +1,7 @@
"use strict";
import {
Fieldset, Section, Form, Div, Nav, UL, LI, Span, Pre
Fieldset, Section, Form, Div, Nav, UL, LI, Span, Pre, Article
} from "../Utils/HTMLDSL.ecma.js";
import {MarkDown} from "../Utils/MarkDown.ecma.js";
import {Common} from "../Utils/Common.ecma.js";
@ -46,7 +46,13 @@ export const AIChatComponent = (function(){
return Fieldset({class : "aichat"}, [
anp.components.i18n(name, "legend"),
Section({class : "messages"}),
Section({class : "conversations"}, [
Article({
class : "messages",
data_conversation : anp.unique_keys.get(),
data_selected : true
})
]),
Form({
method : "post",
action : "#",
@ -144,7 +150,8 @@ export const AIChatComponent = (function(){
const send = (item, event) => {
const text_box = item.querySelector("[name=message]"),
text = text_box.value.trim();
text = text_box.value.trim(),
conversation = document.querySelector(".aichat [data-conversation][data-selected=true]").getAttribute("data-conversation");
event.preventDefault();
@ -153,7 +160,7 @@ export const AIChatComponent = (function(){
const data_id = anp.unique_keys.get();
Common.HTML(
".aichat .messages",
".aichat [data-conversation=" + conversation + "]",
build_message(data_id, "user", text, "done"),
build_message(data_id, "bot")
);
@ -161,7 +168,8 @@ export const AIChatComponent = (function(){
anp.web_sockets_clients.send("anp", "ai", "message", {
message_id : data_id,
message : text
message : text,
conversation : conversation
});
};
@ -174,7 +182,7 @@ export const AIChatComponent = (function(){
};
this.write_response = (id, fragment, ok, done) => {
console.log([id, fragment]);
// console.log([id, fragment]);
const box = document.querySelector(".aichat .messages>[data-type=bot][data-id='" + id + "']"),
status = (

View File

@ -161,7 +161,7 @@ export const WebSocketsClientsDriver = (function(){
controller : controller,
action : action,
data : data,
id : self.id
id : _super.id
}));
};

View File

@ -1,6 +1,6 @@
"use strict";
import {Check} from "../Utils/Check.ecma.js";
import {Check} from "../Utils/Checks.ecma.js";
import {Common} from "../Utils/Common.ecma.js";
/**

View File

@ -213,6 +213,17 @@ export const UniqueKeysManager = (function(){
});
};
/**
* @param {!(string|Array.<string>)} new_keys
* @returns {void}
* @access public
*/
this.set = new_keys => {
Common.get_keys(new_keys).forEach(key => {
keys.includes(key) || keys.push(key);
});
};
constructor();
};

View File

@ -32,6 +32,7 @@ class AIInterpretersAbstract(ABC):
self.sessions_i:int = 0
self.think:bool = self.anp.settings.get(("ai_interpreter_think", "ai_think", "think"), inputs, False)
self.allow_contexts:bool = self.anp.settings.get(("ai_interpreter_allow_contexts", "ai_allow_contexts", "allow_contexts"), inputs, True)
self.temperature:float = self.anp.settings.get(("ai_interpreter_temperature", "ai_temperature", "temperature"), inputs, 0.7)
def start(self:Self) -> None:
pass
@ -39,18 +40,26 @@ class AIInterpretersAbstract(ABC):
def close(self:Self) -> None:
self.sessions = {}
def get_session(self:Self, id:int|None = None) -> tuple[int, list[int]]:
def get_session(self:Self, id:int|None = None, conversation:str|None = None) -> tuple[int, list[int]]:
if id is None or id not in self.sessions:
id = self.sessions_i
self.sessions_i += 1
self.sessions[id] = []
self.sessions[id] = {}
return id, self.sessions[id]
return id, self.sessions[id][conversation] if conversation in self.sessions[id] else []
def save_context(self:Self, id:int, context:list[int]) -> None:
def save_context(self:Self, id:int, conversation:str, context:list[int]) -> None:
if self.allow_contexts and id in self.sessions:
self.sessions[id] = context
if conversation not in self.sessions[id]:
self.sessions[id][conversation] = context
self.sessions[id][conversation] = context
def close_conversation(self:Self, id:int, conversation:str) -> bool:
if id in self.sessions and conversation in self.sessions[id]:
del self.sessions[id][conversation]
return True
return False
def close_session(self:Self, id:int) -> bool:
if id in self.sessions:
@ -62,29 +71,34 @@ class AIInterpretersAbstract(ABC):
return self.sessions[id] if id in self.sessions else []
def get_orders(self:Self, orders:Optional[str|list[str]] = None) -> str:
return (
orders if Check.is_string(orders) else
"\n".join(orders) if Check.is_array(orders) else
"")
results:str = ""
i:int = 0
# results:str = ""
# i:int = 0
for block in (self.orders, orders):
if block:
if Check.is_array(block):
# for block in (self.orders, orders):
# if block:
# if Check.is_array(block):
block_string:str = "".join(str(i + 1 + j) + ". " + str(order) + "\n" for j, order in enumerate(block))
# block_string:str = "".join(str(i + 1 + j) + ". " + str(order) + "\n" for j, order in enumerate(block))
i += len(block)
results += ("\n\n" if results else "") + block_string.strip()
# i += len(block)
# results += ("\n\n" if results else "") + block_string.strip()
else:
results += ("\n\n" if results else "") + str(block).strip()
# else:
# results += ("\n\n" if results else "") + str(block).strip()
return results
# return results
@abstractmethod
def request(self:Self,
session:int|None,
conversation:str|None,
message:str,
orders:list[str] = [],
orders:str|list[str] = [],
callback:Optional[Callable[[int, AIResponseModel], None]] = None,
context:list[int] = []
custom_context:list[int] = []
) -> tuple[int|None, AIResponseModel]:pass

View File

@ -3,6 +3,7 @@
from abc import ABC, abstractmethod
from typing import Any, Self, Optional, Sequence
from re import Match as REMath
from Interfaces.Application.AnPInterface import AnPInterface
from Utils.Common import Common
@ -20,6 +21,7 @@ class HTTPServersAbstract(ABC):
"port": self.port,
"host": self.host
}
self._session_timeout:int = anp.settings.get(("sessions_timeout", "timeout"), inputs, 3600)
self.key:str = key
self.update()
@ -51,3 +53,41 @@ class HTTPServersAbstract(ABC):
self.__update_print_data()
self.update()
def load_cookies(self:Self, cookies:str|None) -> dict[str, Any|None]:
if not cookies:
return {}
cookie:str
results:dict[str, Any|None] = {}
for cookie in cookies.split(";"):
if "=" in cookie:
key:str
value:str
key, value = cookie.split("=", 1)
results[key.strip()] = value.strip()
return results
@staticmethod
def get_variables_from(source:str|None) -> dict[str, Any|None]:
if not source:
return {}
json:dict[str, Any|None] = Common.data_decode(source)
if json is not None:
return Common.get_dictionary(json)
json = {}
def callback(matches:REMath) -> str:
json[matches.group(1)] = matches.group(2)
return matches.group(0)
Common.replace(self.HTTP_VARIABLE, source, callback)
return json

View File

@ -14,6 +14,7 @@ class WebSocketServersAbstract(ABC):
self.key:str = key
self.host:str = self.anp.settings.get(("web_socket_server_host", "host"), inputs, "")
self.port:int = self.anp.settings.get(("web_socket_server_port", "port"), inputs, 18765)
self.__sessions:dict[str, str] = {}
self.on_new_client:Event = Event()
self.on_message:Event = Event()
self.on_close:Event = Event()
@ -40,3 +41,14 @@ class WebSocketServersAbstract(ABC):
@abstractmethod
def send(self:Self, controller:str, action:str, data:Any|None, ids:Optional[str|Sequence[str]] = None, code:int = 200) -> None:pass
def set_session(self:Self, id:str, session:str) -> None:
if id not in self.__sessions:
self.__sessions[id] = session
def get_session(self:Self, id:str) -> str|None:
return self.__sessions.get(id)
def remove_session(self:Self, id:str) -> None:
if id in self.__sessions:
del self.__sessions[id]

View File

@ -5,6 +5,7 @@ from typing import Self, Any, Optional, Sequence
import datetime
from re import Match as REMatch
from traceback import extract_tb as extract_traceback, format_stack as trace_format_stack
from time import time as timestamp, sleep
from Managers.I18NManager import I18NManager
from Managers.SettingsManager import SettingsManager
from Managers.PrintTypesManager import PrintTypesManager
@ -171,3 +172,10 @@ class AnP:
data["end"] = Common.string_variables(self.__exception_format, data)
message and self.print("exception", message, data, i + 2)
def wait(self:Self, time:str|float) -> None:
date:float = timestamp()
while self.__working and timestamp() - date < float(time):
sleep(.1)

View File

@ -9,54 +9,128 @@ from Models.PseudoLoRAModel import PseudoLoRAModel
class AIController(ControllerAbstract, ModelAbstract):
def __test_execution(self:Self, end:Callable[[], None], request:RequestModel) -> None:
self.anp.ai_interpreters.request(
"anp_responses",
None,
request.get("message", "Hola, Gemma. ¿Me puedes ayudar a instalar una impresora Canon?"),
# lambda id, response: print((id, response.response, request.get("client_id"))),
lambda id, response: self.anp.web_socket_servers.send("anp", "ai", "test", {
"id" : id,
"response" : response.response
}, request.get("client_id")),
# [
# "# Títulos\n" + "".join(
# "\n - " + title for title in [
# "Información, gestión e instalación de Cividas",
# "Información, gestión e instalación de Impresoras/Fotocopiadoras/Multifuncionales Canon"
# ]
# ),
# ]
)
end()
# def __message_execution(self:Self, end:Callable[[], None], request:RequestModel) -> None:
def test(self:Self, request:RequestModel) -> None:
self.anp.queues.add("anp", self.__test_execution, request)
request.set_response({
"ok" : True,
"code" : 200,
"message" : "ok"
})
# session:str|None = request.session.get("anp_ai_session")
# message_id:str|None = request.get("message_id")
# client_id:str|None = request.get("client_id")
# session, _ = self.anp.ai_interpreters.request(
# "anp_responses",
# session,
# request.get("conversation"),
# request.get("message"),
# [],
# lambda id, response: self.anp.web_socket_servers.send("anp", "ai", "message", {
# "id" : id,
# "conversation" : response.conversation,
# "response" : response.response,
# "ok" : response.ok,
# "done" : response.done,
# "data_id" : message_id
# }, client_id)
# )
# if session is not None:
# request.session.set("anp_ai_session", session)
# end()
def __analyse_loras(self:Self, data:dict[str, Any], request:RequestModel, loras:list[str]) -> list[tuple[str, str]]:
session:str|None = request.session.get("anp_loras_session")
results:list[tuple[str, str]] = []
print(self.anp.i18n.get("ai_controller_loras_system", {
"items" : len(loras),
"list" : "".join("\n" + str(i) + ". " + title for i, title in enumerate(loras))
}))
# session, results = self.anp.ai_interpreters.request(
# "anp_loras",
# session,
# data["conversation"],
# data["message"],
# self.anp.i18n.get("ai_controller_loras_system", {
# "items" : len(loras),
# "list" : "".join("\n" + str(i) + ". " + title for i, title in enumerate(loras))
# })
# )
data["i"] += 1
# if session is not None or data["i"] == 1:
# request.session.set("anp_loras_session", session)
return results
def __message_execution(self:Self, end:Callable[[], None], request:RequestModel) -> None:
session:str|None = None
session:str|None = request.session.get("anp_ai_session")
message_id:str|None = request.get("message_id")
client_id:str|None = request.get("client_id")
conversation:str = request.get("conversation")
message:str = request.get("message")
loras:list[tuple[str, str]]
loras_data:dict[str, Any] = {
"conversation" : conversation,
"message" : message,
"i" : 0
}
session, _ = self.anp.ai_interpreters.request(
"anp_responses",
session,
request.get("message"),
lambda id, response: self.anp.web_socket_servers.send("anp", "ai", "message", {
"id" : id,
"response" : response.response,
"ok" : response.ok,
"done" : response.done,
"data_id" : request.get("message_id")
}, request.get("client_id"))
)
loras = self.anp.pseudoloras.get(lambda loras:self.__analyse_loras(loras_data, request, loras))
print([title for title, _ in loras])
# session, _ = self.anp.ai_interpreters.request(
# "anp_responses",
# session,
# conversation,
# message,
# ("Usa las siguientes guías para responder y dar soporte.\n\n" + "".join(
# "# " + title + "\n\n" + text + "\n\n" for title, text in loras
# ) if len(loras) else []),
# lambda id, response: self.anp.web_socket_servers.send("anp", "ai", "message", {
# "id" : id,
# "conversation" : response.conversation,
# "response" : response.response,
# "ok" : response.ok,
# "done" : response.done,
# "data_id" : message_id
# }, client_id)
# )
# if session is not None:
# request.session.set("anp_ai_session", session)
end()
# def __message_by_themes_execution(self:Self, end:Callable[[], None], request:RequestModel) -> None:
# session:str|None = request.session.get("anp_ai_session")
# message_id:str|None = request.get("message_id")
# client_id:str|None = request.get("client_id")
# session, _ = self.anp.ai_interpreters.request(
# "anp_responses",
# session,
# request.get("conversation"),
# request.get("message"),
# [],
# lambda id, response: self.anp.web_socket_servers.send("anp", "ai", "message", {
# "id" : id,
# "conversation" : response.conversation,
# "response" : response.response,
# "ok" : response.ok,
# "done" : response.done,
# "data_id" : message_id
# }, client_id)
# )
# if session is not None:
# request.session.set("anp_ai_session", session)
# end()
def message(self:Self, request:RequestModel) -> None:
self.anp.queues.add("anp", self.__message_execution, request)
request.set_response({

View File

@ -7,6 +7,7 @@ from Abstracts.ModelAbstract import ModelAbstract
from Models.RequestModel import RequestModel
from threading import Thread
from http.server import BaseHTTPRequestHandler, HTTPServer
from http.cookies import SimpleCookie
from Abstracts.HTTPServersAbstract import HTTPServersAbstract
class HTTPDriver(HTTPServersAbstract, ModelAbstract):
@ -16,19 +17,50 @@ class HTTPDriver(HTTPServersAbstract, ModelAbstract):
def __process(self:Self, method:str) -> None:
anp:AnPInterface = self.server.anp
server:HTTPServersAbstract = self.server.itself
request:RequestModel = RequestModel()
session_id:str|None = None
cookies:SimpleCookie|None = None
request.method = method
request.path = self.path
request.path = self.path.split("?")[0]
request.headers = dict(self.headers)
request.client_host = self.client_address[0]
request.client_port = self.client_address[1]
request.get_variables = server.get_variables_from(self.path[self.path.find("?") + 1:] if "?" in self.path else None)
request.post_variables = server.get_variables_from(self.rfile.read(int(self.headers.get("Content-Length", 0))))
request.cookies = server.load_cookies(self.headers.get("Cookie"))
session_id = request.get("session")
request.session = anp.sessions._get_instance(session_id)
if session_id is None or request.session is None:
cookies = SimpleCookie()
session_id = anp.sessions.create()
cookies["session"] = session_id
cookies["session"]["path"] = "/"
cookies["session"]["max-age"] = server._session_timeout
# cookies["session"]["HttpOnly"] = True
# cookies["session"]["Secure"] = True
request.session = anp.sessions._get_instance(session_id)
anp.routes.go([self.server.key], method, self.path, request)
self.send_response(request.response_code)
self.send_header("Content-Type", request.response_mime)
self.send_header("Content-Length", str(len(request.response)))
if cookies is not None:
morsel:str
for morsel in cookies.values():
self.send_header("Set-Cookie", morsel.OutputString())
self.end_headers()
self.wfile.write(
@ -113,5 +145,6 @@ class HTTPDriver(HTTPServersAbstract, ModelAbstract):
def __run_service(self:Self) -> None:
self.__server = HTTPServer((self.host, self.port), self.HTTPRequestHandler)
self.__server.anp = self.anp
self.__server.itself = self
self.__server.key = self.key
self.__server.serve_forever()

View File

@ -22,24 +22,24 @@ class OllamaDriver(AIInterpretersAbstract, ModelAbstract):
def request(self:Self,
session:int|None,
conversation:str|None,
message:str,
callback:Optional[Callable[[int, AIResponseModel], None]] = None,
orders:str|list[str] = [],
custom_context:Optional[list[int]] = None
callback:Optional[Callable[[int, AIResponseModel], None]] = None,
custom_context:Optional[list[int]] = None,
save_session:bool = True
) -> tuple[int|None, AIResponseModel]:
response:Response
context:list[int]
options:dict[str, Any] = {}
results:AIResponseModel = AIResponseModel()
options:dict[str, Any] = {key : value for key, value in {
"num_predict" : self.maximum_response_tokens,
"num_ctx" : self.maximum_tokens_per_session,
"temperature" : self.temperature
}.items() if value is not None}
results:AIResponseModel = AIResponseModel(conversation)
if self.maximum_response_tokens is not None:
options["num_predict"] = self.maximum_response_tokens
if self.maximum_tokens_per_session is not None:
options["num_ctx"] = self.maximum_tokens_per_session
session, context = custom_context or self.get_session(session)
session, context = custom_context or self.get_session(session, conversation)
orders = self.get_orders(orders)
if custom_context:
@ -75,7 +75,7 @@ class OllamaDriver(AIInterpretersAbstract, ModelAbstract):
if chunk:
results.update(Common.json_decode(chunk))
if results.done:
self.save_context(session, results.context)
save_session and self.save_context(session, conversation, results.context)
break
Common.execute(callback, session, results)

View File

@ -3,6 +3,7 @@
from threading import Thread
from typing import Any, Self, Sequence, Optional
from http.cookies import SimpleCookie
from Abstracts.WebSocketServersAbstract import WebSocketServersAbstract
from Abstracts.ModelAbstract import ModelAbstract
from websockets.sync.server import serve as server_serve
@ -60,10 +61,14 @@ class WebSocketServerDriver(WebSocketServersAbstract, ModelAbstract):
def __handler(self:Self, client:WebSocketClient) -> None:
id:str = self.anp.unique_keys.get()
cookies:SimpleCookie = SimpleCookie()
self.__clients[id] = client
self.on_new_client.execute(id)
cookies.load(client.request.headers.get("Cookie", ''))
self.set_session(id, cookies.get("session").value)
self.anp.print("info", "web_socket_server_client_connected", {
"id": id,
"port": self.port,
@ -92,6 +97,7 @@ class WebSocketServerDriver(WebSocketServersAbstract, ModelAbstract):
self.__clients[id].close()
except Exception as _:
pass
self.remove_session(id)
del self.__clients[id]
self.anp.unique_keys.remove(id)
self.on_close.execute(id)
@ -106,6 +112,8 @@ class WebSocketServerDriver(WebSocketServersAbstract, ModelAbstract):
success:bool = True
id:str
# print([ids, list(self.__clients.keys())])
for id in (
list(self.__clients.keys()) if ids is None else
ids if Check.is_array(ids) else
@ -113,6 +121,7 @@ class WebSocketServerDriver(WebSocketServersAbstract, ModelAbstract):
if id in self.__clients:
try:
self.__clients[id].send(self.format_data(controller, action, data, id, code))
# print(["WS", controller, action, data, ids, code, list(self.__clients.keys())])
except Exception as exception:
self.anp.exception(exception, "web_socket_server_client_send_exception", {
"id": id,

View File

@ -67,3 +67,6 @@ class AnPInterface(ABC):
inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None,
i:int = 0
) -> None:pass
@abstractmethod
def wait(self:Self, time:str|float) -> None:pass

View File

@ -27,8 +27,9 @@ class AIInterpretersManagerInterface(ABC):
key:str,
session:int|None,
message:str,
callback:Callable[[int, AIResponseModel], None],
orders:list[str] = []
orders:list[str] = [],
callback:Optional[Callable[[int, AIResponseModel], None]] = None,
custom_context:list[int] = []
) -> int|None:pass
@abstractmethod

View File

@ -3,8 +3,9 @@
from typing import Self, Optional, Any
from abc import ABC, abstractmethod
from Models.SessionModel import SessionModel
class SessionsManagerInterfaces(ABC):
class SessionsManagerInterface(ABC):
@abstractmethod
def update(self:Self) -> None:pass
@ -12,6 +13,12 @@ class SessionsManagerInterfaces(ABC):
@abstractmethod
def reset(self:Self) -> None:pass
@abstractmethod
def create(self:Self) -> SessionModel:pass
@abstractmethod
def _get_instance(self:Self, id:str) -> SessionModel|None:pass
@abstractmethod
def get(self:Self, id:str, key:str, default:Optional[Any] = None) -> Any|None:pass

View File

@ -75,13 +75,14 @@ class AIInterpretersManager:
key:str,
session:int|None,
message:str,
callback:Callable[[int, AIResponseModel], None],
orders:list[str] = []
orders:str|list[str] = [],
callback:Optional[Callable[[int, AIResponseModel], None]] = None,
custom_context:list[int] = []
) -> tuple[int|None, AIResponseModel|None]:
response:AIResponseModel|None = None
if key in self.__interpreters:
session, response = self.__interpreters[key].request(session, message, callback, orders)
session, response = self.__interpreters[key].request(session, message, orders, callback, custom_context)
return session, response

View File

@ -15,6 +15,7 @@ class PseudoLoRAsManager:
self.__maximum_cache:int = (1 << 20) * 100
self.__memory_cached:int = 0
self.__cache:dict[int, PseudoLoRAModel] = {}
self.__cache_i:int = 0
self.__loras:list[PseudoLoRAModel] = []
self.update()
@ -89,58 +90,62 @@ class PseudoLoRAsManager:
for lora in self.__loras:
lora.clean_cache()
def get(self:Self, callback:Callable[[list[PseudoLoRAModel]], bool], keys:list[str] = []) -> list[tuple[str, str]]:
def get(self:Self,
callback:Callable[[list[PseudoLoRAModel]], bool],
loras:Optional[list[PseudoLoRAModel]] = None
) -> list[tuple[str, str]]:
next:list[PseudoLoRAModel] = []
results:list[tuple[str, str]] = []
i:int
ok:bool
has_keys:bool = len(keys) > 0
for i, ok in enumerate(callback(
lora.title for lora in self.__loras if not has_keys or any(
key in lora.keys for key in keys
)
)):
if loras is None:
loras = self.__loras.copy()
loras_is:list[bool] = [(i, callback([lora.title])) for i, lora in enumerate(loras)]
new_loras:list[PseudoLoRAModel] = []
for i, ok in enumerate(loras_is):
if not ok:
continue
lora:PseudoLoRAModel = self.__loras[i]
lora:PseudoLoRAModel = loras[i]
if lora.path is not None:
results.append((lora.title, Common.load_file(lora.path, "r")))
data:str|None
# data:str|None
if lora.cacheable:
if not lora.cache:
# if lora.cacheable:
# if not lora.cache:
lora.cache = Common.load_file(lora.path, "r")
lora.memory = len(lora.cache)
self.__memory_cached += lora.memory
# lora.cache = Common.load_file(lora.path, "r")
# lora.memory = len(lora.cache)
# self.__memory_cached += lora.memory
if self.__cache[lora.i]:
del self.__cache[lora.i]
lora.i += 1
if lora.i in self.__cache:
self.__cache[lora.i].append(lora)
else:
self.__cache[lora.i] = [lora]
# if self.__cache[lora.i]:
# del self.__cache[lora.i]
if self.__memory_cached > self.__maximum_cache:
# lora.i = self.__cache_i
# self.__cache_i += 1
# self.__cache[lora.i] = lora
i:int = min(self.__cache.keys())
# if self.__memory_cached > self.__maximum_cache:
for lora in self.__cache[i]:
lora.clean_cache()
del self.__cache[i]
# i:int = min(self.__cache.keys())
if (data := lora.cache or Common.load_file(lora.path, "r")):
results.append((lora.title, lora.path))
# for lora in self.__cache[i]:
# lora.clean_cache()
# del self.__cache[i]
# if (data := lora.cache or Common.load_file(lora.path, "r")):
# results.append((lora.title, lora.path))
else:
next.extend(lora.nested)
new_loras.extend(lora.nested)
if len(next):
results.extend(callback(next))
if len(new_loras):
results.extend(self.get(callback, new_loras))
return results

View File

@ -35,6 +35,9 @@ class RoutesManager:
route:RouteModel
if request.session is None:
request.session = self.anp.sessions._get_instance(request.get("session")) or None
for route in self.__routes:
if route.match(key, method, path, request):
if not request.response:

View File

@ -3,7 +3,7 @@
from typing import Self, Optional, Any
from threading import Thread
from time import sleep, time as timestamp
from time import time as timestamp
from Interfaces.Application.AnPInterface import AnPInterface
from Models.SessionModel import SessionModel
@ -39,21 +39,36 @@ class SessionsManager:
if time - session.get("date_last", time) > self.__timeout:
self.remove(id)
sleep(self.__clean_waiter)
self.anp.wait(self.__clean_waiter)
def create(self:Self) -> SessionModel:
id:str = self.anp.unique_keys.get()
self.__sessions[id] = SessionModel(id)
return id
def _get_instance(self:Self, id:str) -> SessionModel|None:
if id in self.__sessions and not self.__sessions[id].removed:
return self.__sessions[id]
return None
def get(self:Self, id:str, key:str, default:Optional[Any] = None) -> Any|None:
if id in self.__sessions:
if id in self.__sessions and not self.__sessions[id].removed:
return self.__sessions[id].get(key, default)
return default
def set(self:Self, id:str, key:str, value:Any|None) -> bool:
if id in self.__sessions:
if id in self.__sessions and not self.__sessions[id].removed:
self.__sessions[id].set(key, value)
return True
return False
def remove(self:Self, id:str) -> bool:
if id in self.__sessions:
self.__sessions[id].remove()
del self.__sessions[id]
return True
return False

View File

@ -105,7 +105,7 @@ class WebSocketServersManager:
except Exception as exception:
self.anp.exception(exception, "web_socket_server_send_exception", {"name": name})
def __receive(self:Self, web_socket:WebSocketServersAbstract, client:int, raw_data:str, name:str) -> None:
def __receive(self:Self, web_socket:WebSocketServersAbstract, client:str, raw_data:str, name:str) -> None:
data:dict[str, Any|None] = Common.data_decode(raw_data)
@ -119,6 +119,7 @@ class WebSocketServersManager:
request.variables["web_socket"] = web_socket
request.variables["client_id"] = client
request.variables["web_socket_name"] = name
request.session = self.anp.sessions._get_instance(web_socket.get_session(client))
self.anp.controllers.execute(
data["controller"],

View File

@ -6,7 +6,8 @@ from time import time as timestamp
class AIResponseModel:
def __init__(self:Self) -> None:
def __init__(self:Self, conversation:str) -> None:
self.conversation:str = conversation
self.start:float = timestamp()
self.model:str = ""
self.response:str = ""

View File

@ -9,10 +9,11 @@ from Utils.Common import Common
class RequestModel:
def __init__(self:Self) -> None:
def __init__(self:Self, session:Optional[SessionModel] = None) -> None:
self.post_variables:dict[str, Any|None] = {}
self.get_variables:dict[str, Any|None] = {}
self.url_variables:dict[str, Any|None] = {}
self.cookies:dict[str, Any|None] = {}
self.variables:dict[str, Any|None] = {}
self.request_headers:dict[str, Any|None] = {}
self.method:str|None = None
@ -23,15 +24,22 @@ class RequestModel:
self.response_headers:dict[str, Any|None] = {}
self.callback:Callable[[RequestModel, str|bytes|None], None]|None = None
self.data:Any|None = None
self.session:SessionModel|None = None
self.session:SessionModel|None = session
def get(self:Self, key:str|Sequence[str], default:Optional[Any] = None) -> Any|None:
return self.session.get(key, Common.get_value(key, (
self.url_variables, self.get_variables, self.post_variables, self.variables
), default))
if self.session is not None:
results:Any|None = self.session.get(key)
if results is not None:
return results
return Common.get_value(key, (
self.cookies, self.url_variables, self.get_variables, self.post_variables, self.variables
), default)
def set_variables(self:Self, inputs:dict[str, Any|None], on:Optional[str] = None) -> None:
(
self.cookies if on == "cookies" else
self.url_variables if on == "url" else
self.get_variables if on == "get" else
self.post_variables if on == "post" else

View File

@ -11,6 +11,7 @@ class SessionModel:
self.date_from:float = timestamp()
self.date_last:float = timestamp()
self.variables:dict[str, Any|None] = {}
self.removed:bool = False
def set(self:Self, key:str, value:Any|None) -> None:
self.date_last = timestamp()
@ -19,3 +20,6 @@ class SessionModel:
def get(self:Self, key:str, default:Any|None = None) -> Any|None:
self.date_last = timestamp()
return self.variables.get(key, default)
def remove(self:Self) -> None:
self.removed = True

View File

@ -14,3 +14,4 @@ class RE:
ROUTE_KEY:REPattern = re_compile(r'\\\{([a-z_][a-z0-9_]*)\\\}', RE_IGNORECASE)
EXCEPTION:REPattern = re_compile(r'^\s*File "([^"]+)", line ([0-9]+), in ([^\n]+)(.*|[\r\n]*)*$')
NEW_LINE:REPattern = re_compile(r'\r\n|[\r\n]')
HTTP_VARIABLE:REPattern = re_compile(r'([^=&]+)=([^&]*)')