docforge-sdk 0.24.0__tar.gz → 0.26.0__tar.gz
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.
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/PKG-INFO +1 -1
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/__init__.py +14 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/_transport_async.py +24 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/_transport_sync.py +24 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/_version.py +1 -1
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/models/__init__.py +14 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/models/explorer.py +106 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/models/search.py +95 -1
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/resources/documents.py +24 -8
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/resources/explorer.py +215 -14
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/resources/search.py +58 -2
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/tests/openapi_snapshot.json +596 -7
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/tests/parity_map.py +12 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/tests/route_map.py +3 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/tests/unit/test_documents.py +12 -0
- docforge_sdk-0.26.0/tests/unit/test_explorer.py +194 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/tests/unit/test_search.py +52 -1
- docforge_sdk-0.24.0/tests/unit/test_explorer.py +0 -97
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/.gitignore +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/.python-version +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/LICENSE +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/README.md +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/_exceptions.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/_requestspec.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/_transport_base.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/client.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/models/_shared.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/models/audit.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/models/auth.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/models/blobs.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/models/capabilities.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/models/collections.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/models/corpus.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/models/documents.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/models/estimate.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/models/health.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/models/ir.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/models/jobs.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/models/pipelines.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/models/preview.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/models/reingest.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/models/snippets.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/models/storage.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/models/trace.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/models/transfers.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/py.typed +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/resources/__init__.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/resources/_base.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/resources/audit.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/resources/auth.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/resources/blobs.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/resources/capabilities.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/resources/collections.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/resources/corpus.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/resources/health.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/resources/jobs.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/resources/pipelines.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/resources/snippets.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/docforge_sdk/resources/transfers.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/pyproject.toml +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/tests/__init__.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/tests/check_schema_drift.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/tests/live/__init__.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/tests/live/test_openapi_parity_live.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/tests/unit/__init__.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/tests/unit/test_audit.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/tests/unit/test_auth.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/tests/unit/test_blobs.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/tests/unit/test_collections.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/tests/unit/test_corpus.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/tests/unit/test_health.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/tests/unit/test_jobs.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/tests/unit/test_models_offline_parity.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/tests/unit/test_pipelines.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/tests/unit/test_resource_parity.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/tests/unit/test_route_coverage.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/tests/unit/test_snippets.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/tests/unit/test_transfers.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/tests/unit/test_transport.py +0 -0
- {docforge_sdk-0.24.0 → docforge_sdk-0.26.0}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: docforge-sdk
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.26.0
|
|
4
4
|
Summary: Typed async + sync Python client for the DocForge REST API (standalone, zero server deps).
|
|
5
5
|
Project-URL: Homepage, https://github.com/Florian-BARRE/docforge
|
|
6
6
|
Project-URL: Repository, https://github.com/Florian-BARRE/docforge
|
|
@@ -72,12 +72,17 @@ from .models.estimate import (
|
|
|
72
72
|
from .models.explorer import (
|
|
73
73
|
BulkChunkEnabledPatch,
|
|
74
74
|
BulkChunkEnabledResponse,
|
|
75
|
+
ChunkContext,
|
|
75
76
|
ChunkEnabledPatch,
|
|
76
77
|
ChunkEnabledResult,
|
|
77
78
|
ChunkInfo,
|
|
79
|
+
ChunkPage,
|
|
80
|
+
ContextChunk,
|
|
78
81
|
DocumentDetail,
|
|
79
82
|
DocumentListItem,
|
|
83
|
+
DocumentOutline,
|
|
80
84
|
MetadataValue,
|
|
85
|
+
OutlineHeading,
|
|
81
86
|
PageInfo,
|
|
82
87
|
)
|
|
83
88
|
|
|
@@ -134,6 +139,8 @@ from .models.preview import (
|
|
|
134
139
|
# ------------------- Search models ------------------- #
|
|
135
140
|
from .models.search import (
|
|
136
141
|
BlockLocation,
|
|
142
|
+
ChunkBrowseRequest,
|
|
143
|
+
ChunkBrowseResponse,
|
|
137
144
|
SearchHealthSummary,
|
|
138
145
|
SearchHit,
|
|
139
146
|
SearchRequest,
|
|
@@ -208,6 +215,11 @@ __all__ = [
|
|
|
208
215
|
"DocumentDetail",
|
|
209
216
|
"PageInfo",
|
|
210
217
|
"ChunkInfo",
|
|
218
|
+
"ChunkPage",
|
|
219
|
+
"ChunkContext",
|
|
220
|
+
"ContextChunk",
|
|
221
|
+
"DocumentOutline",
|
|
222
|
+
"OutlineHeading",
|
|
211
223
|
"ChunkEnabledPatch",
|
|
212
224
|
"BulkChunkEnabledPatch",
|
|
213
225
|
"ChunkEnabledResult",
|
|
@@ -225,6 +237,8 @@ __all__ = [
|
|
|
225
237
|
"BlockLocation",
|
|
226
238
|
"SearchHit",
|
|
227
239
|
"SearchResponse",
|
|
240
|
+
"ChunkBrowseRequest",
|
|
241
|
+
"ChunkBrowseResponse",
|
|
228
242
|
"SearchHealthSummary",
|
|
229
243
|
# Preview
|
|
230
244
|
"PreviewIrSummary",
|
|
@@ -91,6 +91,30 @@ class AsyncTransport(_TransportBase):
|
|
|
91
91
|
self._raise_for_status(response)
|
|
92
92
|
return self._parse(response, model)
|
|
93
93
|
|
|
94
|
+
async def request_with_total(self, spec: RequestSpec, model: type[T]) -> tuple[T, int | None]:
|
|
95
|
+
"""
|
|
96
|
+
Execute a request spec and also return the ``X-Total-Count`` header it carried.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
spec (RequestSpec): The request description.
|
|
100
|
+
model (type[T]): The target type to validate the response into.
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
tuple[T, int | None]: The validated body and the integer total, or None when the
|
|
104
|
+
header is absent or not an integer (older servers).
|
|
105
|
+
"""
|
|
106
|
+
response = await self._send(
|
|
107
|
+
spec.method,
|
|
108
|
+
self._url(spec.path),
|
|
109
|
+
params=self._clean(spec.params),
|
|
110
|
+
json=spec.json,
|
|
111
|
+
files=spec.files,
|
|
112
|
+
)
|
|
113
|
+
self._raise_for_status(response)
|
|
114
|
+
raw_total = response.headers.get("x-total-count", "")
|
|
115
|
+
total = int(raw_total) if raw_total.isdigit() else None
|
|
116
|
+
return self._parse(response, model), total
|
|
117
|
+
|
|
94
118
|
async def request_bare(self, spec: RequestSpec, model: type[T]) -> T:
|
|
95
119
|
"""
|
|
96
120
|
Execute a request spec against the BARE origin (outside ``/api/v1``) and parse it.
|
|
@@ -91,6 +91,30 @@ class SyncTransport(_TransportBase):
|
|
|
91
91
|
self._raise_for_status(response)
|
|
92
92
|
return self._parse(response, model)
|
|
93
93
|
|
|
94
|
+
def request_with_total(self, spec: RequestSpec, model: type[T]) -> tuple[T, int | None]:
|
|
95
|
+
"""
|
|
96
|
+
Execute a request spec and also return the ``X-Total-Count`` header it carried.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
spec (RequestSpec): The request description.
|
|
100
|
+
model (type[T]): The target type to validate the response into.
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
tuple[T, int | None]: The validated body and the integer total, or None when the
|
|
104
|
+
header is absent or not an integer (older servers).
|
|
105
|
+
"""
|
|
106
|
+
response = self._send(
|
|
107
|
+
spec.method,
|
|
108
|
+
self._url(spec.path),
|
|
109
|
+
params=self._clean(spec.params),
|
|
110
|
+
json=spec.json,
|
|
111
|
+
files=spec.files,
|
|
112
|
+
)
|
|
113
|
+
self._raise_for_status(response)
|
|
114
|
+
raw_total = response.headers.get("x-total-count", "")
|
|
115
|
+
total = int(raw_total) if raw_total.isdigit() else None
|
|
116
|
+
return self._parse(response, model), total
|
|
117
|
+
|
|
94
118
|
def request_bare(self, spec: RequestSpec, model: type[T]) -> T:
|
|
95
119
|
"""
|
|
96
120
|
Execute a request spec against the BARE origin (outside ``/api/v1``) and parse it.
|
|
@@ -84,12 +84,17 @@ from .estimate import (
|
|
|
84
84
|
from .explorer import (
|
|
85
85
|
BulkChunkEnabledPatch,
|
|
86
86
|
BulkChunkEnabledResponse,
|
|
87
|
+
ChunkContext,
|
|
87
88
|
ChunkEnabledPatch,
|
|
88
89
|
ChunkEnabledResult,
|
|
89
90
|
ChunkInfo,
|
|
91
|
+
ChunkPage,
|
|
92
|
+
ContextChunk,
|
|
90
93
|
DocumentDetail,
|
|
91
94
|
DocumentListItem,
|
|
95
|
+
DocumentOutline,
|
|
92
96
|
MetadataValue,
|
|
97
|
+
OutlineHeading,
|
|
93
98
|
PageInfo,
|
|
94
99
|
)
|
|
95
100
|
|
|
@@ -164,6 +169,8 @@ from .preview import (
|
|
|
164
169
|
# ------------------- Search models ------------------- #
|
|
165
170
|
from .search import (
|
|
166
171
|
BlockLocation,
|
|
172
|
+
ChunkBrowseRequest,
|
|
173
|
+
ChunkBrowseResponse,
|
|
167
174
|
SearchHealthSummary,
|
|
168
175
|
SearchHint,
|
|
169
176
|
SearchHit,
|
|
@@ -269,6 +276,11 @@ __all__ = [
|
|
|
269
276
|
"DocumentDetail",
|
|
270
277
|
"PageInfo",
|
|
271
278
|
"ChunkInfo",
|
|
279
|
+
"ChunkPage",
|
|
280
|
+
"ChunkContext",
|
|
281
|
+
"ContextChunk",
|
|
282
|
+
"DocumentOutline",
|
|
283
|
+
"OutlineHeading",
|
|
272
284
|
"ChunkEnabledPatch",
|
|
273
285
|
"BulkChunkEnabledPatch",
|
|
274
286
|
"ChunkEnabledResult",
|
|
@@ -287,6 +299,8 @@ __all__ = [
|
|
|
287
299
|
"SearchHint",
|
|
288
300
|
"SearchHit",
|
|
289
301
|
"SearchResponse",
|
|
302
|
+
"ChunkBrowseRequest",
|
|
303
|
+
"ChunkBrowseResponse",
|
|
290
304
|
"SearchHealthSummary",
|
|
291
305
|
# Jobs
|
|
292
306
|
"JobStatus",
|
|
@@ -236,6 +236,107 @@ class ChunkInfo(BaseModel):
|
|
|
236
236
|
)
|
|
237
237
|
|
|
238
238
|
|
|
239
|
+
class ChunkPage(BaseModel):
|
|
240
|
+
"""
|
|
241
|
+
One page of a document's chunks together with the document's total chunk count.
|
|
242
|
+
|
|
243
|
+
SDK-only wrapper (not an OpenAPI schema): the REST body is a bare chunk array and the total
|
|
244
|
+
travels in the ``X-Total-Count`` response header.
|
|
245
|
+
|
|
246
|
+
Attributes:
|
|
247
|
+
items (list[ChunkInfo]): The chunks of this page, in chunk_index order.
|
|
248
|
+
total (int | None): The document's total chunk count; None against a server that predates
|
|
249
|
+
the header.
|
|
250
|
+
"""
|
|
251
|
+
|
|
252
|
+
items: list[ChunkInfo] = Field(description="The chunks of this page, in chunk_index order.")
|
|
253
|
+
total: int | None = Field(
|
|
254
|
+
default=None, description="The document's total chunk count (X-Total-Count header)."
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
class OutlineHeading(BaseModel):
|
|
259
|
+
"""
|
|
260
|
+
One heading of a document's table of contents.
|
|
261
|
+
|
|
262
|
+
Attributes:
|
|
263
|
+
level (int): Heading depth (1 = top level).
|
|
264
|
+
text (str): The heading text.
|
|
265
|
+
page_number (int | None): 1-based page the heading sits on; None for page-less documents.
|
|
266
|
+
chunk_id (str | None): The first chunk of this section; None when no chunk carries it.
|
|
267
|
+
"""
|
|
268
|
+
|
|
269
|
+
level: int = Field(description="Heading depth (1 = top level; 1 when the parser set none).")
|
|
270
|
+
text: str = Field(description="The heading text.")
|
|
271
|
+
page_number: int | None = Field(
|
|
272
|
+
default=None, description="1-based page the heading sits on; null for a page-less document."
|
|
273
|
+
)
|
|
274
|
+
chunk_id: str | None = Field(
|
|
275
|
+
default=None, description="The first chunk of this section; null when none carries it."
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
class DocumentOutline(BaseModel):
|
|
280
|
+
"""
|
|
281
|
+
A document's heading tree - the cheap table of contents to read before fetching content.
|
|
282
|
+
|
|
283
|
+
Attributes:
|
|
284
|
+
document_id (str): The document's UUID.
|
|
285
|
+
display_title (str): The title to show ('' when none).
|
|
286
|
+
page_count (int | None): Pages of the document; None before parse / for page-less formats.
|
|
287
|
+
headings (list[OutlineHeading]): Every heading, in reading order.
|
|
288
|
+
"""
|
|
289
|
+
|
|
290
|
+
document_id: str = Field(description="The document's UUID.")
|
|
291
|
+
display_title: str = Field(description="The title to show ('' when none).")
|
|
292
|
+
page_count: int | None = Field(default=None, description="Pages of the document.")
|
|
293
|
+
headings: list[OutlineHeading] = Field(
|
|
294
|
+
default_factory=list, description="Every heading, in reading order ([] when none)."
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
class ContextChunk(BaseModel):
|
|
299
|
+
"""
|
|
300
|
+
One chunk of a context window (lean projection of a chunk).
|
|
301
|
+
|
|
302
|
+
Attributes:
|
|
303
|
+
chunk_id (str): The chunk UUID.
|
|
304
|
+
chunk_index (int): Position of the chunk within its document.
|
|
305
|
+
text (str): The chunk's (enriched) text.
|
|
306
|
+
page_number (int | None): 1-based page of the chunk's leading block; None when unlocated.
|
|
307
|
+
heading_path (list[str]): The chunk's section breadcrumb (outer to inner).
|
|
308
|
+
token_count (int): Token length of the text.
|
|
309
|
+
is_target (bool): True for the chunk the window was requested around.
|
|
310
|
+
"""
|
|
311
|
+
|
|
312
|
+
chunk_id: str = Field(description="The chunk UUID.")
|
|
313
|
+
chunk_index: int = Field(description="Position of the chunk within its document.")
|
|
314
|
+
text: str = Field(description="The chunk's (enriched) text.")
|
|
315
|
+
page_number: int | None = Field(default=None, description="1-based page; null when unlocated.")
|
|
316
|
+
heading_path: list[str] = Field(
|
|
317
|
+
default_factory=list, description="The chunk's section breadcrumb (outer to inner)."
|
|
318
|
+
)
|
|
319
|
+
token_count: int = Field(description="Token length of the text.")
|
|
320
|
+
is_target: bool = Field(description="True for the chunk the window was requested around.")
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
class ChunkContext(BaseModel):
|
|
324
|
+
"""
|
|
325
|
+
A chunk and its neighbours within the same document (a reading window around a search hit).
|
|
326
|
+
|
|
327
|
+
Attributes:
|
|
328
|
+
document_id (str): The owning document's UUID.
|
|
329
|
+
display_title (str): The owning document's display title.
|
|
330
|
+
chunks (list[ContextChunk]): The window in chunk_index order, the target flagged.
|
|
331
|
+
"""
|
|
332
|
+
|
|
333
|
+
document_id: str = Field(description="The owning document's UUID.")
|
|
334
|
+
display_title: str = Field(description="The owning document's display title.")
|
|
335
|
+
chunks: list[ContextChunk] = Field(
|
|
336
|
+
description="The window in chunk_index order, the target flagged is_target."
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
|
|
239
340
|
class ChunkEnabledPatch(BaseModel):
|
|
240
341
|
"""
|
|
241
342
|
The desired searchability state for one chunk (its enabled_override).
|
|
@@ -321,6 +422,11 @@ __all__ = [
|
|
|
321
422
|
"DocumentDetail",
|
|
322
423
|
"PageInfo",
|
|
323
424
|
"ChunkInfo",
|
|
425
|
+
"ChunkPage",
|
|
426
|
+
"OutlineHeading",
|
|
427
|
+
"DocumentOutline",
|
|
428
|
+
"ContextChunk",
|
|
429
|
+
"ChunkContext",
|
|
324
430
|
"ChunkEnabledPatch",
|
|
325
431
|
"BulkChunkEnabledPatch",
|
|
326
432
|
"ChunkEnabledResult",
|
|
@@ -44,13 +44,25 @@ class SearchRequest(BaseModel):
|
|
|
44
44
|
return_fields (list[str] | None): Hit fields to return (lean response). None → the full hit.
|
|
45
45
|
group_by (Literal["document"] | None): ``"document"`` caps hits per document.
|
|
46
46
|
max_per_document (int): The per-document cap under ``group_by`` (1-10).
|
|
47
|
+
min_score (float | None): Drop hits scoring below this (scale = the response's score_kind).
|
|
48
|
+
rerank (bool | None): Per-request override of the rerank stage (None = the pipeline decides).
|
|
49
|
+
fusion (Literal["rrf", "dbsf"] | None): Per-request override of the dense/sparse fusion.
|
|
50
|
+
debug (bool): Add each hit's ``fusion_score`` / ``rerank_score``.
|
|
47
51
|
"""
|
|
48
52
|
|
|
49
53
|
query: str = Field(min_length=1, description="The natural-language query to search for.")
|
|
50
54
|
limit: int = Field(default=10, ge=1, le=100, description="Number of fused results.")
|
|
51
55
|
filters: dict[str, Any] | None = Field(
|
|
52
56
|
default=None,
|
|
53
|
-
description="
|
|
57
|
+
description="Metadata filters, ANDed across fields: {field: value}. A scalar = equality "
|
|
58
|
+
"(string/enum/keyword_list match case-insensitively); a list = any-of (max 100); an object "
|
|
59
|
+
'= ONE operator: {"eq": v}, {"in": [..]}, {"not": v}, {"not_in": [..]}, '
|
|
60
|
+
'{"contains": "sub"} / {"prefix": "pre"} (string-ish fields: case-insensitive '
|
|
61
|
+
'match against stored values; text fields: contains = full-text), {"exists": true|false}, '
|
|
62
|
+
'or range bounds {"gte","gt","lte","lt"} on integer/float/datetime fields '
|
|
63
|
+
"(datetime bounds = ISO-8601 strings). Only filterable fields; an operator not valid for the "
|
|
64
|
+
"field type -> 422 listing the valid ones. A value no document stores yields a response hint "
|
|
65
|
+
"with the closest stored values.",
|
|
54
66
|
)
|
|
55
67
|
search_in: list[SearchTarget] | None = Field(
|
|
56
68
|
default=None,
|
|
@@ -79,6 +91,26 @@ class SearchRequest(BaseModel):
|
|
|
79
91
|
description="Per-document hit cap when group_by='document' (default 1). Only valid "
|
|
80
92
|
"together with group_by.",
|
|
81
93
|
)
|
|
94
|
+
min_score: float | None = Field(
|
|
95
|
+
default=None,
|
|
96
|
+
ge=0.0,
|
|
97
|
+
description="Drop hits whose final score is below this threshold (on the scale named by "
|
|
98
|
+
"the response's score_kind). None -> no threshold.",
|
|
99
|
+
)
|
|
100
|
+
rerank: bool | None = Field(
|
|
101
|
+
default=None,
|
|
102
|
+
description="Override the collection's rerank stage for this request: false skips it, "
|
|
103
|
+
"true requires it (422 when the search pipeline has none). None -> the pipeline decides.",
|
|
104
|
+
)
|
|
105
|
+
fusion: Literal["rrf", "dbsf"] | None = Field(
|
|
106
|
+
default=None,
|
|
107
|
+
description="Override how the dense and sparse branches are fused for this request: 'rrf' "
|
|
108
|
+
"(rank-based) or 'dbsf' (distribution-based). None -> the collection's configured fusion.",
|
|
109
|
+
)
|
|
110
|
+
debug: bool = Field(
|
|
111
|
+
default=False,
|
|
112
|
+
description="True -> each hit also carries fusion_score and, when reranked, rerank_score.",
|
|
113
|
+
)
|
|
82
114
|
|
|
83
115
|
|
|
84
116
|
class BlockLocation(BaseModel):
|
|
@@ -172,6 +204,16 @@ class SearchHit(BaseModel):
|
|
|
172
204
|
default_factory=list,
|
|
173
205
|
description="Every source block's page + NORMALISED bbox — draw one box per block.",
|
|
174
206
|
)
|
|
207
|
+
fusion_score: float | None = Field(
|
|
208
|
+
default=None,
|
|
209
|
+
description="The retrieval fusion score before any rerank (only when the request set "
|
|
210
|
+
"debug=true).",
|
|
211
|
+
)
|
|
212
|
+
rerank_score: float | None = Field(
|
|
213
|
+
default=None,
|
|
214
|
+
description="The cross-encoder rerank score (only when debug=true and a rerank stage "
|
|
215
|
+
"re-scored the hit).",
|
|
216
|
+
)
|
|
175
217
|
|
|
176
218
|
|
|
177
219
|
class SearchCost(BaseModel):
|
|
@@ -254,6 +296,56 @@ class SearchResponse(BaseModel):
|
|
|
254
296
|
)
|
|
255
297
|
|
|
256
298
|
|
|
299
|
+
class ChunkBrowseRequest(BaseModel):
|
|
300
|
+
"""
|
|
301
|
+
List a collection's chunks by filter, without a query.
|
|
302
|
+
|
|
303
|
+
Attributes:
|
|
304
|
+
filters (dict[str, Any] | None): The same filter map as search; None -> every chunk.
|
|
305
|
+
limit (int): Page size (1-200).
|
|
306
|
+
cursor (str | None): The previous page's ``next_cursor``; None -> the first page.
|
|
307
|
+
return_fields (list[str] | None): Chunk fields to return (as search; ``score`` is not one).
|
|
308
|
+
"""
|
|
309
|
+
|
|
310
|
+
filters: dict[str, Any] | None = Field(
|
|
311
|
+
default=None,
|
|
312
|
+
description="Constraints on the FILTERABLE metadata fields - exactly the grammar of search "
|
|
313
|
+
"`filters`. None -> every searchable chunk of the collection.",
|
|
314
|
+
)
|
|
315
|
+
limit: int = Field(default=20, ge=1, le=200, description="Chunks per page (1-200).")
|
|
316
|
+
cursor: str | None = Field(
|
|
317
|
+
default=None,
|
|
318
|
+
description="Opaque cursor: the previous page's `next_cursor`, sent back unchanged with the "
|
|
319
|
+
"SAME filters. None -> the first page.",
|
|
320
|
+
)
|
|
321
|
+
return_fields: list[str] | None = Field(
|
|
322
|
+
default=None,
|
|
323
|
+
max_length=64,
|
|
324
|
+
description="The chunk fields to return - any search hit field except score, or "
|
|
325
|
+
"'metadata.<field>'. chunk_id and document_id are ALWAYS returned. None -> every field "
|
|
326
|
+
"except geometry (page_number is kept). Omitted fields are absent (not null).",
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
class ChunkBrowseResponse(BaseModel):
|
|
331
|
+
"""
|
|
332
|
+
One page of browsed chunks.
|
|
333
|
+
|
|
334
|
+
Attributes:
|
|
335
|
+
chunks (list[SearchHit]): The page, ordered by document id then chunk_index (no score).
|
|
336
|
+
next_cursor (str | None): Pass back as ``cursor`` for the next page; None on the last page.
|
|
337
|
+
hints (list[SearchHint]): Filter hints (a value nothing stores; the culprit of an empty page).
|
|
338
|
+
"""
|
|
339
|
+
|
|
340
|
+
chunks: list[SearchHit] = Field(
|
|
341
|
+
default_factory=list, description="The page's chunks in browse order."
|
|
342
|
+
)
|
|
343
|
+
next_cursor: str | None = Field(
|
|
344
|
+
default=None, description="Cursor of the next page; null on the last page."
|
|
345
|
+
)
|
|
346
|
+
hints: list[SearchHint] = Field(default_factory=list, description="Filter hints, as search.")
|
|
347
|
+
|
|
348
|
+
|
|
257
349
|
class SearchHealthSummary(BaseModel):
|
|
258
350
|
"""
|
|
259
351
|
A compact, tile-friendly roll-up of search-runtime health for the deployment cockpit.
|
|
@@ -297,5 +389,7 @@ __all__ = [
|
|
|
297
389
|
"SearchCost",
|
|
298
390
|
"SearchHint",
|
|
299
391
|
"SearchResponse",
|
|
392
|
+
"ChunkBrowseRequest",
|
|
393
|
+
"ChunkBrowseResponse",
|
|
300
394
|
"SearchHealthSummary",
|
|
301
395
|
]
|
|
@@ -212,7 +212,9 @@ class AsyncDocuments(AsyncResource, _DocumentsSpecs):
|
|
|
212
212
|
self._purge_trace_payloads_spec(document_id), TracePurgeResult
|
|
213
213
|
)
|
|
214
214
|
|
|
215
|
-
async def get_markdown(
|
|
215
|
+
async def get_markdown(
|
|
216
|
+
self, document_id: str, download: bool = False, pages: str | None = None
|
|
217
|
+
) -> DocumentView:
|
|
216
218
|
"""
|
|
217
219
|
Render a document as an on-the-fly markdown view generated from the canonical IR.
|
|
218
220
|
|
|
@@ -220,16 +222,20 @@ class AsyncDocuments(AsyncResource, _DocumentsSpecs):
|
|
|
220
222
|
document_id (str): The document to render.
|
|
221
223
|
download (bool): When true, ask the server for the attachment-style response (the caller
|
|
222
224
|
still only gets the text back; the flag only affects the server-side response header).
|
|
225
|
+
pages (str | None): Render only these 1-based pages ('5', '5-7', '5,7-9'); the whole
|
|
226
|
+
document when None (the parameter is then not sent at all).
|
|
223
227
|
|
|
224
228
|
Returns:
|
|
225
229
|
DocumentView: The rendered markdown body and its ``text/markdown`` content type.
|
|
226
230
|
"""
|
|
227
231
|
content, mime_type = await self._transport.get_text_typed(
|
|
228
|
-
self._markdown_path(document_id), params={"download": download}
|
|
232
|
+
self._markdown_path(document_id), params={"download": download, "pages": pages}
|
|
229
233
|
)
|
|
230
234
|
return DocumentView(content=content, mime_type=mime_type)
|
|
231
235
|
|
|
232
|
-
async def get_html(
|
|
236
|
+
async def get_html(
|
|
237
|
+
self, document_id: str, download: bool = False, pages: str | None = None
|
|
238
|
+
) -> DocumentView:
|
|
233
239
|
"""
|
|
234
240
|
Render a document as an on-the-fly HTML view generated from the canonical IR.
|
|
235
241
|
|
|
@@ -237,12 +243,14 @@ class AsyncDocuments(AsyncResource, _DocumentsSpecs):
|
|
|
237
243
|
document_id (str): The document to render.
|
|
238
244
|
download (bool): When true, ask the server for the attachment-style response (the caller
|
|
239
245
|
still only gets the text back; the flag only affects the server-side response header).
|
|
246
|
+
pages (str | None): Render only these 1-based pages ('5', '5-7', '5,7-9'); the whole
|
|
247
|
+
document when None (the parameter is then not sent at all).
|
|
240
248
|
|
|
241
249
|
Returns:
|
|
242
250
|
DocumentView: The rendered HTML body and its ``text/html`` content type.
|
|
243
251
|
"""
|
|
244
252
|
content, mime_type = await self._transport.get_text_typed(
|
|
245
|
-
self._html_path(document_id), params={"download": download}
|
|
253
|
+
self._html_path(document_id), params={"download": download, "pages": pages}
|
|
246
254
|
)
|
|
247
255
|
return DocumentView(content=content, mime_type=mime_type)
|
|
248
256
|
|
|
@@ -303,7 +311,9 @@ class SyncDocuments(SyncResource, _DocumentsSpecs):
|
|
|
303
311
|
self._purge_trace_payloads_spec(document_id), TracePurgeResult
|
|
304
312
|
)
|
|
305
313
|
|
|
306
|
-
def get_markdown(
|
|
314
|
+
def get_markdown(
|
|
315
|
+
self, document_id: str, download: bool = False, pages: str | None = None
|
|
316
|
+
) -> DocumentView:
|
|
307
317
|
"""
|
|
308
318
|
Render a document as an on-the-fly markdown view generated from the canonical IR.
|
|
309
319
|
|
|
@@ -311,16 +321,20 @@ class SyncDocuments(SyncResource, _DocumentsSpecs):
|
|
|
311
321
|
document_id (str): The document to render.
|
|
312
322
|
download (bool): When true, ask the server for the attachment-style response (the caller
|
|
313
323
|
still only gets the text back; the flag only affects the server-side response header).
|
|
324
|
+
pages (str | None): Render only these 1-based pages ('5', '5-7', '5,7-9'); the whole
|
|
325
|
+
document when None (the parameter is then not sent at all).
|
|
314
326
|
|
|
315
327
|
Returns:
|
|
316
328
|
DocumentView: The rendered markdown body and its ``text/markdown`` content type.
|
|
317
329
|
"""
|
|
318
330
|
content, mime_type = self._transport.get_text_typed(
|
|
319
|
-
self._markdown_path(document_id), params={"download": download}
|
|
331
|
+
self._markdown_path(document_id), params={"download": download, "pages": pages}
|
|
320
332
|
)
|
|
321
333
|
return DocumentView(content=content, mime_type=mime_type)
|
|
322
334
|
|
|
323
|
-
def get_html(
|
|
335
|
+
def get_html(
|
|
336
|
+
self, document_id: str, download: bool = False, pages: str | None = None
|
|
337
|
+
) -> DocumentView:
|
|
324
338
|
"""
|
|
325
339
|
Render a document as an on-the-fly HTML view generated from the canonical IR.
|
|
326
340
|
|
|
@@ -328,12 +342,14 @@ class SyncDocuments(SyncResource, _DocumentsSpecs):
|
|
|
328
342
|
document_id (str): The document to render.
|
|
329
343
|
download (bool): When true, ask the server for the attachment-style response (the caller
|
|
330
344
|
still only gets the text back; the flag only affects the server-side response header).
|
|
345
|
+
pages (str | None): Render only these 1-based pages ('5', '5-7', '5,7-9'); the whole
|
|
346
|
+
document when None (the parameter is then not sent at all).
|
|
331
347
|
|
|
332
348
|
Returns:
|
|
333
349
|
DocumentView: The rendered HTML body and its ``text/html`` content type.
|
|
334
350
|
"""
|
|
335
351
|
content, mime_type = self._transport.get_text_typed(
|
|
336
|
-
self._html_path(document_id), params={"download": download}
|
|
352
|
+
self._html_path(document_id), params={"download": download, "pages": pages}
|
|
337
353
|
)
|
|
338
354
|
return DocumentView(content=content, mime_type=mime_type)
|
|
339
355
|
|