nucliadb 6.2.1.post2882__py3-none-any.whl → 6.2.1.post2887__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.
- nucliadb/common/datamanagers/fields.py +2 -0
- nucliadb/ingest/orm/resource.py +24 -14
- nucliadb/ingest/serialize.py +44 -19
- nucliadb/ingest/service/writer.py +2 -60
- nucliadb/reader/api/models.py +2 -0
- nucliadb/reader/api/v1/resource.py +17 -3
- nucliadb/writer/api/v1/__init__.py +1 -0
- nucliadb/writer/api/v1/knowledgebox.py +2 -46
- nucliadb/writer/api/v1/upload.py +9 -3
- nucliadb/writer/api/v1/vectorsets.py +79 -0
- nucliadb/writer/vectorsets.py +10 -3
- {nucliadb-6.2.1.post2882.dist-info → nucliadb-6.2.1.post2887.dist-info}/METADATA +5 -5
- {nucliadb-6.2.1.post2882.dist-info → nucliadb-6.2.1.post2887.dist-info}/RECORD +17 -16
- {nucliadb-6.2.1.post2882.dist-info → nucliadb-6.2.1.post2887.dist-info}/WHEEL +0 -0
- {nucliadb-6.2.1.post2882.dist-info → nucliadb-6.2.1.post2887.dist-info}/entry_points.txt +0 -0
- {nucliadb-6.2.1.post2882.dist-info → nucliadb-6.2.1.post2887.dist-info}/top_level.txt +0 -0
- {nucliadb-6.2.1.post2882.dist-info → nucliadb-6.2.1.post2887.dist-info}/zip-safe +0 -0
nucliadb/ingest/orm/resource.py
CHANGED
@@ -69,7 +69,9 @@ from nucliadb_protos.resources_pb2 import Origin as PBOrigin
|
|
69
69
|
from nucliadb_protos.resources_pb2 import Relations as PBRelations
|
70
70
|
from nucliadb_protos.utils_pb2 import Relation as PBRelation
|
71
71
|
from nucliadb_protos.writer_pb2 import BrokerMessage
|
72
|
+
from nucliadb_utils import const
|
72
73
|
from nucliadb_utils.storages.storage import Storage
|
74
|
+
from nucliadb_utils.utilities import has_feature
|
73
75
|
|
74
76
|
if TYPE_CHECKING: # pragma: no cover
|
75
77
|
from nucliadb.ingest.orm.knowledgebox import KnowledgeBox
|
@@ -535,6 +537,7 @@ class Resource:
|
|
535
537
|
for (field_type, field), errors in errors_by_field.items():
|
536
538
|
field_obj = await self.get_field(field, field_type, load=False)
|
537
539
|
if from_processor:
|
540
|
+
# Create a new field status to clear all errors
|
538
541
|
status = writer_pb2.FieldStatus()
|
539
542
|
else:
|
540
543
|
status = await field_obj.get_status() or writer_pb2.FieldStatus()
|
@@ -548,7 +551,7 @@ class Resource:
|
|
548
551
|
|
549
552
|
# We infer the status for processor messages
|
550
553
|
if message.source == BrokerMessage.MessageSource.PROCESSOR:
|
551
|
-
if len(errors) > 0:
|
554
|
+
if len(status.errors) > 0:
|
552
555
|
status.status = writer_pb2.FieldStatus.Status.ERROR
|
553
556
|
else:
|
554
557
|
status.status = writer_pb2.FieldStatus.Status.PROCESSED
|
@@ -563,14 +566,19 @@ class Resource:
|
|
563
566
|
)
|
564
567
|
if field_status:
|
565
568
|
status.status = field_status
|
569
|
+
# If the field was not found and the message comes from the writer, this implicitly sets the
|
570
|
+
# status to the default value, which is PROCESSING. This covers the case of new field creation.
|
566
571
|
|
567
572
|
await field_obj.set_status(status)
|
568
573
|
|
569
574
|
async def update_status(self):
|
570
575
|
field_ids = await self.get_all_field_ids(for_update=False)
|
576
|
+
if field_ids is None:
|
577
|
+
return
|
571
578
|
field_statuses = await datamanagers.fields.get_statuses(
|
572
579
|
self.txn, kbid=self.kb.kbid, rid=self.uuid, fields=field_ids.fields
|
573
580
|
)
|
581
|
+
|
574
582
|
# If any field is processing -> PENDING
|
575
583
|
if any((f.status == writer_pb2.FieldStatus.Status.PENDING for f in field_statuses)):
|
576
584
|
self.basic.metadata.status = PBMetadata.Status.PENDING
|
@@ -594,12 +602,11 @@ class Resource:
|
|
594
602
|
|
595
603
|
@processor_observer.wrap({"type": "apply_extracted"})
|
596
604
|
async def apply_extracted(self, message: BrokerMessage):
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
errors = True
|
605
|
+
if not has_feature(const.Features.FIELD_STATUS):
|
606
|
+
field_obj: Field
|
607
|
+
for error in message.errors:
|
608
|
+
field_obj = await self.get_field(error.field, error.field_type, load=False)
|
609
|
+
await field_obj.set_error(error)
|
603
610
|
|
604
611
|
await self.get_basic()
|
605
612
|
if self.basic is None:
|
@@ -608,11 +615,6 @@ class Resource:
|
|
608
615
|
previous_basic = Basic()
|
609
616
|
previous_basic.CopyFrom(self.basic)
|
610
617
|
|
611
|
-
if errors:
|
612
|
-
self.basic.metadata.status = PBMetadata.Status.ERROR
|
613
|
-
elif errors is False and message.source is message.MessageSource.PROCESSOR:
|
614
|
-
self.basic.metadata.status = PBMetadata.Status.PROCESSED
|
615
|
-
|
616
618
|
maybe_update_basic_icon(self.basic, get_text_field_mimetype(message))
|
617
619
|
|
618
620
|
for question_answers in message.question_answers:
|
@@ -621,9 +623,17 @@ class Resource:
|
|
621
623
|
for extracted_text in message.extracted_text:
|
622
624
|
await self._apply_extracted_text(extracted_text)
|
623
625
|
|
624
|
-
#
|
626
|
+
# Update field and resource status depending on processing results
|
625
627
|
await self.apply_fields_status(message, self._modified_extracted_text)
|
626
|
-
|
628
|
+
if has_feature(const.Features.FIELD_STATUS):
|
629
|
+
# Compute resource status based on all fields statuses
|
630
|
+
await self.update_status()
|
631
|
+
else:
|
632
|
+
# Old code path, compute resource status based on the presence of errors in this BrokerMessage
|
633
|
+
if message.errors:
|
634
|
+
self.basic.metadata.status = PBMetadata.Status.ERROR
|
635
|
+
elif message.source is message.MessageSource.PROCESSOR:
|
636
|
+
self.basic.metadata.status = PBMetadata.Status.PROCESSED
|
627
637
|
|
628
638
|
extracted_languages = []
|
629
639
|
|
nucliadb/ingest/serialize.py
CHANGED
@@ -17,7 +17,8 @@
|
|
17
17
|
# You should have received a copy of the GNU Affero General Public License
|
18
18
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
19
19
|
#
|
20
|
-
|
20
|
+
|
21
|
+
from typing import Optional, Union
|
21
22
|
|
22
23
|
import nucliadb_models as models
|
23
24
|
from nucliadb.common import datamanagers
|
@@ -50,7 +51,9 @@ from nucliadb_models.resource import (
|
|
50
51
|
)
|
51
52
|
from nucliadb_models.search import ResourceProperties
|
52
53
|
from nucliadb_models.security import ResourceSecurity
|
53
|
-
from
|
54
|
+
from nucliadb_protos.writer_pb2 import FieldStatus
|
55
|
+
from nucliadb_utils import const
|
56
|
+
from nucliadb_utils.utilities import get_storage, has_feature
|
54
57
|
|
55
58
|
|
56
59
|
async def set_resource_field_extracted_data(
|
@@ -145,6 +148,40 @@ async def serialize(
|
|
145
148
|
)
|
146
149
|
|
147
150
|
|
151
|
+
async def serialize_field_errors(
|
152
|
+
field: Field,
|
153
|
+
serialized: Union[
|
154
|
+
TextFieldData, FileFieldData, LinkFieldData, ConversationFieldData, GenericFieldData
|
155
|
+
],
|
156
|
+
):
|
157
|
+
if has_feature(const.Features.FIELD_STATUS):
|
158
|
+
status = await field.get_status()
|
159
|
+
if status is None:
|
160
|
+
status = FieldStatus()
|
161
|
+
serialized.status = status.Status.Name(status.status)
|
162
|
+
if status.errors:
|
163
|
+
serialized.errors = []
|
164
|
+
for error in status.errors:
|
165
|
+
serialized.errors.append(
|
166
|
+
Error(
|
167
|
+
body=error.source_error.error,
|
168
|
+
code=error.source_error.code,
|
169
|
+
code_str=error.source_error.ErrorCode.Name(error.source_error.code),
|
170
|
+
created=error.created.ToDatetime(),
|
171
|
+
)
|
172
|
+
)
|
173
|
+
serialized.error = serialized.errors[-1]
|
174
|
+
else:
|
175
|
+
field_error = await field.get_error()
|
176
|
+
if field_error is not None:
|
177
|
+
serialized.error = Error(
|
178
|
+
body=field_error.error,
|
179
|
+
code=field_error.code,
|
180
|
+
code_str=field_error.ErrorCode.Name(field_error.code),
|
181
|
+
created=None,
|
182
|
+
)
|
183
|
+
|
184
|
+
|
148
185
|
async def managed_serialize(
|
149
186
|
txn: Transaction,
|
150
187
|
kbid: str,
|
@@ -249,9 +286,7 @@ async def managed_serialize(
|
|
249
286
|
serialized_value = from_proto.field_text(value) if value is not None else None
|
250
287
|
resource.data.texts[field.id].value = serialized_value
|
251
288
|
if include_errors:
|
252
|
-
|
253
|
-
if error is not None:
|
254
|
-
resource.data.texts[field.id].error = Error(body=error.error, code=error.code)
|
289
|
+
await serialize_field_errors(field, resource.data.texts[field.id])
|
255
290
|
if include_extracted_data:
|
256
291
|
resource.data.texts[field.id].extracted = TextFieldExtractedData()
|
257
292
|
await set_resource_field_extracted_data(
|
@@ -272,9 +307,7 @@ async def managed_serialize(
|
|
272
307
|
resource.data.files[field.id].value = None
|
273
308
|
|
274
309
|
if include_errors:
|
275
|
-
|
276
|
-
if error is not None:
|
277
|
-
resource.data.files[field.id].error = Error(body=error.error, code=error.code)
|
310
|
+
await serialize_field_errors(field, resource.data.files[field.id])
|
278
311
|
|
279
312
|
if include_extracted_data:
|
280
313
|
resource.data.files[field.id].extracted = FileFieldExtractedData()
|
@@ -293,9 +326,7 @@ async def managed_serialize(
|
|
293
326
|
resource.data.links[field.id].value = from_proto.field_link(value)
|
294
327
|
|
295
328
|
if include_errors:
|
296
|
-
|
297
|
-
if error is not None:
|
298
|
-
resource.data.links[field.id].error = Error(body=error.error, code=error.code)
|
329
|
+
await serialize_field_errors(field, resource.data.links[field.id])
|
299
330
|
|
300
331
|
if include_extracted_data:
|
301
332
|
resource.data.links[field.id].extracted = LinkFieldExtractedData()
|
@@ -311,11 +342,7 @@ async def managed_serialize(
|
|
311
342
|
if field.id not in resource.data.conversations:
|
312
343
|
resource.data.conversations[field.id] = ConversationFieldData()
|
313
344
|
if include_errors:
|
314
|
-
|
315
|
-
if error is not None:
|
316
|
-
resource.data.conversations[field.id].error = Error(
|
317
|
-
body=error.error, code=error.code
|
318
|
-
)
|
345
|
+
await serialize_field_errors(field, resource.data.conversations[field.id])
|
319
346
|
if include_value and isinstance(field, Conversation):
|
320
347
|
value = await field.get_metadata()
|
321
348
|
resource.data.conversations[field.id].value = from_proto.field_conversation(value)
|
@@ -335,9 +362,7 @@ async def managed_serialize(
|
|
335
362
|
if include_value:
|
336
363
|
resource.data.generics[field.id].value = value
|
337
364
|
if include_errors:
|
338
|
-
|
339
|
-
if error is not None:
|
340
|
-
resource.data.generics[field.id].error = Error(body=error.error, code=error.code)
|
365
|
+
await serialize_field_errors(field, resource.data.generics[field.id])
|
341
366
|
if include_extracted_data:
|
342
367
|
resource.data.generics[field.id].extracted = TextFieldExtractedData(
|
343
368
|
text=models.ExtractedText(text=resource.data.generics[field.id].value)
|
@@ -31,12 +31,12 @@ from nucliadb.common.maindb.utils import setup_driver
|
|
31
31
|
from nucliadb.ingest import SERVICE_NAME, logger
|
32
32
|
from nucliadb.ingest.orm.broker_message import generate_broker_message
|
33
33
|
from nucliadb.ingest.orm.entities import EntitiesManager
|
34
|
-
from nucliadb.ingest.orm.exceptions import KnowledgeBoxConflict
|
34
|
+
from nucliadb.ingest.orm.exceptions import KnowledgeBoxConflict
|
35
35
|
from nucliadb.ingest.orm.knowledgebox import KnowledgeBox as KnowledgeBoxORM
|
36
36
|
from nucliadb.ingest.orm.processor import Processor, sequence_manager
|
37
37
|
from nucliadb.ingest.orm.resource import Resource as ResourceORM
|
38
38
|
from nucliadb.ingest.settings import settings
|
39
|
-
from nucliadb_protos import
|
39
|
+
from nucliadb_protos import writer_pb2, writer_pb2_grpc
|
40
40
|
from nucliadb_protos.knowledgebox_pb2 import (
|
41
41
|
DeleteKnowledgeBoxResponse,
|
42
42
|
KnowledgeBoxID,
|
@@ -44,13 +44,10 @@ from nucliadb_protos.knowledgebox_pb2 import (
|
|
44
44
|
KnowledgeBoxUpdate,
|
45
45
|
SemanticModelMetadata,
|
46
46
|
UpdateKnowledgeBoxResponse,
|
47
|
-
VectorSetConfig,
|
48
47
|
)
|
49
48
|
from nucliadb_protos.writer_pb2 import (
|
50
49
|
BrokerMessage,
|
51
50
|
DelEntitiesRequest,
|
52
|
-
DelVectorSetRequest,
|
53
|
-
DelVectorSetResponse,
|
54
51
|
GetEntitiesGroupRequest,
|
55
52
|
GetEntitiesGroupResponse,
|
56
53
|
GetEntitiesRequest,
|
@@ -63,8 +60,6 @@ from nucliadb_protos.writer_pb2 import (
|
|
63
60
|
ListMembersResponse,
|
64
61
|
NewEntitiesGroupRequest,
|
65
62
|
NewEntitiesGroupResponse,
|
66
|
-
NewVectorSetRequest,
|
67
|
-
NewVectorSetResponse,
|
68
63
|
OpStatusWriter,
|
69
64
|
SetEntitiesRequest,
|
70
65
|
UpdateEntitiesGroupRequest,
|
@@ -472,56 +467,3 @@ class WriterServicer(writer_pb2_grpc.WriterServicer):
|
|
472
467
|
errors.capture_exception(e)
|
473
468
|
logger.error("Error in ingest gRPC servicer", exc_info=True)
|
474
469
|
raise
|
475
|
-
|
476
|
-
async def NewVectorSet( # type: ignore
|
477
|
-
self, request: NewVectorSetRequest, context=None
|
478
|
-
) -> NewVectorSetResponse:
|
479
|
-
config = VectorSetConfig(
|
480
|
-
vectorset_id=request.vectorset_id,
|
481
|
-
vectorset_index_config=nodewriter_pb2.VectorIndexConfig(
|
482
|
-
similarity=request.similarity,
|
483
|
-
normalize_vectors=request.normalize_vectors,
|
484
|
-
vector_type=request.vector_type,
|
485
|
-
vector_dimension=request.vector_dimension,
|
486
|
-
),
|
487
|
-
matryoshka_dimensions=request.matryoshka_dimensions,
|
488
|
-
storage_key_kind=VectorSetConfig.StorageKeyKind.VECTORSET_PREFIX,
|
489
|
-
)
|
490
|
-
response = NewVectorSetResponse()
|
491
|
-
try:
|
492
|
-
async with self.driver.transaction() as txn:
|
493
|
-
kbobj = KnowledgeBoxORM(txn, self.storage, request.kbid)
|
494
|
-
await kbobj.create_vectorset(config)
|
495
|
-
await txn.commit()
|
496
|
-
except VectorSetConflict as exc:
|
497
|
-
response.status = NewVectorSetResponse.Status.ERROR
|
498
|
-
response.details = str(exc)
|
499
|
-
except Exception as exc:
|
500
|
-
errors.capture_exception(exc)
|
501
|
-
logger.error("Error in ingest gRPC while creating a vectorset", exc_info=True)
|
502
|
-
response.status = NewVectorSetResponse.Status.ERROR
|
503
|
-
response.details = str(exc)
|
504
|
-
else:
|
505
|
-
response.status = NewVectorSetResponse.Status.OK
|
506
|
-
return response
|
507
|
-
|
508
|
-
async def DelVectorSet( # type: ignore
|
509
|
-
self, request: DelVectorSetRequest, context=None
|
510
|
-
) -> DelVectorSetResponse:
|
511
|
-
response = DelVectorSetResponse()
|
512
|
-
try:
|
513
|
-
async with self.driver.transaction() as txn:
|
514
|
-
kbobj = KnowledgeBoxORM(txn, self.storage, request.kbid)
|
515
|
-
await kbobj.delete_vectorset(request.vectorset_id)
|
516
|
-
await txn.commit()
|
517
|
-
except VectorSetConflict as exc:
|
518
|
-
response.status = DelVectorSetResponse.Status.ERROR
|
519
|
-
response.details = str(exc)
|
520
|
-
except Exception as exc:
|
521
|
-
errors.capture_exception(exc)
|
522
|
-
logger.error("Error in ingest gRPC while deleting a vectorset", exc_info=True)
|
523
|
-
response.status = DelVectorSetResponse.Status.ERROR
|
524
|
-
response.details = str(exc)
|
525
|
-
else:
|
526
|
-
response.status = DelVectorSetResponse.Status.OK
|
527
|
-
return response
|
nucliadb/reader/api/models.py
CHANGED
@@ -52,6 +52,8 @@ class ResourceField(BaseModel):
|
|
52
52
|
value: ValueType = None
|
53
53
|
extracted: Optional[ExtractedDataType] = None
|
54
54
|
error: Optional[Error] = None
|
55
|
+
status: Optional[str] = None
|
56
|
+
errors: Optional[list[Error]] = None
|
55
57
|
|
56
58
|
|
57
59
|
FIELD_NAME_TO_EXTRACTED_DATA_FIELD_MAP: dict[FieldTypeName, Any] = {
|
@@ -52,6 +52,7 @@ from nucliadb_models.resource import (
|
|
52
52
|
)
|
53
53
|
from nucliadb_models.search import ResourceProperties
|
54
54
|
from nucliadb_protos import resources_pb2
|
55
|
+
from nucliadb_protos.writer_pb2 import FieldStatus
|
55
56
|
from nucliadb_telemetry import errors
|
56
57
|
from nucliadb_utils.authentication import requires, requires_one
|
57
58
|
from nucliadb_utils.utilities import get_audit, get_storage
|
@@ -388,9 +389,22 @@ async def _get_resource_field(
|
|
388
389
|
)
|
389
390
|
|
390
391
|
if ResourceFieldProperties.ERROR in show:
|
391
|
-
|
392
|
-
if
|
393
|
-
|
392
|
+
status = await field.get_status()
|
393
|
+
if status is None:
|
394
|
+
status = FieldStatus()
|
395
|
+
resource_field.status = status.Status.Name(status.status)
|
396
|
+
if status.errors:
|
397
|
+
resource_field.errors = []
|
398
|
+
for error in status.errors:
|
399
|
+
resource_field.errors.append(
|
400
|
+
Error(
|
401
|
+
body=error.source_error.error,
|
402
|
+
code=error.source_error.code,
|
403
|
+
code_str=error.source_error.ErrorCode.Name(error.source_error.code),
|
404
|
+
created=error.created.ToDatetime(),
|
405
|
+
)
|
406
|
+
)
|
407
|
+
resource_field.error = resource_field.errors[-1]
|
394
408
|
|
395
409
|
return Response(
|
396
410
|
content=resource_field.model_dump_json(exclude_unset=True, by_alias=True),
|
@@ -20,7 +20,7 @@
|
|
20
20
|
import asyncio
|
21
21
|
from functools import partial
|
22
22
|
|
23
|
-
from fastapi import HTTPException
|
23
|
+
from fastapi import HTTPException
|
24
24
|
from fastapi_versioning import version
|
25
25
|
from starlette.requests import Request
|
26
26
|
|
@@ -32,7 +32,7 @@ from nucliadb.common.external_index_providers.exceptions import (
|
|
32
32
|
from nucliadb.common.maindb.utils import get_driver
|
33
33
|
from nucliadb.ingest.orm.exceptions import KnowledgeBoxConflict
|
34
34
|
from nucliadb.ingest.orm.knowledgebox import KnowledgeBox
|
35
|
-
from nucliadb.writer import logger
|
35
|
+
from nucliadb.writer import logger
|
36
36
|
from nucliadb.writer.api.utils import only_for_onprem
|
37
37
|
from nucliadb.writer.api.v1.router import KB_PREFIX, KBS_PREFIX, api
|
38
38
|
from nucliadb.writer.utilities import get_processing
|
@@ -248,47 +248,3 @@ def to_pinecone_serverless_cloud_pb(
|
|
248
248
|
PineconeServerlessCloud.AZURE_EASTUS2: knowledgebox_pb2.PineconeServerlessCloud.AZURE_EASTUS2,
|
249
249
|
PineconeServerlessCloud.GCP_US_CENTRAL1: knowledgebox_pb2.PineconeServerlessCloud.GCP_US_CENTRAL1,
|
250
250
|
}[serverless]
|
251
|
-
|
252
|
-
|
253
|
-
@api.post(
|
254
|
-
f"/{KB_PREFIX}/{{kbid}}/vectorsets/{{vectorset_id}}",
|
255
|
-
status_code=200,
|
256
|
-
summary="Add a vectorset to Knowledge Box",
|
257
|
-
tags=["Knowledge Boxes"],
|
258
|
-
# TODO: remove when the feature is mature
|
259
|
-
include_in_schema=False,
|
260
|
-
)
|
261
|
-
@requires(NucliaDBRoles.MANAGER)
|
262
|
-
@version(1)
|
263
|
-
async def add_vectorset(request: Request, kbid: str, vectorset_id: str) -> Response:
|
264
|
-
try:
|
265
|
-
await vectorsets.add(kbid, vectorset_id)
|
266
|
-
except learning_proxy.ProxiedLearningConfigError as err:
|
267
|
-
return Response(
|
268
|
-
status_code=err.status_code,
|
269
|
-
content=err.content,
|
270
|
-
media_type=err.content_type,
|
271
|
-
)
|
272
|
-
return Response(status_code=200)
|
273
|
-
|
274
|
-
|
275
|
-
@api.delete(
|
276
|
-
f"/{KB_PREFIX}/{{kbid}}/vectorsets/{{vectorset_id}}",
|
277
|
-
status_code=200,
|
278
|
-
summary="Delete vectorset from Knowledge Box",
|
279
|
-
tags=["Knowledge Boxes"],
|
280
|
-
# TODO: remove when the feature is mature
|
281
|
-
include_in_schema=False,
|
282
|
-
)
|
283
|
-
@requires(NucliaDBRoles.MANAGER)
|
284
|
-
@version(1)
|
285
|
-
async def delete_vectorset(request: Request, kbid: str, vectorset_id: str) -> Response:
|
286
|
-
try:
|
287
|
-
await vectorsets.delete(kbid, vectorset_id)
|
288
|
-
except learning_proxy.ProxiedLearningConfigError as err:
|
289
|
-
return Response(
|
290
|
-
status_code=err.status_code,
|
291
|
-
content=err.content,
|
292
|
-
media_type=err.content_type,
|
293
|
-
)
|
294
|
-
return Response(status_code=200)
|
nucliadb/writer/api/v1/upload.py
CHANGED
@@ -64,8 +64,8 @@ from nucliadb_models import content_types
|
|
64
64
|
from nucliadb_models.resource import NucliaDBRoles
|
65
65
|
from nucliadb_models.utils import FieldIdString
|
66
66
|
from nucliadb_models.writer import CreateResourcePayload, ResourceFileUploaded
|
67
|
-
from nucliadb_protos.resources_pb2 import CloudFile, FieldFile, Metadata
|
68
|
-
from nucliadb_protos.writer_pb2 import BrokerMessage
|
67
|
+
from nucliadb_protos.resources_pb2 import CloudFile, FieldFile, FieldID, FieldType, Metadata
|
68
|
+
from nucliadb_protos.writer_pb2 import BrokerMessage, FieldIDStatus, FieldStatus
|
69
69
|
from nucliadb_utils.authentication import requires_one
|
70
70
|
from nucliadb_utils.exceptions import LimitsExceededError, SendToProcessError
|
71
71
|
from nucliadb_utils.storages.storage import KB_RESOURCE_FIELD
|
@@ -511,7 +511,7 @@ async def _tus_patch(
|
|
511
511
|
|
512
512
|
if offset != dm.offset:
|
513
513
|
raise HTTPConflict(
|
514
|
-
detail=f"Current upload offset({offset}) does not match
|
514
|
+
detail=f"Current upload offset({offset}) does not match object offset {dm.offset}"
|
515
515
|
)
|
516
516
|
|
517
517
|
storage_manager = get_storage_manager()
|
@@ -946,6 +946,12 @@ async def store_file_on_nuclia_db(
|
|
946
946
|
writer.files[field].CopyFrom(file_field)
|
947
947
|
# Do not store passwords on maindb
|
948
948
|
writer.files[field].ClearField("password")
|
949
|
+
writer.field_statuses.append(
|
950
|
+
FieldIDStatus(
|
951
|
+
id=FieldID(field_type=FieldType.FILE, field=field),
|
952
|
+
status=FieldStatus.Status.PENDING,
|
953
|
+
)
|
954
|
+
)
|
949
955
|
|
950
956
|
toprocess.filefield[field] = await processing.convert_internal_filefield_to_str(
|
951
957
|
file_field, storage=storage
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# Copyright (C) 2021 Bosutech XXI S.L.
|
2
|
+
#
|
3
|
+
# nucliadb is offered under the AGPL v3.0 and as commercial software.
|
4
|
+
# For commercial licensing, contact us at info@nuclia.com.
|
5
|
+
#
|
6
|
+
# AGPL:
|
7
|
+
# This program is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU Affero General Public License as
|
9
|
+
# published by the Free Software Foundation, either version 3 of the
|
10
|
+
# License, or (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU Affero General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Affero General Public License
|
18
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
#
|
20
|
+
|
21
|
+
from fastapi import Response
|
22
|
+
from fastapi_versioning import version
|
23
|
+
from starlette.requests import Request
|
24
|
+
|
25
|
+
from nucliadb import learning_proxy
|
26
|
+
from nucliadb.ingest.orm.exceptions import VectorSetConflict
|
27
|
+
from nucliadb.models.responses import HTTPConflict
|
28
|
+
from nucliadb.writer import vectorsets
|
29
|
+
from nucliadb.writer.api.v1.router import KB_PREFIX, api
|
30
|
+
from nucliadb_models.resource import (
|
31
|
+
NucliaDBRoles,
|
32
|
+
)
|
33
|
+
from nucliadb_utils.authentication import requires
|
34
|
+
|
35
|
+
|
36
|
+
@api.post(
|
37
|
+
f"/{KB_PREFIX}/{{kbid}}/vectorsets/{{vectorset_id}}",
|
38
|
+
status_code=200,
|
39
|
+
summary="Add a vectorset to Knowledge Box",
|
40
|
+
tags=["Knowledge Boxes"],
|
41
|
+
# TODO: remove when the feature is mature
|
42
|
+
include_in_schema=False,
|
43
|
+
)
|
44
|
+
@requires(NucliaDBRoles.MANAGER)
|
45
|
+
@version(1)
|
46
|
+
async def add_vectorset(request: Request, kbid: str, vectorset_id: str) -> Response:
|
47
|
+
try:
|
48
|
+
await vectorsets.add(kbid, vectorset_id)
|
49
|
+
except learning_proxy.ProxiedLearningConfigError as err:
|
50
|
+
return Response(
|
51
|
+
status_code=err.status_code,
|
52
|
+
content=err.content,
|
53
|
+
media_type=err.content_type,
|
54
|
+
)
|
55
|
+
return Response(status_code=200)
|
56
|
+
|
57
|
+
|
58
|
+
@api.delete(
|
59
|
+
f"/{KB_PREFIX}/{{kbid}}/vectorsets/{{vectorset_id}}",
|
60
|
+
status_code=200,
|
61
|
+
summary="Delete vectorset from Knowledge Box",
|
62
|
+
tags=["Knowledge Boxes"],
|
63
|
+
# TODO: remove when the feature is mature
|
64
|
+
include_in_schema=False,
|
65
|
+
)
|
66
|
+
@requires(NucliaDBRoles.MANAGER)
|
67
|
+
@version(1)
|
68
|
+
async def delete_vectorset(request: Request, kbid: str, vectorset_id: str) -> Response:
|
69
|
+
try:
|
70
|
+
await vectorsets.delete(kbid, vectorset_id)
|
71
|
+
except VectorSetConflict as exc:
|
72
|
+
return HTTPConflict(detail=str(exc))
|
73
|
+
except learning_proxy.ProxiedLearningConfigError as err:
|
74
|
+
return Response(
|
75
|
+
status_code=err.status_code,
|
76
|
+
content=err.content,
|
77
|
+
media_type=err.content_type,
|
78
|
+
)
|
79
|
+
return Response(status_code=200)
|
nucliadb/writer/vectorsets.py
CHANGED
@@ -59,9 +59,10 @@ async def add(kbid: str, vectorset_id: str) -> None:
|
|
59
59
|
assert lconfig is not None
|
60
60
|
|
61
61
|
# Then, add the vectorset to the index if it's not already there
|
62
|
+
storage = await get_storage()
|
63
|
+
vectorset_config = get_vectorset_config(lconfig, vectorset_id)
|
62
64
|
async with datamanagers.with_rw_transaction() as txn:
|
63
|
-
kbobj = KnowledgeBox(txn,
|
64
|
-
vectorset_config = get_vectorset_config(lconfig, vectorset_id)
|
65
|
+
kbobj = KnowledgeBox(txn, storage, kbid)
|
65
66
|
try:
|
66
67
|
await kbobj.create_vectorset(vectorset_config)
|
67
68
|
await txn.commit()
|
@@ -77,11 +78,17 @@ async def delete(kbid: str, vectorset_id: str) -> None:
|
|
77
78
|
if vectorset_id in semantic_models:
|
78
79
|
semantic_models.remove(vectorset_id)
|
79
80
|
await learning_proxy.update_configuration(kbid, {"semantic_models": semantic_models})
|
81
|
+
|
82
|
+
storage = await get_storage()
|
80
83
|
try:
|
81
84
|
async with datamanagers.with_rw_transaction() as txn:
|
82
|
-
kbobj = KnowledgeBox(txn,
|
85
|
+
kbobj = KnowledgeBox(txn, storage, kbid)
|
83
86
|
await kbobj.delete_vectorset(vectorset_id=vectorset_id)
|
84
87
|
await txn.commit()
|
88
|
+
|
89
|
+
except VectorSetConflict:
|
90
|
+
# caller should handle this error
|
91
|
+
raise
|
85
92
|
except Exception as ex:
|
86
93
|
errors.capture_exception(ex)
|
87
94
|
logger.exception(
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: nucliadb
|
3
|
-
Version: 6.2.1.
|
3
|
+
Version: 6.2.1.post2887
|
4
4
|
Home-page: https://docs.nuclia.dev/docs/management/nucliadb/intro
|
5
5
|
Author: NucliaDB Community
|
6
6
|
Author-email: nucliadb@nuclia.com
|
@@ -22,10 +22,10 @@ Classifier: Programming Language :: Python :: 3.12
|
|
22
22
|
Classifier: Programming Language :: Python :: 3 :: Only
|
23
23
|
Requires-Python: >=3.9, <4
|
24
24
|
Description-Content-Type: text/markdown
|
25
|
-
Requires-Dist: nucliadb-telemetry[all]>=6.2.1.
|
26
|
-
Requires-Dist: nucliadb-utils[cache,fastapi,storages]>=6.2.1.
|
27
|
-
Requires-Dist: nucliadb-protos>=6.2.1.
|
28
|
-
Requires-Dist: nucliadb-models>=6.2.1.
|
25
|
+
Requires-Dist: nucliadb-telemetry[all]>=6.2.1.post2887
|
26
|
+
Requires-Dist: nucliadb-utils[cache,fastapi,storages]>=6.2.1.post2887
|
27
|
+
Requires-Dist: nucliadb-protos>=6.2.1.post2887
|
28
|
+
Requires-Dist: nucliadb-models>=6.2.1.post2887
|
29
29
|
Requires-Dist: nucliadb-admin-assets>=1.0.0.post1224
|
30
30
|
Requires-Dist: nucliadb-node-binding>=2.26.0
|
31
31
|
Requires-Dist: nuclia-models>=0.24.2
|
@@ -71,7 +71,7 @@ nucliadb/common/datamanagers/atomic.py,sha256=DU7RihO8WaGNuh_GTEpQ-8hkoinY5GSpNS
|
|
71
71
|
nucliadb/common/datamanagers/cluster.py,sha256=psTwAWSLj83vhFnC1iJJ6holrolAI4nKos9PuEWspYY,1500
|
72
72
|
nucliadb/common/datamanagers/entities.py,sha256=hqw4YcEOumGK_1vgNNfxP-WafHvWN5jf61n4U01WJtc,5311
|
73
73
|
nucliadb/common/datamanagers/exceptions.py,sha256=Atz_PP_GGq4jgJaWcAkcRbHBoBaGcC9yJvFteylKtTE,883
|
74
|
-
nucliadb/common/datamanagers/fields.py,sha256=
|
74
|
+
nucliadb/common/datamanagers/fields.py,sha256=9KqBzTssAT68FR5hd17Xu_CSwAYdKFuYic1ITnrfFNc,3971
|
75
75
|
nucliadb/common/datamanagers/kb.py,sha256=P7EhF4tApIUG2jw_HH1oMufTKG9__kuOLKnrCNGbDM4,6156
|
76
76
|
nucliadb/common/datamanagers/labels.py,sha256=Zm0GQpSPoGXEEysUY7VsDIcyKSIIQsMVphj23IyM9_c,4502
|
77
77
|
nucliadb/common/datamanagers/processing.py,sha256=ByxdZzdbAfJGqC6__mY-zryjk040TyQfcUq3rxujeoY,1587
|
@@ -115,7 +115,7 @@ nucliadb/ingest/cache.py,sha256=w7jMMzamOmQ7gwXna6Dqm6isRNBVv6l5BTBlTxaYWjE,1005
|
|
115
115
|
nucliadb/ingest/partitions.py,sha256=2NIhMYbNT0TNBL6bX1UMSi7vxFGICstCKEqsB0TXHOE,2410
|
116
116
|
nucliadb/ingest/processing.py,sha256=gg1DqbMFwqdOsmCSGsZc2abRdYz86xOZJun9vrHOCzs,20618
|
117
117
|
nucliadb/ingest/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
118
|
-
nucliadb/ingest/serialize.py,sha256=
|
118
|
+
nucliadb/ingest/serialize.py,sha256=13NcAP0Tw0zxMsjdudnSnedsg1YpiqFrA-TTIxQA6Ww,16634
|
119
119
|
nucliadb/ingest/settings.py,sha256=0B-wQNa8FLqtNcQgRzh-fuIuGptM816XHcbH1NQKfmE,3050
|
120
120
|
nucliadb/ingest/utils.py,sha256=l1myURu3r8oA11dx3GpHw-gNTUc1AFX8xdPm9Lgl2rA,2275
|
121
121
|
nucliadb/ingest/consumer/__init__.py,sha256=cp15ZcFnHvpcu_5-aK2A4uUyvuZVV_MJn4bIXMa20ks,835
|
@@ -142,7 +142,7 @@ nucliadb/ingest/orm/entities.py,sha256=2PslT1FZ6yCvJtjR0UpKTSzxJrtS-C_gZx4ZTWHun
|
|
142
142
|
nucliadb/ingest/orm/exceptions.py,sha256=k4Esv4NtL4TrGTcsQpwrSfDhPQpiYcRbB1SpYmBX5MY,1432
|
143
143
|
nucliadb/ingest/orm/knowledgebox.py,sha256=XefDz6YsA0DLMS6T5W8P3VMFTkwr13bIae2ot7wAFpE,25259
|
144
144
|
nucliadb/ingest/orm/metrics.py,sha256=OkwMSPKLZcKba0ZTwtTiIxwBgaLMX5ydhGieKvi2y7E,1096
|
145
|
-
nucliadb/ingest/orm/resource.py,sha256=
|
145
|
+
nucliadb/ingest/orm/resource.py,sha256=CAASCYIPwyhMgwc3_qKjZ-AOVM2IZuaTN-95PlKealg,44658
|
146
146
|
nucliadb/ingest/orm/utils.py,sha256=vCe_9UxHu26JDFGLwQ0wH-XyzJIpQCTK-Ow9dtZR5Vg,2716
|
147
147
|
nucliadb/ingest/orm/processor/__init__.py,sha256=Aqd9wCNTvggkMkCY3WvoI8spdr94Jnqk-0iq9XpLs18,922
|
148
148
|
nucliadb/ingest/orm/processor/auditing.py,sha256=TeYhXGJRyQ7ROytbb2u8R0fIh_FYi3HgTu3S1ribY3U,4623
|
@@ -152,7 +152,7 @@ nucliadb/ingest/orm/processor/processor.py,sha256=2FxAetUvtHvg6l-24xYrmBdsyqc0RU
|
|
152
152
|
nucliadb/ingest/orm/processor/sequence_manager.py,sha256=uqEphtI1Ir_yk9jRl2gPf7BlzzXWovbARY5MNZSBI_8,1704
|
153
153
|
nucliadb/ingest/service/__init__.py,sha256=MME_G_ERxzJR6JW_hfE2qcfXpmpH1kdG-S0a-M0qRm8,2043
|
154
154
|
nucliadb/ingest/service/exceptions.py,sha256=cp15ZcFnHvpcu_5-aK2A4uUyvuZVV_MJn4bIXMa20ks,835
|
155
|
-
nucliadb/ingest/service/writer.py,sha256=
|
155
|
+
nucliadb/ingest/service/writer.py,sha256=IJOuSmetWq0oajtJiq5KmFvZMaYX5LGJa6pa9eGBtHY,20406
|
156
156
|
nucliadb/middleware/__init__.py,sha256=A8NBlBuEkunCFMKpR9gnfNELsVn0Plc55BIQMbWDM8Q,2202
|
157
157
|
nucliadb/migrator/__init__.py,sha256=cp15ZcFnHvpcu_5-aK2A4uUyvuZVV_MJn4bIXMa20ks,835
|
158
158
|
nucliadb/migrator/command.py,sha256=dKbJ1tAmP6X4lMVRSSlz351euaqs2wBPpOczLjATUes,2089
|
@@ -174,13 +174,13 @@ nucliadb/reader/openapi.py,sha256=ZwXYXZPYpxQL68HyWI310YnmMKJMzBUtYe-r9OSbN8I,10
|
|
174
174
|
nucliadb/reader/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
175
175
|
nucliadb/reader/run.py,sha256=AR-iCnON3YVXgI5-KEgg99G4KAPN1BKXDg7nr4dgoDA,1447
|
176
176
|
nucliadb/reader/api/__init__.py,sha256=c-UD29C0FVzQDGEvslebDCKtvnyEcAbiDd-3Q_QgGN4,872
|
177
|
-
nucliadb/reader/api/models.py,sha256=
|
177
|
+
nucliadb/reader/api/models.py,sha256=UHhOPmh8xcHhDjFm8_-8t66yEggXdxRBoY0xV-hI9to,2076
|
178
178
|
nucliadb/reader/api/v1/__init__.py,sha256=G1s6_1SEvv8CrC_V_tB4fvjQ8tLHivAIbK47dOT_lb4,1069
|
179
179
|
nucliadb/reader/api/v1/download.py,sha256=rGv1c5CjrJheDgGwAnNWy76A_4V2shqqHYvwmKGFlpk,10758
|
180
180
|
nucliadb/reader/api/v1/export_import.py,sha256=x4VBNDFjnlY1nIt5kdq0eZTB_DeRzGzT8T7uB7wUhNU,6448
|
181
181
|
nucliadb/reader/api/v1/knowledgebox.py,sha256=Uu-yPB8KKZt1VaFrFNMMaXOvLsclBJDK9dzZ9lF2ctI,3645
|
182
182
|
nucliadb/reader/api/v1/learning_config.py,sha256=w5a_miobPGakKmyLXkmuz1e6tXyIMSas-qLngqzVQTw,4436
|
183
|
-
nucliadb/reader/api/v1/resource.py,sha256=
|
183
|
+
nucliadb/reader/api/v1/resource.py,sha256=SFIv_vpgkdJQv7L_UgYZS5FvubipJ0ligpExGDjKHV0,14064
|
184
184
|
nucliadb/reader/api/v1/router.py,sha256=eyNmEGSP9zHkCIG5XlAXl6sukq950B7gFT3X2peMtIE,1011
|
185
185
|
nucliadb/reader/api/v1/services.py,sha256=B8fD4zcUydZ5Fl1DDxfXGNuW6C8rhGYc920O5Zy5Yv8,11716
|
186
186
|
nucliadb/reader/reader/__init__.py,sha256=cp15ZcFnHvpcu_5-aK2A4uUyvuZVV_MJn4bIXMa20ks,835
|
@@ -310,21 +310,22 @@ nucliadb/writer/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
310
310
|
nucliadb/writer/run.py,sha256=euVZ_rtHDXs-O1kB-Pt1Id8eft9CYVpWH3zJzEoEqls,1448
|
311
311
|
nucliadb/writer/settings.py,sha256=32Umt2SqeIL8PW4_C6hkuq01QT1YmcROiWpmoy1D5Wk,3286
|
312
312
|
nucliadb/writer/utilities.py,sha256=AZ5qEny1Xm0IDsFtH13oJa2usvJZK8f0FdgF1LrnLCw,1036
|
313
|
-
nucliadb/writer/vectorsets.py,sha256=
|
313
|
+
nucliadb/writer/vectorsets.py,sha256=18XJvsyi0-tePQWig8dl5qaNPaufEZb0-uD22IAOTa0,5648
|
314
314
|
nucliadb/writer/api/__init__.py,sha256=cp15ZcFnHvpcu_5-aK2A4uUyvuZVV_MJn4bIXMa20ks,835
|
315
315
|
nucliadb/writer/api/constants.py,sha256=qWEDjFUycrEZnSJyLnNK4PQNodU2oVmkO4NycaEZtio,1738
|
316
316
|
nucliadb/writer/api/utils.py,sha256=wIQHlU8RQiIGVLI72suvyVIKlCU44Unh0Ae0IiN6Qwo,1313
|
317
|
-
nucliadb/writer/api/v1/__init__.py,sha256=
|
317
|
+
nucliadb/writer/api/v1/__init__.py,sha256=akI9A_jloNLb0dU4T5zjfdyvmSAiDeIdjAlzNx74FlU,1128
|
318
318
|
nucliadb/writer/api/v1/export_import.py,sha256=6_gn0-emCjmK6bCUX5kgMvG0qkZr4HlfGmBXhhngsxo,8243
|
319
319
|
nucliadb/writer/api/v1/field.py,sha256=OsWOYA0WQ6onE5Rkl20QIEdtrSi7Jgnu62fUt90Ziy8,17503
|
320
|
-
nucliadb/writer/api/v1/knowledgebox.py,sha256=
|
320
|
+
nucliadb/writer/api/v1/knowledgebox.py,sha256=MLeIuym4jPrJgfy1NTcN9CpUGwuBiqDHMcx0hY9DR7g,9530
|
321
321
|
nucliadb/writer/api/v1/learning_config.py,sha256=GaYaagjBrVG9ZxrWQyVQfqGMQV3tAJjqJ5CStaKhktU,2058
|
322
322
|
nucliadb/writer/api/v1/resource.py,sha256=A8fAHlN5XFsg6XFYKhfWJS8czgNH6yXr-PsnUqz2WUE,18757
|
323
323
|
nucliadb/writer/api/v1/router.py,sha256=RjuoWLpZer6Kl2BW_wznpNo6XL3BOpdTGqXZCn3QrrQ,1034
|
324
324
|
nucliadb/writer/api/v1/services.py,sha256=U8OGxhA1tdt-wxw2uDAjFpwFXFEXSDTfBe1iV5nfmx8,9897
|
325
325
|
nucliadb/writer/api/v1/slug.py,sha256=xlVBDBpRi9bNulpBHZwhyftVvulfE0zFm1XZIWl-AKY,2389
|
326
326
|
nucliadb/writer/api/v1/transaction.py,sha256=d2Vbgnkk_-FLGSTt3vfldwiJIUf0XoyD0wP1jQNz_DY,2430
|
327
|
-
nucliadb/writer/api/v1/upload.py,sha256=
|
327
|
+
nucliadb/writer/api/v1/upload.py,sha256=VOeqNTrZx1_z8iaKjM7p8fVlVcIYMtnQNK1dm72ct6k,33161
|
328
|
+
nucliadb/writer/api/v1/vectorsets.py,sha256=zj-GBnG_H-aIRVq-9WNT9OVryeYeqdFL1YUUfebC-Ag,2758
|
328
329
|
nucliadb/writer/resource/__init__.py,sha256=cp15ZcFnHvpcu_5-aK2A4uUyvuZVV_MJn4bIXMa20ks,835
|
329
330
|
nucliadb/writer/resource/audit.py,sha256=FvxMZPzrNHtd31HgpZEvxzwAkbxJTZRhPLqRYYJi3tA,1426
|
330
331
|
nucliadb/writer/resource/basic.py,sha256=l9zD-Qiq4eUkHezMf0w1Ksx2izKYLYuNoMIlXcNxxpM,11163
|
@@ -339,9 +340,9 @@ nucliadb/writer/tus/local.py,sha256=7jYa_w9b-N90jWgN2sQKkNcomqn6JMVBOVeDOVYJHto,
|
|
339
340
|
nucliadb/writer/tus/s3.py,sha256=vF0NkFTXiXhXq3bCVXXVV-ED38ECVoUeeYViP8uMqcU,8357
|
340
341
|
nucliadb/writer/tus/storage.py,sha256=ToqwjoYnjI4oIcwzkhha_MPxi-k4Jk3Lt55zRwaC1SM,2903
|
341
342
|
nucliadb/writer/tus/utils.py,sha256=MSdVbRsRSZVdkaum69_0wku7X3p5wlZf4nr6E0GMKbw,2556
|
342
|
-
nucliadb-6.2.1.
|
343
|
-
nucliadb-6.2.1.
|
344
|
-
nucliadb-6.2.1.
|
345
|
-
nucliadb-6.2.1.
|
346
|
-
nucliadb-6.2.1.
|
347
|
-
nucliadb-6.2.1.
|
343
|
+
nucliadb-6.2.1.post2887.dist-info/METADATA,sha256=BJ9ngeXJ9o7YbMIoaEcblmpX0bRR0A_xOhtsFnBW8ts,4689
|
344
|
+
nucliadb-6.2.1.post2887.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
345
|
+
nucliadb-6.2.1.post2887.dist-info/entry_points.txt,sha256=XqGfgFDuY3zXQc8ewXM2TRVjTModIq851zOsgrmaXx4,1268
|
346
|
+
nucliadb-6.2.1.post2887.dist-info/top_level.txt,sha256=hwYhTVnX7jkQ9gJCkVrbqEG1M4lT2F_iPQND1fCzF80,20
|
347
|
+
nucliadb-6.2.1.post2887.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
348
|
+
nucliadb-6.2.1.post2887.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|