#wip: ScrapDSL and Drivers.
This commit is contained in:
parent
922f995022
commit
bc0a86900a
@ -200,24 +200,9 @@
|
|||||||
"AnP_HTTPAbstracts_end" : null,
|
"AnP_HTTPAbstracts_end" : null,
|
||||||
|
|
||||||
"AnP_WebSocketsServersManager_start" : null,
|
"AnP_WebSocketsServersManager_start" : null,
|
||||||
"default_web_sockets_servers" : {
|
|
||||||
"anp" : {
|
|
||||||
"type" : "WebSocketServerDriver",
|
|
||||||
"host" : "",
|
|
||||||
"port" : 18765
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AnP_WebSocketsServersManager_end" : null,
|
"AnP_WebSocketsServersManager_end" : null,
|
||||||
|
|
||||||
"AnP_HTTPServersManager_start" : null,
|
"AnP_HTTPServersManager_start" : null,
|
||||||
"default_http_servers" : {
|
|
||||||
"anp" : {
|
|
||||||
"type" : "HTTPServerDriver",
|
|
||||||
"type2" : "HTTPSocketServerDriver",
|
|
||||||
"host" : "",
|
|
||||||
"port" : 18000
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AnP_HTTPServersManager_end" : null,
|
"AnP_HTTPServersManager_end" : null,
|
||||||
|
|
||||||
"AnP_PseudoLoRAsManager_start" : null,
|
"AnP_PseudoLoRAsManager_start" : null,
|
||||||
@ -225,34 +210,6 @@
|
|||||||
"AnP_PseudoLoRAsManager_end" : null,
|
"AnP_PseudoLoRAsManager_end" : null,
|
||||||
|
|
||||||
"AnP_AIInterpretersManager_start" : null,
|
"AnP_AIInterpretersManager_start" : null,
|
||||||
"default_ai_interpreters" : {
|
|
||||||
"anp_titles" : {
|
|
||||||
"type" : "OllamaDriver",
|
|
||||||
"url" : "http://localhost:11434/api/generate/",
|
|
||||||
"model" : "gemma3:1b",
|
|
||||||
"pool" : "anp",
|
|
||||||
"format" : {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "boolean"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"stream" : false,
|
|
||||||
"think" : false,
|
|
||||||
"temperature" : 0.0,
|
|
||||||
"allow_contexts" : true
|
|
||||||
},
|
|
||||||
"anp_responses" : {
|
|
||||||
"type" : "OllamaDriver",
|
|
||||||
"url" : "http://localhost:11434/api/generate/",
|
|
||||||
"model" : "gemma4:e4b",
|
|
||||||
"stream" : true,
|
|
||||||
"pool" : "anp",
|
|
||||||
"think" : false,
|
|
||||||
"temperature" : 0.7,
|
|
||||||
"allow_contexts" : true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AnP_AIInterpretersManager_end" : null,
|
"AnP_AIInterpretersManager_end" : null,
|
||||||
|
|
||||||
"AnP_TitlesManager_start" : null,
|
"AnP_TitlesManager_start" : null,
|
||||||
|
|||||||
@ -61,7 +61,15 @@
|
|||||||
"AnP_CloneController_start" : null,
|
"AnP_CloneController_start" : null,
|
||||||
"anp_clone_controller_file_cloned" : "El archivo '{file}' ha sido clonado desde '{from_path}' a '{to_path}'.",
|
"anp_clone_controller_file_cloned" : "El archivo '{file}' ha sido clonado desde '{from_path}' a '{to_path}'.",
|
||||||
"anp_clone_controller_file_deleted" : "El archivo '{file}' ha sido eliminado de '{to_path}'.",
|
"anp_clone_controller_file_deleted" : "El archivo '{file}' ha sido eliminado de '{to_path}'.",
|
||||||
"AnP_CloneController_end" : null
|
"AnP_CloneController_end" : null,
|
||||||
|
|
||||||
|
"AnP_BrowserAbstract_start" : null,
|
||||||
|
"anp_browser_action_exception" : "Hubo una excepción al intentar ejecutar la acción '{i}' de tipo '{action}' en el navegador '{key}'.",
|
||||||
|
"anp_browser_action_done" : "La acción '{i}' de tipo '{action}' ha sido ejecutada correctamente en el navegador '{key}'.",
|
||||||
|
"anp_browser_action_not_done" : "La acción '{i}' de tipo '{action}' no ha sido ejecutada correctamente en el navegador '{key}'.",
|
||||||
|
"anp_browser_action_not_supported" : "La acción '{i}' de tipo '{action}' no es compatible con el navegador '{key}'.",
|
||||||
|
"anp_browser_action_not_action" : "El elemento '{i}' no es una acción válida en el navegador '{key}'.",
|
||||||
|
"AnP_BrowserAbstract_end" : null
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -56,6 +56,76 @@ export const AIChatComponent = (function(){
|
|||||||
return item;
|
return item;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!string} id
|
||||||
|
* @param {!string} type
|
||||||
|
* @param {?string} [content = ""]
|
||||||
|
* @param {?string} [mode = "waiting"]
|
||||||
|
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
|
||||||
|
* @returns {Array.<any|null>}
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
const build_message = (id, type, content = "", mode = "waiting", inputs = null) => {
|
||||||
|
|
||||||
|
/** @type {[string, string, string]} */
|
||||||
|
const [html, raw_html, md] = format(content),
|
||||||
|
/** @type {number} */
|
||||||
|
date_from = Common.get_value("date_from", inputs) || Date.now();
|
||||||
|
|
||||||
|
return Fieldset({
|
||||||
|
class : "message",
|
||||||
|
data_id : id,
|
||||||
|
data_type : type,
|
||||||
|
data_ok : true,
|
||||||
|
data_status : mode,
|
||||||
|
data_done : mode == "done",
|
||||||
|
data_mode : "html"
|
||||||
|
}, [
|
||||||
|
anp.components.i18n(type, "legend"),
|
||||||
|
Div({class : "message-box html-content"}, html),
|
||||||
|
Pre({class : "message-box raw-html-content"}, raw_html),
|
||||||
|
Pre({class : "message-box md-content"}, md),
|
||||||
|
Nav({class : "view buttons"}, [
|
||||||
|
anp.components.button("html", set_view),
|
||||||
|
anp.components.button("raw_html", set_view),
|
||||||
|
anp.components.button("md", set_view),
|
||||||
|
]),
|
||||||
|
UL({class : "data"}, [
|
||||||
|
build_data_icon("status", mode),
|
||||||
|
build_data_item("ok"),
|
||||||
|
build_data_item("done"),
|
||||||
|
build_data_item("date_from", date_from),
|
||||||
|
build_data_item("date_to", Common.get_value("date_to", inputs) || date_from),
|
||||||
|
build_data_item("time", 0),
|
||||||
|
build_data_item("length", content.length),
|
||||||
|
build_data_item("response_tokens", content.replace(/(?:[^a-z0-9]+|[\r\n]+)+/gi, " ").trim().split(" ").length)
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?string} session
|
||||||
|
* @param {!string} name
|
||||||
|
* @returns {Array.<any|null>}
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
const build_new_conversation = (session, name) => {
|
||||||
|
|
||||||
|
const session_key = session + "-" + name;
|
||||||
|
/** @type {string} */
|
||||||
|
conversation = anp.unique_keys.get();
|
||||||
|
|
||||||
|
cache[cache_key].conversations[conversation] = [];
|
||||||
|
|
||||||
|
document.querySelectorAll(".aichat[")
|
||||||
|
|
||||||
|
return Article({
|
||||||
|
class : "messages",
|
||||||
|
data_conversation : conversation,
|
||||||
|
data_selected : true
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
|
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
|
||||||
* @returns {Array.<any|null>}
|
* @returns {Array.<any|null>}
|
||||||
@ -64,20 +134,49 @@ export const AIChatComponent = (function(){
|
|||||||
this.build = (inputs = null) => {
|
this.build = (inputs = null) => {
|
||||||
|
|
||||||
/** @type {string} */
|
/** @type {string} */
|
||||||
const name = Common.get_value("name", inputs, "aichat");
|
const name = Common.get_value("name", inputs, "aichat"),
|
||||||
|
/** @type {string|null} */
|
||||||
|
session = Common.get_value("session", inputs, null),
|
||||||
|
/** @type {string} */
|
||||||
|
cache_key = session + "-" + name;
|
||||||
|
|
||||||
|
if(session){
|
||||||
|
cache[cache_key] = {
|
||||||
|
selected : conversations[conversations.length - 1],
|
||||||
|
conversations : conversations.reduce((dictionary, conversation) => {
|
||||||
|
|
||||||
|
dictionary[conversation] = [];
|
||||||
|
|
||||||
|
return dictionary;
|
||||||
|
}, {})
|
||||||
|
};
|
||||||
|
Common.preload("[data-name=" + name + "]", (chats, asynchronous, ok) => {
|
||||||
|
if(ok){
|
||||||
|
|
||||||
|
const data = Common.data_decode(anp.sessions.get_value(session, name));
|
||||||
|
|
||||||
|
if(data){
|
||||||
|
cache[cache_key] = data;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
Common.HTML(chats.querySelector(".conversations"), build_new_conversation(session, name));
|
||||||
|
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return Fieldset({
|
return Fieldset({
|
||||||
class : "aichat",
|
class : "aichat",
|
||||||
data_name : Common.get_value("name", inputs, "aichat")
|
data_name : name,
|
||||||
|
data_session : session
|
||||||
}, [
|
}, [
|
||||||
anp.components.i18n(name, "legend"),
|
anp.components.i18n(name, "legend"),
|
||||||
Section({class : "conversations"}, [
|
Section({class : "conversations"}, conversations.map(conversation => Article({
|
||||||
Article({
|
class : "messages",
|
||||||
class : "messages",
|
data_conversation : conversation,
|
||||||
data_conversation : anp.unique_keys.get(),
|
data_selected : true
|
||||||
data_selected : true
|
}))),
|
||||||
})
|
|
||||||
]),
|
|
||||||
Form({
|
Form({
|
||||||
method : "post",
|
method : "post",
|
||||||
action : "#",
|
action : "#",
|
||||||
@ -172,52 +271,6 @@ export const AIChatComponent = (function(){
|
|||||||
return [html, html.replace(/</g, "<").replace(/>/g, ">"), content];
|
return [html, html.replace(/</g, "<").replace(/>/g, ">"), content];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {!string} id
|
|
||||||
* @param {!string} type
|
|
||||||
* @param {?string} [content = ""]
|
|
||||||
* @param {?string} [mode = "waiting"]
|
|
||||||
* @returns {HTMLFielsetElement}
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
const build_message = (id, type, content = "", mode = "waiting") => {
|
|
||||||
|
|
||||||
/** @type {[string, string, string]} */
|
|
||||||
const [html, raw_html, md] = format(content),
|
|
||||||
/** @type {number} */
|
|
||||||
date = Date.now();
|
|
||||||
|
|
||||||
return Fieldset({
|
|
||||||
class : "message",
|
|
||||||
data_id : id,
|
|
||||||
data_type : type,
|
|
||||||
data_ok : true,
|
|
||||||
data_status : mode,
|
|
||||||
data_done : mode == "done",
|
|
||||||
data_mode : "html"
|
|
||||||
}, [
|
|
||||||
anp.components.i18n(type, "legend"),
|
|
||||||
Div({class : "message-box html-content"}, html),
|
|
||||||
Pre({class : "message-box raw-html-content"}, raw_html),
|
|
||||||
Pre({class : "message-box md-content"}, md),
|
|
||||||
Nav({class : "view buttons"}, [
|
|
||||||
anp.components.button("html", set_view),
|
|
||||||
anp.components.button("raw_html", set_view),
|
|
||||||
anp.components.button("md", set_view),
|
|
||||||
]),
|
|
||||||
UL({class : "data"}, [
|
|
||||||
build_data_icon("status", mode),
|
|
||||||
build_data_item("ok"),
|
|
||||||
build_data_item("done"),
|
|
||||||
build_data_item("date_from", date),
|
|
||||||
build_data_item("date_to", date),
|
|
||||||
build_data_item("time", 0),
|
|
||||||
build_data_item("length", content.length),
|
|
||||||
build_data_item("response_tokens", content.replace(/(?:[^a-z0-9]+|[\r\n]+)+/gi, " ").trim().split(" ").length)
|
|
||||||
])
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {!HTMLElement} item
|
* @param {!HTMLElement} item
|
||||||
@ -238,8 +291,6 @@ export const AIChatComponent = (function(){
|
|||||||
|
|
||||||
if(text){
|
if(text){
|
||||||
|
|
||||||
console.log([item, item.querySelector("[name=message]"), item.querySelector("[name=message]").parentNode.parentNode.getAttribute("data-connection")]);
|
|
||||||
|
|
||||||
/** @type {string} */
|
/** @type {string} */
|
||||||
const data_id = anp.unique_keys.get(),
|
const data_id = anp.unique_keys.get(),
|
||||||
/** @type {[string, string, string]} */
|
/** @type {[string, string, string]} */
|
||||||
|
|||||||
@ -28,7 +28,9 @@ export const SessionsManager = (function(){
|
|||||||
/** @type {SessionsManager} */
|
/** @type {SessionsManager} */
|
||||||
const self = this,
|
const self = this,
|
||||||
/** @type {Object.<number, SessionModel>} */
|
/** @type {Object.<number, SessionModel>} */
|
||||||
sessions = {};
|
sessions = {},
|
||||||
|
/** @type {Object.<string, number>} */
|
||||||
|
keys = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
@ -36,17 +38,31 @@ export const SessionsManager = (function(){
|
|||||||
*/
|
*/
|
||||||
const constructor = () => {};
|
const constructor = () => {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!(string|number)} id
|
||||||
|
* @returns {SessionModel|null}
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
const get = id => sessions[id] || sessions[keys[id]] || null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {!(Object.<string, any|null>|Array.<any|null>)} inputs
|
* @param {!(Object.<string, any|null>|Array.<any|null>)} inputs
|
||||||
* @return {number}
|
* @return {number|null}
|
||||||
* @access public
|
* @access public
|
||||||
*/
|
*/
|
||||||
this.set = inputs => {
|
this.set = inputs => {
|
||||||
|
|
||||||
|
const key = Common.get_value("key", inputs, null);
|
||||||
|
|
||||||
|
if(keys[key])
|
||||||
|
return null;
|
||||||
|
|
||||||
/** @type {number} */
|
/** @type {number} */
|
||||||
let i;
|
let i;
|
||||||
|
|
||||||
while(sessions[i = Math.random() * (1 << 28) | 0]);
|
while(sessions[i = Math.random() * (1 << 28) | 0]);
|
||||||
|
if(key)
|
||||||
|
keys[key] = i;
|
||||||
|
|
||||||
return (sessions[i] = new SessionModel(i, inputs)).i;
|
return (sessions[i] = new SessionModel(i, inputs)).i;
|
||||||
};
|
};
|
||||||
@ -57,16 +73,24 @@ export const SessionsManager = (function(){
|
|||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
* @access public
|
* @access public
|
||||||
*/
|
*/
|
||||||
this.check_permissions = (ids, permissions) => Common.get_array(ids).some(id => (
|
this.check_permissions = (ids, permissions) => Common.get_array(ids).some(id => {
|
||||||
sessions[id] && sessions[id].check_permissions(permissions)
|
|
||||||
));
|
/** @type {SessionModel|null} */
|
||||||
|
const session = get(id);
|
||||||
|
|
||||||
|
return session && session.check_permissions(permissions)
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {!number} id
|
* @param {!(string|number)} id
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
* @access public
|
* @access public
|
||||||
*/
|
*/
|
||||||
this.close = id => {
|
this.close = id => {
|
||||||
|
if(keys[id]){
|
||||||
|
id = keys[id];
|
||||||
|
delete keys[id];
|
||||||
|
};
|
||||||
if(sessions[id]){
|
if(sessions[id]){
|
||||||
delete sessions[id];
|
delete sessions[id];
|
||||||
return true;
|
return true;
|
||||||
@ -74,6 +98,49 @@ export const SessionsManager = (function(){
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!(string|number)} id
|
||||||
|
* @param {!string} key
|
||||||
|
* @returns {boolean}
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
this.has_value = (id, key) => {
|
||||||
|
|
||||||
|
/** @type {SessionModel|null} */
|
||||||
|
const session = get(id);
|
||||||
|
|
||||||
|
return session ? session.has(key) : false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!(string|number)} id
|
||||||
|
* @param {!string} key
|
||||||
|
* @returns {any|null}
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
this.get_value = (id, key) => {
|
||||||
|
|
||||||
|
/** @type {SessionModel|null} */
|
||||||
|
const session = get(id);
|
||||||
|
|
||||||
|
return session ? session.get(key) : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!(string|number)} id
|
||||||
|
* @param {!string} key
|
||||||
|
* @param {?any} [value = null]
|
||||||
|
* @returns {boolean}
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
this.set_value = (id, key, value) => {
|
||||||
|
|
||||||
|
/** @type {SessionModel|null} */
|
||||||
|
const session = get(id);
|
||||||
|
|
||||||
|
return session ? session.set(key, value) : null;
|
||||||
|
};
|
||||||
|
|
||||||
constructor();
|
constructor();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
196
Public/ecma/Models/AIChatModel.ecma.js
Normal file
196
Public/ecma/Models/AIChatModel.ecma.js
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
import {Event} from "../Application/Event.ecma.js";
|
||||||
|
import {Common} from "../Utils/Common.ecma.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class AIChatMessageModel
|
||||||
|
* @constructor
|
||||||
|
* @param {!AIChatConversationModel} conversation
|
||||||
|
* @param {!(Object.<string, any|null>|Array.<any|null>)} inputs
|
||||||
|
* @return {void}
|
||||||
|
* @access public
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
export const AIChatMessageModel = (function(){
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructs AIChatMessageModel
|
||||||
|
* @param {!AIChatConversationModel} conversation
|
||||||
|
* @param {!(Object.<string, any|null>|Array.<any|null>)} inputs
|
||||||
|
* @return {void}
|
||||||
|
* @access private
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
const AIChatMessageModel = function(conversation, inputs){
|
||||||
|
/** @type {AIChatConversationModel} */
|
||||||
|
this.conversation = conversation;
|
||||||
|
/** @type {string} */
|
||||||
|
this.status = Common.get_value("status", inputs, "unloaded");
|
||||||
|
/** @type {string|null} */
|
||||||
|
this.id = Common.get_value("id", inputs);
|
||||||
|
/** @type {string} */
|
||||||
|
this.role = Common.get_value("role", inputs, "unknown");
|
||||||
|
/** @type {boolean} */
|
||||||
|
this.ok = Common.get_value("ok", inputs, false);
|
||||||
|
/** @type {boolean} */
|
||||||
|
this.done = Common.get_value("done", inputs, false);
|
||||||
|
/** @type {string} */
|
||||||
|
this.message = (Common.get_value("message", inputs, ""));
|
||||||
|
/** @type {number} */
|
||||||
|
this.tokens = Common.get_value("tokens", inputs, 0);
|
||||||
|
/** @type {number} */
|
||||||
|
this.date_from = Common.get_value("date_from", inputs, Date.now());
|
||||||
|
/** @type {number} */
|
||||||
|
this.date_to = Common.get_value("date_to", inputs, Date.now());
|
||||||
|
};
|
||||||
|
|
||||||
|
return AIChatMessageModel;
|
||||||
|
})();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class AIChatConversationModel
|
||||||
|
* @constructor
|
||||||
|
* @param {!AIChatModel} chat
|
||||||
|
* @param {!(Object.<string, any|null>|Array.<any|null>)} inputs
|
||||||
|
* @return {void}
|
||||||
|
* @access public
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
export const AIChatConversationModel = (function(){
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructs AIChatConversationModel
|
||||||
|
* @param {!AIChatModel} chat
|
||||||
|
* @param {!(Object.<string, any|null>|Array.<any|null>)} inputs
|
||||||
|
* @return {void}
|
||||||
|
* @access private
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
const AIChatConversationModel = function(chat, inputs){
|
||||||
|
/** @type {AIChatModel} */
|
||||||
|
this.chat = chat;
|
||||||
|
/** @type {string} */
|
||||||
|
this.id = Common.get_value("id", inputs);
|
||||||
|
/** @type {Array.<AIChatMessageModel>} */
|
||||||
|
this.messages = Common.get_value("messages", inputs, []).map(message => new AIChatMessageModel(this, message));
|
||||||
|
/** @type {boolean} */
|
||||||
|
this.selected = Common.get_value("selected", inputs, true);
|
||||||
|
};
|
||||||
|
|
||||||
|
return AIChatConversationModel;
|
||||||
|
})();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class AIChatModel
|
||||||
|
* @constructor
|
||||||
|
* @return {void}
|
||||||
|
* @access private
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
export const AIChatModel = (function(){
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructs AIChatModel
|
||||||
|
* @return {void}
|
||||||
|
* @access private
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
const AIChatModel = function(){
|
||||||
|
|
||||||
|
/** @type {AIChatModel} */
|
||||||
|
const self = this;
|
||||||
|
|
||||||
|
/** @type {Array.<AIChatConversationModel>} */
|
||||||
|
this.conversations = [];
|
||||||
|
/** @type {AIChatConversationModel|null} */
|
||||||
|
this.selected_conversation = null;
|
||||||
|
|
||||||
|
/** @type {Event} */
|
||||||
|
this.on_change = new Event();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {void}
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
const constructor = () => {
|
||||||
|
|
||||||
|
self.on_change.add(update_changes);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!AIChatMessageModel} model
|
||||||
|
* @returns {void}
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
const update_changes = model => {
|
||||||
|
|
||||||
|
/** @type {HTMLElement|null} */
|
||||||
|
const message = document.querySelector(".aichat [data-conversation='" + model.conversation.id + "'] .aichat-message[data-id='" + model.id + "']");
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!string} conversation
|
||||||
|
* @param {!string} id
|
||||||
|
* @returns {AIChatMessageModel|null}
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
const get_message = (conversation, id) => {
|
||||||
|
|
||||||
|
/** @type {AIChatConversationModel|null} */
|
||||||
|
const conversation_model = self.conversations.find(model => model.id === conversation);
|
||||||
|
|
||||||
|
if(conversation_model)
|
||||||
|
return conversation_model.messages.find(model => model.id === id) || null;
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!string} message
|
||||||
|
* @param {!boolean} [done = false]
|
||||||
|
* @returns {boolean}
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
this.update = (conversation, id, message, done = false) => {
|
||||||
|
|
||||||
|
/** @type {AIChatMessageModel|null} */
|
||||||
|
let model = get_message(conversation, id);
|
||||||
|
|
||||||
|
if(!model)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
model.message += message;
|
||||||
|
model.tokens ++;
|
||||||
|
model.done = done;
|
||||||
|
conversation_model.chat.on_change.execute(model);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!string} status
|
||||||
|
* @returns {boolean}
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
this.set_status = status => {
|
||||||
|
|
||||||
|
/** @type {AIChatMessageModel|null} */
|
||||||
|
let model = get_message(conversation, id);
|
||||||
|
|
||||||
|
if(!model)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
model.status = status;
|
||||||
|
conversation_model.chat.on_change.execute(model);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
return AIChatModel;
|
||||||
|
})();
|
||||||
@ -23,13 +23,19 @@ export const SessionModel = (function(){
|
|||||||
const SessionModel = function(i, inputs){
|
const SessionModel = function(i, inputs){
|
||||||
|
|
||||||
/** @type {SessionModel} */
|
/** @type {SessionModel} */
|
||||||
const self = this;
|
const self = this,
|
||||||
|
/** @type {Object.<string, any|null>} */
|
||||||
|
data = {};
|
||||||
/** @type {number|null} */
|
/** @type {number|null} */
|
||||||
let id = null,
|
let id = null,
|
||||||
/** @type {Array.<string>} */
|
/** @type {Array.<string>} */
|
||||||
permissions = [],
|
permissions = [],
|
||||||
/** @type {number} */
|
/** @type {number} */
|
||||||
last_check = 0;
|
last_check = 0,
|
||||||
|
/** @type {string|null} */
|
||||||
|
cookie_key = null,
|
||||||
|
/** @type {integer|null} */
|
||||||
|
timeout = null;
|
||||||
|
|
||||||
/** @type {string|null} */
|
/** @type {string|null} */
|
||||||
this.nick = null;
|
this.nick = null;
|
||||||
@ -43,11 +49,36 @@ export const SessionModel = (function(){
|
|||||||
* @access private
|
* @access private
|
||||||
*/
|
*/
|
||||||
const constructor = () => {
|
const constructor = () => {
|
||||||
id = Common.get_value("id", inputs, null);
|
|
||||||
permissions = Common.get_value("permissions", inputs, []);
|
/** @type {string|null} */
|
||||||
self.nick = Common.get_value("nick", inputs, null);
|
const cookie = anp.cookies.get(cookie_key = Common.get_value("cookie", inputs, null));
|
||||||
self.type = Common.get_value("type", inputs, self.type);
|
|
||||||
|
if(cookie){
|
||||||
|
|
||||||
|
/** @type {string} */
|
||||||
|
let raw_permissions,
|
||||||
|
/** @type {string} */
|
||||||
|
raw_data,
|
||||||
|
/** @type {string} */
|
||||||
|
raw_type,
|
||||||
|
/** @type {string} */
|
||||||
|
raw_id;
|
||||||
|
|
||||||
|
[raw_id, self.nick, raw_type, raw_permissions, raw_data] = cookie.split("|");
|
||||||
|
permissions = raw_permissions.split(",");
|
||||||
|
Object.assign(Common.data_encode(raw_data)).forEach(([key, value]) => self.set(key, value, false));
|
||||||
|
self.type = Number(raw_type) || SessionModel.LOCAL;
|
||||||
|
id = Number(raw_id) || null;
|
||||||
|
|
||||||
|
}else{
|
||||||
|
id = Common.get_value("id", inputs, null);
|
||||||
|
permissions = Common.get_value("permissions", inputs, []);
|
||||||
|
self.nick = Common.get_value("nick", inputs, null);
|
||||||
|
self.type = Number(Common.get_value("type", inputs, self.type)) || SessionModel.LOCAL;
|
||||||
|
};
|
||||||
last_check = Date.now();
|
last_check = Date.now();
|
||||||
|
timeout = Common.get_value(["session_timeout", "timeout"], inputs, 300000);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -57,6 +88,57 @@ export const SessionModel = (function(){
|
|||||||
*/
|
*/
|
||||||
this.check_permissions = permissions => permissions.some(self.permissions.includes);
|
this.check_permissions = permissions => permissions.some(self.permissions.includes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!string} key
|
||||||
|
* @returns {boolean}
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
this.has = key => data[key] !== undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!string} key
|
||||||
|
* @param {?any} [value = null]
|
||||||
|
* @param {!boolean} [overwrite = true]
|
||||||
|
* @returns {boolean}
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
this.set = (key, value = null, overwrite = true) => {
|
||||||
|
if(Check.is_key(key) && (overwrite || !self.has(key))){
|
||||||
|
data[key] = value;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!string} key
|
||||||
|
* @returns {any|null}
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
this.get = key => self.has(key) ? data[key] : null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {boolean}
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
this.save = () => {
|
||||||
|
if(cookie_key){
|
||||||
|
anp.cookies.set(cookie_key, Common.data_encode([
|
||||||
|
id,
|
||||||
|
self.nick,
|
||||||
|
self.type,
|
||||||
|
permissions.join(","),
|
||||||
|
Common.data_encode(data)
|
||||||
|
]).join("|"), {
|
||||||
|
overwrite : true,
|
||||||
|
expires : new Date(Date.now() + timeout),
|
||||||
|
path : "/"
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
constructor();
|
constructor();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -32,6 +32,7 @@
|
|||||||
"raw_html" : "Código HTML",
|
"raw_html" : "Código HTML",
|
||||||
"minimum" : "Mínimo",
|
"minimum" : "Mínimo",
|
||||||
"maximum" : "Máximo",
|
"maximum" : "Máximo",
|
||||||
"ai" : "IA"
|
"ai" : "IA",
|
||||||
|
"anpbot" : "AnPBot"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
181
Python/AnP/Abstracts/BrowserAbstract.py
Normal file
181
Python/AnP/Abstracts/BrowserAbstract.py
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from typing import Optional, Self, Any, Callable, Sequence, TypeVar
|
||||||
|
from abc import abstractmethod
|
||||||
|
from AnP.Interfaces.Application.AnPInterface import AnPInterface
|
||||||
|
from AnP.DSLs.ScrapDSL import (
|
||||||
|
Execute, Action, Open, Close, Switch, Wait, Do, Go, Get, ForEach, And, Or, Not,
|
||||||
|
If, While, DoWhile, Download
|
||||||
|
)
|
||||||
|
from AnP.Utils.Common import Common
|
||||||
|
from AnP.Abstracts.ModelAbstract import ModelAbstract
|
||||||
|
|
||||||
|
T = TypeVar("T")
|
||||||
|
|
||||||
|
class BrowserAbstract(ModelAbstract):
|
||||||
|
|
||||||
|
def __init__(self:Self, anp:AnPInterface, key:str, TabType:T, inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None) -> None:
|
||||||
|
self.anp:AnPInterface = anp
|
||||||
|
self.key:str = key
|
||||||
|
self.working:bool = True
|
||||||
|
self.tabs:dict[str, T] = {}
|
||||||
|
self.tab_selected:str = ""
|
||||||
|
self.human_time:float|int|Sequence[float|int] = Common.get_value("human_time", inputs, 0.0)
|
||||||
|
self.actions:dict[Action, Callable[[Action, dict[str, Any|None], Optional[Any]], None]] = {
|
||||||
|
Execute : self.execute,
|
||||||
|
Open : self.open,
|
||||||
|
Close : self.close,
|
||||||
|
Switch : self.switch,
|
||||||
|
Wait : self.wait,
|
||||||
|
Do : self.do,
|
||||||
|
Go : self.go,
|
||||||
|
Get : self.get,
|
||||||
|
ForEach : self.foreach,
|
||||||
|
And : self._and,
|
||||||
|
Or : self._or,
|
||||||
|
Not : self._not
|
||||||
|
}
|
||||||
|
|
||||||
|
def start(self:Self) -> None:
|
||||||
|
self.working = True
|
||||||
|
|
||||||
|
def close(self:Self) -> None:
|
||||||
|
self.working = False
|
||||||
|
self.tabs.clear()
|
||||||
|
self.tab_selected = ""
|
||||||
|
|
||||||
|
def is_working(self:Self) -> bool:
|
||||||
|
return self.working and self.anp.working()
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def run(self:Self, actions:Sequence[Action], shared:dict[str, Any|None] = {}) -> dict[str, Any|None]:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def execute(self:Self, action:Execute, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def open(self:Self, action:Open, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def close(self:Self, action:Close, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def switch(self:Self, action:Switch, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:pass
|
||||||
|
|
||||||
|
def wait(self:Self, action:Wait, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
|
||||||
|
if action.is_fixed:
|
||||||
|
self.anp.wait(action.time)
|
||||||
|
else:
|
||||||
|
if action.is_range:
|
||||||
|
self.anp.wait(Common.random_number(*action.time[0]))
|
||||||
|
else:
|
||||||
|
self.anp.wait(Common.random(*action.time))
|
||||||
|
action.done = True
|
||||||
|
|
||||||
|
def do(self:Self, action:Do, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
|
||||||
|
|
||||||
|
subaction:Action
|
||||||
|
i:int
|
||||||
|
|
||||||
|
action.done = True
|
||||||
|
|
||||||
|
for i, subaction in enumerate(action.actions):
|
||||||
|
if not self.anp.working():
|
||||||
|
action.done = False
|
||||||
|
return
|
||||||
|
|
||||||
|
if isinstance(subaction, Action):
|
||||||
|
subaction.done = False
|
||||||
|
subaction.exception = None
|
||||||
|
if subaction.__class__ in self.actions:
|
||||||
|
try:
|
||||||
|
|
||||||
|
ok:bool
|
||||||
|
|
||||||
|
self.actions[subaction.__class__](subaction, shared, last_item)
|
||||||
|
ok = subaction.done and subaction.exception is None
|
||||||
|
|
||||||
|
if not ok and not subaction.ignore_fail:
|
||||||
|
if subaction.exception is None:
|
||||||
|
subaction.print_errors and self.anp.print("warning", "anp_browser_action_not_done", {
|
||||||
|
"key" : self.key,
|
||||||
|
"action": subaction.__class__.__name__,
|
||||||
|
"i" : i
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
self.anp.exception(subaction.exception, "anp_browser_action_exception", {
|
||||||
|
"key" : self.key,
|
||||||
|
"action": subaction.__class__.__name__,
|
||||||
|
"i" : i
|
||||||
|
})
|
||||||
|
action.done = False
|
||||||
|
break
|
||||||
|
|
||||||
|
if subaction.wait:
|
||||||
|
self.wait(Wait(self.human_time, True))
|
||||||
|
|
||||||
|
ok and subaction.print_ok and self.anp.print("info", "anp_browser_action_done", {
|
||||||
|
"key" : self.key,
|
||||||
|
"action": subaction.__class__.__name__,
|
||||||
|
"i" : i
|
||||||
|
})
|
||||||
|
|
||||||
|
except Exception as exception:
|
||||||
|
subaction.exception = exception
|
||||||
|
subaction.print_errors and self.anp.exception(exception, "anp_browser_action_exception", {
|
||||||
|
"key" : self.key,
|
||||||
|
"action": subaction.__class__.__name__,
|
||||||
|
"i" : i
|
||||||
|
})
|
||||||
|
if not subaction.ignore_fail:
|
||||||
|
action.done = False
|
||||||
|
break
|
||||||
|
|
||||||
|
else:
|
||||||
|
subaction.print_errors and self.anp.print("warning", "anp_browser_action_not_supported", {
|
||||||
|
"key" : self.key,
|
||||||
|
"action": subaction.__class__.__name__,
|
||||||
|
"i" : i
|
||||||
|
})
|
||||||
|
if not subaction.ignore_fail:
|
||||||
|
action.done = False
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
self.anp.print("warning", "anp_browser_action_not_action", {
|
||||||
|
"key" : self.key,
|
||||||
|
"i" : i
|
||||||
|
})
|
||||||
|
action.done = False
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def go(self:Self, action:Go, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get(self:Self, action:Get, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def foreach(self:Self, action:ForEach, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def _and(self:Self, action:And, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> bool:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def _or(self:Self, action:Or, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> bool:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def _not(self:Self, action:Not, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> bool:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def _if(self:Self, action:If, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def _while(self:Self, action:While, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def do_while(self:Self, action:DoWhile, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def download(self:Self, action:Download, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:pass
|
||||||
@ -24,6 +24,7 @@ from AnP.Managers.WebSocketServersManager import WebSocketServersManager
|
|||||||
from AnP.Managers.HTTPServersManager import HTTPServersManager
|
from AnP.Managers.HTTPServersManager import HTTPServersManager
|
||||||
from AnP.Managers.PseudoLoRAsManager import PseudoLoRAsManager
|
from AnP.Managers.PseudoLoRAsManager import PseudoLoRAsManager
|
||||||
from AnP.Managers.AIInterpretersManager import AIInterpretersManager
|
from AnP.Managers.AIInterpretersManager import AIInterpretersManager
|
||||||
|
from AnP.Managers.BrowsersManager import BrowsersManager
|
||||||
from AnP.Utils.Common import Common
|
from AnP.Utils.Common import Common
|
||||||
from AnP.Utils.Patterns import RE
|
from AnP.Utils.Patterns import RE
|
||||||
|
|
||||||
@ -62,6 +63,7 @@ class AnP:
|
|||||||
self.http_servers:HTTPServersManager = HTTPServersManager(self)
|
self.http_servers:HTTPServersManager = HTTPServersManager(self)
|
||||||
self.pseudoloras:PseudoLoRAsManager = PseudoLoRAsManager(self)
|
self.pseudoloras:PseudoLoRAsManager = PseudoLoRAsManager(self)
|
||||||
self.ai_interpreters:AIInterpretersManager = AIInterpretersManager(self)
|
self.ai_interpreters:AIInterpretersManager = AIInterpretersManager(self)
|
||||||
|
self.browsers:BrowsersManager = BrowsersManager(self)
|
||||||
|
|
||||||
def update(self:Self) -> None:
|
def update(self:Self) -> None:
|
||||||
self.settings.update()
|
self.settings.update()
|
||||||
@ -81,6 +83,7 @@ class AnP:
|
|||||||
self.http_servers.update()
|
self.http_servers.update()
|
||||||
self.pseudoloras.update()
|
self.pseudoloras.update()
|
||||||
self.ai_interpreters.update()
|
self.ai_interpreters.update()
|
||||||
|
self.browsers.update()
|
||||||
|
|
||||||
def reset(self:Self) -> None:
|
def reset(self:Self) -> None:
|
||||||
self.settings.reset()
|
self.settings.reset()
|
||||||
@ -98,6 +101,7 @@ class AnP:
|
|||||||
self.web_socket_servers.reset()
|
self.web_socket_servers.reset()
|
||||||
self.http_servers.reset()
|
self.http_servers.reset()
|
||||||
self.ai_interpreters.reset()
|
self.ai_interpreters.reset()
|
||||||
|
self.browsers.reset()
|
||||||
|
|
||||||
def close(self:Self) -> None:
|
def close(self:Self) -> None:
|
||||||
self.__working = False
|
self.__working = False
|
||||||
@ -105,6 +109,7 @@ class AnP:
|
|||||||
self.ai_interpreters.close()
|
self.ai_interpreters.close()
|
||||||
self.web_socket_servers.close()
|
self.web_socket_servers.close()
|
||||||
self.http_servers.close()
|
self.http_servers.close()
|
||||||
|
self.browsers.close()
|
||||||
|
|
||||||
def working(self:Self) -> bool:
|
def working(self:Self) -> bool:
|
||||||
return self.__working
|
return self.__working
|
||||||
|
|||||||
2
Python/AnP/DSLs/HTMLDLS.py
Normal file
2
Python/AnP/DSLs/HTMLDLS.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
166
Python/AnP/DSLs/ScrapDSL.py
Normal file
166
Python/AnP/DSLs/ScrapDSL.py
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from typing import Self, Sequence, Any, Optional, Callable
|
||||||
|
from re import Pattern as REPattern, Match as REMatch
|
||||||
|
|
||||||
|
class Action:
|
||||||
|
def __init__(self:Self) -> None:
|
||||||
|
self.exception:Exception|None = None
|
||||||
|
self.print_errors:bool = True
|
||||||
|
self.print_ok:bool = False
|
||||||
|
self.done:bool = False
|
||||||
|
self.wait:bool = True
|
||||||
|
|
||||||
|
class Execute(Action):
|
||||||
|
def __init__(self:Self, callback:Callable[[dict[str, Any|None]], None]) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.callback:Callable[[dict[str, Any|None]], None] = callback
|
||||||
|
|
||||||
|
class Open(Action):
|
||||||
|
def __init__(self:Self, key:str, url:Optional[str] = None) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.key:str = key
|
||||||
|
self.url:str|None = url
|
||||||
|
|
||||||
|
class Close(Action):
|
||||||
|
def __init__(self:Self, key:Optional[str] = None) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.key:str|None = key
|
||||||
|
|
||||||
|
class Switch(Action):
|
||||||
|
def __init__(self:Self, key:str) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.key:str = key
|
||||||
|
|
||||||
|
class Wait(Action):
|
||||||
|
def __init__(self:Self, time:float|int|Sequence[float|int], is_range:bool = True) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.time:float|int|Sequence[float|int] = time
|
||||||
|
self.is_fixed:bool = isinstance(time, (float, int))
|
||||||
|
self.is_range:bool = is_range
|
||||||
|
|
||||||
|
class Do(Action):
|
||||||
|
def __init__(self:Self, *actions:Action) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.actions:tuple[Action, ...] = actions
|
||||||
|
|
||||||
|
class Go(Action):
|
||||||
|
def __init__(self:Self, url:str, tab:Optional[str] = None) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.url:str = url
|
||||||
|
self.tab:str|None = tab
|
||||||
|
|
||||||
|
class Selector(Action):
|
||||||
|
def __init__(self:Self,
|
||||||
|
selector:str,
|
||||||
|
multiple:bool = False
|
||||||
|
) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.selector:str = selector
|
||||||
|
self.multiple:bool = multiple
|
||||||
|
|
||||||
|
class XPath(Selector):pass
|
||||||
|
|
||||||
|
class CSS(Selector):pass
|
||||||
|
|
||||||
|
class ID(Selector):pass
|
||||||
|
|
||||||
|
class Class(Selector):pass
|
||||||
|
|
||||||
|
class LinkText(Selector):pass
|
||||||
|
|
||||||
|
class Name(Selector):pass
|
||||||
|
|
||||||
|
class Get(Action):
|
||||||
|
def __init__(self:Self,
|
||||||
|
key:str,
|
||||||
|
attribute:str = "CDATA",
|
||||||
|
selector:Optional[Selector] = None,
|
||||||
|
reset:bool = False,
|
||||||
|
pattern:tuple[Optional[REPattern], str|Callable[[REMatch], str]] = None
|
||||||
|
) -> None:
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.key:str = key
|
||||||
|
self.attribute:str = attribute
|
||||||
|
self.selector:Selector|None = selector
|
||||||
|
self.reset:bool = reset
|
||||||
|
self.pattern:REPattern|None = None
|
||||||
|
self.matches:str|Callable[[REMatch], str]|None = None
|
||||||
|
|
||||||
|
if pattern is not None:
|
||||||
|
self.pattern, self.matches = pattern
|
||||||
|
|
||||||
|
class ForEach(Action):
|
||||||
|
def __init__(self:Self,
|
||||||
|
items:Selector|Sequence[Any|None],
|
||||||
|
actions:Sequence[Action],
|
||||||
|
callback:Optional[Callable[[Any|None], None]] = None
|
||||||
|
) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.items:Selector|Sequence[Any|None] = items
|
||||||
|
self.actions:Sequence[Action] = actions
|
||||||
|
self.callback:Callable[[Any|None], None]|None = callback
|
||||||
|
|
||||||
|
class Condition(Action):
|
||||||
|
def __init__(self:Self, conditions:Sequence[Callable[[dict[str, Any|None]], bool]]|Selector|Self) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.conditions:Sequence[Callable[[dict[str, Any|None]], bool]|Selector|Condition|bool] = conditions
|
||||||
|
self.ok:bool = False
|
||||||
|
|
||||||
|
class And(Condition):pass
|
||||||
|
|
||||||
|
class Or(Condition):pass
|
||||||
|
|
||||||
|
class Not(Action):
|
||||||
|
def __init__(self:Self, condition:Callable[[dict[str, Any|None]], bool]|Selector|Condition|bool) -> None:
|
||||||
|
super().__init__([condition])
|
||||||
|
self.condition:Callable[[dict[str, Any|None]], bool]|Selector|Condition|bool = condition
|
||||||
|
self.ok:bool = False
|
||||||
|
|
||||||
|
class If(Action):
|
||||||
|
def __init__(self:Self,
|
||||||
|
condition:Condition|Callable[[dict[str, Any|None]], bool]|Selector|bool,
|
||||||
|
if_actions:Optional[Sequence[Action]] = None,
|
||||||
|
else_actions:Optional[Sequence[Action]] = None
|
||||||
|
) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.condition:Condition|Callable[[dict[str, Any|None]], bool]|Selector|bool = condition
|
||||||
|
self.if_actions:Sequence[Action]|None = if_actions
|
||||||
|
self.else_actions:Sequence[Action]|None = else_actions
|
||||||
|
|
||||||
|
class While(Action):
|
||||||
|
def __init__(self:Self,
|
||||||
|
condition:Condition|Callable[[dict[str, Any|None]], bool]|Selector|bool,
|
||||||
|
actions:Sequence[Action]
|
||||||
|
) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.condition:Condition|Callable[[dict[str, Any|None]], bool]|Selector|bool = condition
|
||||||
|
self.actions:Sequence[Action] = actions
|
||||||
|
|
||||||
|
class DoWhile(Action):
|
||||||
|
def __init__(self:Self,
|
||||||
|
condition:Condition|Callable[[dict[str, Any|None]], bool]|Selector|bool,
|
||||||
|
actions:Sequence[Action]
|
||||||
|
) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.condition:Condition|Callable[[dict[str, Any|None]], bool]|Selector|bool = condition
|
||||||
|
self.actions:Sequence[Action] = actions
|
||||||
|
|
||||||
|
class Download(Action):
|
||||||
|
def __init__(self:Self,
|
||||||
|
url:str,
|
||||||
|
key:Optional[str] = None,
|
||||||
|
attribute:Optional[str] = None,
|
||||||
|
path:Optional[str] = None,
|
||||||
|
multiple:bool = False,
|
||||||
|
overwrite:bool = False
|
||||||
|
) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.url:str = url
|
||||||
|
self.key:str|None = key
|
||||||
|
self.attribute:str|None = attribute
|
||||||
|
self.path:str|None = path
|
||||||
|
self.multiple:bool = multiple
|
||||||
|
self.overwrite:bool = overwrite
|
||||||
2
Python/AnP/Drivers/MySQLDriver.py
Normal file
2
Python/AnP/Drivers/MySQLDriver.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
2
Python/AnP/Drivers/SQLServerDriver.py
Normal file
2
Python/AnP/Drivers/SQLServerDriver.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
2
Python/AnP/Drivers/SQLiteDriver.py
Normal file
2
Python/AnP/Drivers/SQLiteDriver.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
12
Python/AnP/Drivers/SeleniumDriver.py
Normal file
12
Python/AnP/Drivers/SeleniumDriver.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from typing import Self
|
||||||
|
from AnP.DSLs.ScrapDSL import Action
|
||||||
|
from AnP.Interfaces.Application import AnPInterface
|
||||||
|
from AnP.Abstracts.BrowserAbstract import BrowserAbstract
|
||||||
|
|
||||||
|
class SeleniumDriver(BrowserAbstract):
|
||||||
|
|
||||||
|
def __init__(self:Self, anp:AnPInterface) -> None:
|
||||||
|
super().__init__(anp)
|
||||||
309
Python/AnP/Drivers/XMLScrapDriver.py
Normal file
309
Python/AnP/Drivers/XMLScrapDriver.py
Normal file
@ -0,0 +1,309 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from typing import Self, Any, Optional, Sequence, Callable
|
||||||
|
from requests import get, Response
|
||||||
|
from parsel import Selector as ParseSelector, SelectorList as ParseSelectorList
|
||||||
|
from AnP.DSLs.ScrapDSL import (
|
||||||
|
Execute, Selector, CSS, XPath, Name, LinkText, Class, ID, Open, Close, Switch,
|
||||||
|
Go, Get, ForEach, Do, Condition, And, Or, Not, If, While, DoWhile, Download,
|
||||||
|
Action
|
||||||
|
)
|
||||||
|
from AnP.Interfaces.Application import AnPInterface
|
||||||
|
from AnP.Abstracts.BrowserAbstract import BrowserAbstract
|
||||||
|
from AnP.Models.XMLScrapTabModel import XMLScrapTabModel
|
||||||
|
|
||||||
|
class XMLScrapDriver(BrowserAbstract):
|
||||||
|
|
||||||
|
def __init__(self:Self, anp:AnPInterface, key:str, inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None) -> None:
|
||||||
|
super().__init__(anp, key, XMLScrapTabModel, inputs)
|
||||||
|
|
||||||
|
def run(self:Self, actions:Sequence[Action], shared:dict[str, Any|None] = {}) -> dict[str, Any|None]:
|
||||||
|
|
||||||
|
self.do(Do(*actions), shared)
|
||||||
|
|
||||||
|
return shared
|
||||||
|
|
||||||
|
def __load(self:Self, url:str) -> Exception|None:
|
||||||
|
try:
|
||||||
|
|
||||||
|
response:Response
|
||||||
|
|
||||||
|
with get(url) as response:
|
||||||
|
self.tabs[self.tab_selected].set(response.text)
|
||||||
|
|
||||||
|
except Exception as exception:
|
||||||
|
return exception
|
||||||
|
return None
|
||||||
|
|
||||||
|
def execute(self:Self, action:Execute, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
|
||||||
|
try:
|
||||||
|
action.callback(shared)
|
||||||
|
action.done = True
|
||||||
|
except Exception as exception:
|
||||||
|
action.exception = exception
|
||||||
|
|
||||||
|
def open(self:Self, action:Open, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
|
||||||
|
|
||||||
|
url:str = shared[action.url] if action.url in shared and isinstance(shared[action.url], str) else action.url
|
||||||
|
|
||||||
|
self.tabs[action.key] = XMLScrapTabModel(action.key, url)
|
||||||
|
self.tab_selected = action.key
|
||||||
|
if url is not None:
|
||||||
|
action.exception = self.__load(url)
|
||||||
|
action.done = action.exception is None
|
||||||
|
|
||||||
|
def close(self:Self, action:Close, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
|
||||||
|
if action.key in self.tabs:
|
||||||
|
del self.tabs[action.key]
|
||||||
|
if len(self.tabs):
|
||||||
|
self.tab_selected = list(self.tabs.keys())[-1]
|
||||||
|
action.done = True
|
||||||
|
|
||||||
|
def switch(self:Self, action:Switch, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
|
||||||
|
if action.key in self.tabs:
|
||||||
|
self.tab_selected = action.key
|
||||||
|
action.done = True
|
||||||
|
|
||||||
|
def go(self:Self, action:Go, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
|
||||||
|
|
||||||
|
url:str = shared[action.url] if action.url in shared and isinstance(shared[action.url], str) else action.url
|
||||||
|
|
||||||
|
action.exception = self.__load(url)
|
||||||
|
action.done = action.exception is None
|
||||||
|
|
||||||
|
def get_selector(self:Self, selector:str, from_item:Optional[Selector] = None, force_multiple:bool = False) -> ParseSelectorList|ParseSelector|None:
|
||||||
|
if self.tab_selected in self.tabs:
|
||||||
|
|
||||||
|
path:ParseSelector = self.tabs[self.tab_selected].selector
|
||||||
|
items:ParseSelectorList = (
|
||||||
|
path.css(selector) if isinstance(selector, CSS) else
|
||||||
|
path.xpath(selector) if isinstance(selector, XPath) else
|
||||||
|
path.css(f"[name='{selector}']") if isinstance(selector, Name) else
|
||||||
|
path.css(f"a:contains('{selector}')") if isinstance(selector, LinkText) else
|
||||||
|
path.css(f".{selector}") if isinstance(selector, Class) else
|
||||||
|
path.css(f"#{selector}") if isinstance(selector, ID) else
|
||||||
|
path.css(selector))
|
||||||
|
|
||||||
|
return (
|
||||||
|
items if force_multiple or selector.multiple else
|
||||||
|
items[0] if len(items) else
|
||||||
|
None)
|
||||||
|
return [] if force_multiple or selector.multiple else None
|
||||||
|
|
||||||
|
def get(self:Self, action:Get, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
|
||||||
|
|
||||||
|
item:ParseSelector|ParseSelectorList|None = last_item if action.selector is None else self.get_selector(action.selector, last_item)
|
||||||
|
multiple:bool = False if action.selector is None else action.selector.multiple
|
||||||
|
attribute:str = "::text" if action.attribute == "CDATA" else f"::attr({action.attribute})"
|
||||||
|
|
||||||
|
if action.reset and action.key in shared:
|
||||||
|
del shared[action.key]
|
||||||
|
|
||||||
|
if multiple:
|
||||||
|
if action.key not in shared or not isinstance(shared[action.key], list):
|
||||||
|
shared[action.key] = []
|
||||||
|
shared[action.key].extend([subitem.css(attribute).get() for subitem in item])
|
||||||
|
else:
|
||||||
|
shared[action.key] = None if item is None else item.css(attribute).get()
|
||||||
|
|
||||||
|
def foreach(self:Self, action:ForEach, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
|
||||||
|
|
||||||
|
item:ParseSelector|Any|None
|
||||||
|
done:bool = True
|
||||||
|
|
||||||
|
for item in (
|
||||||
|
self.get_selector(action.items, last_item, True) if isinstance(action.items, Selector) else
|
||||||
|
action.items):
|
||||||
|
|
||||||
|
if not self.anp.working():
|
||||||
|
done = False
|
||||||
|
break
|
||||||
|
|
||||||
|
if action.callback is not None:
|
||||||
|
try:
|
||||||
|
item = action.callback(item)
|
||||||
|
except Exception as exception:
|
||||||
|
action.exception = exception
|
||||||
|
done = False
|
||||||
|
break
|
||||||
|
|
||||||
|
subactions:Do = Do(*action.actions)
|
||||||
|
|
||||||
|
self.do(subactions, shared, item if isinstance(item, ParseSelector) else last_item)
|
||||||
|
if not subactions.done or subactions.exception is not None:
|
||||||
|
action.exception = subactions.exception
|
||||||
|
done = False
|
||||||
|
break
|
||||||
|
|
||||||
|
action.done = done
|
||||||
|
|
||||||
|
def _and(self:Self, action:And, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> bool:
|
||||||
|
|
||||||
|
condition:Callable[[dict[str, Any|None]], bool]|Selector|Condition
|
||||||
|
|
||||||
|
action.ok = True
|
||||||
|
|
||||||
|
for condition in action.conditions:
|
||||||
|
if isinstance(condition, Condition):
|
||||||
|
self.do(condition, shared, last_item)
|
||||||
|
if not condition.ok:
|
||||||
|
action.ok = False
|
||||||
|
break
|
||||||
|
elif isinstance(condition, Selector):
|
||||||
|
if not self.get_selector(condition, last_item):
|
||||||
|
action.ok = False
|
||||||
|
break
|
||||||
|
elif callable(condition):
|
||||||
|
try:
|
||||||
|
if not condition(shared):
|
||||||
|
action.ok = False
|
||||||
|
break
|
||||||
|
except Exception as exception:
|
||||||
|
action.exception = exception
|
||||||
|
action.ok = False
|
||||||
|
break
|
||||||
|
|
||||||
|
def _or(self:Self, action:Or, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> bool:
|
||||||
|
|
||||||
|
condition:Callable[[dict[str, Any|None]], bool]|Selector|Condition
|
||||||
|
|
||||||
|
action.ok = False
|
||||||
|
|
||||||
|
for condition in action.conditions:
|
||||||
|
if isinstance(condition, Condition):
|
||||||
|
self.do(condition, shared, last_item)
|
||||||
|
if condition.ok:
|
||||||
|
action.ok = True
|
||||||
|
break
|
||||||
|
elif isinstance(condition, Selector):
|
||||||
|
if self.get_selector(condition, last_item):
|
||||||
|
action.ok = True
|
||||||
|
break
|
||||||
|
elif callable(condition):
|
||||||
|
try:
|
||||||
|
if condition(shared):
|
||||||
|
action.ok = True
|
||||||
|
break
|
||||||
|
except Exception as exception:
|
||||||
|
action.exception = exception
|
||||||
|
action.ok = False
|
||||||
|
break
|
||||||
|
|
||||||
|
def _not(self:Self, action:Not, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> bool:
|
||||||
|
if isinstance(action.condition, Condition):
|
||||||
|
self.do(action.condition, shared, last_item)
|
||||||
|
action.ok = not action.condition.ok
|
||||||
|
elif isinstance(action.condition, Selector):
|
||||||
|
action.ok = not self.get_selector(action.condition, last_item)
|
||||||
|
elif callable(action.condition):
|
||||||
|
try:
|
||||||
|
action.ok = not action.condition(shared)
|
||||||
|
except Exception as exception:
|
||||||
|
action.exception = exception
|
||||||
|
action.ok = False
|
||||||
|
|
||||||
|
def _if(self:Self, action:If, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
|
||||||
|
|
||||||
|
if not isinstance(action.condition, Condition):
|
||||||
|
action.condition = Condition((action.condition,))
|
||||||
|
|
||||||
|
self.do(action.condition, shared, last_item)
|
||||||
|
|
||||||
|
if action.condition.done and action.condition.exception is None:
|
||||||
|
|
||||||
|
subactions:Do = Do(*((action.if_actions if action.condition.ok else action.else_actions) or []))
|
||||||
|
|
||||||
|
self.do(subactions, shared, last_item)
|
||||||
|
action.done = subactions.done and subactions.exception is None
|
||||||
|
action.exception = subactions.exception
|
||||||
|
|
||||||
|
else:
|
||||||
|
action.done = action.condition.done
|
||||||
|
action.exception = action.condition.exception
|
||||||
|
|
||||||
|
def _while(self:Self, action:While, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
|
||||||
|
|
||||||
|
if not isinstance(action.condition, Condition):
|
||||||
|
action.condition = Condition((action.condition,))
|
||||||
|
|
||||||
|
while True:
|
||||||
|
if not self.anp.working():
|
||||||
|
action.done = False
|
||||||
|
break
|
||||||
|
|
||||||
|
self.do(action.condition, shared, last_item)
|
||||||
|
|
||||||
|
if not action.condition.done or action.condition.exception is not None:
|
||||||
|
action.done = action.condition.done
|
||||||
|
action.exception = action.condition.exception
|
||||||
|
break
|
||||||
|
|
||||||
|
if action.condition.ok:
|
||||||
|
|
||||||
|
subactions:Do = Do(*action.actions)
|
||||||
|
|
||||||
|
self.do(subactions, shared, last_item)
|
||||||
|
if not subactions.done or subactions.exception is not None:
|
||||||
|
action.exception = subactions.exception
|
||||||
|
action.done = False
|
||||||
|
break
|
||||||
|
|
||||||
|
else:
|
||||||
|
action.done = True
|
||||||
|
break
|
||||||
|
|
||||||
|
def do_while(self:Self, action:DoWhile, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
|
||||||
|
|
||||||
|
if not isinstance(action.condition, Condition):
|
||||||
|
action.condition = Condition((action.condition,))
|
||||||
|
|
||||||
|
while True:
|
||||||
|
if not self.anp.working():
|
||||||
|
action.done = False
|
||||||
|
break
|
||||||
|
|
||||||
|
subactions:Do = Do(*action.actions)
|
||||||
|
|
||||||
|
self.do(subactions, shared, last_item)
|
||||||
|
if not subactions.done or subactions.exception is not None:
|
||||||
|
action.exception = subactions.exception
|
||||||
|
action.done = False
|
||||||
|
break
|
||||||
|
|
||||||
|
self.do(action.condition, shared, last_item)
|
||||||
|
|
||||||
|
if not action.condition.done or action.condition.exception is not None:
|
||||||
|
action.done = action.condition.done
|
||||||
|
action.exception = action.condition.exception
|
||||||
|
break
|
||||||
|
|
||||||
|
if not action.condition.ok:
|
||||||
|
action.done = True
|
||||||
|
break
|
||||||
|
|
||||||
|
def download(self:Self, action:Download, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
|
||||||
|
if action.key or action.path:
|
||||||
|
try:
|
||||||
|
|
||||||
|
response:Response
|
||||||
|
url:str = shared[action.url] if action.url in shared and isinstance(shared[action.url], str) else action.url
|
||||||
|
|
||||||
|
with get(url) as response:
|
||||||
|
if response.content is not None:
|
||||||
|
if action.key:
|
||||||
|
if action.multiple:
|
||||||
|
if action.key not in shared or not isinstance(shared[action.key], list):
|
||||||
|
shared[action.key] = []
|
||||||
|
shared[action.key].append(response.content)
|
||||||
|
action.done = True
|
||||||
|
elif action.overwrite or action.key not in shared:
|
||||||
|
shared[action.key] = response.content
|
||||||
|
action.done = True
|
||||||
|
else:
|
||||||
|
if action.overwrite or not self.anp.files.exists(action.path):
|
||||||
|
self.anp.files.save(action.path, response.content)
|
||||||
|
action.done = True
|
||||||
|
|
||||||
|
except Exception as exception:
|
||||||
|
action.exception = exception
|
||||||
72
Python/AnP/Interfaces/Abstracts/BrowserAbstractInterface.py
Normal file
72
Python/AnP/Interfaces/Abstracts/BrowserAbstractInterface.py
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from typing import Optional, Self, Any, Sequence
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
from AnP.DSLs.ScrapDSL import (
|
||||||
|
Execute, Action, Open, Close, Switch, Wait, Do, Go, Get, ForEach, And, Or, Not,
|
||||||
|
If, While, DoWhile, Download
|
||||||
|
)
|
||||||
|
from AnP.Abstracts.ModelAbstract import ModelAbstract
|
||||||
|
|
||||||
|
class BrowserAbstractInterface(ABC, ModelAbstract):
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def start(self:Self) -> None:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def close(self:Self) -> None:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def is_working(self:Self) -> bool:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def run(self:Self, actions:Sequence[Action], shared:dict[str, Any|None] = {}) -> dict[str, Any|None]:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def execute(self:Self, action:Execute, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def open(self:Self, action:Open, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def close(self:Self, action:Close, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def switch(self:Self, action:Switch, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def wait(self:Self, action:Wait, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def do(self:Self, action:Do, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def go(self:Self, action:Go, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get(self:Self, action:Get, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def foreach(self:Self, action:ForEach, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def _and(self:Self, action:And, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> bool:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def _or(self:Self, action:Or, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> bool:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def _not(self:Self, action:Not, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> bool:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def _if(self:Self, action:If, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def _while(self:Self, action:While, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def do_while(self:Self, action:DoWhile, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def download(self:Self, action:Download, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:pass
|
||||||
@ -1,10 +1,11 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from typing import Self, Sequence
|
from typing import Self, Sequence, Any
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
|
from AnP.Abstracts.ModelAbstract import ModelAbstract
|
||||||
|
|
||||||
class FilesAbstractInterface(ABC):
|
class FilesAbstractInterface(ABC, ModelAbstract):
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def get_parents(path:str, levels:int = 1) -> list[str]:pass
|
def get_parents(path:str, levels:int = 1) -> list[str]:pass
|
||||||
@ -43,4 +44,10 @@ class FilesAbstractInterface(ABC):
|
|||||||
def save(self:Self, path:str, content:str|bytes) -> bool:pass
|
def save(self:Self, path:str, content:str|bytes) -> bool:pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def delete(self:Self, path:str) -> bool:pass
|
def delete(self:Self, path:str) -> bool:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def load_json(self:Self, inputs:Any|None, only_dictionaries:bool = True) -> list[dict[str, Any|None]|Sequence[Any|None]]:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def list_directory_items(self:Self, path:str) -> list[str]:pass
|
||||||
@ -3,8 +3,9 @@
|
|||||||
|
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from typing import Self
|
from typing import Self
|
||||||
|
from AnP.Abstracts.ModelAbstract import ModelAbstract
|
||||||
|
|
||||||
class HTTPServersAbstractInterface(ABC):
|
class HTTPServersAbstractInterface(ABC, ModelAbstract):
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def start(self:Self) -> None:pass
|
def start(self:Self) -> None:pass
|
||||||
|
|||||||
@ -3,8 +3,9 @@
|
|||||||
|
|
||||||
from typing import Any, Self, Optional, Sequence
|
from typing import Any, Self, Optional, Sequence
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
|
from AnP.Abstracts.ModelAbstract import ModelAbstract
|
||||||
|
|
||||||
class WebSocketServersAbstractInterface(ABC):
|
class WebSocketServersAbstractInterface(ABC, ModelAbstract):
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def start(self:Self) -> None:pass
|
def start(self:Self) -> None:pass
|
||||||
|
|||||||
@ -20,6 +20,7 @@ from AnP.Interfaces.Managers.WebSocketServersManagerInterface import WebSocketSe
|
|||||||
from AnP.Interfaces.Managers.HTTPServersManagerInterface import HTTPServersManagerInterface
|
from AnP.Interfaces.Managers.HTTPServersManagerInterface import HTTPServersManagerInterface
|
||||||
from AnP.Interfaces.Managers.PseudoLoRAsManagerInterface import PseudoLoRAsManagerInterface
|
from AnP.Interfaces.Managers.PseudoLoRAsManagerInterface import PseudoLoRAsManagerInterface
|
||||||
from AnP.Interfaces.Managers.AIInterpretersManagerInterface import AIInterpretersManagerInterface
|
from AnP.Interfaces.Managers.AIInterpretersManagerInterface import AIInterpretersManagerInterface
|
||||||
|
from AnP.Interfaces.Managers.BrowsersManagerInterface import BrowsersManagerInterface
|
||||||
|
|
||||||
class AnPInterface(ABC):
|
class AnPInterface(ABC):
|
||||||
|
|
||||||
@ -41,6 +42,7 @@ class AnPInterface(ABC):
|
|||||||
self.http_servers:HTTPServersManagerInterface = None
|
self.http_servers:HTTPServersManagerInterface = None
|
||||||
self.pseudoloras:PseudoLoRAsManagerInterface = None
|
self.pseudoloras:PseudoLoRAsManagerInterface = None
|
||||||
self.ai_interpreters:AIInterpretersManagerInterface = None
|
self.ai_interpreters:AIInterpretersManagerInterface = None
|
||||||
|
self.browsers:BrowsersManagerInterface = None
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def update(self:Self) -> None:pass
|
def update(self:Self) -> None:pass
|
||||||
|
|||||||
27
Python/AnP/Interfaces/Managers/BrowsersManagerInterface.py
Normal file
27
Python/AnP/Interfaces/Managers/BrowsersManagerInterface.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from typing import Self, Any, Sequence
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
from AnP.Interfaces.Abstracts.BrowserAbstractInterface import BrowserAbstractInterface
|
||||||
|
from AnP.DSLs.ScrapDSL import Action
|
||||||
|
|
||||||
|
class BrowsersManagerInterface(ABC):
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def update(self:Self) -> None:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def reset(self:Self) -> None:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def close(self:Self) -> None:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def add(self:Self, inputs:Any|None, overwrite:bool = False) -> None:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get(self:Self, key:str) -> BrowserAbstractInterface|None:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def run(self:Self, key:str, actions:Sequence[Action], shared:dict[str, Any|None] = {}) -> dict[str, Any|None]:pass
|
||||||
69
Python/AnP/Managers/BrowsersManager.py
Normal file
69
Python/AnP/Managers/BrowsersManager.py
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from typing import Self, Any, Sequence
|
||||||
|
from AnP.Interfaces.Application.AnPInterface import AnPInterface
|
||||||
|
from AnP.Abstracts.BrowserAbstract import BrowserAbstract
|
||||||
|
from AnP.Utils.Checks import Check
|
||||||
|
from AnP.DSLs.ScrapDSL import Action
|
||||||
|
|
||||||
|
class BrowsersManager:
|
||||||
|
|
||||||
|
def __init__(self:Self, anp:AnPInterface) -> None:
|
||||||
|
self.anp:AnPInterface = anp
|
||||||
|
self.__browsers:dict[str, BrowserAbstract] = {}
|
||||||
|
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def update(self:Self) -> None:
|
||||||
|
|
||||||
|
key:str
|
||||||
|
|
||||||
|
for key in ("default_browsers_files", "browsers_files", "default_browsers", "browsers"):
|
||||||
|
self.add(self.anp.settings.get(key), True)
|
||||||
|
|
||||||
|
def reset(self:Self) -> None:
|
||||||
|
|
||||||
|
self.__browsers = {}
|
||||||
|
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def close(self:Self) -> None:
|
||||||
|
for key, browser in list(self.__browsers.items()):
|
||||||
|
browser.close()
|
||||||
|
del self.__browsers[key]
|
||||||
|
|
||||||
|
def add(self:Self, inputs:Any|None, overwrite:bool = False) -> None:
|
||||||
|
|
||||||
|
subinputs:dict[str, Any|None]
|
||||||
|
|
||||||
|
for subinputs in self.anp.files.load_json(inputs, True):
|
||||||
|
|
||||||
|
key:str
|
||||||
|
browser:Any|None
|
||||||
|
|
||||||
|
for key, browser in subinputs.items():
|
||||||
|
|
||||||
|
BrowserClass:type[BrowserAbstract]|None
|
||||||
|
|
||||||
|
if Check.is_string(browser):
|
||||||
|
BrowserClass = self.anp.models.get(BrowserAbstract, browser)
|
||||||
|
elif issubclass(browser, BrowserAbstract):
|
||||||
|
BrowserClass = browser
|
||||||
|
elif Check.is_dictionary(browser) and "type" in browser and Check.is_string(browser["type"]):
|
||||||
|
BrowserClass = self.anp.models.get(BrowserAbstract, browser["type"])
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if BrowserClass and (
|
||||||
|
overwrite or key not in self.__browsers
|
||||||
|
):
|
||||||
|
self.__browsers[key] = BrowserClass(self.anp, key, (
|
||||||
|
browser if Check.is_dictionary(browser) else
|
||||||
|
None))
|
||||||
|
|
||||||
|
def get(self:Self, key:str) -> BrowserAbstract|None:
|
||||||
|
return self.__browsers.get(key, None)
|
||||||
|
|
||||||
|
def run(self:Self, key:str, actions:Sequence[Action], shared:dict[str, Any|None] = {}) -> dict[str, Any|None]:
|
||||||
|
return self.__browsers[key].run(actions, shared) if key in self.__browsers else shared
|
||||||
@ -34,6 +34,10 @@ class ControllersManager:
|
|||||||
subinputs:dict[str, Any|None]
|
subinputs:dict[str, Any|None]
|
||||||
|
|
||||||
for subinputs in self.anp.files.load_json(inputs, True):
|
for subinputs in self.anp.files.load_json(inputs, True):
|
||||||
|
|
||||||
|
key:str
|
||||||
|
controller:Any|None
|
||||||
|
|
||||||
for key, controller in subinputs.items():
|
for key, controller in subinputs.items():
|
||||||
if Check.is_mark_key(key) and controller is None:
|
if Check.is_mark_key(key) and controller is None:
|
||||||
continue
|
continue
|
||||||
|
|||||||
@ -33,6 +33,10 @@ class DispatchesManager:
|
|||||||
subinputs:dict[str, Any|None]
|
subinputs:dict[str, Any|None]
|
||||||
|
|
||||||
for subinputs in self.anp.files.load_json(inputs, True):
|
for subinputs in self.anp.files.load_json(inputs, True):
|
||||||
|
|
||||||
|
key:str
|
||||||
|
dispatch:Any|None
|
||||||
|
|
||||||
for key, dispatch in subinputs.items():
|
for key, dispatch in subinputs.items():
|
||||||
if Check.is_mark_key(key) and dispatch is None:
|
if Check.is_mark_key(key) and dispatch is None:
|
||||||
continue
|
continue
|
||||||
|
|||||||
13
Python/AnP/Models/CoordenateModel.py
Normal file
13
Python/AnP/Models/CoordenateModel.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from typing import Self
|
||||||
|
|
||||||
|
class CoordenateModel:
|
||||||
|
|
||||||
|
def __init__(self:Self,
|
||||||
|
x:float|int,
|
||||||
|
y:float|int
|
||||||
|
) -> None:
|
||||||
|
self.x:float|int = x
|
||||||
|
self.y:float|int = y
|
||||||
30
Python/AnP/Models/PositionModel.py
Normal file
30
Python/AnP/Models/PositionModel.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from typing import Self
|
||||||
|
from random import random
|
||||||
|
from AnP.Models.CoordenateModel import CoordenateModel
|
||||||
|
|
||||||
|
class PositionModel(CoordenateModel):
|
||||||
|
|
||||||
|
def __init__(self:Self,
|
||||||
|
x:float|int,
|
||||||
|
y:float|int,
|
||||||
|
size:int|float|list[int|float, int|float]|tuple[int|float, int|float] = 0,
|
||||||
|
margin:int|float|list[int|float, int|float]|tuple[int|float, int|float] = 0
|
||||||
|
) -> None:
|
||||||
|
super().__init__(x, y)
|
||||||
|
self.size:CoordenateModel = CoordenateModel(*(
|
||||||
|
size if isinstance(size, (list, tuple)) else
|
||||||
|
(size, size) if isinstance(size, (int, float)) else
|
||||||
|
(0, 0)))
|
||||||
|
self.margin:CoordenateModel = CoordenateModel(*(
|
||||||
|
margin if isinstance(margin, (list, tuple)) else
|
||||||
|
(margin, margin) if isinstance(margin, (int, float)) else
|
||||||
|
(0, 0)))
|
||||||
|
|
||||||
|
def get(self:Self) -> tuple[float, float]:
|
||||||
|
return (
|
||||||
|
self.x + random() * (self.size.x - 2 * self.margin.x) + self.margin.x,
|
||||||
|
self.y + random() * (self.size.y - 2 * self.margin.y) + self.margin.y
|
||||||
|
)
|
||||||
17
Python/AnP/Models/XMLScrapTabModel.py
Normal file
17
Python/AnP/Models/XMLScrapTabModel.py
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from typing import Self
|
||||||
|
from parsel import Selector
|
||||||
|
|
||||||
|
class XMLScrapTabModel:
|
||||||
|
|
||||||
|
def __init__(self:Self, key:str, url:str) -> None:
|
||||||
|
self.key:str = key
|
||||||
|
self.url:str = url
|
||||||
|
self.data:str = ""
|
||||||
|
self.selector:Selector|None = None
|
||||||
|
|
||||||
|
def set(self:Self, data:str) -> None:
|
||||||
|
self.data = data
|
||||||
|
self.selector = Selector(text = data, type = "xml")
|
||||||
@ -10,7 +10,7 @@ from mimetypes import guess_type as get_mime_by_extension
|
|||||||
from inspect import FrameInfo, stack as get_stack
|
from inspect import FrameInfo, stack as get_stack
|
||||||
from json import dumps as json_encode, loads as json_decode
|
from json import dumps as json_encode, loads as json_decode
|
||||||
from base64 import b64encode as base64_encode, b64decode as base64_decode
|
from base64 import b64encode as base64_encode, b64decode as base64_decode
|
||||||
from random import choice as random_choice
|
from random import choice as random_choice, random as random_number
|
||||||
from AnP.Utils.Checks import Check
|
from AnP.Utils.Checks import Check
|
||||||
from AnP.Utils.Patterns import RE
|
from AnP.Utils.Patterns import RE
|
||||||
|
|
||||||
@ -350,4 +350,12 @@ class Common:
|
|||||||
def random(items:str|Sequence[Any|None]) -> Any|None:
|
def random(items:str|Sequence[Any|None]) -> Any|None:
|
||||||
return random_choice(items) if (
|
return random_choice(items) if (
|
||||||
Check.is_string(items) or Check.is_array(items)
|
Check.is_string(items) or Check.is_array(items)
|
||||||
) and len(items) else None
|
) and len(items) else None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def random_number(minimum:Optional[int|float] = None, maximum:Optional[int|float] = None) -> int|float:
|
||||||
|
if minimum is None:
|
||||||
|
return random_number()
|
||||||
|
if maximum is None:
|
||||||
|
return random_number() * minimum
|
||||||
|
return random_number() * (maximum - minimum) + minimum
|
||||||
@ -8,6 +8,7 @@ from AnP.Drivers.HTTPSocketServerDriver import HTTPSocketServerDriver
|
|||||||
from AnP.Drivers.HTTPServerDriver import HTTPServerDriver
|
from AnP.Drivers.HTTPServerDriver import HTTPServerDriver
|
||||||
from AnP.Drivers.OllamaDriver import OllamaDriver
|
from AnP.Drivers.OllamaDriver import OllamaDriver
|
||||||
from AnP.Drivers.FilesDriver import FilesDriver
|
from AnP.Drivers.FilesDriver import FilesDriver
|
||||||
|
from AnP.Drivers.XMLScrapDriver import XMLScrapDriver
|
||||||
from AnP.Controllers.CloneController import CloneController
|
from AnP.Controllers.CloneController import CloneController
|
||||||
from AnP.Controllers.AITranslateController import AITranslateController
|
from AnP.Controllers.AITranslateController import AITranslateController
|
||||||
|
|
||||||
@ -20,7 +21,8 @@ inputs:dict[str, dict[str, Any|None]] = {
|
|||||||
"HTTPSocketServerDriver" : HTTPSocketServerDriver,
|
"HTTPSocketServerDriver" : HTTPSocketServerDriver,
|
||||||
"HTTPServerDriver" : HTTPServerDriver,
|
"HTTPServerDriver" : HTTPServerDriver,
|
||||||
"OllamaDriver" : OllamaDriver,
|
"OllamaDriver" : OllamaDriver,
|
||||||
"FilesDriver" : FilesDriver
|
"FilesDriver" : FilesDriver,
|
||||||
|
"XMLScrapDriver" : XMLScrapDriver
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user