nucliadb-models 6.9.6.post5453__py3-none-any.whl → 6.11.1.post5822__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.
Files changed (35) hide show
  1. nucliadb_models/agents/ingestion.py +4 -4
  2. nucliadb_models/augment.py +294 -24
  3. nucliadb_models/common.py +57 -57
  4. nucliadb_models/configuration.py +8 -8
  5. nucliadb_models/content_types.py +13 -11
  6. nucliadb_models/conversation.py +25 -26
  7. nucliadb_models/entities.py +17 -18
  8. nucliadb_models/external_index_providers.py +1 -2
  9. nucliadb_models/extracted.py +82 -83
  10. nucliadb_models/file.py +10 -11
  11. nucliadb_models/filters.py +79 -75
  12. nucliadb_models/graph/requests.py +40 -48
  13. nucliadb_models/graph/responses.py +13 -1
  14. nucliadb_models/hydration.py +48 -50
  15. nucliadb_models/internal/predict.py +7 -9
  16. nucliadb_models/internal/shards.py +2 -3
  17. nucliadb_models/labels.py +18 -11
  18. nucliadb_models/link.py +18 -19
  19. nucliadb_models/metadata.py +66 -54
  20. nucliadb_models/notifications.py +3 -3
  21. nucliadb_models/processing.py +1 -2
  22. nucliadb_models/resource.py +85 -102
  23. nucliadb_models/retrieval.py +147 -0
  24. nucliadb_models/search.py +300 -276
  25. nucliadb_models/security.py +2 -3
  26. nucliadb_models/text.py +7 -8
  27. nucliadb_models/trainset.py +1 -2
  28. nucliadb_models/utils.py +2 -3
  29. nucliadb_models/vectors.py +2 -5
  30. nucliadb_models/writer.py +56 -57
  31. {nucliadb_models-6.9.6.post5453.dist-info → nucliadb_models-6.11.1.post5822.dist-info}/METADATA +1 -1
  32. nucliadb_models-6.11.1.post5822.dist-info/RECORD +41 -0
  33. {nucliadb_models-6.9.6.post5453.dist-info → nucliadb_models-6.11.1.post5822.dist-info}/WHEEL +1 -1
  34. nucliadb_models-6.9.6.post5453.dist-info/RECORD +0 -40
  35. {nucliadb_models-6.9.6.post5453.dist-info → nucliadb_models-6.11.1.post5822.dist-info}/top_level.txt +0 -0
@@ -15,12 +15,13 @@
15
15
 
16
16
  from collections.abc import Sequence
17
17
  from enum import Enum
18
- from typing import Any, Generic, Literal, Optional, TypeVar, Union
18
+ from typing import Annotated, Any, Generic, Literal, TypeVar
19
19
  from uuid import UUID
20
20
 
21
21
  import pydantic
22
22
  from pydantic import AliasChoices, BaseModel, Discriminator, Tag, field_validator, model_validator
23
- from typing_extensions import Annotated, Self
23
+ from pydantic.config import ConfigDict
24
+ from typing_extensions import Self
24
25
 
25
26
  from .common import FieldTypeName, Paragraph
26
27
  from .metadata import ResourceProcessingStatus
@@ -33,7 +34,10 @@ class And(BaseModel, Generic[F], extra="forbid"):
33
34
  """AND of other expressions"""
34
35
 
35
36
  operands: Sequence[F] = pydantic.Field(
36
- serialization_alias="and", validation_alias=AliasChoices("operands", "and"), min_length=1
37
+ title="And Operands",
38
+ serialization_alias="and",
39
+ validation_alias=AliasChoices("operands", "and"),
40
+ min_length=1,
37
41
  )
38
42
 
39
43
  @pydantic.model_serializer
@@ -45,7 +49,10 @@ class Or(BaseModel, Generic[F], extra="forbid"):
45
49
  """OR of other expressions"""
46
50
 
47
51
  operands: Sequence[F] = pydantic.Field(
48
- serialization_alias="or", validation_alias=AliasChoices("operands", "or"), min_length=1
52
+ title="Or Operands",
53
+ serialization_alias="or",
54
+ validation_alias=AliasChoices("operands", "or"),
55
+ min_length=1,
49
56
  )
50
57
 
51
58
  @pydantic.model_serializer
@@ -57,7 +64,7 @@ class Not(BaseModel, Generic[F], extra="forbid"):
57
64
  """NOT another expression"""
58
65
 
59
66
  operand: F = pydantic.Field(
60
- serialization_alias="not", validation_alias=AliasChoices("operand", "not")
67
+ title="Not Operand", serialization_alias="not", validation_alias=AliasChoices("operand", "not")
61
68
  )
62
69
 
63
70
  @pydantic.model_serializer
@@ -78,11 +85,11 @@ class FilterProp(BaseModel):
78
85
  class Resource(FilterProp, extra="forbid"):
79
86
  """Matches all fields of a resource given its id or slug"""
80
87
 
88
+ model_config = ConfigDict(title="Resource Filter")
89
+
81
90
  prop: Literal["resource"] = "resource"
82
- id: Optional[str] = pydantic.Field(default=None, description="UUID of the resource to match")
83
- slug: Optional[SlugString] = pydantic.Field(
84
- default=None, description="Slug of the resource to match"
85
- )
91
+ id: str | None = pydantic.Field(default=None, description="UUID of the resource to match")
92
+ slug: SlugString | None = pydantic.Field(default=None, description="Slug of the resource to match")
86
93
 
87
94
  @field_validator("id", mode="after")
88
95
  def validate_id(cls, v: str) -> str:
@@ -90,7 +97,7 @@ class Resource(FilterProp, extra="forbid"):
90
97
  try:
91
98
  UUID(v)
92
99
  except ValueError:
93
- raise ValueError("Invalid UUID")
100
+ raise ValueError(f"resource id filter '{v}' should be a valid UUID")
94
101
  return v
95
102
 
96
103
  @model_validator(mode="after")
@@ -107,8 +114,9 @@ class Field(FilterProp, extra="forbid"):
107
114
 
108
115
  prop: Literal["field"] = "field"
109
116
  type: FieldTypeName = pydantic.Field(description="Type of the field to match, ")
110
- name: Optional[str] = pydantic.Field(
117
+ name: str | None = pydantic.Field(
111
118
  default=None,
119
+ title="Field Filter",
112
120
  description="Name of the field to match. If blank, matches all fields of the given type",
113
121
  )
114
122
 
@@ -124,10 +132,10 @@ class DateCreated(FilterProp, extra="forbid"):
124
132
  """Matches all fields created in a date range"""
125
133
 
126
134
  prop: Literal["created"] = "created"
127
- since: Optional[DateTime] = pydantic.Field(
135
+ since: DateTime | None = pydantic.Field(
128
136
  default=None, description="Start of the date range. Leave blank for unbounded"
129
137
  )
130
- until: Optional[DateTime] = pydantic.Field(
138
+ until: DateTime | None = pydantic.Field(
131
139
  default=None, description="End of the date range. Leave blank for unbounded"
132
140
  )
133
141
 
@@ -142,10 +150,10 @@ class DateModified(FilterProp, extra="forbid"):
142
150
  """Matches all fields modified in a date range"""
143
151
 
144
152
  prop: Literal["modified"] = "modified"
145
- since: Optional[DateTime] = pydantic.Field(
153
+ since: DateTime | None = pydantic.Field(
146
154
  default=None, description="Start of the date range. Leave blank for unbounded"
147
155
  )
148
- until: Optional[DateTime] = pydantic.Field(
156
+ until: DateTime | None = pydantic.Field(
149
157
  default=None, description="End of the date range. Leave blank for unbounded"
150
158
  )
151
159
 
@@ -160,8 +168,8 @@ class Label(FilterProp, extra="forbid"):
160
168
  """Matches fields/paragraphs with a label (or labelset)"""
161
169
 
162
170
  prop: Literal["label"] = "label"
163
- labelset: str = pydantic.Field(description="The labelset to match")
164
- label: Optional[str] = pydantic.Field(
171
+ labelset: str = pydantic.Field(description="The ID of the labelset to match")
172
+ label: str | None = pydantic.Field(
165
173
  default=None,
166
174
  description="The label to match. If blank, matches all labels in the given labelset",
167
175
  )
@@ -177,7 +185,7 @@ class ResourceMimetype(FilterProp, extra="forbid"):
177
185
  type: str = pydantic.Field(
178
186
  description="Type of the mimetype to match. e.g: In image/jpeg, type is image"
179
187
  )
180
- subtype: Optional[str] = pydantic.Field(
188
+ subtype: str | None = pydantic.Field(
181
189
  default=None,
182
190
  description=(
183
191
  "Type of the mimetype to match. e.g: In image/jpeg, subtype is jpeg."
@@ -193,7 +201,7 @@ class FieldMimetype(FilterProp, extra="forbid"):
193
201
  type: str = pydantic.Field(
194
202
  description="Type of the mimetype to match. e.g: In image/jpeg, type is image"
195
203
  )
196
- subtype: Optional[str] = pydantic.Field(
204
+ subtype: str | None = pydantic.Field(
197
205
  default=None,
198
206
  description=(
199
207
  "Type of the mimetype to match. e.g: In image/jpeg, subtype is jpeg."
@@ -207,7 +215,7 @@ class Entity(FilterProp, extra="forbid"):
207
215
 
208
216
  prop: Literal["entity"] = "entity"
209
217
  subtype: str = pydantic.Field(description="Type of the entity. e.g: PERSON")
210
- value: Optional[str] = pydantic.Field(
218
+ value: str | None = pydantic.Field(
211
219
  default=None,
212
220
  description="Value of the entity. e.g: Anna. If blank, matches any entity of the given type",
213
221
  )
@@ -235,8 +243,8 @@ class OriginMetadata(FilterProp, extra="forbid"):
235
243
  """Matches metadata from the origin"""
236
244
 
237
245
  prop: Literal["origin_metadata"] = "origin_metadata"
238
- field: str = pydantic.Field(description="Metadata field")
239
- value: Optional[str] = pydantic.Field(
246
+ field: str = pydantic.Field(title="Origin Metadata Field", description="Metadata field")
247
+ value: str | None = pydantic.Field(
240
248
  default=None,
241
249
  description="Value of the metadata field. If blank, matches any document with the given metadata field set (to any value)",
242
250
  )
@@ -246,7 +254,7 @@ class OriginPath(FilterProp, extra="forbid"):
246
254
  """Matches the origin path"""
247
255
 
248
256
  prop: Literal["origin_path"] = "origin_path"
249
- prefix: Optional[str] = pydantic.Field(
257
+ prefix: str | None = pydantic.Field(
250
258
  default=None,
251
259
  description=(
252
260
  "Prefix of the path, matches all paths under this prefix"
@@ -259,7 +267,7 @@ class OriginSource(FilterProp, extra="forbid"):
259
267
  """Matches the origin source id"""
260
268
 
261
269
  prop: Literal["origin_source"] = "origin_source"
262
- id: Optional[str] = pydantic.Field(default=None, description=("Source ID"))
270
+ id: str | None = pydantic.Field(default=None, description=("Source ID"))
263
271
 
264
272
 
265
273
  class OriginCollaborator(FilterProp, extra="forbid"):
@@ -276,7 +284,7 @@ class Generated(FilterProp, extra="forbid"):
276
284
  by: Literal["data-augmentation"] = pydantic.Field(
277
285
  description="Generator for this field. Currently, only data-augmentation is supported"
278
286
  )
279
- da_task: Optional["str"] = pydantic.Field(
287
+ da_task: str | None = pydantic.Field(
280
288
  default=None, description="Matches field generated by an specific DA task, given its prefix"
281
289
  )
282
290
 
@@ -297,7 +305,7 @@ class Status(FilterProp, extra="forbid"):
297
305
 
298
306
  # The discriminator function is optional, everything works without it.
299
307
  # We implement it because it makes pydantic produce more user-friendly errors
300
- def filter_discriminator(v: Any) -> Optional[str]:
308
+ def filter_discriminator(v: Any) -> str | None:
301
309
  if isinstance(v, dict):
302
310
  if "and" in v:
303
311
  return "and"
@@ -319,59 +327,53 @@ def filter_discriminator(v: Any) -> Optional[str]:
319
327
 
320
328
 
321
329
  FieldFilterExpression = Annotated[
322
- Union[
323
- Annotated[And["FieldFilterExpression"], Tag("and")],
324
- Annotated[Or["FieldFilterExpression"], Tag("or")],
325
- Annotated[Not["FieldFilterExpression"], Tag("not")],
326
- Annotated[Resource, Tag("resource")],
327
- Annotated[Field, Tag("field")],
328
- Annotated[Keyword, Tag("keyword")],
329
- Annotated[DateCreated, Tag("created")],
330
- Annotated[DateModified, Tag("modified")],
331
- Annotated[Label, Tag("label")],
332
- Annotated[ResourceMimetype, Tag("resource_mimetype")],
333
- Annotated[FieldMimetype, Tag("field_mimetype")],
334
- Annotated[Entity, Tag("entity")],
335
- Annotated[Language, Tag("language")],
336
- Annotated[OriginTag, Tag("origin_tag")],
337
- Annotated[OriginMetadata, Tag("origin_metadata")],
338
- Annotated[OriginPath, Tag("origin_path")],
339
- Annotated[OriginSource, Tag("origin_source")],
340
- Annotated[OriginCollaborator, Tag("origin_collaborator")],
341
- Annotated[Generated, Tag("generated")],
342
- ],
330
+ Annotated[And["FieldFilterExpression"], Tag("and")]
331
+ | Annotated[Or["FieldFilterExpression"], Tag("or")]
332
+ | Annotated[Not["FieldFilterExpression"], Tag("not")]
333
+ | Annotated[Resource, Tag("resource")]
334
+ | Annotated[Field, Tag("field")]
335
+ | Annotated[Keyword, Tag("keyword")]
336
+ | Annotated[DateCreated, Tag("created")]
337
+ | Annotated[DateModified, Tag("modified")]
338
+ | Annotated[Label, Tag("label")]
339
+ | Annotated[ResourceMimetype, Tag("resource_mimetype")]
340
+ | Annotated[FieldMimetype, Tag("field_mimetype")]
341
+ | Annotated[Entity, Tag("entity")]
342
+ | Annotated[Language, Tag("language")]
343
+ | Annotated[OriginTag, Tag("origin_tag")]
344
+ | Annotated[OriginMetadata, Tag("origin_metadata")]
345
+ | Annotated[OriginPath, Tag("origin_path")]
346
+ | Annotated[OriginSource, Tag("origin_source")]
347
+ | Annotated[OriginCollaborator, Tag("origin_collaborator")]
348
+ | Annotated[Generated, Tag("generated")],
343
349
  Discriminator(filter_discriminator),
344
350
  ]
345
351
 
346
352
  ParagraphFilterExpression = Annotated[
347
- Union[
348
- Annotated[And["ParagraphFilterExpression"], Tag("and")],
349
- Annotated[Or["ParagraphFilterExpression"], Tag("or")],
350
- Annotated[Not["ParagraphFilterExpression"], Tag("not")],
351
- Annotated[Label, Tag("label")],
352
- Annotated[Kind, Tag("kind")],
353
- ],
353
+ Annotated[And["ParagraphFilterExpression"], Tag("and")]
354
+ | Annotated[Or["ParagraphFilterExpression"], Tag("or")]
355
+ | Annotated[Not["ParagraphFilterExpression"], Tag("not")]
356
+ | Annotated[Label, Tag("label")]
357
+ | Annotated[Kind, Tag("kind")],
354
358
  Discriminator(filter_discriminator),
355
359
  ]
356
360
 
357
361
  ResourceFilterExpression = Annotated[
358
- Union[
359
- Annotated[And["ResourceFilterExpression"], Tag("and")],
360
- Annotated[Or["ResourceFilterExpression"], Tag("or")],
361
- Annotated[Not["ResourceFilterExpression"], Tag("not")],
362
- Annotated[Resource, Tag("resource")],
363
- Annotated[DateCreated, Tag("created")],
364
- Annotated[DateModified, Tag("modified")],
365
- Annotated[Label, Tag("label")],
366
- Annotated[ResourceMimetype, Tag("resource_mimetype")],
367
- Annotated[Language, Tag("language")],
368
- Annotated[OriginTag, Tag("origin_tag")],
369
- Annotated[OriginMetadata, Tag("origin_metadata")],
370
- Annotated[OriginPath, Tag("origin_path")],
371
- Annotated[OriginSource, Tag("origin_source")],
372
- Annotated[OriginCollaborator, Tag("origin_collaborator")],
373
- Annotated[Status, Tag("status")],
374
- ],
362
+ Annotated[And["ResourceFilterExpression"], Tag("and")]
363
+ | Annotated[Or["ResourceFilterExpression"], Tag("or")]
364
+ | Annotated[Not["ResourceFilterExpression"], Tag("not")]
365
+ | Annotated[Resource, Tag("resource")]
366
+ | Annotated[DateCreated, Tag("created")]
367
+ | Annotated[DateModified, Tag("modified")]
368
+ | Annotated[Label, Tag("label")]
369
+ | Annotated[ResourceMimetype, Tag("resource_mimetype")]
370
+ | Annotated[Language, Tag("language")]
371
+ | Annotated[OriginTag, Tag("origin_tag")]
372
+ | Annotated[OriginMetadata, Tag("origin_metadata")]
373
+ | Annotated[OriginPath, Tag("origin_path")]
374
+ | Annotated[OriginSource, Tag("origin_source")]
375
+ | Annotated[OriginCollaborator, Tag("origin_collaborator")]
376
+ | Annotated[Status, Tag("status")],
375
377
  Discriminator(filter_discriminator),
376
378
  ]
377
379
 
@@ -388,10 +390,10 @@ class FilterExpression(BaseModel, extra="forbid"):
388
390
  AND = "and"
389
391
  OR = "or"
390
392
 
391
- field: Optional[FieldFilterExpression] = pydantic.Field(
392
- default=None, description="Filter to apply to fields"
393
+ field: FieldFilterExpression | None = pydantic.Field(
394
+ default=None, title="Field Filters", description="Filter to apply to fields"
393
395
  )
394
- paragraph: Optional[ParagraphFilterExpression] = pydantic.Field(
396
+ paragraph: ParagraphFilterExpression | None = pydantic.Field(
395
397
  default=None, description="Filter to apply to each text block"
396
398
  )
397
399
 
@@ -413,4 +415,6 @@ class CatalogFilterExpression(BaseModel, extra="forbid"):
413
415
  `filters`, `range_*`, `with_status`.
414
416
  """
415
417
 
416
- resource: ResourceFilterExpression = pydantic.Field(description="Filter to apply to resources")
418
+ resource: ResourceFilterExpression = pydantic.Field(
419
+ title="Resource filters", description="Filter to apply to resources"
420
+ )
@@ -13,7 +13,7 @@
13
13
  # limitations under the License.
14
14
  #
15
15
  from enum import Enum
16
- from typing import Annotated, Any, Literal, Optional, Union
16
+ from typing import Annotated, Any, Literal
17
17
 
18
18
  from pydantic import BaseModel, Discriminator, Field, Tag, model_validator
19
19
  from typing_extensions import Self
@@ -38,17 +38,18 @@ class GraphProp(BaseModel):
38
38
  class NodeMatchKindName(str, Enum):
39
39
  EXACT = "exact"
40
40
  FUZZY = "fuzzy"
41
+ FUZZY_WORDS = "fuzzy_words"
41
42
 
42
43
 
43
44
  class GraphNode(BaseModel, extra="forbid"):
44
- value: Optional[str] = None
45
+ value: str | None = None
45
46
  match: NodeMatchKindName = NodeMatchKindName.EXACT
46
- type: Optional[RelationNodeType] = RelationNodeType.ENTITY
47
- group: Optional[str] = None
47
+ type: RelationNodeType | None = RelationNodeType.ENTITY
48
+ group: str | None = None
48
49
 
49
50
  @model_validator(mode="after")
50
51
  def validate_fuzzy_usage(self) -> Self:
51
- if self.match == NodeMatchKindName.FUZZY:
52
+ if self.match in (NodeMatchKindName.FUZZY, NodeMatchKindName.FUZZY_WORDS):
52
53
  if self.value is None:
53
54
  raise ValueError("Fuzzy match can only be used if a node value is provided")
54
55
  else:
@@ -60,8 +61,8 @@ class GraphNode(BaseModel, extra="forbid"):
60
61
 
61
62
 
62
63
  class GraphRelation(BaseModel, extra="forbid"):
63
- label: Optional[str] = None
64
- type: Optional[RelationType] = None
64
+ label: str | None = None
65
+ type: RelationType | None = None
65
66
 
66
67
 
67
68
  ## Models for query expressions
@@ -85,9 +86,9 @@ class Relation(GraphRelation, GraphProp):
85
86
 
86
87
  class GraphPath(GraphProp, extra="forbid"):
87
88
  prop: Literal["path"] = "path"
88
- source: Optional[GraphNode] = None
89
- relation: Optional[GraphRelation] = None
90
- destination: Optional[GraphNode] = None
89
+ source: GraphNode | None = None
90
+ relation: GraphRelation | None = None
91
+ destination: GraphNode | None = None
91
92
  undirected: bool = False
92
93
 
93
94
 
@@ -102,7 +103,7 @@ class Generated(GraphProp, extra="forbid"):
102
103
 
103
104
  prop: Literal["generated"] = "generated"
104
105
  by: Generator = Field(description="Generator for this field.")
105
- da_task: Optional["str"] = Field(
106
+ da_task: str | None = Field(
106
107
  default=None, description="Matches relations generated by an specific DA task, given its prefix"
107
108
  )
108
109
 
@@ -122,12 +123,14 @@ class GraphFilterExpression(BaseModel, extra="forbid"):
122
123
  Filtering examples can be found here: https://docs.nuclia.dev/docs/rag/advanced/search-filters
123
124
  """
124
125
 
125
- field: FieldFilterExpression = Field(description="Filter to apply to fields")
126
+ field: FieldFilterExpression = Field(
127
+ title="Graph Field Filters", description="Filter to apply to fields"
128
+ )
126
129
 
127
130
 
128
131
  class BaseGraphSearchRequest(BaseModel):
129
132
  top_k: int = Field(default=50, le=500, title="Number of results to retrieve")
130
- filter_expression: Optional[GraphFilterExpression] = Field(
133
+ filter_expression: GraphFilterExpression | None = Field(
131
134
  default=None,
132
135
  title="Filter resource by an expression",
133
136
  description=(
@@ -135,10 +138,10 @@ class BaseGraphSearchRequest(BaseModel):
135
138
  "Filtering examples can be found here: https://docs.nuclia.dev/docs/rag/advanced/search-filters "
136
139
  ),
137
140
  )
138
- security: Optional[RequestSecurity] = Field(
141
+ security: RequestSecurity | None = Field(
139
142
  default=None,
140
143
  title="Security",
141
- description="Security metadata for the request. If not provided, the search request is done without the security lookup phase.", # noqa: E501
144
+ description="Security metadata for the request. If not provided, the search request is done without the security lookup phase.",
142
145
  )
143
146
  show_hidden: bool = Field(
144
147
  default=False,
@@ -153,64 +156,53 @@ graph_query_discriminator = filter_discriminator
153
156
  # Paths search
154
157
 
155
158
  GraphPathQuery = Annotated[
156
- Union[
157
- # bool expressions
158
- Annotated[And["GraphPathQuery"], Tag("and")],
159
- Annotated[Or["GraphPathQuery"], Tag("or")],
160
- Annotated[Not["GraphPathQuery"], Tag("not")],
161
- # paths
162
- Annotated[GraphPath, Tag("path")],
163
- # nodes
164
- Annotated[SourceNode, Tag("source_node")],
165
- Annotated[DestinationNode, Tag("destination_node")],
166
- Annotated[AnyNode, Tag("node")],
167
- # relations
168
- Annotated[Relation, Tag("relation")],
169
- # metadata
170
- Annotated[Generated, Tag("generated")],
171
- ],
159
+ Annotated[And["GraphPathQuery"], Tag("and")]
160
+ | Annotated[Or["GraphPathQuery"], Tag("or")]
161
+ | Annotated[Not["GraphPathQuery"], Tag("not")]
162
+ | Annotated[GraphPath, Tag("path")]
163
+ | Annotated[SourceNode, Tag("source_node")]
164
+ | Annotated[DestinationNode, Tag("destination_node")]
165
+ | Annotated[AnyNode, Tag("node")]
166
+ | Annotated[Relation, Tag("relation")]
167
+ | Annotated[Generated, Tag("generated")],
172
168
  Discriminator(graph_query_discriminator),
173
169
  ]
174
170
 
175
171
 
176
172
  class GraphSearchRequest(BaseGraphSearchRequest):
177
- query: GraphPathQuery
173
+ query: GraphPathQuery = Field(title="Graph Path Query")
178
174
 
179
175
 
180
176
  # Nodes search
181
177
 
182
178
  GraphNodesQuery = Annotated[
183
- Union[
184
- Annotated[And["GraphNodesQuery"], Tag("and")],
185
- Annotated[Or["GraphNodesQuery"], Tag("or")],
186
- Annotated[Not["GraphNodesQuery"], Tag("not")],
187
- Annotated[AnyNode, Tag("node")],
188
- Annotated[Generated, Tag("generated")],
189
- ],
179
+ Annotated[And["GraphNodesQuery"], Tag("and")]
180
+ | Annotated[Or["GraphNodesQuery"], Tag("or")]
181
+ | Annotated[Not["GraphNodesQuery"], Tag("not")]
182
+ | Annotated[AnyNode, Tag("node")]
183
+ | Annotated[Generated, Tag("generated")],
190
184
  Discriminator(graph_query_discriminator),
191
185
  ]
192
186
 
193
187
 
194
188
  class GraphNodesSearchRequest(BaseGraphSearchRequest):
195
- query: GraphNodesQuery
189
+ query: GraphNodesQuery = Field(title="Graph Nodes Query")
196
190
 
197
191
 
198
192
  # Relations search
199
193
 
200
194
  GraphRelationsQuery = Annotated[
201
- Union[
202
- Annotated[And["GraphRelationsQuery"], Tag("and")],
203
- Annotated[Or["GraphRelationsQuery"], Tag("or")],
204
- Annotated[Not["GraphRelationsQuery"], Tag("not")],
205
- Annotated[Relation, Tag("relation")],
206
- Annotated[Generated, Tag("generated")],
207
- ],
195
+ Annotated[And["GraphRelationsQuery"], Tag("and")]
196
+ | Annotated[Or["GraphRelationsQuery"], Tag("or")]
197
+ | Annotated[Not["GraphRelationsQuery"], Tag("not")]
198
+ | Annotated[Relation, Tag("relation")]
199
+ | Annotated[Generated, Tag("generated")],
208
200
  Discriminator(graph_query_discriminator),
209
201
  ]
210
202
 
211
203
 
212
204
  class GraphRelationsSearchRequest(BaseGraphSearchRequest):
213
- query: GraphRelationsQuery
205
+ query: GraphRelationsQuery = Field(title="Graph Relations Query")
214
206
 
215
207
 
216
208
  # We need this to avoid issues with pydantic and generic types defined in another module
@@ -14,7 +14,7 @@
14
14
  #
15
15
  from enum import Enum
16
16
 
17
- from pydantic import BaseModel
17
+ from pydantic import BaseModel, Field
18
18
 
19
19
  from nucliadb_models.metadata import RelationNodeType, RelationType
20
20
 
@@ -40,10 +40,22 @@ class GraphRelation(BaseModel):
40
40
  type: RelationType
41
41
 
42
42
 
43
+ class PathMetadata(BaseModel):
44
+ # {rid}/{field_type}/{field_id}
45
+ field_id: str | None = Field(
46
+ default=None, description="Field id where the relation has been extracted from"
47
+ )
48
+ # {rid}/{field_type}/{field_id}/{paragraph_start}-{paragraph_end}
49
+ paragraph_id: str | None = Field(
50
+ default=None, description="Paragraph id where the relation has been extracted from"
51
+ )
52
+
53
+
43
54
  class GraphPath(BaseModel):
44
55
  source: GraphNode
45
56
  relation: GraphRelation
46
57
  destination: GraphNode
58
+ metadata: PathMetadata | None
47
59
 
48
60
 
49
61
  class GraphSearchResponse(BaseModel):