prepare stored Docling blobs off the event loop
This commit is contained in:
parent
c6514c9df4
commit
183d595494
1 changed files with 54 additions and 33 deletions
|
|
@ -60,6 +60,30 @@ MAX_ATTACHMENT_DEPTH = 3
|
||||||
_RESERVED_METADATA_KEYS = frozenset({"content_type", "md5", "source_revision"})
|
_RESERVED_METADATA_KEYS = frozenset({"content_type", "md5", "source_revision"})
|
||||||
|
|
||||||
|
|
||||||
|
def _prepare_document_from_docling_sync(
|
||||||
|
document: Document, docling_document: "DoclingDocument"
|
||||||
|
) -> str:
|
||||||
|
"""Populate content/docling blobs from a DoclingDocument.
|
||||||
|
|
||||||
|
This performs size-proportional serialization, JSON splitting, and
|
||||||
|
compression via ``Document.set_docling``. Async ingestion paths should call
|
||||||
|
it through ``_prepare_document_from_docling`` so large image-bearing
|
||||||
|
documents do not block the event loop.
|
||||||
|
"""
|
||||||
|
content = docling_document.export_to_markdown()
|
||||||
|
document.content = content
|
||||||
|
document.set_docling(docling_document)
|
||||||
|
return content
|
||||||
|
|
||||||
|
|
||||||
|
async def _prepare_document_from_docling(
|
||||||
|
document: Document, docling_document: "DoclingDocument"
|
||||||
|
) -> str:
|
||||||
|
return await asyncio.to_thread(
|
||||||
|
_prepare_document_from_docling_sync, document, docling_document
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def parent_uri_filter(parent_uri: str) -> str:
|
def parent_uri_filter(parent_uri: str) -> str:
|
||||||
"""SQL `WHERE` clause matching documents whose ``metadata.parent_uri``
|
"""SQL `WHERE` clause matching documents whose ``metadata.parent_uri``
|
||||||
equals ``parent_uri``. ``metadata`` is stored as a JSON string produced by
|
equals ``parent_uri``. ``metadata`` is stored as a JSON string produced by
|
||||||
|
|
@ -184,18 +208,18 @@ async def create_document(
|
||||||
chunks = await client.chunk(docling_document)
|
chunks = await client.chunk(docling_document)
|
||||||
embedded_chunks = await embed_chunks(chunks, client.embedder, client._config)
|
embedded_chunks = await embed_chunks(chunks, client.embedder, client._config)
|
||||||
|
|
||||||
stored_content = docling_document.export_to_markdown()
|
|
||||||
|
|
||||||
if title is None:
|
|
||||||
title = await resolve_title(client._config, docling_document, stored_content)
|
|
||||||
|
|
||||||
document = Document(
|
document = Document(
|
||||||
content=stored_content,
|
content="",
|
||||||
uri=uri,
|
uri=uri,
|
||||||
title=title,
|
title=title,
|
||||||
metadata=metadata or {},
|
metadata=metadata or {},
|
||||||
)
|
)
|
||||||
document.set_docling(docling_document)
|
stored_content = await _prepare_document_from_docling(document, docling_document)
|
||||||
|
|
||||||
|
if title is None:
|
||||||
|
document.title = await resolve_title(
|
||||||
|
client._config, docling_document, stored_content
|
||||||
|
)
|
||||||
|
|
||||||
return await _store_document_with_chunks(
|
return await _store_document_with_chunks(
|
||||||
client, document, embedded_chunks, docling_document
|
client, document, embedded_chunks, docling_document
|
||||||
|
|
@ -215,17 +239,15 @@ async def import_document(
|
||||||
Use this when conversion, chunking, and embedding were done externally.
|
Use this when conversion, chunking, and embedding were done externally.
|
||||||
Chunks without embeddings will be automatically embedded.
|
Chunks without embeddings will be automatically embedded.
|
||||||
"""
|
"""
|
||||||
content = docling_document.export_to_markdown()
|
|
||||||
if title is None:
|
|
||||||
title = await resolve_title(client._config, docling_document, content)
|
|
||||||
|
|
||||||
document = Document(
|
document = Document(
|
||||||
content=content,
|
content="",
|
||||||
uri=uri,
|
uri=uri,
|
||||||
title=title,
|
title=title,
|
||||||
metadata=metadata or {},
|
metadata=metadata or {},
|
||||||
)
|
)
|
||||||
document.set_docling(docling_document)
|
content = await _prepare_document_from_docling(document, docling_document)
|
||||||
|
if title is None:
|
||||||
|
document.title = await resolve_title(client._config, docling_document, content)
|
||||||
|
|
||||||
return await _store_document_with_chunks(client, document, chunks, docling_document)
|
return await _store_document_with_chunks(client, document, chunks, docling_document)
|
||||||
|
|
||||||
|
|
@ -291,18 +313,17 @@ async def import_documents(
|
||||||
|
|
||||||
prepared: list[tuple[Document, list[Chunk], DoclingDocument]] = []
|
prepared: list[tuple[Document, list[Chunk], DoclingDocument]] = []
|
||||||
for item in imports:
|
for item in imports:
|
||||||
content = item.docling_document.export_to_markdown()
|
|
||||||
title = item.title
|
|
||||||
if title is None:
|
|
||||||
title = await resolve_title(client._config, item.docling_document, content)
|
|
||||||
|
|
||||||
document = Document(
|
document = Document(
|
||||||
content=content,
|
content="",
|
||||||
uri=item.uri,
|
uri=item.uri,
|
||||||
title=title,
|
title=item.title,
|
||||||
metadata=item.metadata or {},
|
metadata=item.metadata or {},
|
||||||
)
|
)
|
||||||
document.set_docling(item.docling_document)
|
content = await _prepare_document_from_docling(document, item.docling_document)
|
||||||
|
if document.title is None:
|
||||||
|
document.title = await resolve_title(
|
||||||
|
client._config, item.docling_document, content
|
||||||
|
)
|
||||||
prepared.append((document, item.chunks, item.docling_document))
|
prepared.append((document, item.chunks, item.docling_document))
|
||||||
|
|
||||||
return await _store_documents_with_chunks(client, prepared)
|
return await _store_documents_with_chunks(client, prepared)
|
||||||
|
|
@ -427,13 +448,13 @@ async def _ingest_fetch_result(
|
||||||
if cleanup_path is not None:
|
if cleanup_path is not None:
|
||||||
cleanup_path.unlink(missing_ok=True)
|
cleanup_path.unlink(missing_ok=True)
|
||||||
|
|
||||||
stored_content = docling_document.export_to_markdown()
|
|
||||||
final_metadata = {**user_metadata, **source_metadata}
|
final_metadata = {**user_metadata, **source_metadata}
|
||||||
|
|
||||||
if existing_doc:
|
if existing_doc:
|
||||||
existing_doc.content = stored_content
|
|
||||||
existing_doc.metadata = final_metadata
|
existing_doc.metadata = final_metadata
|
||||||
existing_doc.set_docling(docling_document)
|
stored_content = await _prepare_document_from_docling(
|
||||||
|
existing_doc, docling_document
|
||||||
|
)
|
||||||
if title is not None:
|
if title is not None:
|
||||||
existing_doc.title = title
|
existing_doc.title = title
|
||||||
elif existing_doc.title is None:
|
elif existing_doc.title is None:
|
||||||
|
|
@ -448,15 +469,17 @@ async def _ingest_fetch_result(
|
||||||
await _reconcile_pdf_attachments(client, updated, result.body, depth=depth)
|
await _reconcile_pdf_attachments(client, updated, result.body, depth=depth)
|
||||||
return updated
|
return updated
|
||||||
|
|
||||||
if title is None:
|
|
||||||
title = await resolve_title(client._config, docling_document, stored_content)
|
|
||||||
document = Document(
|
document = Document(
|
||||||
content=stored_content,
|
content="",
|
||||||
uri=stored_uri,
|
uri=stored_uri,
|
||||||
title=title,
|
title=title,
|
||||||
metadata=final_metadata,
|
metadata=final_metadata,
|
||||||
)
|
)
|
||||||
document.set_docling(docling_document)
|
stored_content = await _prepare_document_from_docling(document, docling_document)
|
||||||
|
if document.title is None:
|
||||||
|
document.title = await resolve_title(
|
||||||
|
client._config, docling_document, stored_content
|
||||||
|
)
|
||||||
with logfire.span("document.store", uri=result.uri, op="create") as store_span:
|
with logfire.span("document.store", uri=result.uri, op="create") as store_span:
|
||||||
created = await _store_document_with_chunks(
|
created = await _store_document_with_chunks(
|
||||||
client, document, embedded_chunks, docling_document
|
client, document, embedded_chunks, docling_document
|
||||||
|
|
@ -807,8 +830,7 @@ async def update_document(
|
||||||
|
|
||||||
if chunks is not None:
|
if chunks is not None:
|
||||||
if docling_document is not None:
|
if docling_document is not None:
|
||||||
existing_doc.content = docling_document.export_to_markdown()
|
await _prepare_document_from_docling(existing_doc, docling_document)
|
||||||
existing_doc.set_docling(docling_document)
|
|
||||||
elif content is not None:
|
elif content is not None:
|
||||||
existing_doc.content = content
|
existing_doc.content = content
|
||||||
|
|
||||||
|
|
@ -817,8 +839,7 @@ async def update_document(
|
||||||
)
|
)
|
||||||
|
|
||||||
if docling_document is not None:
|
if docling_document is not None:
|
||||||
existing_doc.content = docling_document.export_to_markdown()
|
await _prepare_document_from_docling(existing_doc, docling_document)
|
||||||
existing_doc.set_docling(docling_document)
|
|
||||||
|
|
||||||
new_chunks = await client.chunk(docling_document)
|
new_chunks = await client.chunk(docling_document)
|
||||||
embedded_chunks = await embed_chunks(
|
embedded_chunks = await embed_chunks(
|
||||||
|
|
@ -832,7 +853,7 @@ async def update_document(
|
||||||
existing_doc.content = content
|
existing_doc.content = content
|
||||||
converter = get_converter(client._config)
|
converter = get_converter(client._config)
|
||||||
converted_docling = await converter.convert_text(existing_doc.content, format="md")
|
converted_docling = await converter.convert_text(existing_doc.content, format="md")
|
||||||
existing_doc.set_docling(converted_docling)
|
await _prepare_document_from_docling(existing_doc, converted_docling)
|
||||||
|
|
||||||
new_chunks = await client.chunk(converted_docling)
|
new_chunks = await client.chunk(converted_docling)
|
||||||
embedded_chunks = await embed_chunks(new_chunks, client.embedder, client._config)
|
embedded_chunks = await embed_chunks(new_chunks, client.embedder, client._config)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue