ws-bom-robot-app 0.0.67__tar.gz → 0.0.69__tar.gz

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.
Files changed (82) hide show
  1. {ws_bom_robot_app-0.0.67/ws_bom_robot_app.egg-info → ws_bom_robot_app-0.0.69}/PKG-INFO +11 -5
  2. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/README.md +10 -4
  3. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/setup.py +1 -1
  4. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/config.py +7 -7
  5. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/agent_description.py +123 -123
  6. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/agent_handler.py +177 -177
  7. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/agent_lcel.py +45 -45
  8. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/defaut_prompt.py +15 -15
  9. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/feedbacks/feedback_manager.py +66 -66
  10. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/main.py +138 -138
  11. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/models/feedback.py +30 -30
  12. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/nebuly_handler.py +181 -181
  13. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/providers/llm_manager.py +3 -3
  14. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/settings.py +4 -4
  15. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/tools/tool_builder.py +65 -65
  16. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/tools/tool_manager.py +330 -317
  17. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/tools/utils.py +41 -41
  18. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/utils/agent.py +34 -34
  19. ws_bom_robot_app-0.0.69/ws_bom_robot_app/llm/utils/cms.py +109 -0
  20. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/utils/download.py +79 -79
  21. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/utils/print.py +29 -29
  22. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/vector_store/generator.py +137 -137
  23. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/vector_store/integration/manager.py +2 -2
  24. ws_bom_robot_app-0.0.69/ws_bom_robot_app/llm/vector_store/integration/thron.py +123 -0
  25. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/vector_store/loader/json_loader.py +25 -25
  26. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69/ws_bom_robot_app.egg-info}/PKG-INFO +11 -5
  27. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app.egg-info/SOURCES.txt +1 -0
  28. ws_bom_robot_app-0.0.67/ws_bom_robot_app/llm/utils/cms.py +0 -77
  29. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/MANIFEST.in +0 -0
  30. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/pyproject.toml +0 -0
  31. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/requirements.txt +0 -0
  32. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/setup.cfg +0 -0
  33. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/__init__.py +0 -0
  34. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/auth.py +0 -0
  35. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/cron_manager.py +0 -0
  36. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/__init__.py +0 -0
  37. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/agent_context.py +0 -0
  38. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/api.py +0 -0
  39. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/feedbacks/__init__.py +0 -0
  40. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/models/__init__.py +0 -0
  41. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/models/api.py +0 -0
  42. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/models/base.py +0 -0
  43. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/models/kb.py +0 -0
  44. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/providers/__init__.py +0 -0
  45. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/tools/__init__.py +0 -0
  46. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/tools/models/__init__.py +0 -0
  47. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/tools/models/main.py +0 -0
  48. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/utils/__init__.py +0 -0
  49. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/utils/chunker.py +0 -0
  50. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/utils/kb.py +0 -0
  51. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/utils/secrets.py +0 -0
  52. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/utils/webhooks.py +0 -0
  53. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/vector_store/__init__.py +0 -0
  54. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/vector_store/db/__init__.py +0 -0
  55. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/vector_store/db/base.py +0 -0
  56. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/vector_store/db/chroma.py +0 -0
  57. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/vector_store/db/faiss.py +0 -0
  58. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/vector_store/db/manager.py +0 -0
  59. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/vector_store/db/qdrant.py +0 -0
  60. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/vector_store/integration/__init__.py +0 -0
  61. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/vector_store/integration/azure.py +0 -0
  62. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/vector_store/integration/base.py +0 -0
  63. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/vector_store/integration/confluence.py +0 -0
  64. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/vector_store/integration/dropbox.py +0 -0
  65. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/vector_store/integration/gcs.py +0 -0
  66. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/vector_store/integration/github.py +0 -0
  67. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/vector_store/integration/googledrive.py +0 -0
  68. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/vector_store/integration/jira.py +0 -0
  69. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/vector_store/integration/s3.py +0 -0
  70. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/vector_store/integration/sftp.py +0 -0
  71. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/vector_store/integration/sharepoint.py +0 -0
  72. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/vector_store/integration/sitemap.py +0 -0
  73. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/vector_store/integration/slack.py +0 -0
  74. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/vector_store/loader/__init__.py +0 -0
  75. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/vector_store/loader/base.py +0 -0
  76. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/llm/vector_store/loader/docling.py +0 -0
  77. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/main.py +0 -0
  78. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/task_manager.py +0 -0
  79. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app/util.py +0 -0
  80. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app.egg-info/dependency_links.txt +0 -0
  81. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app.egg-info/requires.txt +0 -0
  82. {ws_bom_robot_app-0.0.67 → ws_bom_robot_app-0.0.69}/ws_bom_robot_app.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ws_bom_robot_app
3
- Version: 0.0.67
3
+ Version: 0.0.69
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
@@ -244,7 +244,7 @@ pytest --cov=ws_bom_robot_app --log-cli-level=info
244
244
  launch debugger
245
245
 
246
246
  ```pwsh
247
- streamlit run debugger.py --server.port 6011
247
+ streamlit run debugger.py --server.port 8051
248
248
  ```
249
249
 
250
250
  dockerize base image
@@ -258,11 +258,17 @@ docker build -f Dockerfile-robot-base-gpu -t ghcr.io/websolutespa/ws-bom-robot-b
258
258
  docker push ghcr.io/websolutespa/ws-bom-robot-base:gpu
259
259
  ```
260
260
 
261
- dockerize app from src
261
+ dockerize app
262
262
 
263
263
  ```pwsh
264
- docker build -f Dockerfile-src -t ws-bom-robot-app:src .
265
- docker run --name ws-bom-robot-app-src -d -v "$(pwd)/ws_bom_robot_app:/app/ws_bom_robot_app" -v "$(pwd)/.data:/app/.data" -v "$(pwd)/tests:/app/tests" -v "$(pwd)/tmp:/tmp" -p 6002:6001 ws-bom-robot-app:src
264
+ docker build -f Dockerfile -t ws-bom-robot-app .
265
+ docker run --rm --name ws-bom-robot-app -d -p 6001:6001 ws-bom-robot-app
266
+ ```
267
+
268
+ docker run mounted to src
269
+
270
+ ```pwsh
271
+ docker run --rm --name ws-bom-robot-app-src -d -v "$(pwd)/ws_bom_robot_app:/app/ws_bom_robot_app" -v "$(pwd)/.data:/app/.data" -v "$(pwd)/tmp:/tmp" -p 6001:6001 ws-bom-robot-app
266
272
  ```
267
273
 
268
274
  ### ✈️ publish
@@ -179,7 +179,7 @@ pytest --cov=ws_bom_robot_app --log-cli-level=info
179
179
  launch debugger
180
180
 
181
181
  ```pwsh
182
- streamlit run debugger.py --server.port 6011
182
+ streamlit run debugger.py --server.port 8051
183
183
  ```
184
184
 
185
185
  dockerize base image
@@ -193,11 +193,17 @@ docker build -f Dockerfile-robot-base-gpu -t ghcr.io/websolutespa/ws-bom-robot-b
193
193
  docker push ghcr.io/websolutespa/ws-bom-robot-base:gpu
194
194
  ```
195
195
 
196
- dockerize app from src
196
+ dockerize app
197
197
 
198
198
  ```pwsh
199
- docker build -f Dockerfile-src -t ws-bom-robot-app:src .
200
- docker run --name ws-bom-robot-app-src -d -v "$(pwd)/ws_bom_robot_app:/app/ws_bom_robot_app" -v "$(pwd)/.data:/app/.data" -v "$(pwd)/tests:/app/tests" -v "$(pwd)/tmp:/tmp" -p 6002:6001 ws-bom-robot-app:src
199
+ docker build -f Dockerfile -t ws-bom-robot-app .
200
+ docker run --rm --name ws-bom-robot-app -d -p 6001:6001 ws-bom-robot-app
201
+ ```
202
+
203
+ docker run mounted to src
204
+
205
+ ```pwsh
206
+ docker run --rm --name ws-bom-robot-app-src -d -v "$(pwd)/ws_bom_robot_app:/app/ws_bom_robot_app" -v "$(pwd)/.data:/app/.data" -v "$(pwd)/tmp:/tmp" -p 6001:6001 ws-bom-robot-app
201
207
  ```
202
208
 
203
209
  ### ✈️ publish
@@ -4,7 +4,7 @@ _requirements = [line.split('#')[0].strip() for line in open("requirements.txt")
4
4
 
5
5
  setup(
6
6
  name="ws_bom_robot_app",
7
- version="0.0.67",
7
+ version="0.0.69",
8
8
  description="A FastAPI application serving ws bom/robot/llm platform ai.",
9
9
  long_description=open("README.md", encoding='utf-8').read(),
10
10
  long_description_content_type="text/markdown",
@@ -54,7 +54,7 @@ class Settings(BaseSettings):
54
54
 
55
55
  class RuntimeOptions(BaseModel):
56
56
  @staticmethod
57
- def _get_number_of_workers() -> int:
57
+ def _get_sys_arg(arg: str, default: int) -> int:
58
58
  """
59
59
  Returns the number of worker processes to use for the application.
60
60
 
@@ -72,18 +72,18 @@ class Settings(BaseSettings):
72
72
  """
73
73
  import sys
74
74
  try:
75
- for i, arg in enumerate(sys.argv):
76
- if arg == "--workers" and i + 1 < len(sys.argv):
75
+ for i, argv in enumerate(sys.argv):
76
+ if argv == f"--{arg}" and i + 1 < len(sys.argv):
77
77
  return int(sys.argv[i + 1])
78
78
  except (ValueError, IndexError):
79
79
  pass
80
- return 1
80
+ return default
81
81
  debug: bool
82
+ tcp_port: int = _get_sys_arg("port", 6001)
82
83
  loader_show_progress: bool
83
84
  loader_silent_errors: bool
84
- number_of_workers: int = _get_number_of_workers()
85
- is_multi_process: bool = _get_number_of_workers() > 1
86
-
85
+ number_of_workers: int = _get_sys_arg("workers", 1)
86
+ is_multi_process: bool = _get_sys_arg("workers", 1) > 1
87
87
 
88
88
  def runtime_options(self) -> RuntimeOptions:
89
89
  """_summary_
@@ -1,123 +1,123 @@
1
- import json, requests, re
2
- from typing import Any
3
- from abc import ABC, abstractmethod
4
- from langchain_core.prompts import ChatPromptTemplate
5
- from langchain_core.messages import AIMessage
6
- from langchain_core.runnables import RunnableSerializable
7
- from langchain_core.runnables import RunnableLambda
8
- from bs4 import BeautifulSoup
9
- from ws_bom_robot_app.llm.models.api import LlmRules
10
- from ws_bom_robot_app.llm.providers.llm_manager import LlmInterface
11
- from ws_bom_robot_app.llm.utils.agent import get_rules
12
-
13
- # SafeDict helper class
14
- class SafeDict(dict):
15
- def __missing__(self, key):
16
- return ''
17
-
18
- # Strategy Interface
19
- class AgentDescriptorStrategy(ABC):
20
- @abstractmethod
21
- def enrich_prompt(self, prompt: str, input: dict) -> str:
22
- pass
23
-
24
- @abstractmethod
25
- def rule_input(self, input: dict) -> str:
26
- pass
27
-
28
- # Concrete Strategy for Default Agent
29
- class DefaultAgentDescriptor(AgentDescriptorStrategy):
30
- def enrich_prompt(self, prompt: str, input: dict) -> str:
31
- # Default enrichment logic (could be minimal or no-op)
32
- return prompt.format_map(SafeDict(input))
33
-
34
- def rule_input(self, input: dict) -> str:
35
- return input.get('content', "")
36
-
37
- # Concrete Strategy for URL2Text Agent
38
- class URL2TextAgentDescriptor(AgentDescriptorStrategy):
39
- def enrich_prompt(self, prompt: str, input: dict) -> str:
40
- input["context"] = self._get_page_text(input)
41
- return prompt.format_map(SafeDict(input))
42
-
43
- def rule_input(self, input: dict) -> str:
44
- return input.get('context', "")
45
-
46
- def _get_page_text(self, input: dict) -> str:
47
- url = input.get("content", "")
48
- exclusions = input.get("exclude", {})
49
- response = requests.get(url)
50
- response.raise_for_status()
51
- soup = BeautifulSoup(response.content, 'html5lib')
52
- classes_to_exclude = exclusions.get("classes", [])
53
- ids_to_exclude = exclusions.get("ids", [])
54
- for class_name in classes_to_exclude:
55
- for element in soup.find_all(class_=class_name):
56
- element.extract()
57
- for id_name in ids_to_exclude:
58
- for element in soup.find_all(id=id_name):
59
- element.extract()
60
- for script in soup(["script", "noscript", "style", "head", "footer", "iframe"]):
61
- script.extract()
62
- return re.sub(' +', ' ', soup.get_text())
63
-
64
-
65
- class AgentDescriptor:
66
- # Dictionary to hold all agent strategies
67
- _list: dict[str,AgentDescriptorStrategy] = {
68
- "default": DefaultAgentDescriptor(),
69
- "url2text": URL2TextAgentDescriptor(),
70
- }
71
-
72
- # Functions to manage strategies
73
- @staticmethod
74
- def add_strategy(name: str, strategy: AgentDescriptorStrategy):
75
- """_summary_
76
- add a new strategy to the dictionary
77
- Args:
78
- name (str): name of the strategy, in lowercase
79
- strategy (AgentDescriptorStrategy): class implementing the strategy
80
- Examples:
81
- AgentDescriptor.add_strategy("custom_agent_descriptor", CustomAgentDescriptor())
82
- """
83
- AgentDescriptor._list[name.lower()] = strategy
84
-
85
- @staticmethod
86
- def get_strategy(name: str) -> AgentDescriptorStrategy:
87
- return AgentDescriptor._list.get(name.lower(), DefaultAgentDescriptor())
88
-
89
- def __init__(self, llm: LlmInterface, prompt: str, mode: str, rules: LlmRules = None):
90
- self.__prompt = prompt
91
- self.__llm = llm
92
- self.rules= rules
93
- self.strategy = self.get_strategy(mode) # Selects the strategy from the dictionary
94
-
95
- async def __create_prompt(self, input_dict: dict):
96
- input_data = json.loads(input_dict.get("input", {}))
97
- system = self.strategy.enrich_prompt(self.__prompt, input_data)
98
- if self.rules:
99
- rule_input = self.strategy.rule_input(input_data)
100
- rules_prompt = await get_rules(self.__llm.get_embeddings(), self.rules, rule_input)
101
- system += rules_prompt
102
- return ChatPromptTemplate.from_messages(
103
- [
104
- ("system", system),
105
- ("user", input_data.get("content", ""))
106
- ]
107
- )
108
-
109
- def __create_agent_descriptor(self, content) -> RunnableSerializable[Any, Any]:
110
- content = json.loads(content)
111
- agent = (
112
- {
113
- "input": lambda x: x["input"],
114
- }
115
- | RunnableLambda(self.__create_prompt)
116
- | self.__llm.get_llm()
117
- )
118
- return agent
119
-
120
- async def run_agent(self, content) -> Any:
121
- agent_descriptor = self.__create_agent_descriptor(content)
122
- response: AIMessage = await agent_descriptor.ainvoke({"input": content})
123
- return response
1
+ import json, requests, re
2
+ from typing import Any
3
+ from abc import ABC, abstractmethod
4
+ from langchain_core.prompts import ChatPromptTemplate
5
+ from langchain_core.messages import AIMessage
6
+ from langchain_core.runnables import RunnableSerializable
7
+ from langchain_core.runnables import RunnableLambda
8
+ from bs4 import BeautifulSoup
9
+ from ws_bom_robot_app.llm.models.api import LlmRules
10
+ from ws_bom_robot_app.llm.providers.llm_manager import LlmInterface
11
+ from ws_bom_robot_app.llm.utils.agent import get_rules
12
+
13
+ # SafeDict helper class
14
+ class SafeDict(dict):
15
+ def __missing__(self, key):
16
+ return ''
17
+
18
+ # Strategy Interface
19
+ class AgentDescriptorStrategy(ABC):
20
+ @abstractmethod
21
+ def enrich_prompt(self, prompt: str, input: dict) -> str:
22
+ pass
23
+
24
+ @abstractmethod
25
+ def rule_input(self, input: dict) -> str:
26
+ pass
27
+
28
+ # Concrete Strategy for Default Agent
29
+ class DefaultAgentDescriptor(AgentDescriptorStrategy):
30
+ def enrich_prompt(self, prompt: str, input: dict) -> str:
31
+ # Default enrichment logic (could be minimal or no-op)
32
+ return prompt.format_map(SafeDict(input))
33
+
34
+ def rule_input(self, input: dict) -> str:
35
+ return input.get('content', "")
36
+
37
+ # Concrete Strategy for URL2Text Agent
38
+ class URL2TextAgentDescriptor(AgentDescriptorStrategy):
39
+ def enrich_prompt(self, prompt: str, input: dict) -> str:
40
+ input["context"] = self._get_page_text(input)
41
+ return prompt.format_map(SafeDict(input))
42
+
43
+ def rule_input(self, input: dict) -> str:
44
+ return input.get('context', "")
45
+
46
+ def _get_page_text(self, input: dict) -> str:
47
+ url = input.get("content", "")
48
+ exclusions = input.get("exclude", {})
49
+ response = requests.get(url)
50
+ response.raise_for_status()
51
+ soup = BeautifulSoup(response.content, 'html5lib')
52
+ classes_to_exclude = exclusions.get("classes", [])
53
+ ids_to_exclude = exclusions.get("ids", [])
54
+ for class_name in classes_to_exclude:
55
+ for element in soup.find_all(class_=class_name):
56
+ element.extract()
57
+ for id_name in ids_to_exclude:
58
+ for element in soup.find_all(id=id_name):
59
+ element.extract()
60
+ for script in soup(["script", "noscript", "style", "head", "footer", "iframe"]):
61
+ script.extract()
62
+ return re.sub(' +', ' ', soup.get_text())
63
+
64
+
65
+ class AgentDescriptor:
66
+ # Dictionary to hold all agent strategies
67
+ _list: dict[str,AgentDescriptorStrategy] = {
68
+ "default": DefaultAgentDescriptor(),
69
+ "url2text": URL2TextAgentDescriptor(),
70
+ }
71
+
72
+ # Functions to manage strategies
73
+ @staticmethod
74
+ def add_strategy(name: str, strategy: AgentDescriptorStrategy):
75
+ """_summary_
76
+ add a new strategy to the dictionary
77
+ Args:
78
+ name (str): name of the strategy, in lowercase
79
+ strategy (AgentDescriptorStrategy): class implementing the strategy
80
+ Examples:
81
+ AgentDescriptor.add_strategy("custom_agent_descriptor", CustomAgentDescriptor())
82
+ """
83
+ AgentDescriptor._list[name.lower()] = strategy
84
+
85
+ @staticmethod
86
+ def get_strategy(name: str) -> AgentDescriptorStrategy:
87
+ return AgentDescriptor._list.get(name.lower(), DefaultAgentDescriptor())
88
+
89
+ def __init__(self, llm: LlmInterface, prompt: str, mode: str, rules: LlmRules = None):
90
+ self.__prompt = prompt
91
+ self.__llm = llm
92
+ self.rules= rules
93
+ self.strategy = self.get_strategy(mode) # Selects the strategy from the dictionary
94
+
95
+ async def __create_prompt(self, input_dict: dict):
96
+ input_data = json.loads(input_dict.get("input", {}))
97
+ system = self.strategy.enrich_prompt(self.__prompt, input_data)
98
+ if self.rules:
99
+ rule_input = self.strategy.rule_input(input_data)
100
+ rules_prompt = await get_rules(self.__llm.get_embeddings(), self.rules, rule_input)
101
+ system += rules_prompt
102
+ return ChatPromptTemplate.from_messages(
103
+ [
104
+ ("system", system),
105
+ ("user", input_data.get("content", ""))
106
+ ]
107
+ )
108
+
109
+ def __create_agent_descriptor(self, content) -> RunnableSerializable[Any, Any]:
110
+ content = json.loads(content)
111
+ agent = (
112
+ {
113
+ "input": lambda x: x["input"],
114
+ }
115
+ | RunnableLambda(self.__create_prompt)
116
+ | self.__llm.get_llm()
117
+ )
118
+ return agent
119
+
120
+ async def run_agent(self, content) -> Any:
121
+ agent_descriptor = self.__create_agent_descriptor(content)
122
+ response: AIMessage = await agent_descriptor.ainvoke({"input": content})
123
+ return response