Browse Source

修改data_flow表结构
修改元数据字段。
修改数据模型编辑功能。
修改数据资源编辑功能。
修改数据流编辑功能。
修改DERIVES_FROM关系为DERIVED_FROM关系。

maxiaolong 6 ngày trước cách đây
mục cha
commit
a6b118853d

+ 46 - 0
Deepseek-prompt.txt

@@ -0,0 +1,46 @@
+你是一名数据库工程师,正在构建一个PostgreSQL数据中的汇总逻辑。请为以下需求生成一段标准的 PostgreSQL SQL 脚本:
+1.有一个源表: personal_loan_resource,它的定义语句如下:
+CREATE TABLE personal_loan_resource (
+    employee_profit_sharing_ratio numeric(18,6) COMMENT '员工分润比例',
+    customer_level_identifier smallint COMMENT '管户层级标识',
+    superior_organization_code varchar(15) COMMENT '上级机构编码',
+    amount_disbursed numeric(15,2) COMMENT '发放金额',
+    unified_authentication_code_2 varchar(255) COMMENT '统一认证码2',
+    customer_weight_coefficient numeric(18,6) COMMENT '客户权重系数',
+    monthly_interest_received_total numeric(15,2) COMMENT '月累计实收利息',
+    institution_code varchar(15) COMMENT '机构编码',
+    agreement_status_code varchar(10) COMMENT '协议状态代码',
+    secondary_subject_code varchar(50) COMMENT '二级科目编码',
+    unified_authentication_code_1 varchar(255) COMMENT '统一认证码1',
+    data_date date COMMENT '数据日期',
+    customer_category_identifier smallint COMMENT '客户类别标识',
+    customer_id varchar(50) COMMENT '客户编号',
+    disbursement_date date COMMENT '发放日期'
+);
+COMMENT ON TABLE personal_loan_resource IS '个人贷款_资源';
+
+2.有一个目标表:customer_service_ledger,它的定义语句如下:
+CREATE TABLE customer_service_ledger (
+    original_profit_sharing_record char COMMENT '原始分润记录',
+    unified_authentication_code_2 varchar(255) COMMENT '统一认证码2',
+    data_date date COMMENT '数据日期',
+    customer_category_identifier smallint COMMENT '客户类别标识',
+    secondary_subject varchar(50) COMMENT '二级科目',
+    primary_subject varchar(50) COMMENT '一级科目',
+    unified_authentication_code_1 varchar(255) COMMENT '统一认证码1',
+    customer_id varchar(50) COMMENT '客户编号',
+    customer_level_identifier smallint COMMENT '管户层级标识',
+    employee_profit_sharing_ratio numeric(18,6) COMMENT '员工分润比例',
+    customer_weight_coefficient numeric(18,6) COMMENT '客户权重系数',
+    amount numeric(15,2) COMMENT '金额',
+    superior_organization_code varchar(15) COMMENT '上级机构编码',
+    institution_code varchar(15) COMMENT '机构编码'
+);
+COMMENT ON TABLE customer_service_ledger IS '客户维业绩流水账';
+
+3.处理逻辑为:从源表里读取记录,根据贷款发放日期进行判断,如果贷款发放日期与数据日期为同一个月,则提取发放金额作为金额,在目标表里插入一条记录,“一级科目”字段设置内容为“当期个人贷款新发放金额”。;如果贷款发放日期与数据日期不是同一个月,则提取月累计实收利息作为金额,在目标表里插入一条记录,“一级科目”字段设置内容为“当期个人贷款月累计收息”。其他字段内容按照目标表的字段定义,从源表中读取对应字段进行填充。
+4.脚本应使用标准的 PostgreSQL 语法,适合在 Airflow、Python 脚本、或调度系统中调用;
+5.无需使用 UPSERT 或 ON CONFLICT
+6.请直接输出SQL,无需进行解释。
+7.请给这段sql起个英文名,不少于三个英文单词,使用"_"分隔,采用蛇形命名法。把sql的名字作为注释写在返回的sql中。
+8.生成的sql在向目标表插入数据的时候,向create_time字段写入当前日期时间now(),不用处理update_time字段

+ 4 - 0
app/api/data_flow/routes.py

@@ -148,6 +148,10 @@ def create_script():
             res = failed("请求数据不能为空", code=400)
             return json.dumps(res, ensure_ascii=False, cls=MyEncoder)
         
+        # 记录接收到的数据用于调试
+        logger.info(f"create_script接收到的数据: {json_data}")
+        logger.info(f"json_data类型: {type(json_data)}")
+        
         # 直接使用前端提交的json_data作为request_data参数
         script_content = DataFlowService.create_script(json_data)
         

+ 3 - 3
app/api/data_resource/routes.py

@@ -485,7 +485,7 @@ def id_data_save():
             
             # 先删除现有关系
             cypher_delete = """
-            MATCH (n:DataResource)-[r:contain]->()
+            MATCH (n:DataResource)-[r:INCLUDES]->()
             WHERE id(n) = $resource_id
             DELETE r
             """
@@ -521,7 +521,7 @@ def id_data_save():
                 # 使用明确的属性名匹配而不是ID
                 rel_cypher = """
                 MATCH (a:DataResource {name: $r_name}), (m:DataMeta {name: $m_name})
-                MERGE (a)-[r:contain]->(m)
+                MERGE (a)-[r:INCLUDES]->(m)
                 RETURN r
                 """
                 
@@ -539,7 +539,7 @@ def id_data_save():
 
                 # 额外验证关系是否创建
                 verify_cypher = """
-                MATCH (a:DataResource {name: $r_name})-[r:contain]->(m:DataMeta {name: $m_name})
+                MATCH (a:DataResource {name: $r_name})-[r:INCLUDES]->(m:DataMeta {name: $m_name})
                 RETURN count(r) as rel_count
                 """
                 

+ 199 - 21
app/core/data_flow/dataflows.py

@@ -1,8 +1,8 @@
 import logging
-from typing import Dict, List, Optional, Any
+from typing import Dict, List, Optional, Any, Union
 from datetime import datetime
 import json
-from app.core.llm.llm_service import llm_client
+from app.core.llm.llm_service import llm_client, llm_sql
 from app.core.graph.graph_operations import connect_graph, create_or_get_node, get_node, relationship_exists
 from app.core.meta_data import translate_and_parse, get_formatted_time
 from py2neo import Relationship
@@ -611,36 +611,115 @@ class DataFlowService:
             raise e
 
     @staticmethod
-    def create_script(request_data: str) -> str:
+    def create_script(request_data: Union[Dict[str, Any], str]) -> str:
         """
-        使用Deepseek模型生成脚本
+        使用Deepseek模型生成SQL脚本
         
         Args:
-            request_data: 请求数据,用户需求的文本描述
+            request_data: 包含input, output, request_content的请求数据字典,或JSON字符串
             
         Returns:
-            生成的脚本内容(TXT格式)
+            生成的SQL脚本内容
         """
         try:
-            # 构建prompt
-            prompt_parts = []
+            logger.info(f"开始处理脚本生成请求: {request_data}")
+            logger.info(f"request_data类型: {type(request_data)}")
+            
+            # 类型检查和处理
+            if isinstance(request_data, str):
+                logger.warning(f"request_data是字符串,尝试解析为JSON: {request_data}")
+                try:
+                    import json
+                    request_data = json.loads(request_data)
+                except json.JSONDecodeError as e:
+                    raise ValueError(f"无法解析request_data为JSON: {str(e)}")
+            
+            if not isinstance(request_data, dict):
+                raise ValueError(f"request_data必须是字典类型,实际类型: {type(request_data)}")
+            
+            # 1. 从传入的request_data中解析input, output, request_content内容
+            input_data = request_data.get('input', '')
+            output_data = request_data.get('output', '')
+           
+            request_content = request_data.get('request_data', '')
+            
+            # 如果request_content是HTML格式,提取纯文本
+            if request_content and (request_content.startswith('<p>') or '<' in request_content):
+                # 简单的HTML标签清理
+                import re
+                request_content = re.sub(r'<[^>]+>', '', request_content).strip()
+            
+            if not input_data or not output_data or not request_content:
+                raise ValueError(f"缺少必要参数:input='{input_data}', output='{output_data}', request_content='{request_content[:100] if request_content else ''}' 不能为空")
+            
+            logger.info(f"解析得到 - input: {input_data}, output: {output_data}, request_content: {request_content}")
+            
+            # 2. 解析input中的多个数据表并生成源表DDL
+            source_tables_ddl = []
+            input_tables = []
+            if input_data:
+                tables = [table.strip() for table in input_data.split(',') if table.strip()]
+                for table in tables:
+                    ddl = DataFlowService._parse_table_and_get_ddl(table, 'input')
+                    if ddl:
+                        input_tables.append(table)
+                        source_tables_ddl.append(ddl)
+                    else:
+                        logger.warning(f"无法获取输入表 {table} 的DDL结构")
+            
+            # 3. 解析output中的数据表并生成目标表DDL
+            target_table_ddl = ""
+            if output_data:
+                target_table_ddl = DataFlowService._parse_table_and_get_ddl(output_data.strip(), 'output')
+                if not target_table_ddl:
+                    logger.warning(f"无法获取输出表 {output_data} 的DDL结构")
             
-            # 添加系统提示
-            prompt_parts.append("请根据以下需求生成相应的数据处理脚本:")
+            # 4. 按照Deepseek-prompt.txt的框架构建提示语
+            prompt_parts = []
             
-            # 直接将request_data作为文本描述添加到prompt中
-            prompt_parts.append(request_data)
+            # 开场白 - 角色定义
+            prompt_parts.append("你是一名数据库工程师,正在构建一个PostgreSQL数据中的汇总逻辑。请为以下需求生成一段标准的 PostgreSQL SQL 脚本:")
+            
+            # 动态生成源表部分(第1点)
+            for i, (table, ddl) in enumerate(zip(input_tables, source_tables_ddl), 1):
+                table_name = table.split(':')[-1] if ':' in table else table
+                prompt_parts.append(f"{i}.有一个源表: {table_name},它的定义语句如下:")
+                prompt_parts.append(ddl)
+                prompt_parts.append("")  # 添加空行分隔
+            
+            # 动态生成目标表部分(第2点)
+            if target_table_ddl:
+                target_table_name = output_data.split(':')[-1] if ':' in output_data else output_data
+                next_index = len(input_tables) + 1
+                prompt_parts.append(f"{next_index}.有一个目标表:{target_table_name},它的定义语句如下:")
+                prompt_parts.append(target_table_ddl)
+                prompt_parts.append("")  # 添加空行分隔
+            
+            # 动态生成处理逻辑部分(第3点)
+            next_index = len(input_tables) + 2 if target_table_ddl else len(input_tables) + 1
+            prompt_parts.append(f"{next_index}.处理逻辑为:{request_content}")
+            prompt_parts.append("")  # 添加空行分隔
+            
+            # 固定的技术要求部分(第4-8点)
+            tech_requirements = [
+                f"{next_index + 1}.脚本应使用标准的 PostgreSQL 语法,适合在 Airflow、Python 脚本、或调度系统中调用;",
+                f"{next_index + 2}.无需使用 UPSERT 或 ON CONFLICT",
+                f"{next_index + 3}.请直接输出SQL,无需进行解释。",
+                f"{next_index + 4}.请给这段sql起个英文名,不少于三个英文单词,使用\"_\"分隔,采用蛇形命名法。把sql的名字作为注释写在返回的sql中。",
+                f"{next_index + 5}.生成的sql在向目标表插入数据的时候,向create_time字段写入当前日期时间now(),不用处理update_time字段"
+            ]
             
-            # 添加格式要求
-            prompt_parts.append("\n请生成完整可执行的脚本代码,包含必要的注释和错误处理。")
+            prompt_parts.extend(tech_requirements)
             
-            # 组合prompt
-            full_prompt = "\n\n".join(prompt_parts)
+            # 组合完整的提示语
+            full_prompt = "\n".join(prompt_parts)
             
-            logger.info(f"开始调用Deepseek模型生成脚本,prompt长度: {len(full_prompt)}")
+            logger.info(f"构建的完整提示语长度: {len(full_prompt)}")
+            logger.info(f"完整提示语内容: {full_prompt}")
             
-            # 调用LLM服务
-            script_content = llm_client(full_prompt)
+            # 5. 调用LLM生成SQL脚本
+            logger.info("开始调用Deepseek模型生成SQL脚本")
+            script_content = llm_sql(full_prompt)
             
             if not script_content:
                 raise ValueError("Deepseek模型返回空内容")
@@ -649,14 +728,113 @@ class DataFlowService:
             if not isinstance(script_content, str):
                 script_content = str(script_content)
             
-            logger.info(f"脚本生成成功,内容长度: {len(script_content)}")
+            logger.info(f"SQL脚本生成成功,内容长度: {len(script_content)}")
             
             return script_content
             
         except Exception as e:
-            logger.error(f"生成脚本失败: {str(e)}")
+            logger.error(f"生成SQL脚本失败: {str(e)}")
             raise e
 
+    @staticmethod
+    def _parse_table_and_get_ddl(table_str: str, table_type: str) -> str:
+        """
+        解析表格式(A:B)并从Neo4j查询元数据生成DDL
+        
+        Args:
+            table_str: 表格式字符串,格式为"label:en_name"
+            table_type: 表类型,用于日志记录(input/output)
+            
+        Returns:
+            DDL格式的表结构字符串
+        """
+        try:
+            # 解析A:B格式
+            if ':' not in table_str:
+                logger.error(f"表格式错误,应为'label:en_name'格式: {table_str}")
+                return ""
+            
+            parts = table_str.split(':', 1)
+            if len(parts) != 2:
+                logger.error(f"表格式解析失败: {table_str}")
+                return ""
+            
+            label = parts[0].strip()
+            en_name = parts[1].strip()
+            
+            if not label or not en_name:
+                logger.error(f"标签或英文名为空: label={label}, en_name={en_name}")
+                return ""
+            
+            logger.info(f"开始查询{table_type}表: label={label}, en_name={en_name}")
+            
+            # 从Neo4j查询节点及其关联的元数据
+            with connect_graph().session() as session:
+                # 查询节点及其关联的元数据
+                cypher = f"""
+                MATCH (n:{label} {{en_name: $en_name}})
+                OPTIONAL MATCH (n)-[:INCLUDES]->(m:DataMeta)
+                RETURN n, collect(m) as metadata
+                """
+                
+                result = session.run(cypher, en_name=en_name)
+                record = result.single()
+                
+                if not record:
+                    logger.error(f"未找到节点: label={label}, en_name={en_name}")
+                    return ""
+                
+                node = record['n']
+                metadata = record['metadata']
+                
+                logger.info(f"找到节点,关联元数据数量: {len(metadata)}")
+                
+                # 生成DDL格式的表结构
+                ddl_lines = []
+                ddl_lines.append(f"CREATE TABLE {en_name} (")
+                
+                if metadata:
+                    column_definitions = []
+                    for meta in metadata:
+                        if meta:  # 确保meta不为空
+                            meta_props = dict(meta)
+                            column_name = meta_props.get('en_name', meta_props.get('name', 'unknown_column'))
+                            data_type = meta_props.get('data_type', 'VARCHAR(255)')
+                            comment = meta_props.get('name', '')
+                            
+                            # 构建列定义
+                            column_def = f"    {column_name} {data_type}"
+                            if comment:
+                                column_def += f" COMMENT '{comment}'"
+                            
+                            column_definitions.append(column_def)
+                    
+                    if column_definitions:
+                        ddl_lines.append(",\n".join(column_definitions))
+                    else:
+                        ddl_lines.append("    id BIGINT PRIMARY KEY COMMENT '主键ID'")
+                else:
+                    # 如果没有元数据,添加默认列
+                    ddl_lines.append("    id BIGINT PRIMARY KEY COMMENT '主键ID'")
+                
+                ddl_lines.append(");")
+                
+                # 添加表注释
+                node_props = dict(node)
+                table_comment = node_props.get('name', node_props.get('describe', en_name))
+                if table_comment and table_comment != en_name:
+                    ddl_lines.append(f"COMMENT ON TABLE {en_name} IS '{table_comment}';")
+                
+                ddl_content = "\n".join(ddl_lines)
+                logger.info(f"{table_type}表DDL生成成功: {en_name}")
+                logger.debug(f"生成的DDL: {ddl_content}")
+                
+                return ddl_content
+                
+        except Exception as e:
+            logger.error(f"解析表格式和生成DDL失败: {str(e)}")
+            return ""
+
     @staticmethod
     def _handle_script_relationships(data: Dict[str, Any],dataflow_name:str,name_en:str):
         """

+ 17 - 13
app/core/data_model/model.py

@@ -244,18 +244,22 @@ def resource_handle_meta_data_model(id_lists, data_model_node_id):
                 logger.info(f"成功创建 {count} 个数据模型与元数据的关系")
 
         # 创建与DataResource的关系 资源关系
-        if resouce_ids:
-            logger.info("开始创建数据模型与数据资源的关系")
-            query = """
-            MATCH (source:DataModel), (target:DataResource)
-            WHERE id(source)=$source_id AND id(target) IN $target_ids
-            MERGE (source)-[:DERIVES_FROM]->(target)
-            RETURN count(*) as count
-            """
-            with connect_graph().session() as session:
-                result = session.run(query, source_id=data_model_node_id, target_ids=resouce_ids)
-                count = result.single()["count"]
-                logger.info(f"成功创建 {count} 个数据模型与数据资源的关系")
+        # 不在创建Modle时创建资源关系,将资源关系创建放在数据流程创建时处理
+        # 关系名称为DERIVED_FROM
+        # commented by mxl 2025-06-27
+        # 
+        # if resouce_ids:
+        #     logger.info("开始创建数据模型与数据资源的关系")
+        #     query = """
+        #     MATCH (source:DataModel), (target:DataResource)
+        #     WHERE id(source)=$source_id AND id(target) IN $target_ids
+        #     MERGE (source)-[:DERIVES_FROM]->(target)
+        #     RETURN count(*) as count
+        #     """
+        #     with connect_graph().session() as session:
+        #         result = session.run(query, source_id=data_model_node_id, target_ids=resouce_ids)
+        #         count = result.single()["count"]
+        #         logger.info(f"成功创建 {count} 个数据模型与数据资源的关系")
                 
     except Exception as e:
         logger.error(f"处理数据模型与元数据的关系时发生错误: {str(e)}")
@@ -441,7 +445,7 @@ def handle_id_model(id):
     cql = """
         MATCH (n:DataModel) WHERE id(n) = $nodeId
         OPTIONAL MATCH (n)-[:INCLUDES]->(meta:DataMeta)  
-        OPTIONAL MATCH (n)-[:DERIVES_FROM]->(resource:DataResource)
+        OPTIONAL MATCH (n)-[:DERIVED_FROM]->(resource:DataResource)
         OPTIONAL MATCH (n)-[:label]->(tag:DataLabel)
         OPTIONAL MATCH (uses:model_use)-[:use]->(n)
         OPTIONAL MATCH (n)-[:has_component]->(component)

+ 9 - 10
app/core/data_parse/parse_card.py

@@ -293,16 +293,15 @@ def add_business_card(card_data, image_file=None):
                 # 创建新记录
                 # 准备初始职业轨迹,包含当前名片信息和图片路径
                 # initial_career_path = card_data.get('career_path', [])
-                if card_data.get('hotel_zh') or card_data.get('hotel_en') or card_data.get('title_zh') or card_data.get('title_en'):
-                    initial_entry = {
-                        'date': datetime.now().strftime('%Y-%m-%d'),
-                        'hotel_zh': card_data.get('hotel_zh', ''),
-                        'hotel_en': card_data.get('hotel_en', ''),
-                        'title_zh': card_data.get('title_zh', ''),
-                        'title_en': card_data.get('title_en', ''),
-                        'image_path': minio_path or '',  # 当前名片的图片路径
-                        'source': 'business_card_creation'
-                    }
+                initial_entry = {
+                    'date': datetime.now().strftime('%Y-%m-%d'),
+                    'hotel_zh': card_data.get('hotel_zh', ''),
+                    'hotel_en': card_data.get('hotel_en', ''),
+                    'title_zh': card_data.get('title_zh', ''),
+                    'title_en': card_data.get('title_en', ''),
+                    'image_path': minio_path or '',  # 当前名片的图片路径
+                    'source': 'business_card_creation'
+                }
                 initial_career_path = [initial_entry]
                 
                 # 导入手机号码处理函数

+ 8 - 8
app/core/data_resource/resource.py

@@ -250,7 +250,7 @@ def handle_node(receiver, head_data, data_source=None, resource_type=None):
                         rel_cypher = """
                         MATCH (a:DataResource), (m:DataMeta)
                         WHERE id(a) = $resource_id AND id(m) = $meta_id
-                        MERGE (a)-[r:contain]->(m)
+                        MERGE (a)-[r:INCLUDES]->(m)
                         RETURN r
                         """
                         
@@ -386,7 +386,7 @@ def handle_id_resource(resource_id):
             
             # 查询关联的元数据 - 支持meta_data和Metadata两种标签
             meta_cypher = """
-            MATCH (n:DataResource)-[:contain]->(m)
+            MATCH (n:DataResource)-[:INCLUDES]->(m)
             WHERE id(n) = $resource_id
             AND (m:DataMeta OR m:Metadata)
             RETURN m
@@ -567,7 +567,7 @@ def id_data_search_list(resource_id, page, page_size, en_name_filter=None,
             
             # 基本匹配语句 - 支持meta_data和Metadata标签
             match_clause = """
-            MATCH (n:DataResource)-[:contain]->(m)
+            MATCH (n:DataResource)-[:INCLUDES]->(m)
             WHERE id(n) = $resource_id
             AND (m:DataMeta OR m:Metadata)
             """
@@ -647,7 +647,7 @@ def resource_kinship_graph(resource_id, include_meta=True):
             
             # 是否包含元数据 - 支持meta_data和Metadata两种标签
             if include_meta:
-                cypher_parts.append("OPTIONAL MATCH (n)-[:contain]->(m) WHERE (m:DataMeta OR m:Metadata)")
+                cypher_parts.append("OPTIONAL MATCH (n)-[:INCLUDES]->(m) WHERE (m:DataMeta OR m:Metadata)")
                 
             cypher_parts.append("RETURN n, l, collect(m) as metadata")
             
@@ -696,10 +696,10 @@ def resource_kinship_graph(resource_id, include_meta=True):
                         
                         # 添加资源-元数据关系
                         relationships.append({
-                            "id": f"rel-{resource_node['id']}-contain-{meta_node['id']}",
+                            "id": f"rel-{resource_node['id']}-INCLUDES-{meta_node['id']}",
                             "source": resource_node["id"],
                             "target": meta_node["id"],
-                            "type": "contain"
+                            "type": "INCLUDES"
                         })
             
             logger.info(f"成功获取资源图谱,ID: {resource_id_int}, 节点数: {len(nodes)}")
@@ -1306,7 +1306,7 @@ def data_resource_edit(data):
             
             # 首先删除旧的元数据关系和清洗资源关系(无论parsed_data是否为空都要执行)
             delete_meta_cypher = """
-            MATCH (n:DataResource)-[r:contain]->()
+            MATCH (n:DataResource)-[r:INCLUDES]->()
             WHERE id(n) = $resource_id
             DELETE r
             """
@@ -1381,7 +1381,7 @@ def data_resource_edit(data):
                         create_meta_cypher = """
                         MATCH (n:DataResource), (m:DataMeta)
                         WHERE id(n) = $resource_id AND id(m) = $meta_id
-                        CREATE (n)-[r:contain]->(m)
+                        CREATE (n)-[r:INCLUDES]->(m)
                         RETURN r
                         """
                         session.run(create_meta_cypher, resource_id=int(resource_id), meta_id=int(meta_id))

+ 54 - 1
app/core/llm/llm_service.py

@@ -135,4 +135,57 @@ def llm_client(content):
                 return "translated_text"
             return content
         except:
-            return content 
+            return content
+
+def llm_sql(request_data):
+    """
+    调用Deepseek大模型生成SQL脚本
+    
+    Args:
+        request_data: 提交给LLM的提示语内容
+        
+    Returns:
+        str: Deepseek模型返回的SQL脚本内容
+    """
+    try:
+        # 使用配置文件中的参数连接Deepseek
+        client = OpenAI(
+            api_key=current_app.config.get('LLM_API_KEY'),
+            base_url=current_app.config.get('LLM_BASE_URL')
+        )
+        
+        model = current_app.config.get('LLM_MODEL_NAME')
+        
+        logger.info(f"开始调用Deepseek模型生成SQL脚本: model={model}")
+        logger.debug(f"输入提示语: {request_data}")
+        
+        # 调用Deepseek API生成SQL脚本
+        completion = client.chat.completions.create(
+            model=model,
+            messages=[
+                {
+                    "role": "system", 
+                    "content": "你是一名专业的数据库工程师,专门负责编写高质量的PostgreSQL SQL脚本。"
+                              "请严格按照用户提供的需求和表结构信息生成SQL脚本。"
+                              "确保生成的SQL语法正确、性能优化,并且能够直接执行。"
+                },
+                {
+                    "role": "user", 
+                    "content": request_data
+                }
+            ],
+            temperature=0.1,  # 使用较低的温度确保结果的一致性和准确性
+            max_tokens=4096,  # 为SQL脚本提供足够的token空间
+            top_p=0.9
+        )
+        
+        response_text = completion.choices[0].message.content.strip()
+        
+        logger.info(f"Deepseek模型成功返回SQL脚本,长度: {len(response_text)} 字符")
+        logger.debug(f"生成的SQL脚本: {response_text}")
+        
+        return response_text
+        
+    except Exception as e:
+        logger.error(f"Deepseek SQL生成调用失败: {str(e)}")
+        raise Exception(f"调用Deepseek模型生成SQL脚本失败: {str(e)}") 

+ 1 - 1
app/core/production_line/production_line.py

@@ -219,7 +219,7 @@ def get_resource_storage_info(resource_id):
                 
             # 查询元数据节点
             metadata_query = """
-            MATCH (n:DataResource)-[:contain]->(m:DataMeta)
+            MATCH (n:DataResource)-[:INCLUDES]->(m:DataMeta)
             WHERE id(n) = $resource_id
             RETURN m.name as name, m.en_name as en_name, m.data_type as data_type
             """