#wip: Web Service communication.
This commit is contained in:
parent
178f678b69
commit
f1371e7389
@ -71,7 +71,7 @@
|
||||
"default_web_sockets_servers2" : {
|
||||
"anp" : {
|
||||
"type" : "WebSocketServerDriver",
|
||||
"host" : "localhost",
|
||||
"host" : "",
|
||||
"port" : 18765
|
||||
}
|
||||
},
|
||||
|
||||
@ -10,6 +10,7 @@ import {SessionsManager} from "../Managers/SessionsManager.ecma.js";
|
||||
import {ModelsManager} from "../Managers/ModelsManager.ecma.js";
|
||||
import {ViewsManager} from "../Managers/ViewsManager.ecma.js";
|
||||
import {RoutesManager} from "../Managers/RoutesManager.ecma.js";
|
||||
import {WebSocketsClientsManager} from "../Managers/WebSocketsClientsManager.ecma.js";
|
||||
import {Components} from "./Components.ecma.js";
|
||||
import {Common} from "../Utils/Common.ecma.js";
|
||||
import {Check} from "../Utils/Checks.ecma.js";
|
||||
@ -73,6 +74,8 @@ export const AnP = (function(){
|
||||
this.views = new ViewsManager(self);
|
||||
/** @type {RoutesManager} */
|
||||
this.routes = new RoutesManager(self);
|
||||
/** @type {WebSocketsClientsManager} */
|
||||
this.web_sockets_clients = new WebSocketsClientsManager(self);
|
||||
|
||||
/**
|
||||
* @returns {void}
|
||||
|
||||
@ -28,7 +28,9 @@ export const AIChatComponent = (function(){
|
||||
|
||||
/** @type {AIChatComponent} */
|
||||
const self = this;
|
||||
|
||||
/** @type {string|null} */
|
||||
let web_socket_id = null;
|
||||
|
||||
/**
|
||||
* @returns {void}
|
||||
* @access private
|
||||
@ -39,6 +41,8 @@ export const AIChatComponent = (function(){
|
||||
|
||||
const name = Common.get_value("name", inputs, "aichat");
|
||||
|
||||
web_socket_id = anp.web_sockets_clients.add("AAA", "https://localhost:18000/");
|
||||
|
||||
return Fieldset({class : "aichat"}, [
|
||||
anp.components.i18n(name, "legend"),
|
||||
Section({class : "messages"}),
|
||||
@ -66,7 +70,8 @@ export const AIChatComponent = (function(){
|
||||
if(text){
|
||||
Common.HTML(".aichat .messages", Fieldset({
|
||||
class : "message",
|
||||
data_type : "user"
|
||||
data_type : "user",
|
||||
data_id : anp.unique_keys.create()
|
||||
}, [
|
||||
anp.components.i18n("user", "legend"),
|
||||
Div({class : "content"}, text)
|
||||
@ -81,6 +86,27 @@ export const AIChatComponent = (function(){
|
||||
event.key == "Enter" && !event.shiftKey && send(item, event);
|
||||
};
|
||||
|
||||
this.write_response = (id, fragment) => {
|
||||
|
||||
let box = document.querySelector(".aichat .messages>[data-type=bot][data-id='" + id + "']");
|
||||
|
||||
if(!box){
|
||||
if(!document.querySelector(".aichat .messages>[data-type=user][data-id='" + id + "']"))
|
||||
return;
|
||||
box = Common.HTML(".aichat .messages", Fieldset({
|
||||
class : "message",
|
||||
data_type : "box",
|
||||
data_id : id
|
||||
}, [
|
||||
anp.components.i18n("assistant", "legend"),
|
||||
Div({class : "content"}, "")
|
||||
]), true)[0];
|
||||
};
|
||||
|
||||
box.querySelector(".content").innerHTML += fragment;
|
||||
|
||||
};
|
||||
|
||||
constructor();
|
||||
};
|
||||
|
||||
|
||||
65
Public/ecma/Managers/WebSocketsClientsManager.ecma.js
Normal file
65
Public/ecma/Managers/WebSocketsClientsManager.ecma.js
Normal file
@ -0,0 +1,65 @@
|
||||
"use strict";
|
||||
|
||||
import {WebSocketClientModel} from "../Models/WebSocketClientModel.ecma.js";
|
||||
|
||||
/**
|
||||
* @typedef {import("../Application/AnP.ecma.js").AnP} AnP
|
||||
*/
|
||||
|
||||
/**
|
||||
* @class WebSocketsClientsManager
|
||||
* @constructor
|
||||
* @param {!AnP} anp
|
||||
* @param {!string} key
|
||||
* @param {!(Object.<string, any|null>|Array.<any|null>)} inputs
|
||||
* @returns {void}
|
||||
* @access private
|
||||
* @static
|
||||
*/
|
||||
export const WebSocketsClientsManager = (function(){
|
||||
|
||||
/**
|
||||
* @constructs WebSocketsClientsManager
|
||||
* @param {!AnP} anp
|
||||
* @param {!string} key
|
||||
* @param {!(Object.<string, any|null>|Array.<any|null>)} inputs
|
||||
* @returns {void}
|
||||
* @access private
|
||||
* @static
|
||||
*/
|
||||
const WebSocketsClientsManager = function(anp, key, inputs){
|
||||
|
||||
/** @type {WebSocketsClientsManager} */
|
||||
const self = this,
|
||||
/** @type {Object.<string, WebSocketClientModel} */
|
||||
clients = {};
|
||||
|
||||
/**
|
||||
* @returns {void}
|
||||
* @access private
|
||||
*/
|
||||
const constructor = () => {};
|
||||
|
||||
this.add = (key, url) => {
|
||||
|
||||
clients[key] = new WebSocketClientModel(anp, url);
|
||||
|
||||
};
|
||||
|
||||
this.remove = key => {
|
||||
if(key in clients){
|
||||
clients[key].close();
|
||||
delete clients[key];
|
||||
return true;
|
||||
};
|
||||
return false;
|
||||
};
|
||||
|
||||
this.send = (key, data) => {};
|
||||
|
||||
constructor();
|
||||
|
||||
};
|
||||
|
||||
return WebSocketsClientsManager;
|
||||
})();
|
||||
92
Public/ecma/Models/WebSocketClientModel.ecma.js
Normal file
92
Public/ecma/Models/WebSocketClientModel.ecma.js
Normal file
@ -0,0 +1,92 @@
|
||||
"use strict";
|
||||
|
||||
import {Event} from "../Application/Event.ecma.js";
|
||||
import {Check} from "../Utils/Checks.ecma.js";
|
||||
import {Common} from "../Utils/Common.ecma.js";
|
||||
|
||||
/**
|
||||
* @typedef {import("../Application/AnP.ecma.js").AnP} AnP
|
||||
*/
|
||||
|
||||
export const WebSocketClientModel = (function(){
|
||||
|
||||
const WebSocketClientModel = function(anp, inputs){
|
||||
|
||||
const self = this;
|
||||
let web_socket = null,
|
||||
url = null,
|
||||
id = null;
|
||||
|
||||
this.on_open = new Event();
|
||||
this.on_message = new Event();
|
||||
this.on_close = new Event();
|
||||
this.on_error = new Event();
|
||||
|
||||
const constructor = () => {
|
||||
|
||||
Check.is_string(inputs) && (inputs = {url : inputs});
|
||||
|
||||
web_socket = new WebSocket(url = Common.get_value("url", inputs, ""));
|
||||
|
||||
web_socket.onopen = self.on_open.execute;
|
||||
web_socket.onmessage = self.on_message.execute;
|
||||
web_socket.onclose = self.on_close.execute;
|
||||
web_socket.onerror = self.on_error.execute;
|
||||
|
||||
// self.on_open.add(opened);
|
||||
self.on_message.add(reveive_message);
|
||||
self.on_close.add(closed);
|
||||
self.on_error.add(error);
|
||||
|
||||
};
|
||||
|
||||
// const opened = event => {
|
||||
// self.send("web_socket_client", "get_id", null, 200);
|
||||
// };
|
||||
|
||||
const reveive_message = event => {
|
||||
console.log(event);
|
||||
|
||||
const data = Common.data_decode(event.data);
|
||||
|
||||
switch(data.controller + "." + data.method){
|
||||
case "web_socket_client.set_id":
|
||||
id = data.data;
|
||||
break;
|
||||
default:
|
||||
anp.controllers.execute(data.controller, data.method, data.data, data);
|
||||
break;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
this.send = (controller, method, data, code = 200) => {
|
||||
web_socket.send(Common.data_encode({
|
||||
ok : code >= 200 && code < 300,
|
||||
code : code,
|
||||
id : id,
|
||||
controller : controller,
|
||||
method : method,
|
||||
data : data
|
||||
}));
|
||||
};
|
||||
|
||||
this.close = () => {
|
||||
web_socket.close();
|
||||
};
|
||||
|
||||
const closed = event => {
|
||||
id = null;
|
||||
};
|
||||
|
||||
const error = event => {
|
||||
console.error(event);
|
||||
self.close();
|
||||
};
|
||||
|
||||
constructor();
|
||||
|
||||
};
|
||||
|
||||
return WebSocketClientModel;
|
||||
})();
|
||||
@ -18,7 +18,7 @@ class AIInterpretersAbstract(ABC):
|
||||
self.key:str = key
|
||||
self.url:str = self.anp.settings.get(("ai_interpreter_url", "ai_url", "url"), inputs, "")
|
||||
self.stream:bool = self.anp.settings.get(("ai_interpreter_stream", "ai_stream", "stream"), inputs, False)
|
||||
self.orders:list[str] = self.anp.settings.get(("ai_interpreter_orders", "ai_orders", "orders"), inputs, [])
|
||||
self.orders:str|list[str] = self.anp.settings.get(("ai_interpreter_orders", "ai_orders", "orders"), inputs, [])
|
||||
self.maximum_tokens_per_session:int = self.anp.settings.get((
|
||||
"ai_interpreter_maximum_tokens_per_session", "ai_maximum_tokens_per_session", "maximum_tokens_per_session"
|
||||
), inputs, None)
|
||||
@ -55,6 +55,23 @@ class AIInterpretersAbstract(ABC):
|
||||
del self.sessions[id]
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_orders(self:Self, orders:str|list[str]) -> str:
|
||||
|
||||
results:str = ""
|
||||
i:int = 0
|
||||
|
||||
for block in (orders, self.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))
|
||||
|
||||
i += len(block)
|
||||
results += ("\n\n" if results else "") + block_string.strip()
|
||||
|
||||
else:
|
||||
results += ("\n\n" if results else "") + str(block).strip()
|
||||
|
||||
@abstractmethod
|
||||
def request(self:Self,
|
||||
|
||||
@ -5,6 +5,7 @@ from typing import Any, Self, Optional, Sequence
|
||||
from abc import ABC, abstractmethod
|
||||
from Interfaces.Application.AnPInterface import AnPInterface
|
||||
from Application.Event import Event
|
||||
from Utils.Common import Common
|
||||
|
||||
class WebSocketServersAbstract(ABC):
|
||||
|
||||
@ -24,5 +25,14 @@ class WebSocketServersAbstract(ABC):
|
||||
@abstractmethod
|
||||
def close_client(self:Self, id:int) -> None:pass
|
||||
|
||||
def format_data(self:Self, controller:str, method:str, data:Any|None, id:str, code:int = 200) -> str:
|
||||
return Common.data_encode({
|
||||
"controller": controller,
|
||||
"method": method,
|
||||
"data": data,
|
||||
"id": id,
|
||||
"code": code
|
||||
})
|
||||
|
||||
@abstractmethod
|
||||
def send(self:Self, data:Any|None, ids:Optional[int|Sequence[int]] = None) -> None:pass
|
||||
def send(self:Self, controller:str, method:str, data:Any|None, ids:Optional[int|Sequence[int]] = None, code:int = 200) -> None:pass
|
||||
@ -24,7 +24,7 @@ class OllamaDriver(AIInterpretersAbstract, ModelAbstract):
|
||||
session:int|None,
|
||||
message:str,
|
||||
callback:Optional[Callable[[int, AIResponseModel], None]] = None,
|
||||
orders:list[str] = []
|
||||
orders:str|list[str] = []
|
||||
) -> tuple[int|None, AIResponseModel]:
|
||||
|
||||
response:Response
|
||||
@ -38,15 +38,13 @@ class OllamaDriver(AIInterpretersAbstract, ModelAbstract):
|
||||
if self.maximum_tokens_per_session is not None:
|
||||
options["num_ctx"] = self.maximum_tokens_per_session
|
||||
|
||||
orders += self.orders
|
||||
session, context = self.get_session(session)
|
||||
orders = self.get_orders(orders)
|
||||
|
||||
with Post(self.url, json = {
|
||||
"model" : self.model,
|
||||
"prompt": message,
|
||||
**({"system": "\\n".join(
|
||||
str(i + 1) + ". " + order for i, order in enumerate(orders, 1)
|
||||
)} if len(orders) else {}),
|
||||
**({"system": orders} if len(orders) else {}),
|
||||
"stream": self.stream,
|
||||
**(
|
||||
{"format" : self.format} if (
|
||||
|
||||
@ -16,10 +16,9 @@ class WebSocketServerDriver(WebSocketServersAbstract, ModelAbstract):
|
||||
super().__init__(anp, inputs)
|
||||
|
||||
self.__server:WebSocketServer
|
||||
self.__clients:dict[int, WebSocketClient] = {}
|
||||
self.__clients:dict[str, WebSocketClient] = {}
|
||||
self.__host:str = anp.settings.get(("web_socket_server_host", "host"), inputs, "")
|
||||
self.__port:int = anp.settings.get(("web_socket_server_port", "port"), inputs, 8765)
|
||||
self.__client_i:int = 0
|
||||
self.__thread:Thread = None
|
||||
|
||||
anp.settings.get(("web_socket_server_autostart", "autostart"), inputs, True) and self.start()
|
||||
@ -55,9 +54,7 @@ class WebSocketServerDriver(WebSocketServersAbstract, ModelAbstract):
|
||||
|
||||
def __handler(self:Self, client:WebSocketClient) -> None:
|
||||
|
||||
id:int = self.__client_i
|
||||
|
||||
self.__client_i += 1
|
||||
id:int = self.anp.unique_keys.create()
|
||||
|
||||
self.__clients[id] = client
|
||||
self.on_new_client.execute(id)
|
||||
@ -70,6 +67,8 @@ class WebSocketServerDriver(WebSocketServersAbstract, ModelAbstract):
|
||||
"client_port" : client.remote_address[1]
|
||||
})
|
||||
|
||||
self.send("web_socket_client", "set_id", id, id)
|
||||
|
||||
try:
|
||||
while self.anp.working():
|
||||
message:str = client.recv()
|
||||
@ -85,6 +84,7 @@ class WebSocketServerDriver(WebSocketServersAbstract, ModelAbstract):
|
||||
self.on_error.execute(id, exception)
|
||||
finally:
|
||||
self.close_client(id)
|
||||
self.anp.unique_keys.remove(id)
|
||||
self.on_close.execute(id)
|
||||
self.anp.print("info", "web_socket_server_client_disconnected", {
|
||||
"client": id,
|
||||
@ -92,15 +92,18 @@ class WebSocketServerDriver(WebSocketServersAbstract, ModelAbstract):
|
||||
"host": self.host
|
||||
})
|
||||
|
||||
def send(self:Self, data:str, ids:int|Sequence[int]) -> bool:
|
||||
def send(self:Self, controller:str, method:str, data:str, ids:Optional[int|Sequence[int]] = None, code:int = 200) -> bool:
|
||||
|
||||
success:bool = True
|
||||
id:int
|
||||
|
||||
for id in ids if Check.is_array(ids) else [ids]:
|
||||
for id in (
|
||||
list(self.__clients.keys()) if ids is None else
|
||||
ids if Check.is_array(ids) else
|
||||
[ids]):
|
||||
if id in self.__clients:
|
||||
try:
|
||||
self.__clients[id].send(data)
|
||||
self.__clients[id].send(self.format_data(controller, method, data, id, code))
|
||||
except Exception as exception:
|
||||
self.anp.exception(exception, "web_socket_server_client_send_exception", {
|
||||
"client": id,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user