""" 5 LangChain tools ánh xạ trực tiếp với các lệnh trong test_db.py. section_prereqs(section_id) ← test_db.py prereq concepts_needed_for_section(id) ← test_db.py concepts concept_prereqs(concept_name) ← test_db.py cprerq concept_children(concept_name) ← test_db.py children search_knowledge_graph(keyword) ← test_db.py find Tất cả trả về JSON string. Definitions vẫn còn trong payload; masker_node sẽ strip/replace trước khi response_node dùng. """ from __future__ import annotations import json from langchain_core.tools import tool from src.graph_db.client import GraphClient def _db() -> GraphClient: return GraphClient.get() def _json(obj) -> str: return json.dumps(obj, ensure_ascii=False, default=str) # ───────────────────────────────────────────────────────────────────────────── @tool def chapter_info(chapter_id: str) -> str: """ Trả về thông tin của một chapter: tiêu đề, trang bắt đầu, part, và danh sách tất cả các section (tiêu đề + số trang) trong chapter đó. Dùng khi người dùng hỏi: - "Chương 2 bắt đầu từ trang nào?" - "Chương 3 gồm những phần nào?" - "Tiêu đề chương 2 là gì?" - "Chương 2 có mấy section?" Input: chapter ID (chỉ số), ví dụ "2", "3", "4" """ data = _db().chapter_info(chapter_id) if data is None: return _json({"error": f"Chapter '{chapter_id}' not found in knowledge graph."}) return _json({"chapter": data}) @tool def section_info(section_id: str) -> str: """ Trả về thông tin cơ bản của một section: tiêu đề, số trang, chapter, part. Dùng khi người dùng hỏi: - "Section 3.3 ở trang nào?" - "Phần 3.3 nằm ở đâu trong sách?" - "Tên của section 2.4 là gì?" - "Chương nào chứa section 4.1?" Input: section ID, ví dụ "3.3", "2.4", "4.1" """ data = _db().section_info(section_id) if data is None: return _json({"error": f"Section '{section_id}' not found in knowledge graph."}) return _json({"section": data}) @tool def section_prereqs(section_id: str) -> str: """ Trả về danh sách các section cần đọc TRƯỚC khi đọc section_id. Duyệt theo quan hệ REQUIRES (có transitivity tối đa 10 hop). Dùng khi người dùng hỏi: - "Đọc section 3.2 cần đọc gì trước?" - "Trước khi học chương 3.5 cần học những section nào?" - "Prerequisites của section 1.4 là gì?" Input: section ID, ví dụ "3.2", "1.4", "3.5" """ rows = _db().section_prereqs(section_id) return _json({"section_id": section_id, "prereq_sections": rows}) @tool def concepts_needed_for_section(section_id: str) -> str: """ Trả về danh sách các concept cần biết TRƯỚC khi đọc section_id. Lấy từ CONCEPT_REQUIRES của các concept định nghĩa trong section đó, loại bỏ duplicate và loại bỏ concept thuộc chính section đó. Dùng khi người dùng hỏi: - "Cần biết khái niệm gì trước khi học section 3.3?" - "Để hiểu section 2.5 cần nắm những concept nào?" - "Vocabulary cần ôn trước khi đọc chương 3?" Input: section ID, ví dụ "3.3", "2.5" """ rows = _db().concepts_needed_for(section_id) return _json({"section_id": section_id, "concepts_needed": rows}) @tool def concept_prereqs(concept_name: str) -> str: """ Trả về danh sách các concept cần hiểu TRƯỚC khi học concept_name. Duyệt theo quan hệ CONCEPT_REQUIRES (transitivity tối đa 10 hop), kèm depth (số bước) và section định nghĩa. Dùng khi người dùng hỏi: - "Để hiểu tu quoque cần biết gì trước?" - "Cần nắm những khái niệm nào trước khi học hasty generalization?" - "Prerequisites của concept ad hominem là gì?" Input: tên concept bằng tiếng Anh (chữ thường), ví dụ "tu quoque", "hasty generalization", "cogent argument" """ rows = _db().concept_prereqs(concept_name) return _json({"concept": concept_name, "prereq_concepts": rows}) @tool def concept_children(concept_name: str) -> str: """ Trả về các khái niệm con (subtypes) của concept_name theo quan hệ IS_TYPE_OF. Dùng để khám phá taxonomy của một khái niệm lớn. Dùng khi người dùng hỏi: - "Fallacy gồm những loại nào?" - "Fallacy of relevance bao gồm những fallacy nào?" - "Inductive argument có những dạng nào?" - "Liệt kê các loại definition" Input: tên concept cha, ví dụ "fallacy", "informal fallacy", "fallacy of relevance", "deductive argument" """ rows = _db().concept_subtypes(concept_name) return _json({"concept": concept_name, "subtypes": rows}) @tool def search_knowledge_graph(keyword: str) -> str: """ Tìm kiếm full-text trong knowledge graph theo từ khóa. Trả về tối đa 8 concept khớp với keyword (tên hoặc định nghĩa), kèm số trang và section định nghĩa. Dùng khi người dùng hỏi: - "Tìm kiếm 'sufficient condition' trong sách" - "Có concept nào liên quan đến 'circular' không?" - "Tìm tất cả khái niệm liên quan đến 'analogy'" - Hoặc khi không chắc tên chính xác của một concept Input: từ khóa tiếng Anh, ví dụ "sufficient", "circular", "analogy" """ rows = _db().search_concepts(keyword) return _json({"keyword": keyword, "results": rows}) # Danh sách để import vào nodes.py ALL_GRAPH_TOOLS = [ chapter_info, section_info, section_prereqs, concepts_needed_for_section, concept_prereqs, concept_children, search_knowledge_graph, ]