trends_resolution.py 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. from __future__ import annotations
  2. import json
  3. import os
  4. import subprocess
  5. from functools import lru_cache
  6. from typing import Any
  7. from news_mcp.entity_normalize import normalize_entity
  8. @lru_cache(maxsize=1024)
  9. def resolve_entity_via_trends(entity: str) -> dict[str, Any]:
  10. """Resolve a normalized entity through trends-mcp, falling back cleanly.
  11. The input is normalized first using the same local normalization rules used
  12. everywhere else in news-mcp, so query and storage paths stay aligned.
  13. """
  14. normalized = normalize_entity(entity)
  15. if not normalized:
  16. return {
  17. "raw": entity,
  18. "normalized": "",
  19. "canonical_label": "",
  20. "mid": None,
  21. "type": None,
  22. "source": "empty",
  23. }
  24. config = os.getenv("MCPORTER_CONFIG", os.path.expanduser("~/.openclaw/workspace/config/mcporter.json"))
  25. command = [
  26. "mcporter",
  27. "--config",
  28. config,
  29. "call",
  30. "trends.resolve_entity",
  31. f"keyword={normalized}",
  32. ]
  33. try:
  34. proc = subprocess.run(command, capture_output=True, text=True, timeout=20, check=False)
  35. if proc.returncode == 0 and proc.stdout.strip():
  36. payload = json.loads(proc.stdout)
  37. return {
  38. "raw": entity,
  39. "normalized": normalized,
  40. "canonical_label": payload.get("canonical_label") or normalized,
  41. "mid": payload.get("mid"),
  42. "type": payload.get("type"),
  43. "candidates": payload.get("candidates", []),
  44. "source": "trends-mcp",
  45. }
  46. except Exception:
  47. pass
  48. # Conservative fallback: keep the local normalized form and leave MID unset.
  49. return {
  50. "raw": entity,
  51. "normalized": normalized,
  52. "canonical_label": normalized,
  53. "mid": None,
  54. "type": None,
  55. "source": "fallback",
  56. }