ws-bom-robot-app 0.0.14__py3-none-any.whl → 0.0.16__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ws_bom_robot_app/llm/agent_lcel.py +3 -5
- ws_bom_robot_app/llm/main.py +6 -1
- ws_bom_robot_app/llm/tools/tool_manager.py +15 -2
- ws_bom_robot_app/llm/tools/utils.py +6 -3
- ws_bom_robot_app/llm/utils/agent_utils.py +1 -1
- ws_bom_robot_app/main.py +52 -3
- ws_bom_robot_app/task_manager.py +1 -1
- {ws_bom_robot_app-0.0.14.dist-info → ws_bom_robot_app-0.0.16.dist-info}/METADATA +28 -5
- {ws_bom_robot_app-0.0.14.dist-info → ws_bom_robot_app-0.0.16.dist-info}/RECORD +11 -11
- {ws_bom_robot_app-0.0.14.dist-info → ws_bom_robot_app-0.0.16.dist-info}/WHEEL +0 -0
- {ws_bom_robot_app-0.0.14.dist-info → ws_bom_robot_app-0.0.16.dist-info}/top_level.txt +0 -0
|
@@ -53,11 +53,9 @@ class AgentLcel:
|
|
|
53
53
|
def __create_agent(self):
|
|
54
54
|
agent: Any = (
|
|
55
55
|
{
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
),
|
|
60
|
-
"chat_history": lambda x: x["chat_history"],
|
|
56
|
+
"input": lambda x: x["input"],
|
|
57
|
+
"agent_scratchpad": lambda x: format_to_openai_tool_messages(x["intermediate_steps"]),
|
|
58
|
+
"chat_history": lambda x: x["chat_history"],
|
|
61
59
|
}
|
|
62
60
|
| RunnableLambda(self.__create_prompt)
|
|
63
61
|
| self.__llm_with_tools
|
ws_bom_robot_app/llm/main.py
CHANGED
|
@@ -24,7 +24,12 @@ async def invoke(rq: InvokeRequest) -> str:
|
|
|
24
24
|
|
|
25
25
|
async def __stream(rq: StreamRequest,formatted: bool = True) -> None:
|
|
26
26
|
await rq.initialize()
|
|
27
|
-
|
|
27
|
+
if formatted:
|
|
28
|
+
agent_handler = AgentHandler(rq.thread_id)
|
|
29
|
+
else:
|
|
30
|
+
agent_handler = RawAgentHandler()
|
|
31
|
+
os.environ["AGENT_HANDLER_FORMATTED"] = str(formatted)
|
|
32
|
+
callbacks: List[AsyncCallbackHandler] = [agent_handler]
|
|
28
33
|
settings.init()
|
|
29
34
|
|
|
30
35
|
#CREATION OF CHAT HISTORY FOR AGENT
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Optional, Type
|
|
1
|
+
from typing import Optional, Type, Callable
|
|
2
2
|
from ws_bom_robot_app.llm.models.api import LlmAppTool
|
|
3
3
|
from ws_bom_robot_app.llm.utils.faiss_helper import FaissHelper
|
|
4
4
|
from ws_bom_robot_app.llm.tools.utils import getRandomWaitingMessage, translate_text
|
|
@@ -7,13 +7,26 @@ from pydantic import BaseModel, ConfigDict
|
|
|
7
7
|
from langchain_community.utilities.dalle_image_generator import DallEAPIWrapper
|
|
8
8
|
|
|
9
9
|
class ToolConfig(BaseModel):
|
|
10
|
-
function:
|
|
10
|
+
function: Callable
|
|
11
11
|
model: Optional[Type[BaseModel]] = None
|
|
12
12
|
model_config = ConfigDict(
|
|
13
13
|
arbitrary_types_allowed=True
|
|
14
14
|
)
|
|
15
15
|
|
|
16
16
|
class ToolManager:
|
|
17
|
+
"""
|
|
18
|
+
ToolManager is responsible for managing various tools used in the application.
|
|
19
|
+
|
|
20
|
+
Attributes:
|
|
21
|
+
app_tool (LlmAppTool): The application tool configuration.
|
|
22
|
+
api_key (str): The API key for accessing external services.
|
|
23
|
+
callbacks (list): A list of callback functions to be executed.
|
|
24
|
+
|
|
25
|
+
Methods:
|
|
26
|
+
document_retriever(query: str): Asynchronously retrieves documents based on the query.
|
|
27
|
+
image_generator(query: str, language: str = "it"): Asynchronously generates an image based on the query.
|
|
28
|
+
get_coroutine(): Retrieves the coroutine function based on the tool configuration.
|
|
29
|
+
"""
|
|
17
30
|
|
|
18
31
|
def __init__(
|
|
19
32
|
self,
|
|
@@ -1,20 +1,23 @@
|
|
|
1
|
-
import random
|
|
1
|
+
import random, os
|
|
2
2
|
from langchain_openai import ChatOpenAI
|
|
3
3
|
from langchain_core.prompts import PromptTemplate
|
|
4
4
|
from ws_bom_robot_app.llm.utils.print import printString
|
|
5
5
|
|
|
6
|
+
def __print_output(data: str) -> None:
|
|
7
|
+
printString(data) if os.environ.get("AGENT_HANDLER_FORMATTED") == str(True) else print(f"{data} ")
|
|
8
|
+
|
|
6
9
|
def getRandomWaitingMessage(waiting_messages: str, traduction: bool = True) -> str:
|
|
7
10
|
if not waiting_messages: return ""
|
|
8
11
|
messages = [msg.strip() for msg in waiting_messages.split(";") if msg.strip()]
|
|
9
12
|
if not messages: return ""
|
|
10
13
|
chosen_message = random.choice(messages) + "\n"
|
|
11
14
|
if not traduction:
|
|
12
|
-
|
|
15
|
+
__print_output(chosen_message)
|
|
13
16
|
return chosen_message
|
|
14
17
|
|
|
15
18
|
async def translate_text(api_key, language, text: str, callbacks: list) -> str:
|
|
16
19
|
if language == "it":
|
|
17
|
-
|
|
20
|
+
__print_output(text)
|
|
18
21
|
return
|
|
19
22
|
llm = ChatOpenAI(api_key=api_key, model="gpt-3.5-turbo-0125", streaming=True)
|
|
20
23
|
sys_message = """Il tuo compito è di tradurre il testo_da_tradure nella seguente lingua: \n\n lingua: {language}\n\n testo_da_tradure: {testo_da_tradure} \n\nTraduci il testo_da_tradure nella lingua {language} senza aggiungere altro:"""
|
|
@@ -5,7 +5,7 @@ from ws_bom_robot_app.llm.utils.faiss_helper import FaissHelper
|
|
|
5
5
|
|
|
6
6
|
async def get_rules(rules: LlmRules, api_key:str, input: str) -> str:
|
|
7
7
|
with HiddenPrints():
|
|
8
|
-
if any([input=="",rules is None,rules.vector_db == "",not os.path.exists(rules.vector_db)]):
|
|
8
|
+
if any([input=="",rules is None,rules and rules.vector_db == "",rules and not os.path.exists(rules.vector_db)]):
|
|
9
9
|
return ""
|
|
10
10
|
rules_prompt = ""
|
|
11
11
|
rules_doc = await FaissHelper.invoke(rules.vector_db,api_key,input,search_type="similarity_score_threshold", search_kwargs={"score_threshold": rules.threshold}) #type: ignore
|
ws_bom_robot_app/main.py
CHANGED
|
@@ -38,14 +38,45 @@ async def openapi(authenticate: bool = Depends(authenticate)):
|
|
|
38
38
|
@app.get("/api/health",tags=["diag"])
|
|
39
39
|
def health():
|
|
40
40
|
return {"status": "ok"}
|
|
41
|
-
|
|
41
|
+
def __get_size(bytes, suffix="B"):
|
|
42
|
+
"""
|
|
43
|
+
Scale bytes to its proper format
|
|
44
|
+
e.g:
|
|
45
|
+
1253656 => '1.20MB'
|
|
46
|
+
1253656678 => '1.17GB'
|
|
47
|
+
"""
|
|
48
|
+
factor = 1024
|
|
49
|
+
for unit in ["", "K", "M", "G", "T", "P"]:
|
|
50
|
+
if bytes < factor:
|
|
51
|
+
return f"{bytes:.2f}{unit}{suffix}"
|
|
52
|
+
bytes /= factor
|
|
53
|
+
def __get_disk_info():
|
|
54
|
+
import psutil
|
|
55
|
+
partitions = psutil.disk_partitions()
|
|
56
|
+
_disks:list = []
|
|
57
|
+
for partition in partitions:
|
|
58
|
+
device = partition.device
|
|
59
|
+
mountpoint = partition.mountpoint
|
|
60
|
+
fstype = partition.fstype
|
|
61
|
+
try:
|
|
62
|
+
usage = psutil.disk_usage(mountpoint)
|
|
63
|
+
except PermissionError:
|
|
64
|
+
continue
|
|
65
|
+
total = __get_size(usage.total)
|
|
66
|
+
used = __get_size(usage.used)
|
|
67
|
+
free = __get_size(usage.free)
|
|
68
|
+
percent = f"{usage.percent}%"
|
|
69
|
+
_disks.append({"device": device, "mountpoint": mountpoint, "fstype": fstype, "total": total, "used": used, "free": free, "percent": percent})
|
|
70
|
+
return _disks
|
|
42
71
|
@app.get("/api/diag",tags=["diag"])
|
|
43
72
|
def diag(authenticate: bool = Depends(authenticate)):
|
|
44
|
-
import pkg_resources
|
|
73
|
+
import pkg_resources, psutil
|
|
45
74
|
from ws_bom_robot_app.llm.vector_store.loader.base import Loader as wsll
|
|
46
75
|
from ws_bom_robot_app.llm.vector_store.integration.manager import IntegrationManager as wsim
|
|
47
76
|
from ws_bom_robot_app.llm.tools.tool_manager import ToolManager as wstm
|
|
48
77
|
from ws_bom_robot_app.llm.agent_description import AgentDescriptor as wsad
|
|
78
|
+
svmem = psutil.virtual_memory()
|
|
79
|
+
swap = psutil.swap_memory()
|
|
49
80
|
return {
|
|
50
81
|
"status":"ok",
|
|
51
82
|
"uptime": {'from':_uptime,'elapsed':str(datetime.datetime.now()-_uptime)},
|
|
@@ -56,9 +87,27 @@ def diag(authenticate: bool = Depends(authenticate)):
|
|
|
56
87
|
"version": platform.version(),
|
|
57
88
|
"type": platform.machine(),
|
|
58
89
|
"processor": platform.processor(),
|
|
59
|
-
"cpu": os.cpu_count(),
|
|
60
90
|
"architecture": platform.architecture()
|
|
61
91
|
},
|
|
92
|
+
"cpu": {
|
|
93
|
+
"physical_core": psutil.cpu_count(logical=False),
|
|
94
|
+
"total_core": psutil.cpu_count(logical=True),
|
|
95
|
+
"load": f"{psutil.cpu_percent(interval=1)}%"
|
|
96
|
+
},
|
|
97
|
+
"memory": {
|
|
98
|
+
"total": f"{__get_size(svmem.total)}",
|
|
99
|
+
"available": f"{__get_size(svmem.available)}",
|
|
100
|
+
"used": f"{__get_size(svmem.used)}",
|
|
101
|
+
"free": f"{__get_size(svmem.free)}",
|
|
102
|
+
"percent": f"{svmem.percent}%"
|
|
103
|
+
},
|
|
104
|
+
"swap": {
|
|
105
|
+
"total": f"{__get_size(swap.total)}",
|
|
106
|
+
"used": f"{__get_size(swap.used)}",
|
|
107
|
+
"free": f"{__get_size(swap.free)}",
|
|
108
|
+
"percent": f"{swap.percent}%"
|
|
109
|
+
},
|
|
110
|
+
"disk": __get_disk_info(),
|
|
62
111
|
"sys": {
|
|
63
112
|
"version": sys.version,
|
|
64
113
|
"platform": sys.platform,
|
ws_bom_robot_app/task_manager.py
CHANGED
|
@@ -133,7 +133,7 @@ class TaskStatistics(BaseModel):
|
|
|
133
133
|
|
|
134
134
|
#region interface
|
|
135
135
|
class TaskManagerStrategy(ABC):
|
|
136
|
-
def __init__(self, max_concurrent_tasks: int = floor(config.robot_task_max_total_parallelism / config.runtime_options().number_of_workers)):
|
|
136
|
+
def __init__(self, max_concurrent_tasks: int = max(1,floor(config.robot_task_max_total_parallelism / config.runtime_options().number_of_workers))):
|
|
137
137
|
self.max_concurrent_tasks = max_concurrent_tasks
|
|
138
138
|
self.semaphore = asyncio.Semaphore(self.max_concurrent_tasks)
|
|
139
139
|
self.running_tasks = dict[str, TaskEntry]()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ws_bom_robot_app
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.16
|
|
4
4
|
Summary: A FastAPI application serving ws bom/robot/llm platform ai.
|
|
5
5
|
Home-page: https://github.com/websolutespa/bom
|
|
6
6
|
Author: Websolute Spa
|
|
@@ -13,8 +13,8 @@ Description-Content-Type: text/markdown
|
|
|
13
13
|
Requires-Dist: standardwebhooks==1.0.0
|
|
14
14
|
Requires-Dist: apscheduler==3.11.0
|
|
15
15
|
Requires-Dist: aiofiles==24.1.0
|
|
16
|
-
Requires-Dist: pydantic==2.
|
|
17
|
-
Requires-Dist: pydantic-settings==2.6.
|
|
16
|
+
Requires-Dist: pydantic==2.10.3
|
|
17
|
+
Requires-Dist: pydantic-settings==2.6.1
|
|
18
18
|
Requires-Dist: fastapi[standard]==0.115.5
|
|
19
19
|
Requires-Dist: langchain==0.3.9
|
|
20
20
|
Requires-Dist: langchain-openai==0.2.10
|
|
@@ -23,7 +23,6 @@ Requires-Dist: langchain-core==0.3.21
|
|
|
23
23
|
Requires-Dist: faiss-cpu==1.9.0
|
|
24
24
|
Requires-Dist: python-magic==0.4.27
|
|
25
25
|
Requires-Dist: opencv-python-headless==4.10.0.84
|
|
26
|
-
Requires-Dist: jmespath==1.0.1
|
|
27
26
|
Requires-Dist: unstructured[all-docs]==0.15.14
|
|
28
27
|
Requires-Dist: langchain_unstructured==0.1.5
|
|
29
28
|
Requires-Dist: html5lib==1.1
|
|
@@ -174,7 +173,31 @@ py -m pip install --upgrade -e .
|
|
|
174
173
|
py -m pip show ws-bom-robot-app
|
|
175
174
|
```
|
|
176
175
|
|
|
177
|
-
|
|
176
|
+
code quality tools
|
|
177
|
+
|
|
178
|
+
```pwsh
|
|
179
|
+
# .\src\robot
|
|
180
|
+
!py -m pip install -U scanreq prospector[with_everything]
|
|
181
|
+
## unused requirements
|
|
182
|
+
scanreq -r requirements.txt -p ./ws_bom_robot_app
|
|
183
|
+
## style/linting
|
|
184
|
+
prospector ./ws_bom_robot_app -t pylint -t pydocstyle
|
|
185
|
+
## code quality/complexity
|
|
186
|
+
prospector ./ws_bom_robot_app -t vulture -t mccabe -t mypy
|
|
187
|
+
## security
|
|
188
|
+
prospector ./ws_bom_robot_app -t dodgy -t bandit
|
|
189
|
+
## package
|
|
190
|
+
prospector ./ws_bom_robot_app -t pyroma
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
lauch pytest
|
|
194
|
+
|
|
195
|
+
```pwsh
|
|
196
|
+
!py -m pip install -U pytest pytest-asyncio pytest-mock pytest-cov
|
|
197
|
+
pytest --cov=ws_bom_robot_app --log-cli-level=info
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
launch debugger
|
|
178
201
|
|
|
179
202
|
```pwsh
|
|
180
203
|
streamlit run debugger.py --server.port 6002
|
|
@@ -2,16 +2,16 @@ ws_bom_robot_app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,
|
|
|
2
2
|
ws_bom_robot_app/auth.py,sha256=84nIbmJsMrNs0sxIQGEHbjsjc2P6ZrZZGSn8dkiL6is,895
|
|
3
3
|
ws_bom_robot_app/config.py,sha256=V5ZrX_JnzpsN32hTTezTfOvEZYkIQBy0lxIQ9JFHdFE,3170
|
|
4
4
|
ws_bom_robot_app/cron_manager.py,sha256=0Yt5AMTPGlXZ_M5ck0SKMX8wvzoPsseEezg_s0Q3HKY,9224
|
|
5
|
-
ws_bom_robot_app/main.py,sha256=
|
|
6
|
-
ws_bom_robot_app/task_manager.py,sha256=
|
|
5
|
+
ws_bom_robot_app/main.py,sha256=PkWGkBYXCEPBxPUGsaq-Wvdcy7CkTL_0wNeE0s7MGwc,5814
|
|
6
|
+
ws_bom_robot_app/task_manager.py,sha256=vHN2jzFdFDviCg1PDPaZUWeF6dil4ZQIxfsKByPos3k,15943
|
|
7
7
|
ws_bom_robot_app/util.py,sha256=3aBK-bhsvKJwJeWOHh0c1B1BOyJ_tnUxOa1mJmFKwYQ,2618
|
|
8
8
|
ws_bom_robot_app/llm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
9
|
ws_bom_robot_app/llm/agent_description.py,sha256=SDJYMmwfdMxEK3a_HDEQ19bfNKmwMSFf5hqU0VSCCIE,4705
|
|
10
10
|
ws_bom_robot_app/llm/agent_handler.py,sha256=hbOf9i-ynDL3bcClqtUG-yWY8ohbCxONfT5ek9Cv0gY,5667
|
|
11
|
-
ws_bom_robot_app/llm/agent_lcel.py,sha256=
|
|
11
|
+
ws_bom_robot_app/llm/agent_lcel.py,sha256=jkSLMy6y_ZFvWT8bhBBYHY5CO-ea8oMSPMXMahFUBFc,2666
|
|
12
12
|
ws_bom_robot_app/llm/api.py,sha256=5cO49yhU5EXvl20zJORmrZZPc1G_nlvftdcF7cyn4Qc,3252
|
|
13
13
|
ws_bom_robot_app/llm/defaut_prompt.py,sha256=pn5a4lNLWE1NngHYjA_7tD8GasePMgsgude5fIJxsW0,756
|
|
14
|
-
ws_bom_robot_app/llm/main.py,sha256=
|
|
14
|
+
ws_bom_robot_app/llm/main.py,sha256=oD8dPvoEYD2MK8dU8tjdqBmPxxBcILSSPkQzNlMGayk,3712
|
|
15
15
|
ws_bom_robot_app/llm/settings.py,sha256=EkFGCppORenStH9W4e6_dYvQ-5p6xiEMpmUHBqNqG9M,117
|
|
16
16
|
ws_bom_robot_app/llm/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
17
|
ws_bom_robot_app/llm/models/api.py,sha256=KlVUbApyz6uuWefAN9K4B_vWDSps5hLW6hNg1Eo3TBQ,6996
|
|
@@ -19,12 +19,12 @@ ws_bom_robot_app/llm/models/base.py,sha256=1TqxuTK3rjJEALn7lvgoen_1ba3R2brAgGx6E
|
|
|
19
19
|
ws_bom_robot_app/llm/models/kb.py,sha256=9zqwDlVULVrWE48wo5AivzWoOtnjA57k9rsw8KNnyDk,8935
|
|
20
20
|
ws_bom_robot_app/llm/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
21
21
|
ws_bom_robot_app/llm/tools/tool_builder.py,sha256=rkYu0PrXV84PMi7INjCSWlrWMykUCI8aeF-QjZgLysM,854
|
|
22
|
-
ws_bom_robot_app/llm/tools/tool_manager.py,sha256=
|
|
23
|
-
ws_bom_robot_app/llm/tools/utils.py,sha256=
|
|
22
|
+
ws_bom_robot_app/llm/tools/tool_manager.py,sha256=ZRUzSIrHKrJANc7hrp7st8qRZiy_S-_aN8fIgk7g0U8,4353
|
|
23
|
+
ws_bom_robot_app/llm/tools/utils.py,sha256=1uOJGcFKiIDOipLCokEMdlxJLRQpgpOavm1g5-FLjMU,1307
|
|
24
24
|
ws_bom_robot_app/llm/tools/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
25
25
|
ws_bom_robot_app/llm/tools/models/main.py,sha256=LsOJ7vkcSzYLoE1oa3TG0Rs0pr9J5VS_e4li6aDx_fw,260
|
|
26
26
|
ws_bom_robot_app/llm/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
27
|
-
ws_bom_robot_app/llm/utils/agent_utils.py,sha256=
|
|
27
|
+
ws_bom_robot_app/llm/utils/agent_utils.py,sha256=LEfAKQwFrwmIdJL0o54iuGrir9uLcJhkciLL3R6Xqwo,814
|
|
28
28
|
ws_bom_robot_app/llm/utils/download.py,sha256=iAUxH_NiCpTPtGzhC4hBtxotd2HPFt2MBhttslIxqiI,3194
|
|
29
29
|
ws_bom_robot_app/llm/utils/faiss_helper.py,sha256=DowmroVT6eIbvnA-TG84PS_D7ujvxSRIKdLuIcJmd6Q,4650
|
|
30
30
|
ws_bom_robot_app/llm/utils/kb.py,sha256=jja45WCbNI7SGEgqDS99nErlwB5eY8Ga7BMnhdMHZ90,1279
|
|
@@ -39,7 +39,7 @@ ws_bom_robot_app/llm/vector_store/integration/sitemap.py,sha256=nPbIywp-ZwWbWStv
|
|
|
39
39
|
ws_bom_robot_app/llm/vector_store/loader/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
40
40
|
ws_bom_robot_app/llm/vector_store/loader/base.py,sha256=dhZ7F4EJmuYa2TBMggWVpQe4_NmS2wi312lHnNm5Jm0,4571
|
|
41
41
|
ws_bom_robot_app/llm/vector_store/loader/json_loader.py,sha256=qo9ejRZyKv_k6jnGgXnu1W5uqsMMtgqK_uvPpZQ0p74,833
|
|
42
|
-
ws_bom_robot_app-0.0.
|
|
43
|
-
ws_bom_robot_app-0.0.
|
|
44
|
-
ws_bom_robot_app-0.0.
|
|
45
|
-
ws_bom_robot_app-0.0.
|
|
42
|
+
ws_bom_robot_app-0.0.16.dist-info/METADATA,sha256=nZX2UZefJOJ6oQKd6OVC6g7tOeKYPZ1ALCmTH2fSYLY,6443
|
|
43
|
+
ws_bom_robot_app-0.0.16.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
|
44
|
+
ws_bom_robot_app-0.0.16.dist-info/top_level.txt,sha256=Yl0akyHVbynsBX_N7wx3H3ZTkcMLjYyLJs5zBMDAKcM,17
|
|
45
|
+
ws_bom_robot_app-0.0.16.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|