Spaces:
Runtime error
Runtime error
ego commited on
Commit ·
1fe2fca
1
Parent(s): 4822069
fix: improve graph generation reliability (strip thinking blocks, add retry, robust DOT extraction)
Browse files- core/models.py +2 -2
- core/retriever.py +2 -2
- core/visualizer.py +64 -13
- requirements.txt +1 -2
core/models.py
CHANGED
|
@@ -2,7 +2,7 @@ import os
|
|
| 2 |
import streamlit as st
|
| 3 |
from langchain_nvidia_ai_endpoints import ChatNVIDIA, NVIDIAEmbeddings
|
| 4 |
|
| 5 |
-
def get_llm(model_name: str = "nvidia/nemotron-3-nano-30b-a3b"
|
| 6 |
api_key = os.getenv("NV_API_KEY")
|
| 7 |
if not api_key and "NV_API_KEY" in st.secrets:
|
| 8 |
api_key = st.secrets["NV_API_KEY"]
|
|
@@ -15,7 +15,7 @@ def get_llm(model_name: str = "nvidia/nemotron-3-nano-30b-a3b", enable_thinking:
|
|
| 15 |
temperature=0,
|
| 16 |
seed=42,
|
| 17 |
max_tokens=16384,
|
| 18 |
-
extra_body={"chat_template_kwargs": {"enable_thinking":
|
| 19 |
api_key=api_key
|
| 20 |
)
|
| 21 |
|
|
|
|
| 2 |
import streamlit as st
|
| 3 |
from langchain_nvidia_ai_endpoints import ChatNVIDIA, NVIDIAEmbeddings
|
| 4 |
|
| 5 |
+
def get_llm(model_name: str = "nvidia/nemotron-3-nano-30b-a3b"):
|
| 6 |
api_key = os.getenv("NV_API_KEY")
|
| 7 |
if not api_key and "NV_API_KEY" in st.secrets:
|
| 8 |
api_key = st.secrets["NV_API_KEY"]
|
|
|
|
| 15 |
temperature=0,
|
| 16 |
seed=42,
|
| 17 |
max_tokens=16384,
|
| 18 |
+
extra_body={"chat_template_kwargs": {"enable_thinking":True}},
|
| 19 |
api_key=api_key
|
| 20 |
)
|
| 21 |
|
core/retriever.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
import os
|
| 2 |
from langchain_community.document_loaders import PyPDFLoader
|
| 3 |
from langchain_text_splitters import RecursiveCharacterTextSplitter
|
| 4 |
-
from
|
| 5 |
from core.models import get_embeddings
|
| 6 |
import tempfile
|
| 7 |
|
|
@@ -59,7 +59,7 @@ class Retriever:
|
|
| 59 |
self.vector_store = Chroma.from_documents(
|
| 60 |
documents=splits,
|
| 61 |
embedding=self.embeddings,
|
| 62 |
-
collection_name="knowledge_base"
|
| 63 |
)
|
| 64 |
else:
|
| 65 |
self.vector_store.add_documents(splits)
|
|
|
|
| 1 |
import os
|
| 2 |
from langchain_community.document_loaders import PyPDFLoader
|
| 3 |
from langchain_text_splitters import RecursiveCharacterTextSplitter
|
| 4 |
+
from langchain_community.vectorstores import Chroma
|
| 5 |
from core.models import get_embeddings
|
| 6 |
import tempfile
|
| 7 |
|
|
|
|
| 59 |
self.vector_store = Chroma.from_documents(
|
| 60 |
documents=splits,
|
| 61 |
embedding=self.embeddings,
|
| 62 |
+
collection_name="knowledge_base"
|
| 63 |
)
|
| 64 |
else:
|
| 65 |
self.vector_store.add_documents(splits)
|
core/visualizer.py
CHANGED
|
@@ -3,20 +3,71 @@ from core.models import get_llm
|
|
| 3 |
from langchain_core.output_parsers import StrOutputParser
|
| 4 |
from prompts import GRAPH_PROMPT
|
| 5 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
class KnowledgeGraphGenerator:
|
| 7 |
def __init__(self):
|
| 8 |
-
|
| 9 |
-
self.llm = get_llm(enable_thinking=False)
|
| 10 |
|
| 11 |
-
def generate_graph(self, text):
|
|
|
|
| 12 |
chain = GRAPH_PROMPT | self.llm | StrOutputParser()
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
from langchain_core.output_parsers import StrOutputParser
|
| 4 |
from prompts import GRAPH_PROMPT
|
| 5 |
|
| 6 |
+
|
| 7 |
+
def _extract_dot(raw: str) -> str:
|
| 8 |
+
"""从模型输出中提取干净的 DOT 代码。
|
| 9 |
+
|
| 10 |
+
处理以下情况:
|
| 11 |
+
1. <think>...</think> reasoning 块 (enable_thinking=True 时产生)
|
| 12 |
+
2. ```dot ... ``` 或 ``` ... ``` Markdown 代码块
|
| 13 |
+
3. 纯文本中直接包含 digraph {...}
|
| 14 |
+
"""
|
| 15 |
+
# 1. 剥离 <think>...</think> 块(贪婪匹配,跨行)
|
| 16 |
+
raw = re.sub(r"<think>.*?</think>", "", raw, flags=re.DOTALL).strip()
|
| 17 |
+
|
| 18 |
+
# 2. 优先提取 Markdown 代码块内容
|
| 19 |
+
md_match = re.search(r"```(?:dot)?\s*(digraph\s+\w+\s*\{.*?\})\s*```", raw, re.DOTALL)
|
| 20 |
+
if md_match:
|
| 21 |
+
return md_match.group(1).strip()
|
| 22 |
+
|
| 23 |
+
# 3. 直接提取 digraph { ... } 块(处理嵌套花括号)
|
| 24 |
+
digraph_match = re.search(r"(digraph\s+\w+\s*\{)", raw)
|
| 25 |
+
if digraph_match:
|
| 26 |
+
start = digraph_match.start()
|
| 27 |
+
depth = 0
|
| 28 |
+
for i, ch in enumerate(raw[start:], start=start):
|
| 29 |
+
if ch == "{":
|
| 30 |
+
depth += 1
|
| 31 |
+
elif ch == "}":
|
| 32 |
+
depth -= 1
|
| 33 |
+
if depth == 0:
|
| 34 |
+
return raw[start : i + 1].strip()
|
| 35 |
+
|
| 36 |
+
# 4. 兜底:清理 Markdown 标记后返回原文
|
| 37 |
+
cleaned = raw.replace("```dot", "").replace("```", "").strip()
|
| 38 |
+
if "digraph" not in cleaned:
|
| 39 |
+
cleaned = f"digraph G {{ {cleaned} }}"
|
| 40 |
+
return cleaned
|
| 41 |
+
|
| 42 |
+
|
| 43 |
class KnowledgeGraphGenerator:
|
| 44 |
def __init__(self):
|
| 45 |
+
self.llm = get_llm()
|
|
|
|
| 46 |
|
| 47 |
+
def generate_graph(self, text: str, max_retries: int = 3) -> str:
|
| 48 |
+
"""生成 DOT 格式知识图谱,失败时自动重试。"""
|
| 49 |
chain = GRAPH_PROMPT | self.llm | StrOutputParser()
|
| 50 |
+
|
| 51 |
+
last_error = None
|
| 52 |
+
for attempt in range(1, max_retries + 1):
|
| 53 |
+
try:
|
| 54 |
+
raw = chain.invoke({"text": text})
|
| 55 |
+
dot_code = _extract_dot(raw)
|
| 56 |
+
|
| 57 |
+
# 基本合法性校验:必须包含 digraph 和至少一条边
|
| 58 |
+
if "digraph" in dot_code and "->" in dot_code:
|
| 59 |
+
return dot_code
|
| 60 |
+
|
| 61 |
+
last_error = f"Attempt {attempt}: DOT output invalid (no edges found)."
|
| 62 |
+
except Exception as e:
|
| 63 |
+
last_error = f"Attempt {attempt}: {e}"
|
| 64 |
+
|
| 65 |
+
# 全部重试失败,返回最小合法占位图
|
| 66 |
+
return (
|
| 67 |
+
'digraph G {\n'
|
| 68 |
+
' rankdir=LR;\n'
|
| 69 |
+
' node [style="filled", fillcolor="#FFEBEE", shape="box"];\n'
|
| 70 |
+
f' "Generation Failed" -> "Please Retry" [label="error"];\n'
|
| 71 |
+
f' "Reason" [label="{last_error[:80]}"];\n'
|
| 72 |
+
'}'
|
| 73 |
+
)
|
requirements.txt
CHANGED
|
@@ -4,8 +4,7 @@ langchain-community
|
|
| 4 |
langchain-nvidia-ai-endpoints
|
| 5 |
langchain-core
|
| 6 |
langgraph
|
| 7 |
-
chromadb
|
| 8 |
-
langchain-chroma
|
| 9 |
pypdf
|
| 10 |
graphviz
|
| 11 |
python-dotenv
|
|
|
|
| 4 |
langchain-nvidia-ai-endpoints
|
| 5 |
langchain-core
|
| 6 |
langgraph
|
| 7 |
+
chromadb
|
|
|
|
| 8 |
pypdf
|
| 9 |
graphviz
|
| 10 |
python-dotenv
|