main
黄海 5 months ago
parent 1bce02a4aa
commit c2e351396b

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