Skip to content

Commit 74ca079

Browse files
committed
feat: context grounding add create index and ingest data
1 parent 222c29f commit 74ca079

File tree

9 files changed

+321
-21
lines changed

9 files changed

+321
-21
lines changed

sdk/core/uipath_sdk/_models/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from .assets import UserAsset
44
from .connections import Connection, ConnectionToken
55
from .context_grounding import ContextGroundingQueryResponse
6+
from .exceptions import IngestionInProgress
67
from .interrupt_models import CreateAction, InvokeProcess, WaitAction, WaitJob
78
from .job import Job
89
from .processes import Process
@@ -32,4 +33,5 @@
3233
"WaitJob",
3334
"WaitAction",
3435
"CreateAction",
36+
"IngestionInProgress"
3537
]
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
from datetime import datetime
2+
from typing import List, Optional, Any
3+
4+
from pydantic import BaseModel, ConfigDict, Field
5+
6+
class FieldModel(BaseModel):
7+
id: Optional[str] = Field(default=None, alias="id")
8+
name: Optional[str] = Field(default=None, alias="name")
9+
description: Optional[str] = Field(default=None, alias="description")
10+
type: Optional[str] = Field(default=None, alias="type")
11+
is_filterable: Optional[bool] = Field(default=None, alias="isFilterable")
12+
searchable_type: Optional[str] = Field(default=None, alias="searchableType")
13+
is_user_defined: Optional[bool] = Field(default=None, alias="isUserDefined")
14+
15+
16+
class DataSource(BaseModel):
17+
model_config = ConfigDict(
18+
validate_by_name=True,
19+
validate_by_alias=True,
20+
use_enum_values=True,
21+
arbitrary_types_allowed=True,
22+
extra="allow",
23+
json_encoders={datetime: lambda v: v.isoformat() if v else None},
24+
)
25+
id: Optional[str] = Field(default=None, alias="id")
26+
folder: Optional[str] = Field(default=None, alias="folder")
27+
28+
class EcsIndex(BaseModel):
29+
model_config = ConfigDict(
30+
validate_by_name=True,
31+
validate_by_alias=True,
32+
use_enum_values=True,
33+
arbitrary_types_allowed=True,
34+
extra="allow",
35+
json_encoders={datetime: lambda v: v.isoformat() if v else None},
36+
)
37+
id: Optional[str] = Field(default=None, alias="id")
38+
name: Optional[str] = Field(default=None, alias="name")
39+
description: Optional[str] = Field(default=None, alias="description")
40+
memory_usage: Optional[int] = Field(default=None, alias="memoryUsage")
41+
disk_usage: Optional[int] = Field(default=None, alias="diskUsage")
42+
data_source: Optional[DataSource] = Field(default=None, alias="dataSource")
43+
pre_processing: Any = Field(default=None, alias="preProcessing")
44+
fields: Optional[List[FieldModel]] = Field(default=None, alias="fields")
45+
last_ingestion_status: Optional[str] = Field(default=None, alias="lastIngestionStatus")
46+
last_ingested: Optional[datetime] = Field(default=None, alias="lastIngested")
47+
last_queried: Optional[datetime] = Field(default=None, alias="lastQueried")
48+
folder_key: Optional[str] = Field(default=None, alias="folderKey")
49+
50+
def in_progress_ingestion(self):
51+
return self.last_ingestion_status == "Queued" or self.last_ingestion_status == "In Progress"
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
class IngestionInProgress(Exception):
2+
"""An exception that is triggered when a search is attempted on an index that is currently undergoing ingestion."""
3+
def __init__(self, index_name):
4+
self.message = f"index {index_name} cannot be searched during ingestion"
5+
super().__init__(self.message)

sdk/core/uipath_sdk/_services/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from .llm_gateway_service import UiPathLlmChatService, UiPathOpenAIService
99
from .processes_service import ProcessesService
1010
from .queues_service import QueuesService
11+
from .folder_service import FolderService
1112

1213
__all__ = [
1314
"ActionsService",
@@ -21,4 +22,5 @@
2122
"JobsService",
2223
"UiPathOpenAIService",
2324
"UiPathLlmChatService",
25+
"FolderService",
2426
]

sdk/core/uipath_sdk/_services/buckets_service.py

Lines changed: 68 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Any, Dict
1+
from typing import Any, Dict, Optional, Union
22

33
from httpx import request
44

@@ -61,7 +61,9 @@ def download(
6161

6262
def upload(
6363
self,
64-
bucket_key: str,
64+
*,
65+
bucket_key: Optional[str] = None,
66+
bucket_name: Optional[str] = None,
6567
blob_file_path: str,
6668
content_type: str,
6769
source_path: str,
@@ -70,11 +72,18 @@ def upload(
7072
7173
Args:
7274
bucket_key: The key of the bucket
75+
bucket_name: The name of the bucket
7376
blob_file_path: The path where the file will be stored in the bucket
7477
content_type: The MIME type of the file
7578
source_path: The local path of the file to upload
7679
"""
77-
bucket = self.retrieve_by_key(bucket_key)
80+
if not (bucket_name or bucket_key):
81+
raise ValueError("Must specify a bucket name or bucket key")
82+
if bucket_name:
83+
bucket = self.retrieve(bucket_name)
84+
else:
85+
bucket = self.retrieve_by_key(bucket_key)
86+
7887
bucket_id = bucket["Id"]
7988

8089
endpoint = Endpoint(
@@ -101,6 +110,60 @@ def upload(
101110
else:
102111
request("PUT", write_uri, headers=headers, files={"file": file})
103112

113+
def upload_from_memory(
114+
self,
115+
*,
116+
bucket_key: Optional[str] = None,
117+
bucket_name: Optional[str] = None,
118+
blob_file_path: str,
119+
content_type: str,
120+
content: Union[str, bytes],
121+
) -> None:
122+
"""Upload content from memory to a bucket.
123+
124+
Args:
125+
bucket_key: The key of the bucket
126+
bucket_name: The name of the bucket
127+
blob_file_path: The path where the content will be stored in the bucket
128+
content_type: The MIME type of the content
129+
content: The content to upload (string or bytes)
130+
"""
131+
if not (bucket_name or bucket_key):
132+
raise ValueError("Must specify a bucket name or bucket key")
133+
if bucket_name:
134+
bucket = self.retrieve(bucket_name)
135+
else:
136+
bucket = self.retrieve_by_key(bucket_key)
137+
138+
bucket_id = bucket["Id"]
139+
140+
endpoint = Endpoint(
141+
f"/orchestrator_/odata/Buckets({bucket_id})/UiPath.Server.Configuration.OData.GetWriteUri"
142+
)
143+
144+
result = self.request(
145+
"GET",
146+
endpoint,
147+
params={"path": blob_file_path, "contentType": content_type},
148+
).json()
149+
write_uri = result["Uri"]
150+
151+
headers = {
152+
key: value
153+
for key, value in zip(
154+
result["Headers"]["Keys"], result["Headers"]["Values"]
155+
)
156+
}
157+
158+
# Convert string to bytes if needed
159+
if isinstance(content, str):
160+
content = content.encode("utf-8")
161+
162+
if result["RequiresAuth"]:
163+
self.request("PUT", write_uri, headers=headers, content=content)
164+
else:
165+
request("PUT", write_uri, headers=headers, content=content)
166+
104167
@infer_bindings()
105168
def retrieve(self, name: str) -> Any:
106169
"""Retrieve bucket information by its name.
@@ -194,14 +257,14 @@ def custom_headers(self) -> Dict[str, str]:
194257
def _retrieve_spec(self, name: str) -> RequestSpec:
195258
return RequestSpec(
196259
method="GET",
197-
endpoint=Endpoint("/odata/Buckets"),
260+
endpoint=Endpoint("/orchestrator_/odata/Buckets"),
198261
params={"$filter": f"Name eq '{name}'", "$top": 1},
199262
)
200263

201264
def _retrieve_by_key_spec(self, key: str) -> RequestSpec:
202265
return RequestSpec(
203266
method="GET",
204267
endpoint=Endpoint(
205-
f"/odata/Buckets/UiPath.Server.Configuration.OData.GetByKey(identifier={key})"
268+
f"/orchestrator_/odata/Buckets/UiPath.Server.Configuration.OData.GetByKey(identifier={key})"
206269
),
207270
)

0 commit comments

Comments
 (0)