feat(mcp): tool search_organisations (résolution nom -> id)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,37 @@
|
|||||||
|
# src/mcp/queries.py
|
||||||
|
import re
|
||||||
|
|
||||||
|
from src.mcp.serialization import (
|
||||||
|
to_json_records, # noqa: F401 (utilisé aux tâches suivantes)
|
||||||
|
)
|
||||||
|
from src.utils.data import DF_ACHETEURS, DF_TITULAIRES
|
||||||
|
from src.utils.search import search_org
|
||||||
|
|
||||||
|
PAGE_SIZE = 50
|
||||||
|
TOP_N = 10
|
||||||
|
ORG_FRAMES = {"acheteur": DF_ACHETEURS, "titulaire": DF_TITULAIRES}
|
||||||
|
|
||||||
|
|
||||||
|
def _extract_plain_text(html_str: str) -> str:
|
||||||
|
"""Extract plain text from HTML link, e.g. '<a...>123</a>' -> '123'."""
|
||||||
|
match = re.search(r">([^<]+)<", html_str)
|
||||||
|
return match.group(1) if match else html_str
|
||||||
|
|
||||||
|
|
||||||
|
def search_organisations(
|
||||||
|
query: str, org_type: str = "acheteur", limite: int = 20
|
||||||
|
) -> list[dict]:
|
||||||
|
"""Recherche des organisations par nom, résout un nom -> id."""
|
||||||
|
if org_type not in ORG_FRAMES:
|
||||||
|
raise ValueError(
|
||||||
|
f"type invalide: {org_type!r} (attendu 'acheteur' ou 'titulaire')"
|
||||||
|
)
|
||||||
|
df = search_org(ORG_FRAMES[org_type], query, org_type, track=False).head(limite)
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"id": _extract_plain_text(r[f"{org_type}_id"]),
|
||||||
|
"nom": _extract_plain_text(r[f"{org_type}_nom"]),
|
||||||
|
"departement": r.get("Département"),
|
||||||
|
}
|
||||||
|
for r in df.to_dicts()
|
||||||
|
]
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
import src.utils.search as search_mod
|
import src.utils.search as search_mod
|
||||||
|
from src.mcp.queries import search_organisations
|
||||||
from src.utils.data import DF_ACHETEURS
|
from src.utils.data import DF_ACHETEURS
|
||||||
from src.utils.search import search_org
|
from src.utils.search import search_org
|
||||||
|
|
||||||
@@ -19,3 +22,20 @@ def test_search_org_track_true_calls_track_search(monkeypatch):
|
|||||||
search_org(DF_ACHETEURS, "ACHETEUR", "acheteur", track=True)
|
search_org(DF_ACHETEURS, "ACHETEUR", "acheteur", track=True)
|
||||||
|
|
||||||
assert calls == [("ACHETEUR", "home_page_search")]
|
assert calls == [("ACHETEUR", "home_page_search")]
|
||||||
|
|
||||||
|
|
||||||
|
def test_search_organisations_finds_known_acheteur():
|
||||||
|
result = search_organisations("ACHETEUR", "acheteur")
|
||||||
|
assert any(r["id"] == "123" for r in result)
|
||||||
|
first = next(r for r in result if r["id"] == "123")
|
||||||
|
assert set(first.keys()) == {"id", "nom", "departement"}
|
||||||
|
|
||||||
|
|
||||||
|
def test_search_organisations_invalid_type_raises():
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
search_organisations("x", "autre")
|
||||||
|
|
||||||
|
|
||||||
|
def test_search_organisations_respects_limite():
|
||||||
|
result = search_organisations("ACHETEUR", "acheteur", limite=1)
|
||||||
|
assert len(result) <= 1
|
||||||
|
|||||||
Reference in New Issue
Block a user