ws-bom-robot-app 0.0.68__tar.gz → 0.0.70__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 (81) hide show
  1. {ws_bom_robot_app-0.0.68/ws_bom_robot_app.egg-info → ws_bom_robot_app-0.0.70}/PKG-INFO +10 -4
  2. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/README.md +9 -3
  3. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/setup.py +1 -1
  4. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/providers/llm_manager.py +27 -17
  5. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/vector_store/integration/manager.py +2 -2
  6. ws_bom_robot_app-0.0.70/ws_bom_robot_app/llm/vector_store/integration/thron.py +123 -0
  7. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70/ws_bom_robot_app.egg-info}/PKG-INFO +10 -4
  8. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app.egg-info/SOURCES.txt +1 -0
  9. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/MANIFEST.in +0 -0
  10. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/pyproject.toml +0 -0
  11. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/requirements.txt +0 -0
  12. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/setup.cfg +0 -0
  13. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/__init__.py +0 -0
  14. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/auth.py +0 -0
  15. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/config.py +0 -0
  16. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/cron_manager.py +0 -0
  17. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/__init__.py +0 -0
  18. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/agent_context.py +0 -0
  19. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/agent_description.py +0 -0
  20. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/agent_handler.py +0 -0
  21. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/agent_lcel.py +0 -0
  22. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/api.py +0 -0
  23. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/defaut_prompt.py +0 -0
  24. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/feedbacks/__init__.py +0 -0
  25. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/feedbacks/feedback_manager.py +0 -0
  26. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/main.py +0 -0
  27. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/models/__init__.py +0 -0
  28. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/models/api.py +0 -0
  29. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/models/base.py +0 -0
  30. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/models/feedback.py +0 -0
  31. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/models/kb.py +0 -0
  32. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/nebuly_handler.py +0 -0
  33. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/providers/__init__.py +0 -0
  34. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/settings.py +0 -0
  35. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/tools/__init__.py +0 -0
  36. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/tools/models/__init__.py +0 -0
  37. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/tools/models/main.py +0 -0
  38. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/tools/tool_builder.py +0 -0
  39. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/tools/tool_manager.py +0 -0
  40. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/tools/utils.py +0 -0
  41. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/utils/__init__.py +0 -0
  42. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/utils/agent.py +0 -0
  43. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/utils/chunker.py +0 -0
  44. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/utils/cms.py +0 -0
  45. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/utils/download.py +0 -0
  46. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/utils/kb.py +0 -0
  47. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/utils/print.py +0 -0
  48. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/utils/secrets.py +0 -0
  49. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/utils/webhooks.py +0 -0
  50. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/vector_store/__init__.py +0 -0
  51. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/vector_store/db/__init__.py +0 -0
  52. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/vector_store/db/base.py +0 -0
  53. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/vector_store/db/chroma.py +0 -0
  54. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/vector_store/db/faiss.py +0 -0
  55. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/vector_store/db/manager.py +0 -0
  56. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/vector_store/db/qdrant.py +0 -0
  57. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/vector_store/generator.py +0 -0
  58. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/vector_store/integration/__init__.py +0 -0
  59. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/vector_store/integration/azure.py +0 -0
  60. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/vector_store/integration/base.py +0 -0
  61. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/vector_store/integration/confluence.py +0 -0
  62. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/vector_store/integration/dropbox.py +0 -0
  63. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/vector_store/integration/gcs.py +0 -0
  64. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/vector_store/integration/github.py +0 -0
  65. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/vector_store/integration/googledrive.py +0 -0
  66. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/vector_store/integration/jira.py +0 -0
  67. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/vector_store/integration/s3.py +0 -0
  68. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/vector_store/integration/sftp.py +0 -0
  69. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/vector_store/integration/sharepoint.py +0 -0
  70. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/vector_store/integration/sitemap.py +0 -0
  71. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/vector_store/integration/slack.py +0 -0
  72. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/vector_store/loader/__init__.py +0 -0
  73. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/vector_store/loader/base.py +0 -0
  74. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/vector_store/loader/docling.py +0 -0
  75. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/llm/vector_store/loader/json_loader.py +0 -0
  76. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/main.py +0 -0
  77. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/task_manager.py +0 -0
  78. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app/util.py +0 -0
  79. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app.egg-info/dependency_links.txt +0 -0
  80. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/ws_bom_robot_app.egg-info/requires.txt +0 -0
  81. {ws_bom_robot_app-0.0.68 → ws_bom_robot_app-0.0.70}/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.68
3
+ Version: 0.0.70
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
@@ -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
@@ -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.68",
7
+ version="0.0.70",
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",
@@ -107,9 +107,8 @@ class Google(LlmInterface):
107
107
  def get_llm(self):
108
108
  from langchain_google_genai.chat_models import ChatGoogleGenerativeAI
109
109
  return ChatGoogleGenerativeAI(
110
- name="chat",
111
- api_key=self.config.api_key or os.getenv("GOOGLE_API_KEY"),
112
110
  model=self.config.model,
111
+ google_api_key=self.config.api_key or os.getenv("GOOGLE_API_KEY"),
113
112
  temperature=self.config.temperature,
114
113
  disable_streaming=False,
115
114
  )
@@ -117,8 +116,8 @@ class Google(LlmInterface):
117
116
  def get_embeddings(self):
118
117
  from langchain_google_genai.embeddings import GoogleGenerativeAIEmbeddings
119
118
  return GoogleGenerativeAIEmbeddings(
120
- google_api_key=self.config.api_key,
121
- model="models/text-embedding-005")
119
+ google_api_key=self.config.api_key or os.getenv("GOOGLE_API_KEY"),
120
+ model="models/text-embedding-004")
122
121
 
123
122
  def get_models(self):
124
123
  import google.generativeai as genai
@@ -140,22 +139,33 @@ class Gvertex(LlmInterface):
140
139
  temperature=self.config.temperature
141
140
  )
142
141
  def get_embeddings(self):
143
- from langchain_google_vertexai import VertexAIEmbeddings
144
- return VertexAIEmbeddings(model_name="text-embedding-005")
142
+ from langchain_google_vertexai.embeddings import VertexAIEmbeddings
143
+ embeddings = VertexAIEmbeddings(model_name="text-embedding-004")
144
+ #fix gemini-embedding-001 batch size
145
+ #embeddings.instance["max_batch_size"] = 1
146
+ #embeddings.instance["batch_size"] = 1
147
+ return embeddings
145
148
  def get_models(self):
146
- #from google.cloud import aiplatform
147
- #aiplatform.init()
148
- #models = aiplatform.Model.list()
149
+ _models = [
150
+ {"id":"gemini-2.5-pro"},
151
+ {"id":"gemini-2.5-flash"},
152
+ {"id":"gemini-2.0-flash"},
153
+ {"id":"gemini-2.0-flash-lite"}
154
+ ]
155
+ try:
156
+ from google.cloud import aiplatform
157
+ aiplatform.init()
158
+ _list = aiplatform.Model.list()
159
+ if _list:
160
+ _models = list([{"id": model.name} for model in _list])
149
161
  # removed due issue: https://github.com/langchain-ai/langchain-google/issues/733
150
162
  # Message type "google.cloud.aiplatform.v1beta1.GenerateContentResponse" has no field named "createTime" at "GenerateContentResponse". Available Fields(except extensions): "['candidates', 'modelVersion', 'promptFeedback', 'usageMetadata']"
151
-
152
- #see https://cloud.google.com/vertex-ai/generative-ai/docs/learn/locations#united-states for available models
153
- return [
154
- {"id":"gemini-2.5-pro-preview-05-06"},
155
- {"id":"gemini-2.0-flash"},
156
- {"id":"gemini-2.0-flash-lite"},
157
- {"id":"gemini-1.5-pro-002"}
158
- ]
163
+ except Exception as e:
164
+ print(f"Error fetching models from Gvertex: {e}")
165
+ # fallback to hardcoded models
166
+ #see https://cloud.google.com/vertex-ai/generative-ai/docs/learn/locations#united-states for available models
167
+ finally:
168
+ return _models
159
169
 
160
170
  class Groq(LlmInterface):
161
171
  def get_llm(self):
@@ -12,7 +12,7 @@ from ws_bom_robot_app.llm.vector_store.integration.sftp import Sftp
12
12
  from ws_bom_robot_app.llm.vector_store.integration.sharepoint import Sharepoint
13
13
  from ws_bom_robot_app.llm.vector_store.integration.sitemap import Sitemap
14
14
  from ws_bom_robot_app.llm.vector_store.integration.slack import Slack
15
-
15
+ from ws_bom_robot_app.llm.vector_store.integration.thron import Thron
16
16
  class IntegrationManager:
17
17
  _list: dict[str, Type[IntegrationStrategy]] = {
18
18
  "llmkbazure": Azure,
@@ -27,7 +27,7 @@ class IntegrationManager:
27
27
  "llmkbsharepoint": Sharepoint,
28
28
  "llmkbsitemap": Sitemap,
29
29
  "llmkbslack": Slack,
30
-
30
+ "llmkbthron": Thron,
31
31
  }
32
32
  @classmethod
33
33
  def get_strategy(cls, name: str, knowledgebase_path: str, data: dict[str, str]) -> IntegrationStrategy:
@@ -0,0 +1,123 @@
1
+ import asyncio, logging, aiohttp
2
+ from ws_bom_robot_app.llm.vector_store.integration.base import IntegrationStrategy, UnstructuredIngest
3
+ from unstructured_ingest.v2.processes.connectors.fsspec.sftp import SftpConnectionConfig, SftpAccessConfig, SftpDownloaderConfig, SftpIndexerConfig
4
+ from langchain_core.documents import Document
5
+ from ws_bom_robot_app.llm.vector_store.loader.base import Loader
6
+ from typing import List, Union, Optional
7
+ from pydantic import BaseModel, Field, AliasChoices
8
+ import json
9
+ import os
10
+
11
+ class ThronParams(BaseModel):
12
+ """
13
+ ThronParams is a model that defines the parameters required for Thron integration.
14
+
15
+ Attributes:
16
+ app_id (str): The application ID for Thron.
17
+ client_id (str): The client ID for Thron.
18
+ client_secret (str): The client secret for Thron.
19
+ """
20
+ organization_name: str = Field(validation_alias=AliasChoices("organizationName","organization_name"))
21
+ attribute_fields: Optional[List[str]] = Field(default=None, validation_alias=AliasChoices("attributeFields","attribute_fields"))
22
+ client_id: str = Field(validation_alias=AliasChoices("clientId","client_id"))
23
+ client_secret: str = Field(validation_alias=AliasChoices("clientSecret","client_secret"))
24
+
25
+ class Thron(IntegrationStrategy):
26
+ def __init__(self, knowledgebase_path: str, data: dict[str, Union[str,int,list]]):
27
+ super().__init__(knowledgebase_path, data)
28
+ self.__data = ThronParams.model_validate(self.data)
29
+
30
+ def working_subdirectory(self) -> str:
31
+ return 'thron'
32
+
33
+ async def run(self) -> None:
34
+ _data = await self.__get_data()
35
+ transformed_data = self.__transform_data(_data)
36
+ json_file_path = os.path.join(self.working_directory, 'thron_data.json')
37
+ with open(json_file_path, 'w', encoding='utf-8') as f:
38
+ json.dump(transformed_data, f, indent=2, ensure_ascii=False)
39
+
40
+ async def load(self) -> list[Document]:
41
+ await self.run()
42
+ await asyncio.sleep(1)
43
+ return await Loader(self.working_directory).load()
44
+
45
+ async def __get_auth_token(self) -> str:
46
+ try:
47
+ async with aiohttp.ClientSession() as session:
48
+ auth_data = {
49
+ "grant_type": "client_credentials",
50
+ "client_id": self.__data.client_id,
51
+ "client_secret": self.__data.client_secret
52
+ }
53
+ headers = {
54
+ "accept": "application/json",
55
+ "Content-Type": "application/x-www-form-urlencoded"
56
+ }
57
+ async with session.post("https://websolute.thron.com/api/v1/authentication/oauth2/token", data=auth_data, headers=headers) as response:
58
+ result = await response.json()
59
+ return result.get("access_token", "")
60
+ except Exception as e:
61
+ logging.error(f"Error fetching Thron auth token: {e}")
62
+ return None
63
+
64
+ async def __get_data(self) -> dict:
65
+ try:
66
+ token = await self.__get_auth_token()
67
+ if not token:
68
+ logging.error("Failed to obtain Thron authentication token.")
69
+ return {}
70
+ attribute_fields = ",".join(self.__data.attribute_fields) if self.__data.attribute_fields else ""
71
+ async with aiohttp.ClientSession() as session:
72
+ headers = {
73
+ "accept": "application/json",
74
+ "Authorization": f"Bearer {token}"
75
+ }
76
+ async with session.get(f"https://{self.__data.organization_name}.thron.com/api/v1/product-data/products?attributeFields=product_id,{attribute_fields}", headers=headers) as response:
77
+ result = await response.json()
78
+ return result.get("items", {})
79
+ except Exception as e:
80
+ logging.error(f"Error fetching Thron product data: {e}")
81
+ return {}
82
+ return []
83
+
84
+
85
+
86
+ def __transform_data(self, data: dict) -> dict:
87
+ transformed_data = []
88
+
89
+ # First pass: collect all MASTER items
90
+ master_items = {item.get("id"): item for item in data if item.get("hierarchyLevel") == "MASTER"}
91
+
92
+ # Second pass: process items
93
+ for item in data:
94
+ hierarchy_level = item.get("hierarchyLevel")
95
+
96
+ if hierarchy_level == "MASTER":
97
+ # Find matching variants for this master
98
+ master_id = item.get("id")
99
+ item_copy = item.copy()
100
+ item_copy["variants"] = []
101
+
102
+ # Look for variants that belong to this master
103
+ for variant_item in data:
104
+ if (variant_item.get("hierarchyLevel") == "VARIANT" and
105
+ variant_item.get("variation", {}).get("master")):
106
+
107
+ variant_master_id = variant_item.get("variation").get("master").split(":")[-1]
108
+
109
+ # Check if this variant belongs to current master by comparing product_ids
110
+ for attr in item.get("attributes", []):
111
+ if (attr.get("code") == "product_id" and
112
+ attr.get("identifier") == variant_master_id):
113
+ item_copy["variants"].append(variant_item)
114
+ break
115
+
116
+ # Only add master items that have variants
117
+ if item_copy["variants"]:
118
+ transformed_data.append(item_copy)
119
+
120
+ elif hierarchy_level == "SIMPLE":
121
+ transformed_data.append(item)
122
+
123
+ return transformed_data
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ws_bom_robot_app
3
- Version: 0.0.68
3
+ Version: 0.0.70
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
@@ -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
@@ -72,6 +72,7 @@ ws_bom_robot_app/llm/vector_store/integration/sftp.py
72
72
  ws_bom_robot_app/llm/vector_store/integration/sharepoint.py
73
73
  ws_bom_robot_app/llm/vector_store/integration/sitemap.py
74
74
  ws_bom_robot_app/llm/vector_store/integration/slack.py
75
+ ws_bom_robot_app/llm/vector_store/integration/thron.py
75
76
  ws_bom_robot_app/llm/vector_store/loader/__init__.py
76
77
  ws_bom_robot_app/llm/vector_store/loader/base.py
77
78
  ws_bom_robot_app/llm/vector_store/loader/docling.py