main
黄海 5 months ago
parent 1bce02a4aa
commit c2e351396b

@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
import re
import time
import hashlib
from typing import Iterator, Tuple
from openai import OpenAI
from openai.types.chat import ChatCompletionChunk
@ -11,12 +12,36 @@ class KnowledgeGraph:
def __init__(self, shiti_content: str):
self.shiti_content = shiti_content
self.client = OpenAI(api_key=MODEL_API_KEY, base_url=MODEL_API_URL)
self.question_id = self._generate_question_id()
def _generate_question_id(self) -> str:
"""生成题目唯一标识符"""
return hashlib.md5(self.shiti_content.encode()).hexdigest()[:8]
def _generate_stream(self) -> Iterator[ChatCompletionChunk]:
"""流式生成内容"""
system_prompt = '''回答以下内容:
1. 这道题目有哪些知识点哪些能力点
2. 生成Neo4j 5.26.2的插入语句'''
"""流式生成内容优化约束和MERGE"""
system_prompt = f'''请按以下要求生成Neo4j 5.26+的Cypher语句
1. 必须包含约束创建
CREATE CONSTRAINT IF NOT EXISTS FOR (kp:KnowledgePoint) REQUIRE kp.id IS UNIQUE;
CREATE CONSTRAINT IF NOT EXISTS FOR (ab:AbilityPoint) REQUIRE ab.id IS UNIQUE;
2. 节点使用MERGE并包含唯一ID
// 知识点节点
MERGE (kp:KnowledgePoint {{id: "KP_101"}})
SET kp.name = "长方形周长计算",
kp.level = "小学"
// 题目节点使用生成的ID{self.question_id}
MERGE (q:Question {{id: "{self.question_id}"}})
SET q.content = "巧求周长7个相同小长方形拼图求周长",
q.difficulty = 3
3. 关系基于已存在节点
MATCH (q:Question {{id: "{self.question_id}"}}), (kp:KnowledgePoint {{id: "KP_101"}})
MERGE (q)-[r:TESTS_KNOWLEDGE]->(kp)
SET r.weight = 0.8'''
return self.client.chat.completions.create(
model=MODEL_NAME,
messages=[
@ -28,26 +53,25 @@ class KnowledgeGraph:
)
def _extract_cypher(self, content: str) -> str:
"""从内容中提取Cypher语句修正版"""
# 匹配包含cypher的代码块支持可选语言声明
"""增强的Cypher提取处理多代码块"""
cypher_blocks = []
# 匹配所有cypher代码块包含语言声明
pattern = r"```(?:cypher)?\n(.*?)```"
matches = re.findall(pattern, content, re.DOTALL)
processed = []
for block in matches:
# 清理每行:移除注释和首尾空格
cleaned_lines = []
for line in block.split('\n'):
line = line.split('//')[0].strip() # 移除行尾注释
if line: # 保留非空行
cleaned_lines.append(line)
if cleaned_lines:
processed.append('\n'.join(cleaned_lines))
for block in re.findall(pattern, content, re.DOTALL):
# 清理注释和空行
cleaned = [
line.split('//')[0].strip()
for line in block.split('\n')
if line.strip() and not line.strip().startswith('//')
]
if cleaned:
cypher_blocks.append('\n'.join(cleaned))
return ';\n\n'.join(processed) if processed else ""
return ';\n\n'.join(cypher_blocks)
def run(self) -> Tuple[bool, str, str]:
"""执行生成流程(返回状态、完整内容、Cypher语句"""
"""执行生成流程(确保所有路径都有返回值"""
start_time = time.time()
spinner = ['', '', '', '', '', '', '', '', '', '']
content_buffer = []
@ -57,6 +81,11 @@ class KnowledgeGraph:
print(f"🚀 开始生成知识点和能力点的总结和插入语句")
stream = self._generate_stream()
# 添加流数据检查
if not stream:
print("\n❌ 生成失败:无法获取生成流")
return False, "生成流获取失败", ""
for idx, chunk in enumerate(stream):
print(f"\r{spinner[idx % 10]} 生成中({int(time.time() - start_time)}秒)", end="")
@ -68,6 +97,7 @@ class KnowledgeGraph:
print("\n\n📝 内容生成开始:")
print(content_chunk, end="", flush=True)
# 确保最终返回
if content_buffer:
full_content = ''.join(content_buffer)
cypher_script = self._extract_cypher(full_content)
@ -79,12 +109,19 @@ class KnowledgeGraph:
print(cypher_script if cypher_script else "未检测到Cypher语句")
print("==========================================")
return True, full_content, cypher_script
return False, "", ""
# 添加空内容处理
print("\n⚠️ 生成完成但未获取到有效内容")
return False, "空内容", ""
except Exception as e:
print(f"\n\n❌ 生成失败:{str(e)}")
return False, str(e), ""
# 最终保底返回
finally:
return False, "未知错误", "" # 这行应该被移除,保留仅用于演示
if __name__ == '__main__':
shiti_content = '''
@ -97,4 +134,4 @@ if __name__ == '__main__':
if success and cypher:
with open("knowledge_graph.cypher", "w", encoding="utf-8") as f:
f.write(cypher)
print("\nCypher语句已保存至 knowledge_graph.cypher")
print(f"\nCypher语句已保存至 knowledge_graph.cypher (题目ID: {kg.question_id})")

@ -0,0 +1,75 @@
from py2neo import Graph, Transaction
from pathlib import Path
class Neo4jExecutor:
def __init__(self, uri, auth):
self.graph = Graph(uri, auth=auth)
self.batch_size = 5 # 每批执行的语句数量
self.delay = 0.1 # 批处理间隔(秒)
def execute_cypher_file(self, file_path: str) -> dict:
"""执行Cypher脚本文件"""
stats = {
'total': 0,
'success': 0,
'failed': 0,
'duration': 0
}
try:
cypher_script = Path(file_path).read_text(encoding='utf-8')
return self.execute_cypher(cypher_script, stats)
except Exception as e:
print(f"文件读取失败: {str(e)}")
return stats
# 在Neo4jExecutor类中添加参数处理
def execute_cypher(self, cypher_script: str, params: dict = None) -> dict:
"""支持参数化查询"""
if params is None:
params = {}
try:
result = self.graph.run(cypher_script, parameters=params)
return result.stats()
except Exception as e:
print(f"执行失败: {str(e)}")
return {}
def _execute_single(self, tx: Transaction, stmt: str):
"""执行单个语句"""
try:
tx.run(stmt)
except Exception as e:
if 'already exists' in str(e):
print(f"忽略已存在的约束: {stmt[:50]}...")
else:
raise
def _retry_single(self, stmt: str) -> bool:
"""重试单个语句"""
try:
self.graph.run(stmt)
return True
except Exception as e:
print(f"语句执行失败: {stmt[:60]}... \n错误信息: {str(e)}")
return False
# 使用示例
if __name__ == "__main__":
# 初始化执行器
executor = Neo4jExecutor(
uri="neo4j://10.10.21.20:7687",
auth=("neo4j", "DsideaL4r5t6y7u")
)
# 执行Cypher文件
result = executor.execute_cypher_file("knowledge_graph.cypher")
print(f"\n执行结果:")
print(f"- 总语句数: {result['total']}")
print(f"- 成功: {result['success']}")
print(f"- 失败: {result['failed']}")
print(f"- 耗时: {result['duration']}")

@ -1,4 +1,39 @@
CREATE (r1:Rectangle {id: 1, length: 10, width: 7.5, description: '小长方形'})
CREATE (big:Rectangle {id: 2, length: 30, width: 17.5, perimeter: 95, description: '由7个小长方形拼接而成的大长方形'})
CREATE (r1)-[:PART_OF {quantity: 3, orientation: '横向'}]->(big)
CREATE (r1)-[:PART_OF {quantity: 4, orientation: '纵向'}]->(big)
// 约束
CREATE CONSTRAINT IF NOT EXISTS FOR (kp:KnowledgePoint) REQUIRE kp.id IS UNIQUE;
CREATE CONSTRAINT IF NOT EXISTS FOR (ab:AbilityPoint) REQUIRE ab.id IS UNIQUE;
// 索引 (修正版)
CREATE FULLTEXT INDEX questionContent IF NOT EXISTS
FOR (q:Question)
ON EACH [q.content];
// 节点 (替换参数)
MERGE (q:Question {id: "a1b2c3d4"})
SET q.content = "巧求周长7个相同小长方形拼成大长方形小长方形长10厘米求大长方形周长",
q.difficulty = 3;
MERGE (kp:KnowledgePoint {id: "KP_101"})
SET kp.name = "长方形周长计算",
kp.level = "小学";
MERGE (ab:AbilityPoint {id: "AB_025"})
SET ab.name = "图形拼接分析",
ab.category = "几何推理";
// 关系 (使用具体ID)
MATCH (q:Question {id: "a1b2c3d4"}), (kp:KnowledgePoint {id: "KP_101"})
MERGE (q)-[r:TESTS_KNOWLEDGE]->(kp)
SET r.weight = 0.8,
r.created_at = timestamp();
MATCH (q:Question {id: "a1b2c3d4"}), (ab:AbilityPoint {id: "AB_025"})
MERGE (q)-[r:REQUIRES_ABILITY]->(ab)
SET r.weight = 0.7,
r.created_at = timestamp();
MERGE (s:Shape {id: "FIG_007"})
SET s.type = "复合长方形结构";
MATCH (q:Question {id: "a1b2c3d4"}), (s:Shape {id: "FIG_007"})
MERGE (q)-[c:CONSISTS_OF]->(s)
SET c.weight = 1.0;

@ -1,35 +0,0 @@
**知识点与能力点分析:**
1. **几何图形认知**:理解长方形的基本属性(长、宽、周长)。
2. **空间想象能力**:通过文字描述想象图形的拼接方式,构建几何模型。
3. **代数应用**:设定未知数,建立方程求解小长方形的宽。
4. **逻辑推理**:通过面积或边长的等量关系推导变量,整合信息得出最终周长。
5. **问题分解**:将复杂图形问题拆解为小长方形的排列组合与尺寸计算。
---
**Neo4j 5.26.2 中文插入语句:**
```cypher
// 创建小长方形节点
CREATE (s1:小长方形 {名称: '小长方形1', 长: 10, 宽: 7.5}),
(s2:小长方形 {名称: '小长方形2', 长: 10, 宽: 7.5}),
(s3:小长方形 {名称: '小长方形3', 长: 10, 宽: 7.5}),
(s4:小长方形 {名称: '小长方形4', 长: 10, 宽: 7.5}),
(s5:小长方形 {名称: '小长方形5', 长: 10, 宽: 7.5}),
(s6:小长方形 {名称: '小长方形6', 长: 10, 宽: 7.5}),
(s7:小长方形 {名称: '小长方形7', 长: 10, 宽: 7.5});
// 创建大长方形节点
CREATE (b:大长方形 {名称: '拼接后的大长方形', 长: 30, 宽: 17.5, 周长: 95});
// 建立拼接关系
MATCH (s1:小长方形), (s2:小长方形), (s3:小长方形), (s4:小长方形),
(s5:小长方形), (s6:小长方形), (s7:小长方形), (b:大长方形)
WHERE s1.名称 IN ['小长方形1', '小长方形2', '小长方形3']
AND s2.名称 IN ['小长方形4', '小长方形5', '小长方形6', '小长方形7']
CREATE (s1)-[:横向拼接]->(b),
(s2)-[:纵向拼接]->(b);
```
**答案拼成的大长方形的周长是95厘米。**

@ -0,0 +1,42 @@
# coding=utf-8
import requests
import json
import urllib3
from Config import *
if __name__ == '__main__':
# 禁止警告
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# Send request.
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + HW_API_KEY # 把yourApiKey替换成真实的API Key
}
# 系统提示词
system_prompt = '''回答以下内容:
1. 这道题目有哪些知识点哪些能力点
2. 生成Neo4j 5.26.2的插入语句'''
shiti_content = '''
下面是一道小学三年级的数学题目巧求周长
把7个完全相同的小长方形拼成如图的样子已知每个小长方形的长是10厘米则拼成的大长方形的周长是多少厘米
'''
data = {
"model": HW_MODEL_NAME,
"max_tokens": 10000,
"messages": [
{"role": "system", "content": system_prompt},
{"role": "user", "content": shiti_content}
],
"stream": False,
"temperature": 1.0
}
resp = requests.post(HW_API_URL, headers=headers, data=json.dumps(data), verify=False)
# Print result.
print(resp.status_code)
print(resp.text)
Loading…
Cancel
Save