Skip to content

Commit 6caed07

Browse files
committed
feat: context grounding create index and ingest data
1 parent 39adea4 commit 6caed07

File tree

10 files changed

+403
-22
lines changed

10 files changed

+403
-22
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "uipath"
3-
version = "2.0.0.dev1"
3+
version = "2.0.0.dev3"
44
description = "Python SDK and CLI for UiPath Platform, enabling programmatic interaction with automation services, process management, and deployment tools."
55
readme = { file = "README.md", content-type = "text/markdown" }
66
requires-python = ">=3.9"

src/uipath/_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 IngestionInProgressException
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+
"IngestionInProgressException",
3537
]
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
from datetime import datetime
2+
from typing import Any, List, Optional
3+
4+
from pydantic import BaseModel, ConfigDict, Field
5+
6+
7+
class ContextGroundingField(BaseModel):
8+
id: Optional[str] = Field(default=None, alias="id")
9+
name: Optional[str] = Field(default=None, alias="name")
10+
description: Optional[str] = Field(default=None, alias="description")
11+
type: Optional[str] = Field(default=None, alias="type")
12+
is_filterable: Optional[bool] = Field(default=None, alias="isFilterable")
13+
searchable_type: Optional[str] = Field(default=None, alias="searchableType")
14+
is_user_defined: Optional[bool] = Field(default=None, alias="isUserDefined")
15+
16+
17+
class ContextGroundingDataSource(BaseModel):
18+
model_config = ConfigDict(
19+
validate_by_name=True,
20+
validate_by_alias=True,
21+
use_enum_values=True,
22+
arbitrary_types_allowed=True,
23+
extra="allow",
24+
json_encoders={datetime: lambda v: v.isoformat() if v else None},
25+
)
26+
id: Optional[str] = Field(default=None, alias="id")
27+
folder: Optional[str] = Field(default=None, alias="folder")
28+
29+
30+
class ContextGroundingIndex(BaseModel):
31+
model_config = ConfigDict(
32+
validate_by_name=True,
33+
validate_by_alias=True,
34+
use_enum_values=True,
35+
arbitrary_types_allowed=True,
36+
extra="allow",
37+
json_encoders={datetime: lambda v: v.isoformat() if v else None},
38+
)
39+
id: Optional[str] = Field(default=None, alias="id")
40+
name: Optional[str] = Field(default=None, alias="name")
41+
description: Optional[str] = Field(default=None, alias="description")
42+
memory_usage: Optional[int] = Field(default=None, alias="memoryUsage")
43+
disk_usage: Optional[int] = Field(default=None, alias="diskUsage")
44+
data_source: Optional[ContextGroundingDataSource] = Field(default=None, alias="dataSource")
45+
pre_processing: Any = Field(default=None, alias="preProcessing")
46+
fields: Optional[List[ContextGroundingField]] = Field(default=None, alias="fields")
47+
last_ingestion_status: Optional[str] = Field(
48+
default=None, alias="lastIngestionStatus"
49+
)
50+
last_ingested: Optional[datetime] = Field(default=None, alias="lastIngested")
51+
last_queried: Optional[datetime] = Field(default=None, alias="lastQueried")
52+
folder_key: Optional[str] = Field(default=None, alias="folderKey")
53+
54+
def in_progress_ingestion(self):
55+
return (
56+
self.last_ingestion_status == "Queued"
57+
or self.last_ingestion_status == "In Progress"
58+
)

src/uipath/_models/exceptions.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
class IngestionInProgressException(Exception):
2+
"""An exception that is triggered when a search is attempted on an index that is currently undergoing ingestion."""
3+
4+
def __init__(self, index_name):
5+
self.message = f"index {index_name} cannot be searched during ingestion"
6+
super().__init__(self.message)

src/uipath/_services/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from .buckets_service import BucketsService
55
from .connections_service import ConnectionsService
66
from .context_grounding_service import ContextGroundingService
7+
from .folder_service import FolderService
78
from .jobs_service import JobsService
89
from .llm_gateway_service import UiPathLlmChatService, UiPathOpenAIService
910
from .processes_service import ProcessesService
@@ -21,4 +22,5 @@
2122
"JobsService",
2223
"UiPathOpenAIService",
2324
"UiPathLlmChatService",
25+
"FolderService",
2426
]

src/uipath/_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

@@ -59,7 +59,9 @@ def download(
5959

6060
def upload(
6161
self,
62-
bucket_key: str,
62+
*,
63+
bucket_key: Optional[str] = None,
64+
bucket_name: Optional[str] = None,
6365
blob_file_path: str,
6466
content_type: str,
6567
source_path: str,
@@ -68,11 +70,18 @@ def upload(
6870
6971
Args:
7072
bucket_key: The key of the bucket
73+
bucket_name: The name of the bucket
7174
blob_file_path: The path where the file will be stored in the bucket
7275
content_type: The MIME type of the file
7376
source_path: The local path of the file to upload
7477
"""
75-
bucket = self.retrieve_by_key(bucket_key)
78+
if bucket_key:
79+
bucket = self.retrieve_by_key(bucket_key)
80+
elif bucket_name:
81+
bucket = self.retrieve(bucket_name)
82+
else:
83+
raise ValueError("Must specify a bucket name or bucket key")
84+
7685
bucket_id = bucket["Id"]
7786

7887
endpoint = Endpoint(
@@ -99,6 +108,60 @@ def upload(
99108
else:
100109
request("PUT", write_uri, headers=headers, files={"file": file})
101110

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

199262
def _retrieve_by_key_spec(self, key: str) -> RequestSpec:
200263
return RequestSpec(
201264
method="GET",
202265
endpoint=Endpoint(
203-
f"/odata/Buckets/UiPath.Server.Configuration.OData.GetByKey(identifier={key})"
266+
f"/orchestrator_/odata/Buckets/UiPath.Server.Configuration.OData.GetByKey(identifier={key})"
204267
),
205268
)

0 commit comments

Comments
 (0)