Parse non-strings
This commit is contained in:
parent
45d0b47a02
commit
8f3055d37d
3 changed files with 39 additions and 5 deletions
|
|
@ -40,8 +40,9 @@ haiku-rag add-src https://example.com/article.html
|
||||||
# Optionally set a human‑readable title stored in the DB schema
|
# Optionally set a human‑readable title stored in the DB schema
|
||||||
haiku-rag add-src /mnt/data/doc1.pdf --title "Q3 Financial Report"
|
haiku-rag add-src /mnt/data/doc1.pdf --title "Q3 Financial Report"
|
||||||
|
|
||||||
# Optionally attach metadata (repeat --meta)
|
# Optionally attach metadata (repeat --meta). Values use JSON parsing if possible:
|
||||||
haiku-rag add-src /mnt/data/doc1.pdf --meta source=manual --meta lang=en
|
# numbers, booleans, null, arrays/objects; otherwise kept as strings.
|
||||||
|
haiku-rag add-src /mnt/data/doc1.pdf --meta source=manual --meta page_count=12 --meta published=true
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import json
|
||||||
import warnings
|
import warnings
|
||||||
from importlib.metadata import version
|
from importlib.metadata import version
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
import typer
|
import typer
|
||||||
|
|
||||||
|
|
@ -137,12 +139,12 @@ def list_documents(
|
||||||
asyncio.run(app.list_documents())
|
asyncio.run(app.list_documents())
|
||||||
|
|
||||||
|
|
||||||
def _parse_meta_options(meta: list[str] | None) -> dict[str, str]:
|
def _parse_meta_options(meta: list[str] | None) -> dict[str, Any]:
|
||||||
"""Parse repeated --meta KEY=VALUE options into a dictionary.
|
"""Parse repeated --meta KEY=VALUE options into a dictionary.
|
||||||
|
|
||||||
Raises a Typer error if any entry is malformed.
|
Raises a Typer error if any entry is malformed.
|
||||||
"""
|
"""
|
||||||
result: dict[str, str] = {}
|
result: dict[str, Any] = {}
|
||||||
if not meta:
|
if not meta:
|
||||||
return result
|
return result
|
||||||
for item in meta:
|
for item in meta:
|
||||||
|
|
@ -151,7 +153,13 @@ def _parse_meta_options(meta: list[str] | None) -> dict[str, str]:
|
||||||
key, value = item.split("=", 1)
|
key, value = item.split("=", 1)
|
||||||
if not key:
|
if not key:
|
||||||
raise typer.BadParameter("--meta key cannot be empty")
|
raise typer.BadParameter("--meta key cannot be empty")
|
||||||
result[key] = value
|
# Best-effort JSON coercion: numbers, booleans, null, arrays/objects
|
||||||
|
try:
|
||||||
|
parsed = json.loads(value)
|
||||||
|
result[key] = parsed
|
||||||
|
except Exception:
|
||||||
|
# Leave as string if not valid JSON literal
|
||||||
|
result[key] = value
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -112,6 +112,31 @@ def test_add_document_src_with_meta():
|
||||||
assert kwargs.get("metadata") == {"source": "manual", "lang": "en"}
|
assert kwargs.get("metadata") == {"source": "manual", "lang": "en"}
|
||||||
|
|
||||||
|
|
||||||
|
def test_add_document_text_with_numeric_meta():
|
||||||
|
with patch("haiku.rag.app.HaikuRAGApp") as mock_app:
|
||||||
|
mock_app_instance = MagicMock()
|
||||||
|
mock_app_instance.add_document_from_text = AsyncMock()
|
||||||
|
mock_app.return_value = mock_app_instance
|
||||||
|
|
||||||
|
result = runner.invoke(
|
||||||
|
cli,
|
||||||
|
[
|
||||||
|
"add",
|
||||||
|
"some text",
|
||||||
|
"--meta",
|
||||||
|
"version=3",
|
||||||
|
"--meta",
|
||||||
|
"published=true",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result.exit_code == 0
|
||||||
|
mock_app_instance.add_document_from_text.assert_called_once()
|
||||||
|
_, kwargs = mock_app_instance.add_document_from_text.call_args
|
||||||
|
assert kwargs.get("text") == "some text"
|
||||||
|
assert kwargs.get("metadata") == {"version": 3, "published": True}
|
||||||
|
|
||||||
|
|
||||||
def test_get_document():
|
def test_get_document():
|
||||||
with patch("haiku.rag.app.HaikuRAGApp") as mock_app:
|
with patch("haiku.rag.app.HaikuRAGApp") as mock_app:
|
||||||
mock_app_instance = MagicMock()
|
mock_app_instance = MagicMock()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue