kodexa 7.0.1a10177063353__py3-none-any.whl → 7.0.1a11918232720__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.
- kodexa/dataclasses/__init__.py +464 -0
- kodexa/dataclasses/templates/llm_data_class.j2 +15 -0
- kodexa/model/model.py +72 -2
- kodexa/model/objects.py +409 -185
- kodexa/model/persistence.py +169 -6
- kodexa/platform/client.py +165 -13
- kodexa/platform/kodexa.py +24 -14
- kodexa/utils/__init__.py +178 -0
- {kodexa-7.0.1a10177063353.dist-info → kodexa-7.0.1a11918232720.dist-info}/METADATA +4 -4
- {kodexa-7.0.1a10177063353.dist-info → kodexa-7.0.1a11918232720.dist-info}/RECORD +12 -9
- {kodexa-7.0.1a10177063353.dist-info → kodexa-7.0.1a11918232720.dist-info}/LICENSE +0 -0
- {kodexa-7.0.1a10177063353.dist-info → kodexa-7.0.1a11918232720.dist-info}/WHEEL +0 -0
kodexa/model/persistence.py
CHANGED
@@ -4,7 +4,7 @@ import pathlib
|
|
4
4
|
import sqlite3
|
5
5
|
import tempfile
|
6
6
|
import uuid
|
7
|
-
from typing import List
|
7
|
+
from typing import List, Optional
|
8
8
|
|
9
9
|
import msgpack
|
10
10
|
|
@@ -13,8 +13,9 @@ from kodexa.model.model import (
|
|
13
13
|
DocumentMetadata,
|
14
14
|
ContentFeature,
|
15
15
|
ContentException,
|
16
|
-
ModelInsight,
|
16
|
+
ModelInsight, ProcessingStep,
|
17
17
|
)
|
18
|
+
from kodexa.model.objects import DocumentTaxonValidation
|
18
19
|
|
19
20
|
logger = logging.getLogger()
|
20
21
|
|
@@ -1122,6 +1123,131 @@ class SqliteDocumentPersistence(object):
|
|
1122
1123
|
|
1123
1124
|
return content_nodes
|
1124
1125
|
|
1126
|
+
def __ensure_ed_table_exists(self):
|
1127
|
+
"""
|
1128
|
+
Ensure the 'ed' table exists in the database.
|
1129
|
+
Creates the table if it does not exist.
|
1130
|
+
"""
|
1131
|
+
self.cursor.execute("""
|
1132
|
+
CREATE TABLE IF NOT EXISTS ed (
|
1133
|
+
obj BLOB
|
1134
|
+
)
|
1135
|
+
""")
|
1136
|
+
|
1137
|
+
# Check if the table has any rows, if not, insert an initial empty row
|
1138
|
+
result = self.cursor.execute("SELECT COUNT(*) FROM ed").fetchone()
|
1139
|
+
if result[0] == 0:
|
1140
|
+
self.cursor.execute("INSERT INTO ed (obj) VALUES (?)", [sqlite3.Binary(msgpack.packb({}))])
|
1141
|
+
|
1142
|
+
def __ensure_validations_table_exists(self):
|
1143
|
+
"""
|
1144
|
+
Ensure the 'validations' table exists in the database.
|
1145
|
+
Creates the table if it does not exist and initializes it with an empty list.
|
1146
|
+
"""
|
1147
|
+
self.cursor.execute("""
|
1148
|
+
CREATE TABLE IF NOT EXISTS validations (
|
1149
|
+
obj BLOB
|
1150
|
+
)
|
1151
|
+
""")
|
1152
|
+
|
1153
|
+
# Check if the table has any rows, if not, insert an initial empty row
|
1154
|
+
result = self.cursor.execute("SELECT COUNT(*) FROM validations").fetchone()
|
1155
|
+
if result[0] == 0:
|
1156
|
+
self.cursor.execute("INSERT INTO validations (obj) VALUES (?)", [sqlite3.Binary(msgpack.packb([]))])
|
1157
|
+
|
1158
|
+
def set_validations(self, validations: List[DocumentTaxonValidation]):
|
1159
|
+
"""
|
1160
|
+
Sets the validations for the document.
|
1161
|
+
|
1162
|
+
Args:
|
1163
|
+
validations (List[DocumentTaxonValidation]): The validations to store.
|
1164
|
+
"""
|
1165
|
+
self.__ensure_validations_table_exists()
|
1166
|
+
serialized_data = sqlite3.Binary(msgpack.packb([v.model_dump(by_alias=True) for v in validations]))
|
1167
|
+
self.cursor.execute("UPDATE validations SET obj = ? WHERE rowid = 1", [serialized_data])
|
1168
|
+
self.connection.commit()
|
1169
|
+
|
1170
|
+
def get_validations(self) -> List[DocumentTaxonValidation]:
|
1171
|
+
"""
|
1172
|
+
Gets the validations associated with this document.
|
1173
|
+
|
1174
|
+
Returns:
|
1175
|
+
List[DocumentTaxonValidation]: The list of validations stored in the validations table.
|
1176
|
+
"""
|
1177
|
+
self.__ensure_validations_table_exists()
|
1178
|
+
result = self.cursor.execute("SELECT obj FROM validations WHERE rowid = 1").fetchone()
|
1179
|
+
if result and result[0]:
|
1180
|
+
return [DocumentTaxonValidation.model_validate(v) for v in msgpack.unpackb(result[0])]
|
1181
|
+
return []
|
1182
|
+
|
1183
|
+
def set_external_data(self, external_data: dict):
|
1184
|
+
"""
|
1185
|
+
Sets the external data for the document.
|
1186
|
+
|
1187
|
+
Args:
|
1188
|
+
external_data (dict): The external data to store, must be JSON serializable.
|
1189
|
+
"""
|
1190
|
+
self.__ensure_ed_table_exists()
|
1191
|
+
serialized_data = sqlite3.Binary(msgpack.packb(external_data))
|
1192
|
+
self.cursor.execute("UPDATE ed SET obj = ? WHERE rowid = 1", [serialized_data])
|
1193
|
+
self.connection.commit()
|
1194
|
+
|
1195
|
+
def get_external_data(self) -> dict:
|
1196
|
+
"""
|
1197
|
+
Gets the external data associated with this document.
|
1198
|
+
|
1199
|
+
Returns:
|
1200
|
+
dict: The external data stored in the ed table.
|
1201
|
+
"""
|
1202
|
+
self.__ensure_ed_table_exists()
|
1203
|
+
result = self.cursor.execute("SELECT obj FROM ed WHERE rowid = 1").fetchone()
|
1204
|
+
if result and result[0]:
|
1205
|
+
return msgpack.unpackb(result[0])
|
1206
|
+
return {}
|
1207
|
+
|
1208
|
+
def __ensure_steps_table_exists(self):
|
1209
|
+
"""
|
1210
|
+
Ensure the 'steps' table exists in the database.
|
1211
|
+
Creates the table if it does not exist.
|
1212
|
+
"""
|
1213
|
+
self.cursor.execute("""
|
1214
|
+
CREATE TABLE IF NOT EXISTS steps (
|
1215
|
+
obj BLOB
|
1216
|
+
)
|
1217
|
+
""")
|
1218
|
+
|
1219
|
+
# Check if the table has any rows, if not, insert an initial empty row
|
1220
|
+
result = self.cursor.execute("SELECT COUNT(*) FROM steps").fetchone()
|
1221
|
+
if result[0] == 0:
|
1222
|
+
self.cursor.execute("INSERT INTO steps (obj) VALUES (?)", [sqlite3.Binary(msgpack.packb([]))])
|
1223
|
+
|
1224
|
+
def set_steps(self, steps: List[ProcessingStep]):
|
1225
|
+
"""
|
1226
|
+
Sets the processing steps for the document.
|
1227
|
+
|
1228
|
+
Args:
|
1229
|
+
steps (List[ProcessingStep]): A list of ProcessingStep objects to store.
|
1230
|
+
"""
|
1231
|
+
self.__ensure_steps_table_exists()
|
1232
|
+
serialized_steps = [step.to_dict() for step in steps]
|
1233
|
+
packed_data = sqlite3.Binary(msgpack.packb(serialized_steps))
|
1234
|
+
self.cursor.execute("UPDATE steps SET obj = ? WHERE rowid = 1", [packed_data])
|
1235
|
+
self.connection.commit()
|
1236
|
+
|
1237
|
+
def get_steps(self) -> List[ProcessingStep]:
|
1238
|
+
"""
|
1239
|
+
Gets the processing steps associated with this document.
|
1240
|
+
|
1241
|
+
Returns:
|
1242
|
+
List[ProcessingStep]: A list of ProcessingStep objects.
|
1243
|
+
"""
|
1244
|
+
self.__ensure_steps_table_exists()
|
1245
|
+
result = self.cursor.execute("SELECT obj FROM steps WHERE rowid = 1").fetchone()
|
1246
|
+
if result and result[0]:
|
1247
|
+
unpacked_data = msgpack.unpackb(result[0])
|
1248
|
+
return [ProcessingStep(**step) for step in unpacked_data]
|
1249
|
+
return []
|
1250
|
+
|
1125
1251
|
|
1126
1252
|
class SimpleObjectCache(object):
|
1127
1253
|
"""
|
@@ -1146,7 +1272,7 @@ class SimpleObjectCache(object):
|
|
1146
1272
|
self.next_id = 1
|
1147
1273
|
self.dirty_objs = set()
|
1148
1274
|
|
1149
|
-
def get_obj(self, obj_id):
|
1275
|
+
def get_obj(self, obj_id) -> Optional[ContentNode]:
|
1150
1276
|
"""
|
1151
1277
|
Get the object with the given ID.
|
1152
1278
|
|
@@ -1161,7 +1287,7 @@ class SimpleObjectCache(object):
|
|
1161
1287
|
|
1162
1288
|
return None
|
1163
1289
|
|
1164
|
-
def add_obj(self, obj):
|
1290
|
+
def add_obj(self, obj: ContentNode):
|
1165
1291
|
"""
|
1166
1292
|
Add an object to the cache.
|
1167
1293
|
|
@@ -1186,7 +1312,7 @@ class SimpleObjectCache(object):
|
|
1186
1312
|
if obj.uuid in self.dirty_objs:
|
1187
1313
|
self.dirty_objs.remove(obj.uuid)
|
1188
1314
|
|
1189
|
-
def get_dirty_objs(self):
|
1315
|
+
def get_dirty_objs(self) -> list[ContentNode]:
|
1190
1316
|
"""
|
1191
1317
|
Get all dirty objects in the cache.
|
1192
1318
|
|
@@ -1260,6 +1386,40 @@ class PersistenceManager(object):
|
|
1260
1386
|
document, filename, delete_on_close, inmemory=inmemory
|
1261
1387
|
)
|
1262
1388
|
|
1389
|
+
def get_steps(self) -> list[ProcessingStep]:
|
1390
|
+
"""
|
1391
|
+
Gets the processing steps for this document
|
1392
|
+
|
1393
|
+
:return:
|
1394
|
+
"""
|
1395
|
+
return self._underlying_persistence.get_steps()
|
1396
|
+
|
1397
|
+
def set_steps(self, steps: list[ProcessingStep]):
|
1398
|
+
self._underlying_persistence.set_steps(steps)
|
1399
|
+
|
1400
|
+
def set_validations(self, validations: list[DocumentTaxonValidation]):
|
1401
|
+
self._underlying_persistence.set_validations(validations)
|
1402
|
+
|
1403
|
+
def get_validations(self) -> list[DocumentTaxonValidation]:
|
1404
|
+
return self._underlying_persistence.get_validations()
|
1405
|
+
|
1406
|
+
def get_external_data(self) -> dict:
|
1407
|
+
"""
|
1408
|
+
Gets the external data object associated with this document
|
1409
|
+
|
1410
|
+
:return: dict of the external data
|
1411
|
+
"""
|
1412
|
+
return self._underlying_persistence.get_external_data()
|
1413
|
+
|
1414
|
+
def set_external_data(self, external_data:dict):
|
1415
|
+
"""
|
1416
|
+
Sets the external data for this document
|
1417
|
+
|
1418
|
+
:param external_data: dict representing the external data, must be JSON serializable
|
1419
|
+
:return:
|
1420
|
+
"""
|
1421
|
+
self._underlying_persistence.set_external_data(external_data)
|
1422
|
+
|
1263
1423
|
def get_nodes_by_type(self, node_type: str) -> List[ContentNode]:
|
1264
1424
|
"""
|
1265
1425
|
Retrieves all nodes of a given type from the underlying persistence layer.
|
@@ -1283,7 +1443,10 @@ class PersistenceManager(object):
|
|
1283
1443
|
ContentNode: The node with the given uuid.
|
1284
1444
|
"""
|
1285
1445
|
if self.node_cache.get_obj(uuid) is None:
|
1286
|
-
self.
|
1446
|
+
node = self._underlying_persistence.get_node(uuid)
|
1447
|
+
if node:
|
1448
|
+
self.node_cache.add_obj(node)
|
1449
|
+
return node
|
1287
1450
|
|
1288
1451
|
return self.node_cache.get_obj(uuid) # return the cached version
|
1289
1452
|
|
kodexa/platform/client.py
CHANGED
@@ -86,7 +86,7 @@ from kodexa.model.objects import (
|
|
86
86
|
PageExtensionPack,
|
87
87
|
PageOrganization,
|
88
88
|
DocumentFamilyStatistics, MessageContext, PagePrompt, Prompt, GuidanceSet, PageGuidanceSet, DocumentEmbedding,
|
89
|
-
DocumentExternalData,
|
89
|
+
DocumentExternalData, Task, PageTask, RetainedGuidance, PageRetainedGuidance,
|
90
90
|
)
|
91
91
|
|
92
92
|
logger = logging.getLogger()
|
@@ -494,7 +494,7 @@ class ComponentEndpoint(ClientEndpoint, OrganizationOwned):
|
|
494
494
|
self.get_page_class(list_response.json())
|
495
495
|
.model_validate(list_response.json())
|
496
496
|
.set_client(self.client)
|
497
|
-
.to_endpoints()
|
497
|
+
.to_endpoints().content
|
498
498
|
):
|
499
499
|
yield endpoint
|
500
500
|
|
@@ -1173,6 +1173,35 @@ class PagePipelineEndpoint(PagePipeline, PageEndpoint):
|
|
1173
1173
|
return "pipeline"
|
1174
1174
|
|
1175
1175
|
|
1176
|
+
class PageTaskEndpoint(PageTask, PageEndpoint):
|
1177
|
+
def get_type(self) -> Optional[str]:
|
1178
|
+
return "task"
|
1179
|
+
|
1180
|
+
|
1181
|
+
class PageRetainedGuidanceEndpoint(PageRetainedGuidance, PageEndpoint):
|
1182
|
+
"""Represents a page retained guidance endpoint.
|
1183
|
+
|
1184
|
+
This class is used to represent a page retained guidance endpoint which is a
|
1185
|
+
combination of a page retained guidance and a page endpoint.
|
1186
|
+
|
1187
|
+
Attributes:
|
1188
|
+
None
|
1189
|
+
"""
|
1190
|
+
|
1191
|
+
"""Represents a page retained guidance endpoint"""
|
1192
|
+
|
1193
|
+
def get_type(self) -> Optional[str]:
|
1194
|
+
"""Get the type of the endpoint.
|
1195
|
+
|
1196
|
+
This method is used to get the type of the endpoint. In this case,
|
1197
|
+
it will always return "retainedGuidance".
|
1198
|
+
|
1199
|
+
Returns:
|
1200
|
+
str: The type of the endpoint, which is "retainedGuidance".
|
1201
|
+
"""
|
1202
|
+
return "retainedGuidance"
|
1203
|
+
|
1204
|
+
|
1176
1205
|
class PageProjectEndpoint(PageProject, PageEndpoint):
|
1177
1206
|
"""Represents a page project endpoint.
|
1178
1207
|
|
@@ -2517,14 +2546,42 @@ class WorkspaceEndpoint(EntityEndpoint, Workspace):
|
|
2517
2546
|
raise ValueError("Workspace has no channel")
|
2518
2547
|
|
2519
2548
|
|
2549
|
+
class TaskEndpoint(EntityEndpoint, Task):
|
2550
|
+
"""Represents a task endpoint.
|
2551
|
+
|
2552
|
+
This class is used to interact with the task endpoint of the API.
|
2553
|
+
"""
|
2554
|
+
|
2555
|
+
def get_type(self) -> str:
|
2556
|
+
"""Get the type of the endpoint.
|
2557
|
+
|
2558
|
+
Returns:
|
2559
|
+
str: The type of the endpoint, in this case "projects".
|
2560
|
+
"""
|
2561
|
+
return "tasks"
|
2562
|
+
|
2563
|
+
|
2564
|
+
class RetainedGuidanceEndpoint(EntityEndpoint, RetainedGuidance):
|
2565
|
+
"""Represents a retained guidance endpoint.
|
2566
|
+
|
2567
|
+
This class is used to interact with the retained guidance endpoint of the API.
|
2568
|
+
"""
|
2569
|
+
|
2570
|
+
def get_type(self) -> str:
|
2571
|
+
"""Get the type of the endpoint.
|
2572
|
+
|
2573
|
+
Returns:
|
2574
|
+
str: The type of the endpoint, in this case "retainedGuidance".
|
2575
|
+
"""
|
2576
|
+
return "retainedGuidance"
|
2577
|
+
|
2578
|
+
|
2520
2579
|
class ProjectEndpoint(EntityEndpoint, Project):
|
2521
2580
|
"""Represents a project endpoint.
|
2522
2581
|
|
2523
2582
|
This class is used to interact with the project endpoint of the API.
|
2524
2583
|
"""
|
2525
2584
|
|
2526
|
-
"""Represents a project endpoint"""
|
2527
|
-
|
2528
2585
|
def get_type(self) -> str:
|
2529
2586
|
"""Get the type of the endpoint.
|
2530
2587
|
|
@@ -2849,6 +2906,72 @@ class AssistantsEndpoint(EntitiesEndpoint):
|
|
2849
2906
|
return PageAssistantEndpoint
|
2850
2907
|
|
2851
2908
|
|
2909
|
+
class TasksEndpoint(EntitiesEndpoint):
|
2910
|
+
"""Represents a projects endpoint"""
|
2911
|
+
|
2912
|
+
"""Represents a projects endpoint"""
|
2913
|
+
|
2914
|
+
def get_type(self) -> str:
|
2915
|
+
"""
|
2916
|
+
Get the type of the endpoint.
|
2917
|
+
|
2918
|
+
Returns:
|
2919
|
+
str: The type of the endpoint.
|
2920
|
+
"""
|
2921
|
+
return "tasks"
|
2922
|
+
|
2923
|
+
def get_instance_class(self, object_dict=None):
|
2924
|
+
"""
|
2925
|
+
Get the instance class of the endpoint.
|
2926
|
+
|
2927
|
+
Returns:
|
2928
|
+
ProjectEndpoint: The instance class of the endpoint.
|
2929
|
+
"""
|
2930
|
+
return TaskEndpoint
|
2931
|
+
|
2932
|
+
def get_page_class(self, object_dict=None):
|
2933
|
+
"""
|
2934
|
+
Get the page class of the endpoint.
|
2935
|
+
|
2936
|
+
Returns:
|
2937
|
+
PageProjectEndpoint: The page class of the endpoint.
|
2938
|
+
"""
|
2939
|
+
return PageTaskEndpoint
|
2940
|
+
|
2941
|
+
|
2942
|
+
class RetainedGuidancesEndpoint(EntitiesEndpoint):
|
2943
|
+
"""Represents a projects endpoint"""
|
2944
|
+
|
2945
|
+
"""Represents a projects endpoint"""
|
2946
|
+
|
2947
|
+
def get_type(self) -> str:
|
2948
|
+
"""
|
2949
|
+
Get the type of the endpoint.
|
2950
|
+
|
2951
|
+
Returns:
|
2952
|
+
str: The type of the endpoint.
|
2953
|
+
"""
|
2954
|
+
return "retainedGuidance"
|
2955
|
+
|
2956
|
+
def get_instance_class(self, object_dict=None):
|
2957
|
+
"""
|
2958
|
+
Get the instance class of the endpoint.
|
2959
|
+
|
2960
|
+
Returns:
|
2961
|
+
ProjectEndpoint: The instance class of the endpoint.
|
2962
|
+
"""
|
2963
|
+
return RetainedGuidanceEndpoint
|
2964
|
+
|
2965
|
+
def get_page_class(self, object_dict=None):
|
2966
|
+
"""
|
2967
|
+
Get the page class of the endpoint.
|
2968
|
+
|
2969
|
+
Returns:
|
2970
|
+
PageProjectEndpoint: The page class of the endpoint.
|
2971
|
+
"""
|
2972
|
+
return PageRetainedGuidanceEndpoint
|
2973
|
+
|
2974
|
+
|
2852
2975
|
class ProjectsEndpoint(EntitiesEndpoint):
|
2853
2976
|
"""Represents a projects endpoint"""
|
2854
2977
|
|
@@ -3946,6 +4069,18 @@ class TaxonomyEndpoint(ComponentInstanceEndpoint, Taxonomy):
|
|
3946
4069
|
params={"format": "xsd"},
|
3947
4070
|
).text
|
3948
4071
|
|
4072
|
+
def to_json_schema(self) -> dict:
|
4073
|
+
"""
|
4074
|
+
Convert the taxonomy to an XSD.
|
4075
|
+
|
4076
|
+
Returns:
|
4077
|
+
str: The XSD representation of the taxonomy.
|
4078
|
+
"""
|
4079
|
+
return self.client.get(
|
4080
|
+
f'/api/taxonomies/{self.ref.replace(":", "/")}/export',
|
4081
|
+
params={"format": "json-schema"},
|
4082
|
+
).json()
|
4083
|
+
|
3949
4084
|
def get_taxon_by_path(self, path) -> Optional[Taxon]:
|
3950
4085
|
"""
|
3951
4086
|
Get a taxon by its path.
|
@@ -4457,7 +4592,7 @@ class DocumentFamilyEndpoint(DocumentFamily, ClientEndpoint):
|
|
4457
4592
|
response = self.client.get(url)
|
4458
4593
|
process_response(response)
|
4459
4594
|
|
4460
|
-
def get_external_data(self) ->
|
4595
|
+
def get_external_data(self) -> dict:
|
4461
4596
|
"""
|
4462
4597
|
Get the external data of the document family.
|
4463
4598
|
|
@@ -4466,18 +4601,21 @@ class DocumentFamilyEndpoint(DocumentFamily, ClientEndpoint):
|
|
4466
4601
|
"""
|
4467
4602
|
url = f"/api/documentFamilies/{self.id}/externalData"
|
4468
4603
|
response = self.client.get(url)
|
4469
|
-
return
|
4604
|
+
return response.json()
|
4470
4605
|
|
4471
|
-
def
|
4606
|
+
def set_external_data(self, external_data: dict) -> dict:
|
4472
4607
|
"""
|
4473
|
-
|
4608
|
+
Set the external data of the document family.
|
4474
4609
|
|
4475
4610
|
Args:
|
4476
|
-
external_data (
|
4611
|
+
external_data (dict): The external data to set for the document family.
|
4612
|
+
|
4613
|
+
Returns:
|
4614
|
+
dict: The updated external data of the document family.
|
4477
4615
|
"""
|
4478
4616
|
url = f"/api/documentFamilies/{self.id}/externalData"
|
4479
|
-
response = self.client.put(url,
|
4480
|
-
|
4617
|
+
response = self.client.put(url, data=external_data)
|
4618
|
+
return response.json()
|
4481
4619
|
|
4482
4620
|
def export(self) -> bytes:
|
4483
4621
|
"""
|
@@ -5289,6 +5427,7 @@ class DocumentStoreEndpoint(StoreEndpoint):
|
|
5289
5427
|
object_path: Optional[str] = None,
|
5290
5428
|
replace=False,
|
5291
5429
|
additional_metadata: Optional[dict] = None,
|
5430
|
+
external_data: Optional[dict] = None,
|
5292
5431
|
):
|
5293
5432
|
"""
|
5294
5433
|
Upload a file to the store.
|
@@ -5298,6 +5437,7 @@ class DocumentStoreEndpoint(StoreEndpoint):
|
|
5298
5437
|
object_path (Optional[str]): The path to the object (Default is the same the file path).
|
5299
5438
|
replace (bool): Replace the file if it already exists (Default False).
|
5300
5439
|
additional_metadata (Optional[dict]): Additional metadata to add to the file (Default None).
|
5440
|
+
external_data (Optional[dict]): External data to add to the file (Default None).
|
5301
5441
|
"""
|
5302
5442
|
if Path(file_path).is_file():
|
5303
5443
|
logger.info(f"Uploading {file_path}")
|
@@ -5307,6 +5447,7 @@ class DocumentStoreEndpoint(StoreEndpoint):
|
|
5307
5447
|
content=path_content,
|
5308
5448
|
replace=replace,
|
5309
5449
|
additional_metadata=additional_metadata,
|
5450
|
+
external_data=external_data
|
5310
5451
|
)
|
5311
5452
|
else:
|
5312
5453
|
raise Exception(f"{file_path} is not a file")
|
@@ -5317,6 +5458,7 @@ class DocumentStoreEndpoint(StoreEndpoint):
|
|
5317
5458
|
content,
|
5318
5459
|
replace=False,
|
5319
5460
|
additional_metadata: Optional[dict] = None,
|
5461
|
+
external_data: Optional[dict] = None,
|
5320
5462
|
) -> DocumentFamilyEndpoint:
|
5321
5463
|
"""
|
5322
5464
|
Put the content into the store at the given path.
|
@@ -5326,6 +5468,7 @@ class DocumentStoreEndpoint(StoreEndpoint):
|
|
5326
5468
|
content: The content for that object.
|
5327
5469
|
replace (bool): Replace the content if it exists.
|
5328
5470
|
additional_metadata (Optional[dict]): Additional metadata to store with the document (not it can't include 'path').
|
5471
|
+
external_data (Optional[dict]): External data to store with the document.
|
5329
5472
|
|
5330
5473
|
Returns:
|
5331
5474
|
DocumentFamilyEndpoint: The document family that was created.
|
@@ -5335,6 +5478,9 @@ class DocumentStoreEndpoint(StoreEndpoint):
|
|
5335
5478
|
if additional_metadata is None:
|
5336
5479
|
additional_metadata = {}
|
5337
5480
|
|
5481
|
+
if external_data is not None:
|
5482
|
+
additional_metadata["externalData"] = json.dumps(external_data)
|
5483
|
+
|
5338
5484
|
if replace and self.client.exists(
|
5339
5485
|
f"/api/stores/{self.ref.replace(':', '/')}/fs", params={"path": path}
|
5340
5486
|
):
|
@@ -6332,6 +6478,10 @@ class KodexaClient:
|
|
6332
6478
|
executions (ExecutionsEndpoint): An endpoint for executions.
|
6333
6479
|
channels (ChannelsEndpoint): An endpoint for channels.
|
6334
6480
|
messages (MessagesEndpoint): An endpoint for messages.
|
6481
|
+
assistants (AssistantsEndpoint): An endpoint for assistants.
|
6482
|
+
products (ProductsEndpoint): An endpoint for products.
|
6483
|
+
tasks (TasksEndpoint): An endpoint for tasks.
|
6484
|
+
retained_guidances (RetainedGuidancesEndpoint): An endpoint for retained guidances.
|
6335
6485
|
"""
|
6336
6486
|
|
6337
6487
|
def __init__(self, url=None, access_token=None, profile=None):
|
@@ -6354,6 +6504,8 @@ class KodexaClient:
|
|
6354
6504
|
self.messages = MessagesEndpoint(self)
|
6355
6505
|
from kodexa.model.entities.product import ProductsEndpoint
|
6356
6506
|
self.products = ProductsEndpoint(self)
|
6507
|
+
self.tasks = TasksEndpoint(self)
|
6508
|
+
self.retained_guidances = RetainedGuidancesEndpoint(self)
|
6357
6509
|
|
6358
6510
|
@staticmethod
|
6359
6511
|
def login(url, token):
|
@@ -6370,7 +6522,6 @@ class KodexaClient:
|
|
6370
6522
|
Raises:
|
6371
6523
|
Exception: If the status code is not 200.
|
6372
6524
|
"""
|
6373
|
-
from requests.auth import HTTPBasicAuth
|
6374
6525
|
|
6375
6526
|
obj_response = requests.get(
|
6376
6527
|
f"{url}/api/account/me",
|
@@ -6751,7 +6902,6 @@ class KodexaClient:
|
|
6751
6902
|
)
|
6752
6903
|
)
|
6753
6904
|
|
6754
|
-
|
6755
6905
|
def import_project(self, organization: OrganizationEndpoint, import_path: str):
|
6756
6906
|
"""
|
6757
6907
|
A method to import a project.
|
@@ -6947,8 +7097,10 @@ class KodexaClient:
|
|
6947
7097
|
"message": MessageEndpoint,
|
6948
7098
|
"prompt": PromptEndpoint,
|
6949
7099
|
"guidance": GuidanceSetEndpoint,
|
7100
|
+
"retainedGuidance": RetainedGuidanceEndpoint,
|
6950
7101
|
"channel": ChannelEndpoint,
|
6951
7102
|
"product": ProductEndpoint,
|
7103
|
+
"task": TaskEndpoint,
|
6952
7104
|
"productSubscription": ProductSubscriptionEndpoint,
|
6953
7105
|
"checkResponse": CheckResponseEndpoint
|
6954
7106
|
}
|
kodexa/platform/kodexa.py
CHANGED
@@ -29,7 +29,7 @@ from kodexa.model.objects import (
|
|
29
29
|
DocumentFamilyEvent,
|
30
30
|
ChannelEvent,
|
31
31
|
DataObjectEvent,
|
32
|
-
WorkspaceEvent,
|
32
|
+
WorkspaceEvent, DocumentFamily,
|
33
33
|
)
|
34
34
|
from kodexa.pipeline import PipelineContext, PipelineStatistics
|
35
35
|
from kodexa.platform.client import DocumentStoreEndpoint, KodexaClient, process_response
|
@@ -327,7 +327,7 @@ class KodexaPlatform:
|
|
327
327
|
dict: The server information.
|
328
328
|
"""
|
329
329
|
r = requests.get(
|
330
|
-
f"{KodexaPlatform.get_url()}/api",
|
330
|
+
f"{KodexaPlatform.get_url()}/api/overview",
|
331
331
|
headers={
|
332
332
|
"x-access-token": KodexaPlatform.get_access_token(),
|
333
333
|
"cf-access-token": os.environ.get("CF_TOKEN", ""),
|
@@ -884,7 +884,7 @@ class EventHelper:
|
|
884
884
|
ContentObject: The posted content object.
|
885
885
|
"""
|
886
886
|
files = {"content": content}
|
887
|
-
data = {"contentObjectJson": json.dumps(content_object.
|
887
|
+
data = {"contentObjectJson": json.dumps(content_object.model_dump(by_alias=True))}
|
888
888
|
logger.info("Posting back content object to execution object")
|
889
889
|
co_response = requests.post(
|
890
890
|
f"{KodexaPlatform.get_url()}/api/sessions/{self.event.session_id}/executions/{self.event.execution.id}/objects",
|
@@ -901,7 +901,7 @@ class EventHelper:
|
|
901
901
|
|
902
902
|
return ContentObject.model_validate(co_response.json())
|
903
903
|
|
904
|
-
def build_pipeline_context(self) -> PipelineContext:
|
904
|
+
def build_pipeline_context(self, event) -> PipelineContext:
|
905
905
|
"""Builds a pipeline context.
|
906
906
|
|
907
907
|
Returns:
|
@@ -911,16 +911,26 @@ class EventHelper:
|
|
911
911
|
context={}, content_provider=self, execution_id=self.event.execution.id
|
912
912
|
)
|
913
913
|
|
914
|
-
if
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
|
914
|
+
if isinstance(event, dict):
|
915
|
+
event = self.get_base_event(event)
|
916
|
+
|
917
|
+
if isinstance(event, DocumentFamilyEvent):
|
918
|
+
# Can we get the document family
|
919
|
+
dfe:DocumentFamilyEvent = self.event
|
920
|
+
if dfe.document_family:
|
921
|
+
logger.info(f"Setting document family for context: {dfe.document_family}")
|
922
|
+
context.document_family = dfe.document_family
|
923
|
+
logger.info(f"Getting document store for family: {context.document_family.store_ref}")
|
924
|
+
context.document_store = KodexaClient().get_object_by_ref("store", context.document_family.store_ref)
|
925
|
+
if isinstance(event, ContentEvent):
|
926
|
+
ce:ContentEvent = self.event
|
927
|
+
if ce.content_object:
|
928
|
+
logger.info(f"Setting content object for context: {ce.content_object}")
|
929
|
+
context.content_object = ce.content_object
|
930
|
+
context.document_family = ce.document_family
|
931
|
+
logger.info(f"Getting document store for content object: {context.content_object.store_ref}")
|
932
|
+
context.document_store = KodexaClient().get_object_by_ref("store", context.content_object.store_ref)
|
933
|
+
logger.info("Returning context")
|
924
934
|
return context
|
925
935
|
|
926
936
|
def get_input_document(self, context):
|