From c2e351396bdeff5a3d4741c384b5bd751764f4aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B5=B7?= <10402852@qq.com> Date: Tue, 18 Feb 2025 09:46:55 +0800 Subject: [PATCH] 'commit' --- ...KnowledgeGraph.py => K1_KnowledgeGraph.py} | 79 ++++++++++++++----- AI/Neo4j/K2_Neo4jExecutor.py | 75 ++++++++++++++++++ AI/Neo4j/knowledge_graph.cypher | 43 +++++++++- AI/Neo4j/result.txt | 35 -------- AI/Test/HwTest2.py | 42 ++++++++++ 5 files changed, 214 insertions(+), 60 deletions(-) rename AI/Neo4j/{KnowledgeGraph.py => K1_KnowledgeGraph.py} (54%) create mode 100644 AI/Neo4j/K2_Neo4jExecutor.py delete mode 100644 AI/Neo4j/result.txt create mode 100644 AI/Test/HwTest2.py diff --git a/AI/Neo4j/KnowledgeGraph.py b/AI/Neo4j/K1_KnowledgeGraph.py similarity index 54% rename from AI/Neo4j/KnowledgeGraph.py rename to AI/Neo4j/K1_KnowledgeGraph.py index c96c2ada..c6834e06 100644 --- a/AI/Neo4j/KnowledgeGraph.py +++ b/AI/Neo4j/K1_KnowledgeGraph.py @@ -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") \ No newline at end of file + print(f"\nCypher语句已保存至 knowledge_graph.cypher (题目ID: {kg.question_id})") \ No newline at end of file diff --git a/AI/Neo4j/K2_Neo4jExecutor.py b/AI/Neo4j/K2_Neo4jExecutor.py new file mode 100644 index 00000000..76755ef6 --- /dev/null +++ b/AI/Neo4j/K2_Neo4jExecutor.py @@ -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']}秒") \ No newline at end of file diff --git a/AI/Neo4j/knowledge_graph.cypher b/AI/Neo4j/knowledge_graph.cypher index fe0c567b..2eaa20b4 100644 --- a/AI/Neo4j/knowledge_graph.cypher +++ b/AI/Neo4j/knowledge_graph.cypher @@ -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) \ No newline at end of file +// 约束 +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; \ No newline at end of file diff --git a/AI/Neo4j/result.txt b/AI/Neo4j/result.txt deleted file mode 100644 index 8fb6a324..00000000 --- a/AI/Neo4j/result.txt +++ /dev/null @@ -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厘米。** \ No newline at end of file diff --git a/AI/Test/HwTest2.py b/AI/Test/HwTest2.py new file mode 100644 index 00000000..322895a9 --- /dev/null +++ b/AI/Test/HwTest2.py @@ -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)