#wip(py): Scrap system debugging.

This commit is contained in:
KyMAN 2026-07-03 07:30:01 +02:00
parent 306a309df8
commit e3c99a1143
15 changed files with 233 additions and 67 deletions

1
.gitignore vendored
View File

@ -1,5 +1,6 @@
/Data /Data
/Public/data /Public/data
[Ss]ecrets.*
*.[Ss]ecrets.* *.[Ss]ecrets.*
*.[Ss]ecret.* *.[Ss]ecret.*
*.deleted.* *.deleted.*

View File

@ -69,7 +69,12 @@
"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_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_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_browser_action_not_action" : "El elemento '{i}' no es una acción válida en el navegador '{key}'.",
"AnP_BrowserAbstract_end" : null "AnP_BrowserAbstract_end" : null,
"AnP_DirectoryCloneModel_start" : null,
"anp_directory_clone_created" : "El directorio '{directory_name}' ha sido clonado a '{to}'.",
"anp_directory_clone_file_created" : "El archivo '{file_name}' ha sido clonado desde '{from}/{directory_name}' a '{to}/{directory_name}'.",
"AnP_DirectoryCloneModel_end" : null
} }
} }

View File

@ -3,6 +3,7 @@
from typing import Optional, Self, Any, Callable, Sequence, TypeVar from typing import Optional, Self, Any, Callable, Sequence, TypeVar
from abc import abstractmethod from abc import abstractmethod
from time import time as timestamp, sleep
from AnP.Interfaces.Application.AnPInterface import AnPInterface from AnP.Interfaces.Application.AnPInterface import AnPInterface
from AnP.DSLs.ScrapDSL import ( from AnP.DSLs.ScrapDSL import (
Execute, Action, Open, Close, Switch, Wait, Do, Go, Get, ForEach, And, Or, Not, Execute, Action, Open, Close, Switch, Wait, Do, Go, Get, ForEach, And, Or, Not,
@ -36,20 +37,41 @@ class BrowserAbstract(ModelAbstract):
Or : self._or, Or : self._or,
Not : self._not Not : self._not
} }
self.__is_working:dict[str, Callable[[], bool]] = {}
def start(self:Self) -> None: def start(self:Self) -> None:
self.working = True self.working = True
def close(self:Self) -> None: def stop(self:Self) -> None:
self.working = False self.working = False
def remove(self:Self) -> None:
self.stop()
self.tabs.clear() self.tabs.clear()
self.tab_selected = "" self.tab_selected = ""
def is_working(self:Self) -> bool: def is_working(self:Self, shared:Optional[dict[str, Any|None]] = None) -> bool:
return self.working and self.anp.working() return self.working and self.anp.working() and (
shared is None or
"__is_working_key__" not in shared or
shared["__is_working_key__"] not in self.__is_working or
self.__is_working[shared["__is_working_key__"]]()
)
@abstractmethod def run(self:Self,
def run(self:Self, actions:Sequence[Action], shared:dict[str, Any|None] = {}) -> dict[str, Any|None]:pass actions:Sequence[Action],
shared:dict[str, Any|None] = {},
key:Optional[str] = None,
is_working:Optional[Callable[[], bool]] = None
) -> dict[str, Any|None]:
if key is not None and is_working is not None:
self.__is_working[key] = is_working
shared["__is_working_key__"] = key
self.do(Do(*actions), shared)
return shared
def execute(self:Self, action:Execute, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None: def execute(self:Self, action:Execute, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
try: try:
@ -68,13 +90,18 @@ class BrowserAbstract(ModelAbstract):
def switch(self:Self, action:Switch, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:pass 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: 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) date:float = timestamp()
else: time:int|float = (
if action.is_range: action.time if action.is_fixed else
self.anp.wait(Common.random_number(*action.time[0])) Common.random_number(*action.time[0]) if action.is_range else
else: Common.random(*action.time))
self.anp.wait(Common.random(*action.time))
while self.is_working(shared):
sleep(.1)
if timestamp() - date >= time:
break
action.done = True action.done = True
def do(self:Self, action:Do, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None: def do(self:Self, action:Do, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
@ -85,7 +112,7 @@ class BrowserAbstract(ModelAbstract):
action.done = True action.done = True
for i, subaction in enumerate(action.actions): for i, subaction in enumerate(action.actions):
if not self.anp.working(): if not self.is_working(shared):
action.done = False action.done = False
return return
@ -179,7 +206,7 @@ class BrowserAbstract(ModelAbstract):
self.get_selector(action.items, last_item, True) if is_selector else self.get_selector(action.items, last_item, True) if is_selector else
action.items): action.items):
if not self.anp.working(): if not self.is_working(shared):
done = False done = False
break break
@ -291,7 +318,7 @@ class BrowserAbstract(ModelAbstract):
action.condition = Condition((action.condition,)) action.condition = Condition((action.condition,))
while True: while True:
if not self.anp.working(): if not self.is_working(shared):
action.done = False action.done = False
break break
@ -322,7 +349,7 @@ class BrowserAbstract(ModelAbstract):
action.condition = Condition((action.condition,)) action.condition = Condition((action.condition,))
while True: while True:
if not self.anp.working(): if not self.is_working(shared):
action.done = False action.done = False
break break

View File

@ -15,10 +15,10 @@ class FilesAbstract(ABC):
self.anp:AnPInterface = anp self.anp:AnPInterface = anp
root_path:str = directory_name(absolute_path(__file__)) root_path:str = directory_name(absolute_path(__file__))
self._slash:str = Common.get_value("slash", inputs, "/" if "/" in root_path else "\\\\") self._slash:str = Common.get_value("slash", inputs, "/" if "/" in root_path else "\\\\")
self._root_paths:list[str] = Common.get_value( self._root_paths:list[str] = [""] + Common.get_value(
"root_paths", "root_paths",
inputs, inputs,
[""] + self.get_parents(root_path, 4) self.get_parents(root_path, 4)
) )
def set_root_paths(self:Self, paths:str|Sequence[str]) -> None: def set_root_paths(self:Self, paths:str|Sequence[str]) -> None:

View File

@ -42,7 +42,7 @@ class AnP:
def __init__(self:Self, inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None) -> None: def __init__(self:Self, inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None) -> None:
self.__working:bool = True self.__working:bool = True
self.files:FilesAbstract = FilesDriver(self) self.files:FilesAbstract = FilesDriver(self, inputs)
self.settings:SettingsManager = SettingsManager(self, inputs) self.settings:SettingsManager = SettingsManager(self, inputs)
self.i18n:I18NManager = I18NManager(self) self.i18n:I18NManager = I18NManager(self)
self.print_types:PrintTypesManager = PrintTypesManager(self) self.print_types:PrintTypesManager = PrintTypesManager(self)

View File

@ -10,6 +10,7 @@ from selenium.webdriver.common.by import By, ByType
from selenium.webdriver.remote.webdriver import WebDriver, WebElement from selenium.webdriver.remote.webdriver import WebDriver, WebElement
from seleniumwire.utils import decode as sw_decode from seleniumwire.utils import decode as sw_decode
from seleniumwire.request import Request from seleniumwire.request import Request
from selenium.webdriver.common.action_chains import ActionChains
from AnP.DSLs.ScrapDSL import ( from AnP.DSLs.ScrapDSL import (
Open, Close, Switch, Go, Selector, XPath, CSS, Name, LinkText, Class, ID, Open, Close, Switch, Go, Selector, XPath, CSS, Name, LinkText, Class, ID,
Get, Download Get, Download
@ -29,6 +30,12 @@ class SeleniumDriver(BrowserAbstract):
self.__cache_directory:str = self.anp.settings.get(("selenium_cache_directory", "cache_directory"), inputs, "/Data/Cache/Selenium") self.__cache_directory:str = self.anp.settings.get(("selenium_cache_directory", "cache_directory"), inputs, "/Data/Cache/Selenium")
self.__download_timeout:int = self.anp.settings.get(("selenium_download_timeout", "download_timeout"), inputs, 60) self.__download_timeout:int = self.anp.settings.get(("selenium_download_timeout", "download_timeout"), inputs, 60)
def remove(self:Self) -> None:
self.stop()
self.browser and self.browser.quit()
self.tabs.clear()
self.tab_selected = ""
def __load(self:Self, url:str|Callable[[dict[str, Any|None]], str], shared:dict[str, Any|None] = {}) -> None: def __load(self:Self, url:str|Callable[[dict[str, Any|None]], str], shared:dict[str, Any|None] = {}) -> None:
if Check.is_function(url): if Check.is_function(url):
@ -103,13 +110,29 @@ class SeleniumDriver(BrowserAbstract):
shared[action.key] = [] shared[action.key] = []
if multiple: if multiple:
shared[action.key].extend(
[self.get_value(action, element.text) for element in item] if action.attribute == "CDATA" else element:WebElement
[self.get_value(action, element.get_attribute(action.attribute)) for element in item])
for element in item:
ActionChains(self.__browser).move_to_element(element).perform()
shared[action.key].append(element.get_attribute(
"textContent" if action.attribute == "CDATA" else
action.attribute))
else: else:
shared[action.key] = ( ActionChains(self.__browser).move_to_element(item).perform()
self.get_value(action, item.text) if action.attribute == "CDATA" else shared[action.key] = (item.get_attribute(
self.get_value(action, item.get_attribute(action.attribute))) "textContent" if action.attribute == "CDATA" else
action.attribute))
# if multiple:
# shared[action.key].extend(
# [self.get_value(action, element.text) for element in item] if action.attribute == "CDATA" else
# [self.get_value(action, element.get_attribute(action.attribute)) for element in item])
# else:
# shared[action.key] = (
# self.get_value(action, item.text) if action.attribute == "CDATA" else
# self.get_value(action, item.get_attribute(action.attribute)))
action.done = True action.done = True
@ -179,8 +202,15 @@ class SeleniumDriver(BrowserAbstract):
data:bytes|None = method(url) data:bytes|None = method(url)
if data: if data is not None:
if action.key: if action.key:
shared[action.key] = data if action.multiple:
if action.key not in shared:
shared[action.key] = []
shared[action.key].append(data)
else:
shared[action.key] = data
if action.path and (action.overwrite or not self.anp.files.exists(action.path)):
self.anp.files.save(action.path, data)
action.done = True action.done = True
break break

View File

@ -18,12 +18,6 @@ class XMLScrapDriver(BrowserAbstract):
def __init__(self:Self, anp:AnPInterface, key:str, inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None) -> None: 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) 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: def __load(self:Self, url:str) -> Exception|None:
try: try:

View File

@ -2,6 +2,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from typing import Self, Any, Sequence from typing import Self, Any, Sequence
from inspect import isclass
from AnP.Interfaces.Application.AnPInterface import AnPInterface from AnP.Interfaces.Application.AnPInterface import AnPInterface
from AnP.Abstracts.BrowserAbstract import BrowserAbstract from AnP.Abstracts.BrowserAbstract import BrowserAbstract
from AnP.Utils.Checks import Check from AnP.Utils.Checks import Check
@ -30,7 +31,7 @@ class BrowsersManager:
def close(self:Self) -> None: def close(self:Self) -> None:
for key, browser in list(self.__browsers.items()): for key, browser in list(self.__browsers.items()):
browser.close() browser.remove()
del self.__browsers[key] del self.__browsers[key]
def add(self:Self, inputs:Any|None, overwrite:bool = False) -> None: def add(self:Self, inputs:Any|None, overwrite:bool = False) -> None:
@ -48,7 +49,7 @@ class BrowsersManager:
if Check.is_string(browser): if Check.is_string(browser):
BrowserClass = self.anp.models.get(BrowserAbstract, browser) BrowserClass = self.anp.models.get(BrowserAbstract, browser)
elif issubclass(browser, BrowserAbstract): elif isclass(browser) and issubclass(browser, BrowserAbstract):
BrowserClass = browser BrowserClass = browser
elif Check.is_dictionary(browser) and "type" in browser and Check.is_string(browser["type"]): elif Check.is_dictionary(browser) and "type" in browser and Check.is_string(browser["type"]):
BrowserClass = self.anp.models.get(BrowserAbstract, browser["type"]) BrowserClass = self.anp.models.get(BrowserAbstract, browser["type"])

View File

@ -12,6 +12,8 @@ class DirectoriesClonesManager:
self.anp:AnPInterface = anp self.anp:AnPInterface = anp
self.__clones:dict[str, DirectoryCloneModel] = {} self.__clones:dict[str, DirectoryCloneModel] = {}
self.update()
def update(self:Self) -> None: def update(self:Self) -> None:
key:str key:str
@ -53,7 +55,7 @@ class DirectoriesClonesManager:
for key in ( for key in (
keys if Check.is_array(keys) else keys if Check.is_array(keys) else
[keys] if Check.is_string(keys) else [keys] if Check.is_string(keys) else
self.__clones.keys() if keys is None else list(self.__clones.keys()) if keys is None else
[]): []):
self.__clones[key].stop() self.__clones[key].stop()
del self.__clones[key] del self.__clones[key]
@ -65,7 +67,7 @@ class DirectoriesClonesManager:
for key in ( for key in (
keys if Check.is_array(keys) else keys if Check.is_array(keys) else
[keys] if Check.is_string(keys) else [keys] if Check.is_string(keys) else
self.__clones.keys() if keys is None else list(self.__clones.keys()) if keys is None else
[]): []):
self.__clones[key].start() self.__clones[key].start()
@ -76,6 +78,6 @@ class DirectoriesClonesManager:
for key in ( for key in (
keys if Check.is_array(keys) else keys if Check.is_array(keys) else
[keys] if Check.is_string(keys) else [keys] if Check.is_string(keys) else
self.__clones.keys() if keys is None else list(self.__clones.keys()) if keys is None else
[]): []):
self.__clones[key].stop() self.__clones[key].stop()

View File

@ -2,6 +2,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from typing import Self, Any, Sequence, TypeVar from typing import Self, Any, Sequence, TypeVar
from inspect import isclass
from AnP.Interfaces.Application.AnPInterface import AnPInterface from AnP.Interfaces.Application.AnPInterface import AnPInterface
from AnP.Abstracts.ModelAbstract import ModelAbstract from AnP.Abstracts.ModelAbstract import ModelAbstract
from AnP.Utils.Common import Common from AnP.Utils.Common import Common
@ -38,7 +39,7 @@ class ModelsManager:
for key in Common.get_keys(keys): for key in Common.get_keys(keys):
if key in self.__models and ( if key in self.__models and (
isinstance(self.__models[key], Type) or isinstance(self.__models[key], Type) or
issubclass(self.__models[key], Type) (isclass(self.__models[key]) and issubclass(self.__models[key], Type))
): ):
return self.__models[key] return self.__models[key]
return None return None
@ -51,7 +52,7 @@ class ModelsManager:
for key, model in subinputs.items(): for key, model in subinputs.items():
if Check.is_mark_key(key) and model is None: if Check.is_mark_key(key) and model is None:
continue continue
if issubclass(model, ModelAbstract) and ( if isclass(model) and issubclass(model, ModelAbstract) and (
overwrite or key not in self.__models overwrite or key not in self.__models
): ):
self.__models[key] = model self.__models[key] = model

View File

@ -14,9 +14,9 @@ class DirectoryCloneModel:
def __init__(self:Self, anp:AnPInterface, key:str, inputs:dict[str, Any|None]|Sequence[Any|None]) -> None: def __init__(self:Self, anp:AnPInterface, key:str, inputs:dict[str, Any|None]|Sequence[Any|None]) -> None:
self.anp:AnPInterface = anp self.anp:AnPInterface = anp
self.__key:str = key self.__key:str = key
self.__from_path:str = Common.get_value("from_path", inputs) self.__from_path:str = Common.get_value("from", inputs)
self.__to_path:str = Common.get_value("to_path", inputs) self.__to_path:str = Common.get_value("to", inputs)
self.__exceptions:Sequence[str] = Common.get_value("exceptions", inputs, []) self.__exclude:Sequence[str] = Common.get_value("exclude", inputs, [])
self.__time_refresh:float|int = Common.get_value("time_refresh", inputs, 5) self.__time_refresh:float|int = Common.get_value("time_refresh", inputs, 5)
self.__module:str|None = Common.get_value("module", inputs) self.__module:str|None = Common.get_value("module", inputs)
self.__working:bool = False self.__working:bool = False
@ -34,6 +34,8 @@ class DirectoryCloneModel:
self.__to_path = module_path + "/" + self.__to_path self.__to_path = module_path + "/" + self.__to_path
break break
Common.get_value("autorun", inputs, True) and self.start()
def is_working(self:Self) -> bool: def is_working(self:Self) -> bool:
return self.__working and self.anp.working() return self.__working and self.anp.working()
@ -41,8 +43,11 @@ class DirectoryCloneModel:
file_name:str file_name:str
if self.anp.files.exists(self.__to_path + "/" + path): to_path:str = self.__to_path + ("/" + path if path else "")
self.anp.files.make_directory(self.__to_path + "/" + path) from_path:str = self.__from_path + ("/" + path if path else "")
if not self.anp.files.exists(to_path):
self.anp.files.make_directory(to_path)
self.__print_changes and self.anp.print("info", "anp_directory_clone_created", { self.__print_changes and self.anp.print("info", "anp_directory_clone_created", {
"key" : self.__key, "key" : self.__key,
"directory_name" : path, "directory_name" : path,
@ -50,37 +55,37 @@ class DirectoryCloneModel:
"to" : self.__to_path "to" : self.__to_path
}) })
for file_name in self.anp.files.list_directory_items(self.__from_path + "/" + path): for file_name in self.anp.files.list_directory_items(from_path):
if not self.is_working(): if not self.is_working():
break break
if file_name in (".", ".."): if file_name in (".", ".."):
continue continue
from_path:str = self.__from_path + "/" + path + "/" + file_name from_path_file:str = from_path + "/" + file_name
if any(exception in from_path for exception in self.__exceptions): if any(exception in path for exception in self.__exclude):
continue continue
if self.anp.files.is_directory(from_path): if self.anp.files.is_directory(from_path_file):
self.__analyze(path + "/" + file_name) self.__analyze((path + "/" if path else "") + file_name)
elif self.anp.files.is_file(from_path): elif self.anp.files.is_file(from_path_file):
data:bytes = self.anp.files.load(from_path, "rb") data:bytes = self.anp.files.load(from_path_file, "rb")
from_hash:HashModel = hash(data) from_hash:HashModel = HashModel(data)
to_path:str = self.__to_path + "/" + path + "/" + file_name to_path_file:str = to_path + "/" + file_name
if self.anp.files.exists(to_path): if self.anp.files.exists(to_path_file):
if to_path not in self.__cache: if to_path_file not in self.__cache:
self.__cache[to_path] = HashModel(self.anp.files.load(to_path, "rb")) self.__cache[to_path_file] = HashModel(self.anp.files.load(to_path_file, "rb"))
if from_hash.compare(self.__cache[to_path]): if from_hash.compare(self.__cache[to_path_file]):
continue continue
self.__cache[to_path] = from_hash self.__cache[to_path_file] = from_hash
self.anp.files.save(to_path, data) self.anp.files.save(to_path_file, data)
self.__print_changes and self.anp.print("info", "anp_directory_clone_file_created", { self.__print_changes and self.anp.print("info", "anp_directory_clone_file_created", {
"key" : self.__key, "key" : self.__key,
"directory_name" : path, "directory_name" : path,
"from_directory" : self.__from_path, "from" : self.__from_path,
"to_directory" : self.__to_path, "to" : self.__to_path,
"file_name" : file_name "file_name" : file_name
}) })

View File

@ -19,4 +19,4 @@ class RE:
DOUBLE_NEW_LINE:REPattern = re_compile(r'(?:\r\n){2}|\r{2}|\n{2}') DOUBLE_NEW_LINE:REPattern = re_compile(r'(?:\r\n){2}|\r{2}|\n{2}')
HTTP_HEADER_PARAMETER:REPattern = re_compile(r'([^:]+):\s*(.+)') HTTP_HEADER_PARAMETER:REPattern = re_compile(r'([^:]+):\s*(.+)')
HTTP_REQUEST:REPattern = re_compile(r'^([^\s]+)\s([^\s\?\#]+)(?:\?([^#]+))?(?:\#([^\s]+))?\s([^\/]+)\/([0-9\.]+)$') HTTP_REQUEST:REPattern = re_compile(r'^([^\s]+)\s([^\s\?\#]+)(?:\?([^#]+))?(?:\#([^\s]+))?\s([^\/]+)\/([0-9\.]+)$')
PYTHON_MODULES_PATH:REPattern = re_compile(r'[\/\\]python[0-9]+[\/\\]site-packages[\/\\]?$', RE_IGNORECASE) PYTHON_MODULES_PATH:REPattern = re_compile(r'[\/\\]python[0-9\.]+[\/\\]site-packages[\/\\]?$', RE_IGNORECASE)

View File

@ -9,6 +9,7 @@ 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.Drivers.XMLScrapDriver import XMLScrapDriver
from AnP.Drivers.SeleniumDriver import SeleniumDriver
from AnP.Controllers.CloneController import CloneController from AnP.Controllers.CloneController import CloneController
from AnP.Controllers.AITranslateController import AITranslateController from AnP.Controllers.AITranslateController import AITranslateController
@ -22,7 +23,8 @@ inputs:dict[str, dict[str, Any|None]] = {
"HTTPServerDriver" : HTTPServerDriver, "HTTPServerDriver" : HTTPServerDriver,
"OllamaDriver" : OllamaDriver, "OllamaDriver" : OllamaDriver,
"FilesDriver" : FilesDriver, "FilesDriver" : FilesDriver,
"XMLScrapDriver" : XMLScrapDriver "XMLScrapDriver" : XMLScrapDriver,
"SeleniumDriver" : SeleniumDriver
} }
} }

View File

@ -6,4 +6,4 @@ from base import inputs
anp:AnP = AnP(inputs) anp:AnP = AnP(inputs)
anp.controllers.execute("clonations_processes", "execute", None) # anp.controllers.execute("clonations_processes", "execute", None)

100
README.md
View File

@ -1,3 +1,101 @@
# AnP # AnP
Framework. Framework.
Secrets Python file:
```py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# /Python/secrets.py
from typing import Any
secrets:dict[str, Any|None] = {
"root_paths" : ["/ABSOLUTE/PATH/AnP"]
}
```
Web Socket Server Settings:
```json
{
"default_web_sockets_servers" : {
"anp" : {
"type" : "WebSocketServerDriver",
"host" : "",
"port" : 18765
}
}
}
```
HTTP Settings:
```json
{
"default_http_servers" : {
"anp" : {
"type" : "HTTPServerDriver",
"type2" : "HTTPSocketServerDriver",
"host" : "",
"port" : 18000
}
}
}
```
AI Interpreters Settings:
```json
{
"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
}
}
}
```
Directory Cloner Settings:
```json
{
"default_directories_clones_files" : {
"anp" : {
"from" : "/ABSOLUTE/PATH/AnP/Python/AnP",
"to" : "AnP",
"exclude" : ["__pycache__", "deleted", "secret", ".pyc"],
"time_refresh" : 5,
"module" : "python",
"autorun" : true,
"print_changes" : true
}
}
}
```