app: description: 上传提炼知识点 icon: 🤖 icon_background: '#E4FBCC' mode: workflow name: 恩喜-01-知识点分析-考陪练 use_icon_as_answer_icon: false dependencies: - current_identifier: null type: marketplace value: marketplace_plugin_unique_identifier: langgenius/openrouter:0.0.22@99ef4cf4e08292c28806abaf24f295ed66e04e4b9e74385b487fd0767c7f56df version: null kind: app version: 0.5.0 workflow: conversation_variables: [] environment_variables: [] features: file_upload: allowed_file_extensions: - .JPG - .JPEG - .PNG - .GIF - .WEBP - .SVG allowed_file_types: - image allowed_file_upload_methods: - local_file - remote_url enabled: false fileUploadConfig: audio_file_size_limit: 50 batch_count_limit: 5 file_size_limit: 15 image_file_batch_limit: 10 image_file_size_limit: 10 single_chunk_attachment_limit: 10 video_file_size_limit: 100 workflow_file_upload_limit: 10 image: enabled: false number_limits: 3 transfer_methods: - local_file - remote_url number_limits: 3 opening_statement: '' retriever_resource: enabled: true sensitive_word_avoidance: enabled: false speech_to_text: enabled: false suggested_questions: [] suggested_questions_after_answer: enabled: false text_to_speech: enabled: false language: '' voice: '' graph: edges: - data: isInIteration: false isInLoop: false sourceType: document-extractor targetType: llm id: 1757513748987-source-1757513757216-target selected: false source: '1757513748987' sourceHandle: source target: '1757513757216' targetHandle: target type: custom zIndex: 0 - data: isInIteration: false isInLoop: false sourceType: llm targetType: code id: 1757513757216-source-1757516212204-target selected: false source: '1757513757216' sourceHandle: source target: '1757516212204' targetHandle: target type: custom zIndex: 0 - data: isInIteration: false isInLoop: false sourceType: llm targetType: end id: 1757513757216-fail-branch-1757572091560-target selected: false source: '1757513757216' sourceHandle: fail-branch target: '1757572091560' targetHandle: target type: custom zIndex: 0 - data: isInIteration: false isInLoop: false sourceType: code targetType: end id: 1757516212204-fail-branch-1757576655478-target selected: false source: '1757516212204' sourceHandle: fail-branch target: '1757576655478' targetHandle: target type: custom zIndex: 0 - data: isInIteration: false isInLoop: false sourceType: code targetType: iteration id: 1757516212204-source-1757687332404-target selected: false source: '1757516212204' sourceHandle: source target: '1757687332404' targetHandle: target type: custom zIndex: 0 - data: isInLoop: false sourceType: iteration targetType: end id: 1757687332404-source-1757522230050-target selected: false source: '1757687332404' sourceHandle: source target: '1757522230050' targetHandle: target type: custom zIndex: 0 - data: isInIteration: true isInLoop: false iteration_id: '1757687332404' sourceType: iteration-start targetType: code id: 1757687332404start-source-1758575376121-target selected: false source: 1757687332404start sourceHandle: source target: '1758575376121' targetHandle: target type: custom zIndex: 1002 - data: isInIteration: false isInLoop: false sourceType: start targetType: tool id: 1757513649648-source-1766636080995-target source: '1757513649648' sourceHandle: source target: '1766636080995' targetHandle: target type: custom zIndex: 0 - data: isInLoop: false sourceType: tool targetType: document-extractor id: 1766636080995-source-1757513748987-target source: '1766636080995' sourceHandle: source target: '1757513748987' targetHandle: target type: custom zIndex: 0 - data: isInLoop: false sourceType: tool targetType: end id: 1766636080995-fail-branch-1764240729694-target source: '1766636080995' sourceHandle: fail-branch target: '1764240729694' targetHandle: target type: custom zIndex: 0 - data: isInIteration: true isInLoop: false iteration_id: '1757687332404' sourceType: code targetType: tool id: 1758575376121-source-1766636254081-target source: '1758575376121' sourceHandle: source target: '1766636254081' targetHandle: target type: custom zIndex: 1002 nodes: - data: desc: '' selected: false title: 开始 type: start variables: - allowed_file_extensions: [] allowed_file_types: - document - audio - video - image allowed_file_upload_methods: - local_file - remote_url label: file max_length: 1 options: [] required: true type: file variable: file - label: course_name max_length: 255 options: [] required: true type: text-input variable: course_name - default: '1' label: course_id max_length: 48 options: [] required: true type: number variable: course_id - default: '16' label: material_id max_length: 48 options: [] required: true type: number variable: material_id height: 187 id: '1757513649648' position: x: 30 y: 283 positionAbsolute: x: 30 y: 283 selected: false sourcePosition: right targetPosition: left type: custom width: 242 - data: desc: '' is_array_file: true selected: false title: 文档提取器 type: document-extractor variable_selector: - '1757513649648' - file height: 104 id: '1757513748987' position: x: 934 y: 281 positionAbsolute: x: 934 y: 281 selected: false sourcePosition: right targetPosition: left type: custom width: 242 - data: context: enabled: false variable_selector: [] desc: '' error_strategy: fail-branch model: completion_params: temperature: 0.1 mode: chat name: google/gemini-3-pro-preview provider: langgenius/openrouter/openrouter prompt_template: - id: f0a75809-0e24-491f-bd19-964d8b2eae4c role: system text: "# 角色\n你是一个文件拆解高手,擅长将用户提交的内容进行精准拆分,拆分后的内容做个简单的优化处理使其更具可读性,但要尽量使用原文的原词原句。\n\ \n## 技能\n### 技能 1: 内容拆分\n1. 当用户提交内容后,拆分为多段。\n2. 对拆分后的内容做简单优化,使其更具可读性,比如去掉奇怪符号(如换行符、乱码),若语句不通顺,或格式原因导致错位,则重新表达。用户可能会提交录音转文字的内容,因此可能是有错字的,注意修复这些小瑕疵。\n\ 3. 优化过程中,尽量使用原文的原词原句,特别是话术类,必须保持原有的句式、保持原词原句,而不是重构。\n4. 注意是拆分而不是重写,不需要润色,尽量不做任何处理。\n\ 5. 输出到 content。\n\n### 技能 2: 为每一个选段概括一个标题\n1. 为每个拆分出来的选段概括一个标题,并输出到 title。\n\ \n### 技能 3: 为每一个选段说明与主题的关联\n1. 详细说明这一段与全文核心主题的关联,并输出到 topic_relation。\n\ \n### 技能 4: 为每一个选段打上一个类型标签\n1. 用户提交的内容很有可能是一个课程、一篇讲义、一个产品的说明书,通常是用户希望他公司的员工或高管学习的知识。\n\ 2. 用户通常是医疗美容机构或轻医美、生活美容连锁品牌。\n3. 你要为每个选段打上一个知识类型的标签,最好是这几个类型中的一个:\"理论知识\"\ , \"诊断设计\", \"操作步骤\", \"沟通话术\", \"案例分析\", \"注意事项\", \"技巧方法\", \"客诉处理\"\ 。当然你也可以为这个选段匹配一个更适合的。\n\n## 输出要求(严格按要求输出)\n请直接输出一个纯净的 JSON 数组(Array),不要包含\ \ Markdown 标记(如 ```json),也不要包含任何解释性文字。格式如下:\n\n[\n {\n \"title\":\ \ \"知识点标题\",\n \"content\": \"知识点内容\",\n \"topic_relation\": \"\ 知识点与主题的关系\",\n \"type\": \"知识点类型\"\n },\n {\n \"title\": \"第二个知识点标题\"\ ,\n \"content\": \"第二个知识点内容...\",\n \"topic_relation\": \"...\"\ ,\n \"type\": \"...\"\n }\n]\n\n## 限制\n- 仅围绕用户提交的内容进行拆分和关联标注,不涉及其他无关内容。\n\ - 拆分后的内容必须最大程度保持与原文一致。\n- 关联说明需清晰合理。\n- 不论如何,不要拆分超过 20 段!" - id: bc1168ad-45de-475e-9365-8791306c8bb3 role: user text: '课程主题:{{#1757513649648.course_name#}} ## 用户提交的内容: {{#1757513748987.text#}} ## 注意 - 以json的格式输出 - 不论如何,不要拆分超过20 段!' selected: false structured_output: schema: additionalProperties: false properties: content: description: 知识点内容 type: string title: description: 知识点标题 type: string required: - title - content type: object structured_output_enabled: false title: 知识点提取 type: llm variables: [] vision: enabled: false height: 124 id: '1757513757216' position: x: 1236 y: 283 positionAbsolute: x: 1236 y: 283 selected: false sourcePosition: right targetPosition: left type: custom width: 242 - data: code: "import json\nimport re\ndef main(arg1: str) -> dict:\n # --- 内部辅助函数:清洗文本以适配\ \ SQL ---\n def clean_text_for_sql(text):\n if not isinstance(text,\ \ str):\n return text\n \n # 1. 【关键修改】将物理换行符替换为\ \ SQL 转义换行符 (\\\\n)\n # 这样 SQL 语句本身是一行,但数据库会将其解释为换行\n text\ \ = text.replace('\\n', '\\\\n').replace('\\r', '')\n \n #\ \ 2. 将单引号替换为两个单引号(SQL 标准转义),防止截断\n text = text.replace(\"'\", \"\ ''\")\n \n return text\n try:\n if not arg1:\n \ \ return {\"data\": []}\n \n # --- 1. 提取 JSON 字符串\ \ (保持不变) ---\n json_str = arg1\n match = re.search(r'```json\\\ s*(.*?)\\s*```', arg1, re.DOTALL)\n if match:\n json_str\ \ = match.group(1)\n else:\n start = arg1.find('[')\n\ \ end = arg1.rfind(']')\n if start != -1 and end !=\ \ -1:\n json_str = arg1[start:end+1]\n # --- 2. 解析\ \ JSON ---\n data_list = json.loads(json_str)\n \n \ \ # --- 3. 校验与清洗数据 ---\n if not isinstance(data_list, list):\n \ \ if isinstance(data_list, dict) and \"items\" in data_list:\n\ \ data_list = data_list[\"items\"]\n else:\n \ \ return {\"data\": []}\n if len(data_list) >= 30:\n\ \ data_list = data_list[:29]\n \n # 遍历列表进行清洗\n\ \ cleaned_list = []\n for item in data_list:\n \ \ if isinstance(item, dict):\n cleaned_item = {\n \ \ \"title\": clean_text_for_sql(item.get(\"title\", \"\")),\n\ \ \"content\": clean_text_for_sql(item.get(\"content\"\ , \"\")),\n \"topic_relation\": clean_text_for_sql(item.get(\"\ topic_relation\", \"\")),\n \"type\": clean_text_for_sql(item.get(\"\ type\", \"\"))\n }\n cleaned_list.append(cleaned_item)\n\ \ \n return {\"data\": cleaned_list}\n \n except json.JSONDecodeError\ \ as e:\n print(f\"JSON解析错误: {str(e)}\")\n return {\"data\"\ : []}\n except Exception as e:\n print(f\"处理过程中发生错误: {str(e)}\"\ )\n return {\"data\": []}" code_language: python3 desc: '' error_strategy: fail-branch outputs: data: children: null type: array[object] retry_config: max_retries: 3 retry_enabled: true retry_interval: 1000 selected: false title: 转换格式 type: code variables: - value_selector: - '1757513757216' - text value_type: string variable: arg1 height: 117 id: '1757516212204' position: x: 1538 y: 283 positionAbsolute: x: 1538 y: 283 selected: false sourcePosition: right targetPosition: left type: custom width: 242 - data: desc: '' outputs: - value_selector: - '1757687332404' - output value_type: array[string] variable: output selected: false title: 结束 type: end height: 88 id: '1757522230050' position: x: 2708 y: 572 positionAbsolute: x: 2708 y: 572 selected: false sourcePosition: right targetPosition: left type: custom width: 242 - data: desc: '' outputs: - value_selector: - '1757513757216' - error_message value_type: string variable: reasoning_content selected: false title: 结束 2 type: end height: 88 id: '1757572091560' position: x: 1361.0212171476019 y: 472.6567992168116 positionAbsolute: x: 1361.0212171476019 y: 472.6567992168116 selected: false sourcePosition: right targetPosition: left type: custom width: 242 - data: desc: '' outputs: - value_selector: - '1757516212204' - error_message value_type: string variable: result selected: false title: 结束 3 type: end height: 88 id: '1757576655478' position: x: 2123 y: 283 positionAbsolute: x: 2123 y: 283 selected: false sourcePosition: right targetPosition: left type: custom width: 242 - data: desc: '' error_handle_mode: continue-on-error height: 410 is_parallel: true iterator_input_type: array[object] iterator_selector: - '1757516212204' - data output_selector: - '1758575376121' - title output_type: array[string] parallel_nums: 10 selected: false start_node_id: 1757687332404start title: 迭代 type: iteration width: 1310.983478660764 height: 410 id: '1757687332404' position: x: 1939.6507421681436 y: 396.2369270862009 positionAbsolute: x: 1939.6507421681436 y: 396.2369270862009 selected: false sourcePosition: right targetPosition: left type: custom width: 1311 zIndex: 1 - data: desc: '' isInIteration: true selected: false title: '' type: iteration-start draggable: false height: 48 id: 1757687332404start parentId: '1757687332404' position: x: 60 y: 62 positionAbsolute: x: 1999.6507421681436 y: 458.2369270862009 selectable: false selected: false sourcePosition: right targetPosition: left type: custom-iteration-start width: 44 zIndex: 1002 - data: code: "def main(arg1: dict) -> dict:\n # 上一个节点已经完成了所有清洗工作(包括换行符转义 \\n 和单引号转义\ \ '')\n # 这里只需要直接透传数据即可,不要再做任何处理\n return {\n \"title\": arg1.get(\"\ title\"),\n \"content\": arg1.get(\"content\"),\n \"topic_relation\"\ : arg1.get(\"topic_relation\"),\n \"type\": arg1.get(\"type\")\n\ \ }" code_language: python3 desc: '' isInIteration: true isInLoop: false iteration_id: '1757687332404' outputs: content: children: null type: string title: children: null type: string topic_relation: children: null type: string type: children: null type: string selected: false title: 内容提取 type: code variables: - value_selector: - '1757687332404' - item value_type: object variable: arg1 height: 52 id: '1758575376121' parentId: '1757687332404' position: x: 204 y: 60 positionAbsolute: x: 2143.6507421681436 y: 456.2369270862009 selected: false sourcePosition: right targetPosition: left type: custom width: 242 zIndex: 1002 - data: outputs: - value_selector: - '1766636080995' - text value_type: string variable: error_message selected: true title: 结束 5 type: end height: 88 id: '1764240729694' position: x: 934 y: 411 positionAbsolute: x: 934 y: 411 selected: true sourcePosition: right targetPosition: left type: custom width: 242 - data: error_strategy: fail-branch is_team_authorization: true paramSchemas: - auto_generate: null default: null form: llm human_description: en_US: '' ja_JP: '' pt_BR: '' zh_Hans: '' label: en_US: SQL 语句 ja_JP: SQL 语句 pt_BR: SQL 语句 zh_Hans: SQL 语句 llm_description: '' max: null min: null name: sql options: [] placeholder: en_US: '' ja_JP: '' pt_BR: '' zh_Hans: '' precision: null required: true scope: null template: null type: string params: sql: '' plugin_id: null plugin_unique_identifier: null provider_icon: background: '#FFEAD5' content: 🤖 provider_id: 2e7e915c-606c-4230-b4bd-ff95efb72f39 provider_name: 恩喜-00-SQL 执行器-考陪练专用 provider_type: workflow retry_config: max_retries: 3 retry_enabled: true retry_interval: 1000 selected: false title: 恩喜-00-SQL 执行器-考陪练专用 tool_configurations: {} tool_description: 考陪练系统专用的 sql 执行器 tool_label: 恩喜-00-SQL 执行器-考陪练专用 tool_name: SQL_executor_enxi tool_node_version: '2' tool_parameters: sql: type: mixed value: DELETE FROM knowledge_points WHERE material_id = {{#1757513649648.material_id#}}; type: tool height: 117 id: '1766636080995' position: x: 369.1162304946969 y: 472.6567992168116 positionAbsolute: x: 369.1162304946969 y: 472.6567992168116 selected: false sourcePosition: right targetPosition: left type: custom width: 242 - data: isInIteration: true isInLoop: false is_team_authorization: true iteration_id: '1757687332404' paramSchemas: - auto_generate: null default: null form: llm human_description: en_US: '' ja_JP: '' pt_BR: '' zh_Hans: '' label: en_US: SQL 语句 ja_JP: SQL 语句 pt_BR: SQL 语句 zh_Hans: SQL 语句 llm_description: '' max: null min: null name: sql options: [] placeholder: en_US: '' ja_JP: '' pt_BR: '' zh_Hans: '' precision: null required: true scope: null template: null type: string params: sql: '' plugin_id: null plugin_unique_identifier: null provider_icon: background: '#FFEAD5' content: 🤖 provider_id: 2e7e915c-606c-4230-b4bd-ff95efb72f39 provider_name: 恩喜-00-SQL 执行器-考陪练专用 provider_type: workflow selected: false title: 恩喜-00-SQL 执行器-考陪练专用 tool_configurations: {} tool_description: 考陪练系统专用的 sql 执行器 tool_label: 恩喜-00-SQL 执行器-考陪练专用 tool_name: SQL_executor_enxi tool_node_version: '2' tool_parameters: sql: type: mixed value: INSERT INTO knowledge_points (course_id, material_id, name, description, type, source, topic_relation) VALUES ({{#1757513649648.course_id#}}, {{#1757513649648.material_id#}}, '{{#1758575376121.title#}}', '{{#1758575376121.content#}}', '{{#1758575376121.type#}}', 1, '{{#1758575376121.topic_relation#}}'); type: tool height: 52 id: '1766636254081' parentId: '1757687332404' position: x: 552.0682037973988 y: 83.70934394330777 positionAbsolute: x: 2491.7189459655424 y: 479.9462710295087 selected: false sourcePosition: right targetPosition: left type: custom width: 242 zIndex: 1002 viewport: x: -154.69868384174993 y: 184.48211749520988 zoom: 0.5480921885368025 rag_pipeline_variables: []