自动同步: 2026-03-24 02:10

This commit is contained in:
2026-03-24 02:10:04 +08:00
parent c5da76cd04
commit 01885232c3
70 changed files with 2348 additions and 263 deletions
+119 -126
View File
@@ -51,12 +51,12 @@
"abortedLastRun": false,
"chatType": "direct",
"origin": {
"label": "feishu:oc_0",
"label": "feishu:ou_73cc4f75e3c953d7bf11f34f8c8c7618",
"provider": "feishu",
"surface": "feishu",
"chatType": "direct",
"from": "feishu:oc_0",
"to": "oc_0",
"from": "feishu:ou_73cc4f75e3c953d7bf11f34f8c8c7618",
"to": "ou_73cc4f75e3c953d7bf11f34f8c8c7618",
"accountId": "feishu-pm"
},
"sessionFile": "/home/starmen1265/.openclaw/agents/haonan/sessions/e4845dbe-7d4d-41b6-adb5-b8a739e6520d.jsonl",
@@ -715,8 +715,8 @@
"memoryFlushCompactionCount": 0
},
"agent:haonan:cron:41396aeb-6e3a-47b2-9bd3-9156a348c1dc": {
"sessionId": "ee02d903-76a0-4bfc-b79c-3485bfbd6b93",
"updatedAt": 1774202400005,
"sessionId": "8dafc963-2f86-4e58-865c-9775a4461dae",
"updatedAt": 1774288800004,
"systemSent": true,
"model": "glm-5",
"contextTokens": 200000,
@@ -757,11 +757,11 @@
"version": 0
},
"modelProvider": "zhipu",
"inputTokens": 10864,
"outputTokens": 433,
"totalTokens": 16922,
"inputTokens": 14609,
"outputTokens": 517,
"totalTokens": 17201,
"totalTokensFresh": true,
"cacheRead": 39360,
"cacheRead": 52864,
"cacheWrite": 0
},
"agent:haonan:cron:f03b184f-5f1d-4093-ae1b-fc9fe0b59eef": {
@@ -807,9 +807,9 @@
"version": 0
},
"modelProvider": "zhipu",
"inputTokens": 93543,
"outputTokens": 12015,
"totalTokens": 39048,
"inputTokens": 89834,
"outputTokens": 4112,
"totalTokens": 30249,
"deliveryContext": {
"channel": "webchat"
},
@@ -818,7 +818,7 @@
"sessionFile": "/home/starmen1265/.openclaw/agents/haonan/sessions/ccc40ca7-7876-4d82-ab84-7b790feddc19.jsonl",
"abortedLastRun": false,
"totalTokensFresh": true,
"cacheRead": 727060,
"cacheRead": 295587,
"cacheWrite": 0
},
"agent:haonan:cron:3245fca7-045b-4977-8fab-020f6df2e453": {
@@ -861,8 +861,8 @@
"cacheWrite": 0
},
"agent:haonan:cron:aa4d2de9-79be-4262-83ee-af8824793bfc": {
"sessionId": "c36026c9-d70c-48f5-8e92-c45bff98a7f4",
"updatedAt": 1774203000004,
"sessionId": "f28e191e-4a3e-42a3-a584-9b97234c8c6f",
"updatedAt": 1774289400006,
"systemSent": true,
"label": "Cron: openclaw-git-sync",
"skillsSnapshot": {
@@ -910,113 +910,6 @@
"cacheRead": 32768,
"cacheWrite": 0
},
"agent:haonan:cron:f03b184f-5f1d-4093-ae1b-fc9fe0b59eef:run:c36ad784-619d-457f-9e7f-3bac4119e782": {
"sessionId": "c36ad784-619d-457f-9e7f-3bac4119e782",
"updatedAt": 1774117200006,
"systemSent": true,
"model": "glm-4.7-FlashX",
"contextTokens": 200000,
"label": "Cron: capability-evolver-daily",
"skillsSnapshot": {
"prompt": "\n\nThe following skills provide specialized instructions for specific tasks.\nUse the read tool to load a skill's file when the task matches its description.\nWhen a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\n\n<available_skills>\n <skill>\n <name>capability-evolver</name>\n <description>A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.</description>\n <location>~/.openclaw/skills/capability-evolver/SKILL.md</location>\n </skill>\n <skill>\n <name>clawlist</name>\n <description>MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.</description>\n <location>~/.openclaw/skills/clawlist/SKILL.md</location>\n </skill>\n</available_skills>",
"skills": [
{
"name": "capability-evolver"
},
{
"name": "clawlist"
}
],
"skillFilter": [
"clawlist",
"capability-evolver",
"self-improving-agent"
],
"resolvedSkills": [
{
"name": "capability-evolver",
"description": "A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.",
"filePath": "/home/starmen1265/.openclaw/skills/capability-evolver/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/capability-evolver",
"source": "openclaw-managed",
"disableModelInvocation": false
},
{
"name": "clawlist",
"description": "MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.",
"filePath": "/home/starmen1265/.openclaw/skills/clawlist/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/clawlist",
"source": "openclaw-managed",
"disableModelInvocation": false
}
],
"version": 0
},
"modelProvider": "zhipu",
"inputTokens": 93543,
"outputTokens": 12015,
"totalTokens": 39048,
"deliveryContext": {
"channel": "webchat"
},
"lastChannel": "webchat",
"channel": "webchat",
"sessionFile": "/home/starmen1265/.openclaw/agents/haonan/sessions/ccc40ca7-7876-4d82-ab84-7b790feddc19.jsonl",
"abortedLastRun": false,
"totalTokensFresh": true,
"cacheRead": 727060,
"cacheWrite": 0
},
"agent:haonan:cron:41396aeb-6e3a-47b2-9bd3-9156a348c1dc:run:ee02d903-76a0-4bfc-b79c-3485bfbd6b93": {
"sessionId": "ee02d903-76a0-4bfc-b79c-3485bfbd6b93",
"updatedAt": 1774202400005,
"systemSent": true,
"model": "glm-5",
"contextTokens": 200000,
"label": "Cron: backup-openclaw-json",
"skillsSnapshot": {
"prompt": "\n\nThe following skills provide specialized instructions for specific tasks.\nUse the read tool to load a skill's file when the task matches its description.\nWhen a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\n\n<available_skills>\n <skill>\n <name>capability-evolver</name>\n <description>A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.</description>\n <location>~/.openclaw/skills/capability-evolver/SKILL.md</location>\n </skill>\n <skill>\n <name>clawlist</name>\n <description>MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.</description>\n <location>~/.openclaw/skills/clawlist/SKILL.md</location>\n </skill>\n</available_skills>",
"skills": [
{
"name": "capability-evolver"
},
{
"name": "clawlist"
}
],
"skillFilter": [
"clawlist",
"capability-evolver",
"self-improving-agent"
],
"resolvedSkills": [
{
"name": "capability-evolver",
"description": "A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.",
"filePath": "/home/starmen1265/.openclaw/skills/capability-evolver/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/capability-evolver",
"source": "openclaw-managed",
"disableModelInvocation": false
},
{
"name": "clawlist",
"description": "MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.",
"filePath": "/home/starmen1265/.openclaw/skills/clawlist/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/clawlist",
"source": "openclaw-managed",
"disableModelInvocation": false
}
],
"version": 0
},
"modelProvider": "zhipu",
"inputTokens": 10864,
"outputTokens": 433,
"totalTokens": 16922,
"totalTokensFresh": true,
"cacheRead": 39360,
"cacheWrite": 0
},
"agent:haonan:cron:aa4d2de9-79be-4262-83ee-af8824793bfc:run:c36026c9-d70c-48f5-8e92-c45bff98a7f4": {
"sessionId": "c36026c9-d70c-48f5-8e92-c45bff98a7f4",
"updatedAt": 1774203000004,
@@ -1110,9 +1003,9 @@
"version": 0
},
"modelProvider": "zhipu",
"inputTokens": 93543,
"outputTokens": 12015,
"totalTokens": 39048,
"inputTokens": 89834,
"outputTokens": 4112,
"totalTokens": 30249,
"deliveryContext": {
"channel": "webchat"
},
@@ -1121,7 +1014,107 @@
"sessionFile": "/home/starmen1265/.openclaw/agents/haonan/sessions/ccc40ca7-7876-4d82-ab84-7b790feddc19.jsonl",
"abortedLastRun": false,
"totalTokensFresh": true,
"cacheRead": 727060,
"cacheRead": 295587,
"cacheWrite": 0
},
"agent:haonan:cron:41396aeb-6e3a-47b2-9bd3-9156a348c1dc:run:8dafc963-2f86-4e58-865c-9775a4461dae": {
"sessionId": "8dafc963-2f86-4e58-865c-9775a4461dae",
"updatedAt": 1774288800004,
"systemSent": true,
"model": "glm-5",
"contextTokens": 200000,
"label": "Cron: backup-openclaw-json",
"skillsSnapshot": {
"prompt": "\n\nThe following skills provide specialized instructions for specific tasks.\nUse the read tool to load a skill's file when the task matches its description.\nWhen a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\n\n<available_skills>\n <skill>\n <name>capability-evolver</name>\n <description>A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.</description>\n <location>~/.openclaw/skills/capability-evolver/SKILL.md</location>\n </skill>\n <skill>\n <name>clawlist</name>\n <description>MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.</description>\n <location>~/.openclaw/skills/clawlist/SKILL.md</location>\n </skill>\n</available_skills>",
"skills": [
{
"name": "capability-evolver"
},
{
"name": "clawlist"
}
],
"skillFilter": [
"clawlist",
"capability-evolver",
"self-improving-agent"
],
"resolvedSkills": [
{
"name": "capability-evolver",
"description": "A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.",
"filePath": "/home/starmen1265/.openclaw/skills/capability-evolver/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/capability-evolver",
"source": "openclaw-managed",
"disableModelInvocation": false
},
{
"name": "clawlist",
"description": "MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.",
"filePath": "/home/starmen1265/.openclaw/skills/clawlist/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/clawlist",
"source": "openclaw-managed",
"disableModelInvocation": false
}
],
"version": 0
},
"modelProvider": "zhipu",
"inputTokens": 14609,
"outputTokens": 517,
"totalTokens": 17201,
"totalTokensFresh": true,
"cacheRead": 52864,
"cacheWrite": 0
},
"agent:haonan:cron:aa4d2de9-79be-4262-83ee-af8824793bfc:run:f28e191e-4a3e-42a3-a584-9b97234c8c6f": {
"sessionId": "f28e191e-4a3e-42a3-a584-9b97234c8c6f",
"updatedAt": 1774289400006,
"systemSent": true,
"label": "Cron: openclaw-git-sync",
"skillsSnapshot": {
"prompt": "\n\nThe following skills provide specialized instructions for specific tasks.\nUse the read tool to load a skill's file when the task matches its description.\nWhen a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\n\n<available_skills>\n <skill>\n <name>capability-evolver</name>\n <description>A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.</description>\n <location>~/.openclaw/skills/capability-evolver/SKILL.md</location>\n </skill>\n <skill>\n <name>clawlist</name>\n <description>MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.</description>\n <location>~/.openclaw/skills/clawlist/SKILL.md</location>\n </skill>\n</available_skills>",
"skills": [
{
"name": "capability-evolver"
},
{
"name": "clawlist"
}
],
"skillFilter": [
"clawlist",
"capability-evolver",
"self-improving-agent"
],
"resolvedSkills": [
{
"name": "capability-evolver",
"description": "A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.",
"filePath": "/home/starmen1265/.openclaw/skills/capability-evolver/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/capability-evolver",
"source": "openclaw-managed",
"disableModelInvocation": false
},
{
"name": "clawlist",
"description": "MUST use for any multi-step project, long-running task, or infinite monitoring workflow. Plan, execute, track, and verify tasks with checkpoint validation. For projects, automation, and ongoing operations.",
"filePath": "/home/starmen1265/.openclaw/skills/clawlist/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/clawlist",
"source": "openclaw-managed",
"disableModelInvocation": false
}
],
"version": 0
},
"modelProvider": "zhipu",
"model": "glm-5",
"contextTokens": 200000,
"inputTokens": 966,
"outputTokens": 295,
"totalTokens": 17235,
"totalTokensFresh": true,
"cacheRead": 32768,
"cacheWrite": 0
}
}
@@ -0,0 +1,107 @@
# Session: 2026-03-23 16:21:53 UTC
- **Session Key**: agent:knowledge-base:main
- **Session ID**: c6f06c72-ea29-4d72-8ba5-4830ca604107
- **Source**: feishu
## Conversation Summary
user: Conversation info (untrusted metadata):
```json
{
"message_id": "om_x100b53219b1e80f4c3403ec55bc0e66",
"sender_id": "ou_9351c287f42069fa30366ac641d24df7",
"sender": "张青",
"timestamp": "Mon 2026-03-23 23:33 GMT+8"
}
```
Sender (untrusted metadata):
```json
{
"label": "张青 (ou_9351c287f42069fa30366ac641d24df7)",
"id": "ou_9351c287f42069fa30366ac641d24df7",
"name": "张青"
}
```
[message_id: om_x100b53219b1e80f4c3403ec55bc0e66]
张青: https://www.bilibili.com/video/BV1irAGz9EgZ/?t=10&spm_id_from=333.1007.tianma.2-3-6.click&vd_source=1deaab00c5de8885422a7a7690170eba 添加知识库
assistant: 我来帮您处理这个B站视频的知识库添加任务。
首先让我获取视频信息并了解知识库的结构:
assistant: 蒋先生,我看到这是一个关于中东冲突(以色列-伊朗战争)的战况汇总视频,属于时事追踪类内容。
我建议在知识库中这样组织:
- **位置**:`20.领域/25-时事关注/中东冲突2026/`
- **理由**:这是正在发生的重大事件,适合作为持续关注的领域而非单纯的资源
现在为您创建知识库条目:
assistant: ✅ 已完成知识库添加
**创建内容**:
- **位置**:`20.领域/25-时事关注/中东冲突2026/战况汇总.md`
- **内容结构**:
- 完整时间线(3月1日-22日)
- 主要参与方梳理
- 武器装备清单
- 战略要地标注
- 经济影响分析
这个系列视频适合作为持续追踪的时事领域,后续如有新的战况更新可以继续添加到这个文档中。
user: Conversation info (untrusted metadata):
```json
{
"message_id": "om_x100b532193c3c8a0c2c4ae55e5aa0d1",
"sender_id": "ou_9351c287f42069fa30366ac641d24df7",
"sender": "张青",
"timestamp": "Mon 2026-03-23 23:35 GMT+8"
}
```
Sender (untrusted metadata):
```json
{
"label": "张青 (ou_9351c287f42069fa30366ac641d24df7)",
"id": "ou_9351c287f42069fa30366ac641d24df7",
"name": "张青"
}
```
[message_id: om_x100b532193c3c8a0c2c4ae55e5aa0d1]
张青: 怎么不用技能?
assistant: 您说得对!我应该使用 kb-系列技能来管理知识库。让我查看可用的技能:
assistant: 明白了!我应该使用 `kb_workflow` 技能来处理。让我先检查环境变量,然后用正确的方式处理:
assistant: ✅ **已使用 `kb_workflow` 技能完成知识库添加**
### 处理流程
1. **URL解析** → B站视频 BV1irAGz9EgZ
2. **内容下载** → 音频文件 (10:35) + 元数据
3. **ASR识别** → Whisper 转录文本
4. **智能分段** → 8个主题段落
5. **深度分析** → AI 生成结构化内容
6. **自动归档** → 知识库存储
### 生成文件
- **归档位置**:
```
~/work/zq/30.资源/AI分析/bilibili/
20260323_BV1irAGz9EgZ_【3月22日晚上_战况汇总】...analysis.md
```
- **中间文件**:
```
~/work/intermediate/analysis/bilibili_BV1irAGz9EgZ/
├── bilibili_BV1irAGz9EgZ_metadata.json
├── bilibili_BV1irAGz9EgZ.m4a
├── bilibili_BV1irAGz9EgZ_whisper.txt
├── bilibili_BV1irAGz9EgZ_whisper.srt
└── analysis.md
```
### 内容亮点
- 完整转录了10分35秒的视频内容
- 智能分段为8个主题段落
- 包含战况、武器装备、战略分析等关键信息
- 已自动归档到知识库系统
下次添加知识库内容时,我会直接使用 `kb_workflow` 技能!📚
@@ -0,0 +1,20 @@
# 2026-03-23 记忆
## 知识库管理
### 添加中东冲突追踪(使用kb_workflow技能)
- **时间**:23:35
- **用户**:张青
- **内容**:用户要求添加B站视频到知识库
- **视频**:【3月22日晚上 战况汇总】以色列核城市遭伊朗导弹打击
- **技能**:使用 `kb_workflow` 技能进行完整处理
- **处理流程**:
1. ✅ URL解析(B站视频 BV1irAGz9EgZ)
2. ✅ 内容下载(音频文件 m4a + 元数据)
3. ✅ ASR语音识别(Whisper转录)
4. ✅ SRT处理(分段和修正)
5. ✅ 深度分析(AI分析生成结构化内容)
6. ✅ 归档(保存到知识库)
- **归档位置**:`~/work/zq/30.资源/AI分析/bilibili/20260323_BV1irAGz9EgZ_【3月22日晚上_战况汇总】...analysis.md`
- **中间文件**:`~/work/intermediate/analysis/bilibili_BV1irAGz9EgZ/`
- **教训**:应该优先使用技能而非手动创建文件
+241 -11
View File
@@ -1,7 +1,7 @@
{
"agent:ui-designer:main": {
"sessionId": "60827bbf-d985-4a29-bd62-1783159bb38e",
"updatedAt": 1773937164358,
"sessionId": "e72c0831-24b6-41e1-ba9f-dbf74b3bdba4",
"updatedAt": 1774279437070,
"systemSent": true,
"abortedLastRun": false,
"chatType": "direct",
@@ -22,7 +22,7 @@
"to": "user:ou_9847ce84b960736c14554730b41e4957",
"accountId": "feishu-art"
},
"sessionFile": "/home/starmen1265/.openclaw/agents/ui-designer/sessions/60827bbf-d985-4a29-bd62-1783159bb38e.jsonl",
"sessionFile": "/home/starmen1265/.openclaw/agents/ui-designer/sessions/e72c0831-24b6-41e1-ba9f-dbf74b3bdba4.jsonl",
"compactionCount": 0,
"skillsSnapshot": {
"prompt": "\n\nThe following skills provide specialized instructions for specific tasks.\nUse the read tool to load a skill's file when the task matches its description.\nWhen a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\n\n<available_skills>\n <skill>\n <name>capability-evolver</name>\n <description>A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.</description>\n <location>~/.openclaw/skills/capability-evolver/SKILL.md</location>\n </skill>\n</available_skills>",
@@ -51,8 +51,8 @@
"model": "glm-5",
"systemPromptReport": {
"source": "run",
"generatedAt": 1773937122951,
"sessionId": "60827bbf-d985-4a29-bd62-1783159bb38e",
"generatedAt": 1774279351890,
"sessionId": "e72c0831-24b6-41e1-ba9f-dbf74b3bdba4",
"sessionKey": "agent:ui-designer:main",
"provider": "zhipu",
"model": "glm-5",
@@ -64,8 +64,8 @@
"sandboxed": false
},
"systemPrompt": {
"chars": 36876,
"projectContextChars": 24391,
"chars": 45313,
"projectContextChars": 32828,
"nonProjectContextChars": 12485
},
"injectedWorkspaceFiles": [
@@ -301,6 +301,84 @@
"injectedChars": 616,
"truncated": false
},
{
"path": "SELF_IMPROVEMENT_REMINDER.md",
"rawChars": 616,
"injectedChars": 616,
"truncated": false
},
{
"path": "SELF_IMPROVEMENT_REMINDER.md",
"rawChars": 616,
"injectedChars": 616,
"truncated": false
},
{
"path": "SELF_IMPROVEMENT_REMINDER.md",
"rawChars": 616,
"injectedChars": 616,
"truncated": false
},
{
"path": "SELF_IMPROVEMENT_REMINDER.md",
"rawChars": 616,
"injectedChars": 616,
"truncated": false
},
{
"path": "SELF_IMPROVEMENT_REMINDER.md",
"rawChars": 616,
"injectedChars": 616,
"truncated": false
},
{
"path": "SELF_IMPROVEMENT_REMINDER.md",
"rawChars": 616,
"injectedChars": 616,
"truncated": false
},
{
"path": "SELF_IMPROVEMENT_REMINDER.md",
"rawChars": 616,
"injectedChars": 616,
"truncated": false
},
{
"path": "SELF_IMPROVEMENT_REMINDER.md",
"rawChars": 616,
"injectedChars": 616,
"truncated": false
},
{
"path": "SELF_IMPROVEMENT_REMINDER.md",
"rawChars": 616,
"injectedChars": 616,
"truncated": false
},
{
"path": "SELF_IMPROVEMENT_REMINDER.md",
"rawChars": 616,
"injectedChars": 616,
"truncated": false
},
{
"path": "SELF_IMPROVEMENT_REMINDER.md",
"rawChars": 616,
"injectedChars": 616,
"truncated": false
},
{
"path": "SELF_IMPROVEMENT_REMINDER.md",
"rawChars": 616,
"injectedChars": 616,
"truncated": false
},
{
"path": "SELF_IMPROVEMENT_REMINDER.md",
"rawChars": 616,
"injectedChars": 616,
"truncated": false
},
{
"path": "SELF_IMPROVEMENT_REMINDER.md",
"rawChars": 616,
@@ -528,13 +606,13 @@
]
}
},
"cacheRead": 23872,
"cacheRead": 80192,
"cacheWrite": 0,
"totalTokensFresh": true,
"contextTokens": 200000,
"inputTokens": 311770,
"outputTokens": 332,
"totalTokens": 170338
"inputTokens": 74653,
"outputTokens": 2299,
"totalTokens": 80601
},
"agent:ui-designer:cron:78b64c2f-7f91-47ff-9250-d13f546eb21f": {
"sessionId": "03e44b46-c707-4a9f-bf3d-1818aafdcde2",
@@ -573,5 +651,157 @@
"totalTokensFresh": true,
"cacheRead": 441088,
"cacheWrite": 0
},
"agent:ui-designer:cron:a1b2c3d4-e5f6-7890-abcd-ef1234567890": {
"sessionId": "0564cee8-7b1a-4cf6-9e93-df722d0cf77c",
"updatedAt": 1774251000040,
"systemSent": true,
"label": "Cron: 中国核建每日跟踪",
"skillsSnapshot": {
"prompt": "\n\nThe following skills provide specialized instructions for specific tasks.\nUse the read tool to load a skill's file when the task matches its description.\nWhen a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\n\n<available_skills>\n <skill>\n <name>capability-evolver</name>\n <description>A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.</description>\n <location>~/.openclaw/skills/capability-evolver/SKILL.md</location>\n </skill>\n</available_skills>",
"skills": [
{
"name": "capability-evolver"
}
],
"skillFilter": [
"capability-evolver",
"self-improving-agent"
],
"resolvedSkills": [
{
"name": "capability-evolver",
"description": "A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.",
"filePath": "/home/starmen1265/.openclaw/skills/capability-evolver/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/capability-evolver",
"source": "openclaw-managed",
"disableModelInvocation": false
}
],
"version": 0
},
"modelProvider": "zhipu",
"model": "glm-5",
"contextTokens": 200000,
"inputTokens": 37382,
"outputTokens": 5786,
"totalTokens": 39901,
"totalTokensFresh": true,
"cacheRead": 722944,
"cacheWrite": 0
},
"agent:ui-designer:cron:a1b2c3d4-e5f6-7890-abcd-ef1234567890:run:0564cee8-7b1a-4cf6-9e93-df722d0cf77c": {
"sessionId": "0564cee8-7b1a-4cf6-9e93-df722d0cf77c",
"updatedAt": 1774251000040,
"systemSent": true,
"label": "Cron: 中国核建每日跟踪",
"skillsSnapshot": {
"prompt": "\n\nThe following skills provide specialized instructions for specific tasks.\nUse the read tool to load a skill's file when the task matches its description.\nWhen a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\n\n<available_skills>\n <skill>\n <name>capability-evolver</name>\n <description>A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.</description>\n <location>~/.openclaw/skills/capability-evolver/SKILL.md</location>\n </skill>\n</available_skills>",
"skills": [
{
"name": "capability-evolver"
}
],
"skillFilter": [
"capability-evolver",
"self-improving-agent"
],
"resolvedSkills": [
{
"name": "capability-evolver",
"description": "A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.",
"filePath": "/home/starmen1265/.openclaw/skills/capability-evolver/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/capability-evolver",
"source": "openclaw-managed",
"disableModelInvocation": false
}
],
"version": 0
},
"modelProvider": "zhipu",
"model": "glm-5",
"contextTokens": 200000,
"inputTokens": 37382,
"outputTokens": 5786,
"totalTokens": 39901,
"totalTokensFresh": true,
"cacheRead": 722944,
"cacheWrite": 0
},
"agent:ui-designer:cron:b2c3d4e5-f6a7-8901-bcde-f12345678901": {
"sessionId": "db6b8b18-dd48-472b-bc40-f054e79c93c5",
"updatedAt": 1774251457953,
"systemSent": true,
"label": "Cron: 中国海油每日跟踪",
"skillsSnapshot": {
"prompt": "\n\nThe following skills provide specialized instructions for specific tasks.\nUse the read tool to load a skill's file when the task matches its description.\nWhen a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\n\n<available_skills>\n <skill>\n <name>capability-evolver</name>\n <description>A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.</description>\n <location>~/.openclaw/skills/capability-evolver/SKILL.md</location>\n </skill>\n</available_skills>",
"skills": [
{
"name": "capability-evolver"
}
],
"skillFilter": [
"capability-evolver",
"self-improving-agent"
],
"resolvedSkills": [
{
"name": "capability-evolver",
"description": "A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.",
"filePath": "/home/starmen1265/.openclaw/skills/capability-evolver/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/capability-evolver",
"source": "openclaw-managed",
"disableModelInvocation": false
}
],
"version": 0
},
"modelProvider": "zhipu",
"model": "glm-4.7-FlashX",
"contextTokens": 200000,
"inputTokens": 28746,
"outputTokens": 1841,
"totalTokens": 37950,
"totalTokensFresh": true,
"cacheRead": 9204,
"cacheWrite": 0
},
"agent:ui-designer:cron:b2c3d4e5-f6a7-8901-bcde-f12345678901:run:db6b8b18-dd48-472b-bc40-f054e79c93c5": {
"sessionId": "db6b8b18-dd48-472b-bc40-f054e79c93c5",
"updatedAt": 1774251457953,
"systemSent": true,
"label": "Cron: 中国海油每日跟踪",
"skillsSnapshot": {
"prompt": "\n\nThe following skills provide specialized instructions for specific tasks.\nUse the read tool to load a skill's file when the task matches its description.\nWhen a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\n\n<available_skills>\n <skill>\n <name>capability-evolver</name>\n <description>A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.</description>\n <location>~/.openclaw/skills/capability-evolver/SKILL.md</location>\n </skill>\n</available_skills>",
"skills": [
{
"name": "capability-evolver"
}
],
"skillFilter": [
"capability-evolver",
"self-improving-agent"
],
"resolvedSkills": [
{
"name": "capability-evolver",
"description": "A self-evolution engine for AI agents. Analyzes runtime history to identify improvements and applies protocol-constrained evolution.",
"filePath": "/home/starmen1265/.openclaw/skills/capability-evolver/SKILL.md",
"baseDir": "/home/starmen1265/.openclaw/skills/capability-evolver",
"source": "openclaw-managed",
"disableModelInvocation": false
}
],
"version": 0
},
"modelProvider": "zhipu",
"model": "glm-4.7-FlashX",
"contextTokens": 200000,
"inputTokens": 28746,
"outputTokens": 1841,
"totalTokens": 37950,
"totalTokensFresh": true,
"cacheRead": 9204,
"cacheWrite": 0
}
}
+113 -1
View File
@@ -39,4 +39,116 @@
---
*最后更新:2026-03-08*
## 中国核建每日跟踪职责
### 用户
张青 (ou_9847ce84b960736c14554730b41e4957)
### 执行时间
- **周期**:每个交易日
- **定时**:每日15:30(Asia/Shanghai,仅周一至周五)
- **Job ID**:a1b2c3d4-e5f6-7890-abcd-ef1234567890
### 跟踪内容
1. **价格数据**:收盘价、涨跌幅、成交量
2. **资金流向**:主力资金净流入/流出
3. **技术分析**:支撑位/压力位判断
4. **信号提醒**:
- 跌破支撑(15.24元 / 14.80元)
- 主力资金转正
- 放量企稳/反弹
### 关键技术位
- 支撑位:15.24元 → 14.80元
- 压力位:15.79元 → 16.50元
### 报告输出
- **飞书推送**:每日收盘后自动发送
- **文档保存**:`~/work/zq/30.资源/股票跟踪/601611_tracking.md`
### 开始跟踪
- **日期**:2026-03-23
- **初始价格**:15.48元(3月19日收盘)
- **初始状态**:下跌趋势中,主力连续流出
### 相关文件
- 任务配置记录:`memory/2026-03-23.md`
- 跟踪记录:`~/work/zq/30.资源/股票跟踪/601611_tracking.md`
- 定时脚本:`~/.openclaw/cron/scripts/stock-tracker.sh`
---
## 中国海油每日跟踪职责
### 用户
张青 (ou_9847ce84b960736c14554730b41e4957)
### 执行时间
- **周期**:每个交易日
- **定时**:每日15:30(Asia/Shanghai,仅周一至周五)
- **Job ID**:b2c3d4e5-f6a7-8901-bcde-f12345678901
### 跟踪内容
1. **价格数据**:收盘价、涨跌幅、成交量
2. **资金流向**:主力资金净流入/流出
3. **技术分析**:支撑位/压力位判断
4. **油价动态**:布伦特原油价格走势
5. **信号提醒**:
- 突破前高(44.54元)
- 跌破支撑(40元 / 38元)
- 主力资金异动
### 关键技术位
- 支撑位:40元 → 38元
- 压力位:44.54元(前高)
### 报告输出
- **飞书推送**:每日收盘后自动发送
- **文档保存**:`~/work/zq/30.资源/股票跟踪/600938_tracking.md`
### 开始跟踪
- **日期**:2026-03-23
- **初始价格**:44.54元(3月9日高点)
- **初始状态**:强势上涨,年内涨幅43.84%
### 相关文件
- 任务配置记录:`memory/2026-03-23.md`
- 跟踪记录:`~/work/zq/30.资源/股票跟踪/600938_tracking.md`
---
## 每日热点新闻追踪职责
### 用户
张青 (ou_9847ce84b960736c14554730b41e4957)
### 执行时间
- **周期**:每日
- **定时**:每日08:00(Asia/Shanghai)
- **Job ID**:c3d4e5f6-a7b8-9012-cdef-234567890123
### 追踪方向
#### 地缘政治
1. **美国**:政治、经济、外交动态
2. **日本**:政治、经济、外交动态
3. **中东地区**:地区局势
4. **俄乌战争**:最新进展
5. **美以伊战争**:最新进展
#### 科技产业
6. **AI大厂**:OpenAI、Google、Meta、百度、阿里、腾讯、字节等
7. **中国航空航天**:火箭、卫星、载人航天、探月等
8. **新能源**:电动车、电池、光伏、风电、储能等
9. **军工**:国产武器、军售、国防政策等
### 报告输出
- **飞书推送**:每日早上8点自动发送
- **文档保存**:`~/work/zq/30.资源/新闻简报/YYYY-MM-DD.md`
### 开始跟踪
- **日期**:2026-03-23
---
*最后更新:2026-03-23*
@@ -0,0 +1,99 @@
# 2026-03-23
## 股票跟踪任务
### 中国核建(601611)
**跟踪用户**:张青
**当前状态**(2026-03-23):
- 收盘价:15.48元(3月19日)
- 走势特征:连续下跌+缩量
- 主力资金:连续净流出(3/18: -1.62亿, 3/19: -1.82亿)
- 技术位:支撑15.24元,压力15.79元
**跟踪重点**:
1. 是否跌破15.24元支撑位
2. 主力资金是否转正
3. 是否出现放量企稳信号
4. 14.80-15.00元区间的介入机会
**报告频率**:每日收盘后(15:30,仅工作日)
**报告方式**:飞书推送
---
## 上午分析记录
### 缩量下跌技术分析
- 用户询问缩量下跌的含义
- 解答了积极信号(卖压减弱、惜售)和消极信号(买盘乏力、可能阴跌)
- 强调需结合位置判断(高位/下跌趋势/低位)
### 中国核建深度分析
- 基本面:2025Q3营收739亿(-6.32%),净利润11亿(-23.96%)
- 技术面:跌破15.79支撑,考验15.24元
- 行业面:核电黄金周期,装机规模全球第一
- 估值:PB 0.89倍,处于历史低位
- 建议:不急于抄底,等企稳信号
### 中国海油(600938)
**跟踪用户**:张青
**当前状态**(2026-03-23):
- 最新高点:44.54元(3月9日,创上市新高)
- 今年涨幅:+43.84%
- 走势特征:强势上涨,地缘政治催化
- 技术位:支撑40元/38元,压力44.54元(前高)
**跟踪重点**:
1. 是否突破44.54元前高
2. 是否跌破40元支撑
3. 油价走势、地缘政治动态
4. 主力资金流向变化
**报告频率**:每日收盘后(15:30,仅工作日)
**报告方式**:飞书推送
**分析要点**:
- 基本面:2024年净利润1379亿(+11.4%),三桶油中唯一正增长
- 成本优势:桶油成本28美元,全球领先
- 分红政策:2025-2027年股息支付率≥45%
- 风险:地缘平息后油价可能回落,短期涨幅大
- 建议:不追高,等回调至38-40元再介入
---
## 新闻追踪任务
### 每日热点新闻追踪
**设置时间**:2026-03-23 23:22
**执行频率**:每日 08:00
**推送方式**:飞书
**追踪方向**:
**地缘政治**:
1. 美国 - 政治、经济、外交
2. 日本 - 政治、经济、外交
3. 中东地区 - 地区局势
4. 俄乌战争 - 最新进展
5. 美以伊战争 - 最新进展
**科技产业**:
6. AI大厂 - OpenAI/Google/Meta/百度/阿里/腾讯/字节
7. 中国航空航天 - 火箭/卫星/载人航天/探月
8. 新能源 - 电动车/电池/光伏/风电/储能
9. 军工 - 国产武器/军售/国防政策
**输出**:
- 飞书推送
- 保存到 `~/work/zq/30.资源/新闻简报/YYYY-MM-DD.md`
---
*最后更新:2026-03-23 23:25*
+131 -29
View File
@@ -7,7 +7,7 @@
"name": "backup-openclaw-json",
"enabled": true,
"createdAtMs": 1772261581796,
"updatedAtMs": 1774202421534,
"updatedAtMs": 1774288823638,
"schedule": {
"kind": "cron",
"expr": "0 2 * * *",
@@ -23,10 +23,10 @@
"mode": "announce"
},
"state": {
"nextRunAtMs": 1774288800000,
"lastRunAtMs": 1774202400004,
"nextRunAtMs": 1774375200000,
"lastRunAtMs": 1774288800003,
"lastStatus": "ok",
"lastDurationMs": 21530,
"lastDurationMs": 23635,
"consecutiveErrors": 0,
"lastRunStatus": "ok",
"lastDelivered": true,
@@ -59,7 +59,8 @@
"consecutiveErrors": 0,
"lastRunStatus": "ok",
"lastDeliveryStatus": "delivered",
"lastDelivered": true
"lastDelivered": true,
"runningAtMs": 1774289400003
},
"delivery": {
"mode": "announce"
@@ -71,7 +72,7 @@
"name": "capability-evolver-daily",
"enabled": true,
"createdAtMs": 1772550743528,
"updatedAtMs": 1774117800012,
"updatedAtMs": 1774203773939,
"schedule": {
"kind": "cron",
"expr": "20 2 * * *",
@@ -92,14 +93,16 @@
"to": "feishu-pm"
},
"state": {
"nextRunAtMs": 1774203600000,
"lastRunAtMs": 1774117200004,
"lastStatus": "error",
"lastDurationMs": 600008,
"consecutiveErrors": 9,
"lastRunStatus": "error",
"lastDeliveryStatus": "unknown",
"runningAtMs": 1774203600003
"nextRunAtMs": 1774290000000,
"lastRunAtMs": 1774203600004,
"lastStatus": "ok",
"lastDurationMs": 173935,
"consecutiveErrors": 0,
"lastRunStatus": "ok",
"lastDeliveryStatus": "not-delivered",
"lastError": "cron announce delivery failed",
"lastDelivered": false,
"lastDeliveryError": "cron announce delivery failed"
}
},
{
@@ -109,7 +112,7 @@
"description": "每天凌晨2:30整理昨天的已完成任务到每日回顾",
"enabled": true,
"createdAtMs": 1741484880000,
"updatedAtMs": 1774117824773,
"updatedAtMs": 1774204228351,
"schedule": {
"kind": "cron",
"expr": "30 2 * * *",
@@ -127,11 +130,11 @@
"channel": "last"
},
"state": {
"nextRunAtMs": 1774204200000,
"lastRunAtMs": 1774117802034,
"nextRunAtMs": 1774290600000,
"lastRunAtMs": 1774204200008,
"lastRunStatus": "ok",
"lastStatus": "ok",
"lastDurationMs": 22739,
"lastDurationMs": 28343,
"lastDelivered": true,
"lastDeliveryStatus": "delivered",
"consecutiveErrors": 0
@@ -143,7 +146,7 @@
"name": "zq_workspace_sync",
"enabled": true,
"createdAtMs": 1772551807455,
"updatedAtMs": 1774118400007,
"updatedAtMs": 1774204800004,
"schedule": {
"expr": "40 2 * * *",
"kind": "cron",
@@ -156,8 +159,8 @@
"text": "执行 zq 工作区同步:bash ~/.openclaw/cron/scripts/zq_workspace_sync.sh"
},
"state": {
"nextRunAtMs": 1774204800000,
"lastRunAtMs": 1774118400007,
"nextRunAtMs": 1774291200000,
"lastRunAtMs": 1774204800004,
"lastStatus": "skipped",
"lastDurationMs": 0,
"consecutiveErrors": 0,
@@ -173,7 +176,7 @@
"description": "每天早上8点整理与各个 AI 代理的对话记录",
"enabled": true,
"createdAtMs": 1772776369645,
"updatedAtMs": 1774137620376,
"updatedAtMs": 1774224025295,
"schedule": {
"kind": "cron",
"expr": "0 8 * * *",
@@ -191,11 +194,11 @@
"channel": "last"
},
"state": {
"nextRunAtMs": 1774224000000,
"lastRunAtMs": 1774137600029,
"nextRunAtMs": 1774310400000,
"lastRunAtMs": 1774224000006,
"lastRunStatus": "ok",
"lastStatus": "ok",
"lastDurationMs": 20347,
"lastDurationMs": 25289,
"lastDelivered": true,
"lastDeliveryStatus": "delivered",
"consecutiveErrors": 0
@@ -208,7 +211,7 @@
"description": "每天7点同步提醒到CalDAV日历",
"enabled": true,
"createdAtMs": 1772791528528,
"updatedAtMs": 1774134016722,
"updatedAtMs": 1774220419806,
"schedule": {
"kind": "cron",
"expr": "0 7 * * *",
@@ -226,11 +229,11 @@
"channel": "last"
},
"state": {
"nextRunAtMs": 1774220400000,
"lastRunAtMs": 1774134000003,
"nextRunAtMs": 1774306800000,
"lastRunAtMs": 1774220400002,
"lastRunStatus": "ok",
"lastStatus": "ok",
"lastDurationMs": 16719,
"lastDurationMs": 19804,
"lastDeliveryStatus": "delivered",
"consecutiveErrors": 0,
"lastDelivered": true
@@ -271,6 +274,105 @@
"lastDeliveryStatus": "delivered",
"consecutiveErrors": 1
}
},
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"agentId": "ui-designer",
"name": "中国核建每日跟踪",
"description": "每日收盘后跟踪中国核建(601611)股价走势",
"enabled": true,
"createdAtMs": 1774231320000,
"updatedAtMs": 1774251457902,
"schedule": {
"kind": "cron",
"expr": "30 15 * * 1-5",
"tz": "Asia/Shanghai"
},
"sessionTarget": "isolated",
"wakeMode": "now",
"payload": {
"kind": "agentTurn",
"message": "执行中国核建(601611)每日跟踪任务:\n\n1. 通过web_search获取今日收盘价、涨跌幅、成交量、主力资金流向\n2. 对比昨日数据,分析走势变化\n3. 检查关键技术位:支撑15.24元/14.80元,压力15.79元/16.50元\n4. 判断是否出现:跌破支撑/主力回流/放量企稳等信号\n5. 将分析结果保存到~/work/zq/30.资源/股票跟踪/601611_tracking.md\n6. 推送飞书消息给用户\n\n如果今日休市,回复'今日休市'即可。"
},
"delivery": {
"mode": "announce",
"channel": "feishu",
"to": "user:ou_9847ce84b960736c14554730b41e4957"
},
"state": {
"nextRunAtMs": 1774337400000,
"lastRunAtMs": 1774251000004,
"lastRunStatus": "error",
"lastStatus": "error",
"lastDurationMs": 457898,
"lastError": "⚠️ ✉️ Message failed",
"lastDelivered": true,
"lastDeliveryStatus": "delivered",
"consecutiveErrors": 1
}
},
{
"id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"agentId": "ui-designer",
"name": "中国海油每日跟踪",
"description": "每日收盘后跟踪中国海油(600938)股价走势",
"enabled": true,
"createdAtMs": 1774231920000,
"updatedAtMs": 1774252089426,
"schedule": {
"kind": "cron",
"expr": "30 15 * * 1-5",
"tz": "Asia/Shanghai"
},
"sessionTarget": "isolated",
"wakeMode": "now",
"payload": {
"kind": "agentTurn",
"message": "执行中国海油(600938)每日跟踪任务:\n\n1. 通过web_search获取今日收盘价、涨跌幅、成交量、主力资金流向\n2. 对比昨日数据,分析走势变化\n3. 检查关键技术位:支撑40元/38元,压力44.54元(前高)\n4. 关注油价走势、地缘政治动态\n5. 判断是否出现:突破前高/跌破支撑/主力异动等信号\n6. 将分析结果保存到~/work/zq/30.资源/股票跟踪/600938_tracking.md\n7. 推送飞书消息给用户\n\n如果今日休市,回复'今日休市'即可。"
},
"delivery": {
"mode": "announce",
"channel": "feishu",
"to": "user:ou_9847ce84b960736c14554730b41e4957"
},
"state": {
"nextRunAtMs": 1774337400000,
"lastRunAtMs": 1774251457902,
"lastRunStatus": "ok",
"lastStatus": "ok",
"lastDurationMs": 631524,
"lastDelivered": true,
"lastDeliveryStatus": "delivered",
"consecutiveErrors": 0
}
},
{
"id": "c3d4e5f6-a7b8-9012-cdef-234567890123",
"agentId": "ui-designer",
"name": "每日热点新闻追踪",
"description": "每天早上8点追踪热点新闻并推送",
"enabled": true,
"createdAtMs": 1774274400000,
"updatedAtMs": 1774274400000,
"schedule": {
"kind": "cron",
"expr": "0 8 * * *",
"tz": "Asia/Shanghai"
},
"sessionTarget": "isolated",
"wakeMode": "now",
"payload": {
"kind": "agentTurn",
"message": "执行每日热点新闻追踪任务:\n\n通过web_search搜索以下领域的最新新闻:\n\n**地缘政治**:\n1. 美国政治、经济、外交动态\n2. 日本政治、经济、外交动态\n3. 中东地区局势\n4. 俄乌战争最新进展\n5. 美以伊战争最新进展\n\n**科技产业**:\n6. 国内外AI大厂动态(OpenAI、Google、Meta、百度、阿里、腾讯、字节等)\n7. 中国航空航天进展(火箭、卫星、载人航天、探月等)\n8. 新能源行业动态(电动车、电池、光伏、风电、储能等)\n9. 军工行业动态(国产武器、军售、国防政策等)\n\n**输出要求**:\n- 每个领域筛选2-3条重要新闻\n- 标注新闻来源和时间\n- 简要说明新闻影响\n- 报告保存到~/work/zq/30.资源/新闻简报/YYYY-MM-DD.md\n- 推送飞书消息给用户"
},
"delivery": {
"mode": "announce",
"channel": "feishu",
"to": "user:ou_9847ce84b960736c14554730b41e4957"
},
"state": {
"nextRunAtMs": 1774310400000
}
}
]
}
+129 -28
View File
@@ -7,7 +7,7 @@
"name": "backup-openclaw-json",
"enabled": true,
"createdAtMs": 1772261581796,
"updatedAtMs": 1774202421534,
"updatedAtMs": 1774288823638,
"schedule": {
"kind": "cron",
"expr": "0 2 * * *",
@@ -23,10 +23,10 @@
"mode": "announce"
},
"state": {
"nextRunAtMs": 1774288800000,
"lastRunAtMs": 1774202400004,
"nextRunAtMs": 1774375200000,
"lastRunAtMs": 1774288800003,
"lastStatus": "ok",
"lastDurationMs": 21530,
"lastDurationMs": 23635,
"consecutiveErrors": 0,
"lastRunStatus": "ok",
"lastDelivered": true,
@@ -71,7 +71,7 @@
"name": "capability-evolver-daily",
"enabled": true,
"createdAtMs": 1772550743528,
"updatedAtMs": 1774117800012,
"updatedAtMs": 1774203773939,
"schedule": {
"kind": "cron",
"expr": "20 2 * * *",
@@ -92,14 +92,16 @@
"to": "feishu-pm"
},
"state": {
"nextRunAtMs": 1774203600000,
"lastRunAtMs": 1774117200004,
"lastStatus": "error",
"lastDurationMs": 600008,
"consecutiveErrors": 9,
"lastRunStatus": "error",
"lastDeliveryStatus": "unknown",
"lastError": "cron: job execution timed out"
"nextRunAtMs": 1774290000000,
"lastRunAtMs": 1774203600004,
"lastStatus": "ok",
"lastDurationMs": 173935,
"consecutiveErrors": 0,
"lastRunStatus": "ok",
"lastDeliveryStatus": "not-delivered",
"lastError": "cron announce delivery failed",
"lastDelivered": false,
"lastDeliveryError": "cron announce delivery failed"
}
},
{
@@ -109,7 +111,7 @@
"description": "每天凌晨2:30整理昨天的已完成任务到每日回顾",
"enabled": true,
"createdAtMs": 1741484880000,
"updatedAtMs": 1774117824773,
"updatedAtMs": 1774204228351,
"schedule": {
"kind": "cron",
"expr": "30 2 * * *",
@@ -127,11 +129,11 @@
"channel": "last"
},
"state": {
"nextRunAtMs": 1774204200000,
"lastRunAtMs": 1774117802034,
"nextRunAtMs": 1774290600000,
"lastRunAtMs": 1774204200008,
"lastRunStatus": "ok",
"lastStatus": "ok",
"lastDurationMs": 22739,
"lastDurationMs": 28343,
"lastDelivered": true,
"lastDeliveryStatus": "delivered",
"consecutiveErrors": 0
@@ -143,7 +145,7 @@
"name": "zq_workspace_sync",
"enabled": true,
"createdAtMs": 1772551807455,
"updatedAtMs": 1774118400007,
"updatedAtMs": 1774204800004,
"schedule": {
"expr": "40 2 * * *",
"kind": "cron",
@@ -156,8 +158,8 @@
"text": "执行 zq 工作区同步:bash ~/.openclaw/cron/scripts/zq_workspace_sync.sh"
},
"state": {
"nextRunAtMs": 1774204800000,
"lastRunAtMs": 1774118400007,
"nextRunAtMs": 1774291200000,
"lastRunAtMs": 1774204800004,
"lastStatus": "skipped",
"lastDurationMs": 0,
"consecutiveErrors": 0,
@@ -173,7 +175,7 @@
"description": "每天早上8点整理与各个 AI 代理的对话记录",
"enabled": true,
"createdAtMs": 1772776369645,
"updatedAtMs": 1774137620376,
"updatedAtMs": 1774224025295,
"schedule": {
"kind": "cron",
"expr": "0 8 * * *",
@@ -191,11 +193,11 @@
"channel": "last"
},
"state": {
"nextRunAtMs": 1774224000000,
"lastRunAtMs": 1774137600029,
"nextRunAtMs": 1774310400000,
"lastRunAtMs": 1774224000006,
"lastRunStatus": "ok",
"lastStatus": "ok",
"lastDurationMs": 20347,
"lastDurationMs": 25289,
"lastDelivered": true,
"lastDeliveryStatus": "delivered",
"consecutiveErrors": 0
@@ -208,7 +210,7 @@
"description": "每天7点同步提醒到CalDAV日历",
"enabled": true,
"createdAtMs": 1772791528528,
"updatedAtMs": 1774134016722,
"updatedAtMs": 1774220419806,
"schedule": {
"kind": "cron",
"expr": "0 7 * * *",
@@ -226,11 +228,11 @@
"channel": "last"
},
"state": {
"nextRunAtMs": 1774220400000,
"lastRunAtMs": 1774134000003,
"nextRunAtMs": 1774306800000,
"lastRunAtMs": 1774220400002,
"lastRunStatus": "ok",
"lastStatus": "ok",
"lastDurationMs": 16719,
"lastDurationMs": 19804,
"lastDeliveryStatus": "delivered",
"consecutiveErrors": 0,
"lastDelivered": true
@@ -271,6 +273,105 @@
"lastDeliveryStatus": "delivered",
"consecutiveErrors": 1
}
},
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"agentId": "ui-designer",
"name": "中国核建每日跟踪",
"description": "每日收盘后跟踪中国核建(601611)股价走势",
"enabled": true,
"createdAtMs": 1774231320000,
"updatedAtMs": 1774251457902,
"schedule": {
"kind": "cron",
"expr": "30 15 * * 1-5",
"tz": "Asia/Shanghai"
},
"sessionTarget": "isolated",
"wakeMode": "now",
"payload": {
"kind": "agentTurn",
"message": "执行中国核建(601611)每日跟踪任务:\n\n1. 通过web_search获取今日收盘价、涨跌幅、成交量、主力资金流向\n2. 对比昨日数据,分析走势变化\n3. 检查关键技术位:支撑15.24元/14.80元,压力15.79元/16.50元\n4. 判断是否出现:跌破支撑/主力回流/放量企稳等信号\n5. 将分析结果保存到~/work/zq/30.资源/股票跟踪/601611_tracking.md\n6. 推送飞书消息给用户\n\n如果今日休市,回复'今日休市'即可。"
},
"delivery": {
"mode": "announce",
"channel": "feishu",
"to": "user:ou_9847ce84b960736c14554730b41e4957"
},
"state": {
"nextRunAtMs": 1774337400000,
"lastRunAtMs": 1774251000004,
"lastRunStatus": "error",
"lastStatus": "error",
"lastDurationMs": 457898,
"lastError": "⚠️ ✉️ Message failed",
"lastDelivered": true,
"lastDeliveryStatus": "delivered",
"consecutiveErrors": 1
}
},
{
"id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"agentId": "ui-designer",
"name": "中国海油每日跟踪",
"description": "每日收盘后跟踪中国海油(600938)股价走势",
"enabled": true,
"createdAtMs": 1774231920000,
"updatedAtMs": 1774252089426,
"schedule": {
"kind": "cron",
"expr": "30 15 * * 1-5",
"tz": "Asia/Shanghai"
},
"sessionTarget": "isolated",
"wakeMode": "now",
"payload": {
"kind": "agentTurn",
"message": "执行中国海油(600938)每日跟踪任务:\n\n1. 通过web_search获取今日收盘价、涨跌幅、成交量、主力资金流向\n2. 对比昨日数据,分析走势变化\n3. 检查关键技术位:支撑40元/38元,压力44.54元(前高)\n4. 关注油价走势、地缘政治动态\n5. 判断是否出现:突破前高/跌破支撑/主力异动等信号\n6. 将分析结果保存到~/work/zq/30.资源/股票跟踪/600938_tracking.md\n7. 推送飞书消息给用户\n\n如果今日休市,回复'今日休市'即可。"
},
"delivery": {
"mode": "announce",
"channel": "feishu",
"to": "user:ou_9847ce84b960736c14554730b41e4957"
},
"state": {
"nextRunAtMs": 1774337400000,
"lastRunAtMs": 1774251457902,
"lastRunStatus": "ok",
"lastStatus": "ok",
"lastDurationMs": 631524,
"lastDelivered": true,
"lastDeliveryStatus": "delivered",
"consecutiveErrors": 0
}
},
{
"id": "c3d4e5f6-a7b8-9012-cdef-234567890123",
"agentId": "ui-designer",
"name": "每日热点新闻追踪",
"description": "每天早上8点追踪热点新闻并推送",
"enabled": true,
"createdAtMs": 1774274400000,
"updatedAtMs": 1774274400000,
"schedule": {
"kind": "cron",
"expr": "0 8 * * *",
"tz": "Asia/Shanghai"
},
"sessionTarget": "isolated",
"wakeMode": "now",
"payload": {
"kind": "agentTurn",
"message": "执行每日热点新闻追踪任务:\n\n通过web_search搜索以下领域的最新新闻:\n\n**地缘政治**:\n1. 美国政治、经济、外交动态\n2. 日本政治、经济、外交动态\n3. 中东地区局势\n4. 俄乌战争最新进展\n5. 美以伊战争最新进展\n\n**科技产业**:\n6. 国内外AI大厂动态(OpenAI、Google、Meta、百度、阿里、腾讯、字节等)\n7. 中国航空航天进展(火箭、卫星、载人航天、探月等)\n8. 新能源行业动态(电动车、电池、光伏、风电、储能等)\n9. 军工行业动态(国产武器、军售、国防政策等)\n\n**输出要求**:\n- 每个领域筛选2-3条重要新闻\n- 标注新闻来源和时间\n- 简要说明新闻影响\n- 报告保存到~/work/zq/30.资源/新闻简报/YYYY-MM-DD.md\n- 推送飞书消息给用户"
},
"delivery": {
"mode": "announce",
"channel": "feishu",
"to": "user:ou_9847ce84b960736c14554730b41e4957"
},
"state": {
"nextRunAtMs": 1774310400000
}
}
]
}
+45
View File
@@ -0,0 +1,45 @@
#!/bin/bash
# 中国核建(601611)每日跟踪脚本
# 用途:获取股价数据,保存到跟踪记录
STOCK_CODE="601611"
STOCK_NAME="中国核建"
TODAY=$(date +%Y-%m-%d)
LOG_DIR="$HOME/work/zq/30.资源/股票跟踪"
LOG_FILE="$LOG_DIR/${STOCK_CODE}_tracking.md"
# 确保目录存在
mkdir -p "$LOG_DIR"
# 初始化日志文件(如果不存在)
if [ ! -f "$LOG_FILE" ]; then
cat > "$LOG_FILE" << EOF
# 中国核建(601611)跟踪记录
## 基本信息
- 股票代码:601611
- 股票名称:中国核建
- 跟踪用户:张青
- 开始跟踪:${TODAY}
## 关键技术位
- 支撑位:15.24元 / 14.80元
- 压力位:15.79元 / 16.50元
## 跟踪重点
1. 是否跌破支撑位
2. 主力资金流向变化
3. 放量企稳/反弹信号
4. 14.80-15.00元介入机会
---
## 每日记录
EOF
fi
# 输出日期标记(实际数据由 agent 通过 web_search 获取)
echo "触发股票跟踪任务: ${STOCK_NAME} (${STOCK_CODE})"
echo "日期: ${TODAY}"
echo "状态: pending"
@@ -0,0 +1,24 @@
{
"id": "81601882-e50a-4a8b-a8bc-e19b156b7b05",
"enqueuedAt": 1774203652711,
"channel": "feishu",
"to": "ou_73cc4f75e3c953d7bf11f34f8c8c7618",
"accountId": "feishu-pm",
"payloads": [
{
"text": "## Capability Evolver 每日报告\n\n**时间**: 2026年 03月 23日 星期一 02:20 CST\n**结果**: SUCCESS\n**意图**: REPAIR (修复)\n\n### 本次变更\n\n**影响范围**: 4 个修改,6 个新建\n\n**修改文件**:\n- `memory/evolution/evolution_solidify_state.json` (修改)\n- `memory/evolution/evolution_state.json` (修改)\n- `memory/evolution/memory_graph_state.json` (修改)\n- `memory/evolution/personality_state.json` (修改)\n\n**新建文件**:\n- `memory/evolution/gep_prompt_Cycle_#0018_run_1774203606866.json`\n- `memory/evolution/gep_prompt_Cycle_#0018_run_1774203606866.txt`\n\n**代码统计**:\n- 插入: 551 行\n- 删除: 14 行\n\n### 执行摘要\n\n本次 evolver 运行成功,主要修复了 session logs 检测和 fallback 行为的稳定性。\n\n**变更详情**: see `~/work/backup/evolver-output.txt` for full logs.",
"replyToTag": false,
"replyToCurrent": false,
"audioAsVoice": false
}
],
"gifPlayback": false,
"mirror": {
"sessionKey": "agent:haonan:main",
"agentId": "haonan",
"text": "## Capability Evolver 每日报告\n\n**时间**: 2026年 03月 23日 星期一 02:20 CST\n**结果**: SUCCESS\n**意图**: REPAIR (修复)\n\n### 本次变更\n\n**影响范围**: 4 个修改,6 个新建\n\n**修改文件**:\n- `memory/evolution/evolution_solidify_state.json` (修改)\n- `memory/evolution/evolution_state.json` (修改)\n- `memory/evolution/memory_graph_state.json` (修改)\n- `memory/evolution/personality_state.json` (修改)\n\n**新建文件**:\n- `memory/evolution/gep_prompt_Cycle_#0018_run_1774203606866.json`\n- `memory/evolution/gep_prompt_Cycle_#0018_run_1774203606866.txt`\n\n**代码统计**:\n- 插入: 551 行\n- 删除: 14 行\n\n### 执行摘要\n\n本次 evolver 运行成功,主要修复了 session logs 检测和 fallback 行为的稳定性。\n\n**变更详情**: see `~/work/backup/evolver-output.txt` for full logs."
},
"retryCount": 1,
"lastAttemptAt": 1774203652867,
"lastError": "Request failed with status code 400"
}
@@ -0,0 +1,24 @@
{
"id": "89181ed1-39cf-4f24-b4e5-2df4d7b6fd34",
"enqueuedAt": 1774203674178,
"channel": "feishu",
"to": "ou_73cc4f75e3c953d7bf11f34f8c8c7618",
"accountId": "feishu-pm",
"payloads": [
{
"text": "Capability Evolver 每日报告:\n时间:2026-03-23 02:20 CST\n结果:SUCCESS\n意图:REPAIR\n变更:4 修改 + 6 新建\n统计:+551 行,-14 行\n详情:查看 ~/work/backup/evolver-output.txt",
"replyToTag": false,
"replyToCurrent": false,
"audioAsVoice": false
}
],
"gifPlayback": false,
"mirror": {
"sessionKey": "agent:haonan:main",
"agentId": "haonan",
"text": "Capability Evolver 每日报告:\n时间:2026-03-23 02:20 CST\n结果:SUCCESS\n意图:REPAIR\n变更:4 修改 + 6 新建\n统计:+551 行,-14 行\n详情:查看 ~/work/backup/evolver-output.txt"
},
"retryCount": 1,
"lastAttemptAt": 1774203674333,
"lastError": "Request failed with status code 400"
}
@@ -0,0 +1,24 @@
{
"id": "a74a559f-aea8-4d9d-8d4a-46402b208d15",
"enqueuedAt": 1774203665200,
"channel": "feishu",
"to": "ou_73cc4f75e3c953d7bf11f34f8c8c7618",
"accountId": "feishu-pm",
"payloads": [
{
"text": "## Capability Evolver 每日报告\n\n**时间**: 2026年 03月 23日 星期一 02:20 CST\n**结果**: SUCCESS\n**意图**: REPAIR (修复)\n\n### 本次变更\n\n**影响范围**: 4 个修改,6 个新建\n\n**修改文件**:\n- `memory/evolution/evolution_solidify_state.json` (修改)\n- `memory/evolution/evolution_state.json` (修改)\n- `memory/evolution/memory_graph_state.json` (修改)\n- `memory/evolution/personality_state.json` (修改)\n\n**新建文件**:\n- `memory/evolution/gep_prompt_Cycle_#0018_run_1774203606866.json`\n- `memory/evolution/gep_prompt_Cycle_#0018_run_1774203606866.txt`\n\n**代码统计**:\n- 插入: 551 行\n- 删除: 14 行\n\n### 执行摘要\n\n本次 evolver 运行成功,主要修复了 session logs 检测和 fallback 行为的稳定性。\n\n**变更详情**: see `~/work/backup/evolver-output.txt` for full logs.",
"replyToTag": false,
"replyToCurrent": false,
"audioAsVoice": false
}
],
"gifPlayback": false,
"mirror": {
"sessionKey": "agent:haonan:main",
"agentId": "haonan",
"text": "## Capability Evolver 每日报告\n\n**时间**: 2026年 03月 23日 星期一 02:20 CST\n**结果**: SUCCESS\n**意图**: REPAIR (修复)\n\n### 本次变更\n\n**影响范围**: 4 个修改,6 个新建\n\n**修改文件**:\n- `memory/evolution/evolution_solidify_state.json` (修改)\n- `memory/evolution/evolution_state.json` (修改)\n- `memory/evolution/memory_graph_state.json` (修改)\n- `memory/evolution/personality_state.json` (修改)\n\n**新建文件**:\n- `memory/evolution/gep_prompt_Cycle_#0018_run_1774203606866.json`\n- `memory/evolution/gep_prompt_Cycle_#0018_run_1774203606866.txt`\n\n**代码统计**:\n- 插入: 551 行\n- 删除: 14 行\n\n### 执行摘要\n\n本次 evolver 运行成功,主要修复了 session logs 检测和 fallback 行为的稳定性。\n\n**变更详情**: see `~/work/backup/evolver-output.txt` for full logs."
},
"retryCount": 1,
"lastAttemptAt": 1774203665371,
"lastError": "Request failed with status code 400"
}
@@ -0,0 +1,21 @@
{
"id": "be91d785-b914-42dc-9298-f57551587373",
"enqueuedAt": 1774203773787,
"channel": "feishu",
"to": "feishu-pm",
"accountId": "feishu-pm",
"payloads": [
{
"text": "每日 capability-evolver 任务执行完成:\n\n## 每日报告\n\n**时间**: 2026年 03月 23日 星期一 02:20 CST\n**结果**: SUCCESS\n**意图**: REPAIR (修复)\n\n### 本次变更\n\n**影响范围**: 4 个修改,6 个新建\n\n**修改文件**:\n- `memory/evolution/evolution_solidify_state.json` (修改)\n- `memory/evolution/evolution_state.json` (修改)\n- `memory/evolution/memory_graph_state.json` (修改)\n- `memory/evolution/personality_state.json` (修改)\n\n**新建文件**:\n- `memory/evolution/gep_prompt_Cycle_#0018_run_1774203606866.json`\n- `memory/evolution/gep_prompt_Cycle_#0018_run_1774203606866.txt`\n\n**代码统计**:\n- 插入: 551 行\n- 删除: 14 行\n\n### 执行摘要\n\n本次 evolver 运行成功,主要修复了 session logs 检测和 fallback 行为的稳定性。\n\n**变更详情**: see `~/work/backup/evolver-output.txt` for full logs."
}
],
"threadId": null,
"mirror": {
"sessionKey": "agent:haonan:main",
"agentId": "haonan",
"text": "每日 capability-evolver 任务执行完成:\n\n## 每日报告\n\n**时间**: 2026年 03月 23日 星期一 02:20 CST\n**结果**: SUCCESS\n**意图**: REPAIR (修复)\n\n### 本次变更\n\n**影响范围**: 4 个修改,6 个新建\n\n**修改文件**:\n- `memory/evolution/evolution_solidify_state.json` (修改)\n- `memory/evolution/evolution_state.json` (修改)\n- `memory/evolution/memory_graph_state.json` (修改)\n- `memory/evolution/personality_state.json` (修改)\n\n**新建文件**:\n- `memory/evolution/gep_prompt_Cycle_#0018_run_1774203606866.json`\n- `memory/evolution/gep_prompt_Cycle_#0018_run_1774203606866.txt`\n\n**代码统计**:\n- 插入: 551 行\n- 删除: 14 行\n\n### 执行摘要\n\n本次 evolver 运行成功,主要修复了 session logs 检测和 fallback 行为的稳定性。\n\n**变更详情**: see `~/work/backup/evolver-output.txt` for full logs."
},
"retryCount": 1,
"lastAttemptAt": 1774203773932,
"lastError": "Request failed with status code 400"
}
@@ -0,0 +1,24 @@
{
"id": "c7e6e651-ad7b-420f-ac5c-83a1ec63d809",
"enqueuedAt": 1774252049059,
"channel": "feishu",
"to": "ou_f3d9fc3e3a1c4e5b8d7f6a2c9e1b4d3f",
"accountId": "feishu-art",
"payloads": [
{
"text": "## 📊 中国海油 (600938) 每日跟踪 - 2026-03-23\n\n### 收盘数据\n- **最新价**: 42.10 元 (+0.45%)\n- **昨收**: 41.91 元\n- **最高/最低**: 43.20 / 41.72 元\n- **成交额**: 43.43 亿元\n\n### 技术位分析\n- 压力位: 44.54 元(前高,距离5.8%)\n- 支撑位: 40.00 元(距离5.0%)\n- 当前处于震荡区间中部\n\n### 油价动态 🛢️\n- 布伦特原油: 109.32 美元 (+2.51%)\n- ⚠️ 霍尔木兹海峡局势紧张,美以对伊朗军事打击\n- 油价触及110美元上方,地缘政治溢价明显\n\n### 信号判断\n✅ 油价利好 - 原油上涨支撑股价\n⚠️ 关注前高 - 44.54元存在压力\n❌ 未触及支撑位\n\n### 操作建议\n- 持仓观望,突破44.54元可考虑加仓\n- 跌破40元支撑需警惕\n- 中长期受益于高油价环境\n\n详细报告已保存至: `~/work/zq/30.资源/股票跟踪/600938_tracking.md`",
"replyToTag": false,
"replyToCurrent": false,
"audioAsVoice": false
}
],
"gifPlayback": false,
"mirror": {
"sessionKey": "agent:ui-designer:main",
"agentId": "ui-designer",
"text": "## 📊 中国海油 (600938) 每日跟踪 - 2026-03-23\n\n### 收盘数据\n- **最新价**: 42.10 元 (+0.45%)\n- **昨收**: 41.91 元\n- **最高/最低**: 43.20 / 41.72 元\n- **成交额**: 43.43 亿元\n\n### 技术位分析\n- 压力位: 44.54 元(前高,距离5.8%)\n- 支撑位: 40.00 元(距离5.0%)\n- 当前处于震荡区间中部\n\n### 油价动态 🛢️\n- 布伦特原油: 109.32 美元 (+2.51%)\n- ⚠️ 霍尔木兹海峡局势紧张,美以对伊朗军事打击\n- 油价触及110美元上方,地缘政治溢价明显\n\n### 信号判断\n✅ 油价利好 - 原油上涨支撑股价\n⚠️ 关注前高 - 44.54元存在压力\n❌ 未触及支撑位\n\n### 操作建议\n- 持仓观望,突破44.54元可考虑加仓\n- 跌破40元支撑需警惕\n- 中长期受益于高油价环境\n\n详细报告已保存至: `~/work/zq/30.资源/股票跟踪/600938_tracking.md`"
},
"retryCount": 1,
"lastAttemptAt": 1774252049242,
"lastError": "Request failed with status code 400"
}
@@ -0,0 +1,24 @@
{
"id": "e75bc319-49b7-4881-8609-1a78052d3a78",
"enqueuedAt": 1774203670341,
"channel": "feishu",
"to": "ou_73cc4f75e3c953d7bf11f34f8c8c7618",
"accountId": "feishu-pm",
"payloads": [
{
"text": "Capability Evolver 每日报告:\n时间:2026-03-23 02:20 CST\n结果:SUCCESS\n意图:REPAIR\n变更:4 修改 + 6 新建\n统计:+551 行,-14 行\n详情:查看 ~/work/backup/evolver-output.txt",
"replyToTag": false,
"replyToCurrent": false,
"audioAsVoice": false
}
],
"gifPlayback": false,
"mirror": {
"sessionKey": "agent:haonan:main",
"agentId": "haonan",
"text": "Capability Evolver 每日报告:\n时间:2026-03-23 02:20 CST\n结果:SUCCESS\n意图:REPAIR\n变更:4 修改 + 6 新建\n统计:+551 行,-14 行\n详情:查看 ~/work/backup/evolver-output.txt"
},
"retryCount": 1,
"lastAttemptAt": 1774203670490,
"lastError": "Request failed with status code 400"
}
+13 -29
View File
@@ -1,31 +1,15 @@
{
"om_x100b5480d5bba4b4b2c9a4e8bf5b189": 1773881784103,
"om_x100b54808ff17c90b374531d1cf7751": 1773882388481,
"om_x100b5481441a38a4b20013813040b59": 1773883566093,
"om_x100b54816cbffcb8b36dfe46fd84a26": 1773883944086,
"om_x100b54817240a0a0b49ad1ecc4230d1": 1773884361569,
"om_x100b548114fc64a4b34dda488c6c4cf": 1773884835671,
"om_x100b548129129490b4b1770d7f3efcc": 1773885054622,
"om_x100b5481243380b0b10b5bef1b92ca3": 1773885104561,
"om_x100b54813d7144bcb2da847227b06a8": 1773885244462,
"om_x100b548139e42d10b3ffcf9447ed48c": 1773885299355,
"om_x100b548133fa3ca4b219d22fcf41e18": 1773885396226,
"om_x100b5481ce0418a0b26dc9b2f68f007": 1773885453209,
"om_x100b548c9b6dcc78b49c9ec428e44f3": 1773899098605,
"om_x100b548ca39e00acc3362a9bf3873de": 1773899477853,
"om_x100b548d47a538b0c2c282968797cea": 1773899927180,
"om_x100b5489ba663ca0c4c8bc1d9b97937": 1773920075261,
"om_x100b548a50d788b8b2c1f705241dbc5": 1773920738205,
"om_x100b548a72e7f4a8b286f0d7e9aea31": 1773921219213,
"om_x100b548a83211ca8c44bcbf00eb049e": 1773923551363,
"om_x100b548a95d45530c29580a9d1bad9a": 1773923762295,
"om_x100b548b1fa8c8a4c42e95eb381a75c": 1773925655047,
"om_x100b54f49f9f20b0b2d58df353d8a5b": 1773931798109,
"om_x100b54f51931bca0c361d933da09d2b": 1773933952255,
"om_x100b54f52b61f0a4c3650d280bf0dad": 1773934171242,
"om_x100b54f53b8678b0c3188a42d675405": 1773934421286,
"om_x100b54f533291ca4c2cf74f54da005d": 1773934558803,
"om_x100b54f5b9ebf8a0c33674c32a8da6c": 1773936499279,
"om_x100b54f64c3844acc14333ab25a59e5": 1773936688149,
"om_x100b54f650ef80a0c2d3c76a3fbe9be": 1773937122637
"om_x100b533c2cb598b0b38554196b869f8": 1774224936136,
"om_x100b533cf8e108b0b4cedda48be0a42": 1774226275419,
"om_x100b533c8a4b5938b4c45e3d07693ac": 1774226504992,
"om_x100b533c8622c874b392b1a60668c21": 1774226575556,
"om_x100b533d4fff4ca4b4a2d16c627a484": 1774227475867,
"om_x100b533d47fdc090b107d902ed3d741": 1774227603738,
"om_x100b533d45d7093cb34bee17b3c7147": 1774227634685,
"om_x100b533d608888f4b36b9b379cf2e96": 1774228196959,
"om_x100b533d79cfdc8cb321dd3f8ab07ea": 1774228336755,
"om_x100b533d77d348e8b21d6e461881c28": 1774228370751,
"om_x100b533aaa7174b8c32c20a830ba04e": 1774251596497,
"om_x100b533aa54ee080c3ab0e130b922fa": 1774251704904,
"om_x100b5321e5a3a4a0c14df59fcd6968d": 1774279351394
}
+6 -19
View File
@@ -1,21 +1,8 @@
{
"om_x100b54d455778d34c29e5078a416505": 1774059964188,
"om_x100b54ddcdff10a4c10c6a43f3a9b15": 1774098483703,
"om_x100b54ddcb8c98acc440146013bf3ea": 1774098516724,
"om_x100b54dda5ae30a4c103d63b161622d": 1774100150755,
"om_x100b54dda0515ca0c4914152b3fe790": 1774100202332,
"om_x100b54de4314e8a8c450f30e86836c8": 1774100702124,
"om_x100b54de5ee994a8c33ae7a7a33b818": 1774100738775,
"om_x100b54de791d60a4c312fc32c95a374": 1774101373675,
"om_x100b54de757c58a0c3edf82023ed91e": 1774101435678,
"om_x100b54dee46b58a0c45e5db8753fdf2": 1774103210881,
"om_x100b54dee22384a4c49132969d941d8": 1774103247433,
"om_x100b54deac3148a8c333c9c38b7ab7a": 1774104112330,
"om_x100b54deab3784a0c4d6583799df1cb": 1774104160071,
"om_x100b54deb098ccacc140f6982c07d66": 1774104549843,
"om_x100b54df4e8f54acc4c0085d75ba209": 1774104580600,
"om_x100b54df4c052ca0c3a0fbee838fa52": 1774104621124,
"om_x100b54df46cdc4a4c4ee1f9a5b25c4c": 1774104704546,
"om_x100b54df40aeb8a4c14f9ef86aba704": 1774104806595,
"om_x100b54df5937cca0c29c73fdc610d11": 1774104960174
"om_x100b53219b1e80f4c3403ec55bc0e66": 1774280029816,
"om_x100b532193c3c8a0c2c4ae55e5aa0d1": 1774280145525,
"om_x100b5322c4c40ca4c3701e80050a2ca": 1774282913137,
"om_x100b5322c56c10acc4cd9e07359bb10": 1774282938532,
"om_x100b5322d34338a4c3797f179b05ab0": 1774283225420,
"om_x100b532287a368a0c4cc418c0192b3a": 1774283927392
}
+1 -1
View File
@@ -10,7 +10,7 @@
"operator.approvals",
"operator.pairing"
],
"updatedAtMs": 1774203014332
"updatedAtMs": 1774288823167
}
}
}
+1
View File
@@ -67,3 +67,4 @@
{"timestamp":"2026-03-21T13:45:02.174Z","action":"new","sessionKey":"agent:knowledge-base:main","senderId":"ou_9351c287f42069fa30366ac641d24df7","source":"feishu"}
{"timestamp":"2026-03-21T14:26:51.250Z","action":"new","sessionKey":"agent:knowledge-base:main","senderId":"ou_9351c287f42069fa30366ac641d24df7","source":"feishu"}
{"timestamp":"2026-03-21T14:49:40.665Z","action":"new","sessionKey":"agent:knowledge-base:main","senderId":"ou_9351c287f42069fa30366ac641d24df7","source":"feishu"}
{"timestamp":"2026-03-23T16:21:53.453Z","action":"new","sessionKey":"agent:knowledge-base:main","senderId":"ou_9351c287f42069fa30366ac641d24df7","source":"feishu"}
@@ -0,0 +1,43 @@
{
"video_type": "知识类",
"segments": [
{
"title": "3月22日战况汇总:美以空袭与伊朗反击",
"content": "死定门晚上好继续汇报今天的全球局势 战争进入第二十三天 没以连军针对伊朗的多个军师基地和武器存储设施发动广泛的空袭 伊朗核设施再度遭遇一军空袭 伊朗则对等反击对以色列核设施所在的城市发动导弹打击 造成气劲为止最大规模的伤亡 录清离巴嫩的一军地面部对越来越多 总数达到了五个时 珍主党一次使用冰薄多管火箭炮 向以色列北部发起密集打击并造成大规模破坏 董王面临艰难绝则要么通过地面做弹冒险升级冲突 要么接触严重的经济损失 从而毁掉共和党在中期选举中的机会 为此他再次发出了经典的48小时最后通铁 要求伊朗立即开放霍尔木滋海峡 否则将摧毁伊朗所有发电站 伊朗则威胁摧毁美国在中东地区所有的能源基础设施 信息技术系统和海水淡化设施是与美国战斗到底 无在武装称其随时待密 一旦局势继续升级 红海和曼德海峡将被确保封锁 与此同时 福德号离开了红海 正在通过苏伊氏运河 准备退出战斗前往希拉维修 好在简单回顾之后 我们还是先看伊朗这边的情况 当地时间21日下午至22日凌晨 每以继续对伊朗多地发动广泛的轰炸 为于伊朗西部胡锡斯坦省 德资富尔附近的瓦克达地空军基地遭遇美以联军的盟链空习 现场拍摄的视频显示 航空炸弹爆炸后产生的激波清晰和剑 冒出的黑银高达上千米 同时伴随巨大的爆炸声 据以军称该地点是一处伊朗的导弹存储设施 但没有相关的证据可以证明这一点 据以军发布的声明 在过去的24小时 以此类空军对伊朗 与伊斯兰革命未对的弹道导弹生产设施及关键组建储存设施 国防部下属的导弹燃料生产设施 马勒克阿斯塔尔大学和弹道导弹正地操作人员等目标 发动多轮空习 声明称马勒克阿斯塔尔大学是伊朗军事工业与弹道导弹体系的研发机构 例属于伊朗国防部 此外以军还空习了位于伊朗中部的纳坦资游农搜工厂 所幸并未发生辅射洩漏",
"start_index": 0,
"end_index": 487
},
{
"title": null,
"content": "在不十二地区又一架美军的MQ9无人机被伊朗防空部队激落 看着MQ9被打下来 不免让我想起最近换新相机之后闲置的那台旧相机 所以这里想问一下私立门换新后就得都怎么处理 向往那台旧相机找转转上门回收了3100多 转转是一个很好的买家 不仅回收频类丰富而且变现特别快 向威丹运动相机无人机这种摄影器材 甚至是内存条组装机之类不好卖的小众频类 在弹纳都能随时换成钱 比起之前挂网上一直卖不出去 还得跟买家斗志斗友 转转特别适合我这种想快速变现又图神识的人 我听你们试过了 他们回收价格也很不错 像我之前那款Omica还卖了24000多呢 要我说有蓝的处理的钱质就直接卖给转转 钱到时候才是印道里",
"start_index": 488,
"end_index": 835
},
{
"title": "美军战果与伊朗防空伏击F-35战损分析",
"content": "据美国中央司令部司令布拉德库博上将发布的声明 过去两天美国陆军使用精确制导导弹 发起了美国陆军历史上最长的野战炮火打击 此次打击摧毁了伊朗的军事基础设施展示了美军无可疲敌的打击范围和致命性 他表示美军在三周内打击了超过8000个目标 包括120多艘伊朗军舰 这是自第二次世界大战以来在短短三周时间内 对敌方海军造成的最大规模消灭 然后开始吹噱美军在中东的反导系统 拦击了数千价伊朗无人机和导弹 为盟友撑起了可靠的保护散 美国中央司令部还发布了打击伊朗防空系统的画面 其中一段视频显示一套伊朗国产的马基德防空导弹系统被摧毁 据报道 此前击中F35的正式该防空系统发誓的导弹 这是一种安装在卡车上的战术及防空系统 设成紧约8公里 但具备高度激动性 而且采用被动探测系统 也就是说更难被发现 制在一定程度上解释了伊朗为何仁然保有防空能力 由于喪失至空权 伊朗只能采取伏击式防空 即防空导弹系统继续雷达通常处于关闭状态 仅在必要时短暂开机作战 因为一旦雷达开启就会被定位并迅速遭到打击 这些防空系统通常会被红外制导导弹 F35虽然对特定雷达副段隐身 但在红外热情相义的视角下就是个火把子 因为战机发动机产生的高温和周围的空气温度有着极大的区别 所以那家澳门的F35应该是被导弹近距离爆炸损坏的机体维布 但还是亮亮穿着飞回了沙特 美国军方撑起紧急迫降飞行员返回 但据美国国家公共电台五角大楼记者报道 被伊朗防空系统集中的F35战斗机飞行员身受弹骗伤 飞机硬着露在可遇见的未来将无法執行任务",
"start_index": 836,
"end_index": 1646
},
{
"title": "黎巴嫩地面战况与伊朗导弹报复打击迪莫纳",
"content": "尼巴嫩这边 一军持续增加入侵尼巴嫩南部的军队数量 据一军当地时间21日宣布 其D162是已完成部署尼巴嫩南部的准备工作 部署在尼巴嫩南部的一军数量即将达到五个时 目前第146时部署在尼巴嫩南部的西部地区 第91时和第36时在东部战区作战 第214时注查在多富山地区 以军称后续以军还将继续扩大在尼巴嫩南部的军队规模 并进一步扩大所谓的缓冲区 以区族边境上的珍主党威胁 此外以军还称当地时间31日夜间 一次列陆军第91时在尼巴嫩南部与珍主党发生激烈交火 并消灭了多名珍主党人员 一次列空军也在当天对被鲁特及尼巴嫩其他地区的珍主党 只会中心进行了空袭 当地时间21日下午至22日上午 为报复美艺队伊朗和射师以及其他地区的广泛空袭 并造成大规模上网 伊朗伊斯兰更应对继续发动真实沉默死行动的第71至73轮联合打击 使用了法塔克高超因素导弹 获拉姆沙克尔斯重型导弹 卡德尔和艾马德弹导弹等多种类型的先进导弹 目标是以色列南部城市迪莫纳及其中兵地区的军事设施和安全中心 美军在科威特的军事基地的 不久后以色列南部想起了密集防空警告都没导弹激重目标 其中迪莫纳受损最为严重 伊梅伊朗的导弹激重了迪莫纳的建筑群 造成大规模上网 视频可以看到 该导弹接连躲过了多梅蓝杰弹直奔目标 在即将靠近目标时速度明显加分 后续传出的爆炸点搜救视频也可以看到 该地区的建筑严重受损 周围的建筑几乎只剩沉重住 来自当地居民的监控显示 居民并未进入防空洞 爆炸产生的气烂果斜的碎片喷用进居民家中 据以色列媒体报导 正美导弹协待了数百公斤炸药 此次习近共造成超过100人数双 其中10亿人伤势严重 但依然没有人员伤亡的报告 内坦尼亚湖当天在其社交媒体账号上发文称 这是一个艰难的夜晚 以君泽表示 以色列的防空系统在习近期间被激活 但未能蓝杰部分导弹 军方将调查此事并从中吸取教训 聚吸迪莫纳是一座戒备森严的城市 因为该城市为以色列合设室所在地 导弹命中地点距离该合设室约12公里 除了迪莫纳副境的阿拉德也出现了类似的破坏景象 一枚淡到导弹几重该市 造成多动建筑物受損 至少84人数伤 其中10人伤势严重 以色列紧急运输直升机和救护车 持续将商员送往当地医院 贝尔泄霸的索罗坎医院因商员人数增加 宣布进入紧急状态 伊朗伊斯兰革命会队发言人称 打击以色列迪莫纳是对以色列空袭伊朗合设室的回忆 当天晚上大量人群勇上德黑兰的瓦列阿斯尔广场 慶祝革命会队对迪莫纳的打击 高湖革命会队航空航天部队指挥官的名字 并呼吁再次打击",
"start_index": 1647,
"end_index": 2909
},
{
"title": "真主党同步打击与欧洲对伊朗导弹射程的担忧",
"content": "与此同时 珍主党也在同步发起攻击 据珍主党当地时间21日晚上发布的声明 其使用火箭弹无人机和短层导弹对以色列北部发动密集打击 视频显示 珍主党一次使用兵堡多管火箭系统 像以色列北部多地发射火箭弹 后续据以色列方面发布的视频 火箭弹对以色列北部城镇麻阿洛特·塔尔西的建筑 造成严重破坏 至少5人被淡片激重受伤 此外火箭弹还激重了北部城市萨瓦德 造成一条道路和附近建筑轻微损坏 自从华尔街日报报到伊朗使用中城导弹攻击迭格加西亚基地后 引起了欧洲的恐慌 因为迭格加西亚基地距离伊朗近4000公里 这意味着伊朗的导弹涉成接近4000公里 只有冰导阿尔兰和葡萄牙三个欧洲国家 不在伊朗导弹的涉成范围内 以军也在21日继续天游加促 发布声明称 他们探责到了伊朗首次向印度洋发射了一枚远程导弹 其社城接近4000公里 这将对欧洲、亚洲和非洲等数十个国家构成威胁 不过剧土耳其阿纳多鲁通讯社报导 伊朗对印度洋迭格加西亚军事基地的导弹袭击不复有责任 也不是幕后黑手",
"start_index": 2910,
"end_index": 3493
},
{
"title": "美伊政治博弈与红海封锁态势",
"content": "眼看霍尔木茲海峡迟实为开放游价还是下不来 懂王极了再次在社交媒体上警告伊朗 如果伊朗在48小时内不完全开放霍尔木茲海峡 所有发电站首先摧毁其最大发电站 同时他还表示美国已经把伊朗从地图上抹去了 他们的领导层垮台了海军和空军都完蛋了 他们完全没有防御能力去还想跟我做交易 门都没有 伊朗伊斯兰革命维对则回应程 如果美国敢炸伊朗的发电站 那中东地区所有的能源设施信息技术系统 以及海水淡化场设施都将被摧毁 与此同时据中东观察加报导 狐赛武装称其随时代命 一旦局势继续升级 湾德海峡将被确保封锁 报道称霍尔沐资海峡被封锁后 沙特斯海弯主要产游国中 唯一能大规模将持有改造至红海 严补港出口的国家 此举成为其能源逼计划 但仅能部分环节供应冲击 无法替代霍尔沐资海峡 如果红海和湾德海峡也被呼撒武装封锁 那争究一滴游都运不出去了 此外在红海增加了数捉的福特号终于离开了红海 民用卫星拍摄的图像显示福特号航母边对正在通过苏伊氏运河进入地中海 包括福特号三搜区族建以及一搜补几件",
"start_index": 3494,
"end_index": 4107
}
],
"actual_segment_count": 6,
"version": "1.0"
}
Binary file not shown.
+4
View File
@@ -62,6 +62,10 @@ class KBSettings(BaseSettings):
overwrite_archives: bool = Field(
default=False, description="覆盖已存在的归档文件(非交互模式)"
)
enable_semantic_segmentation: bool = Field(
default=True,
description="启用 LLM 语义分段(默认启用)"
)
@lru_cache
+119 -19
View File
@@ -17,7 +17,7 @@ import json
import logging
from datetime import datetime
from pathlib import Path
from typing import Dict, Any, List, Optional
from typing import Dict, Any, List, Optional, Union
from kb_workflow.pipeline.config import get_settings
from kb_workflow.pipeline.processors.base import BaseProcessor
@@ -48,19 +48,70 @@ class SRTProcessor(BaseProcessor):
def __init__(
self,
state_manager: Optional[WorkflowStateManager] = None,
enable_correction: bool = True
enable_correction: bool = True,
enable_semantic_segmentation: Optional[bool] = None,
enable_cache: bool = True
):
"""初始化 SRT 处理器
Args:
state_manager: 状态管理器
enable_correction: 是否启用 ASR 纠错(默认 True)
enable_semantic_segmentation: 是否启用 LLM 语义分段(None 时从配置读取)
enable_cache: 是否启用缓存(默认 True,仅在启用语义分段时有效)
"""
super().__init__(state_manager)
# 如果未明确指定,从配置读取
if enable_semantic_segmentation is None:
settings = get_settings()
enable_semantic_segmentation = settings.enable_semantic_segmentation
logger.info(
f"SRTProcessor using config: "
f"semantic_segmentation={'enabled' if enable_semantic_segmentation else 'disabled'}"
)
elif enable_semantic_segmentation:
logger.info("SRTProcessor using explicit parameter: semantic_segmentation=enabled")
else:
logger.info("SRTProcessor using explicit parameter: semantic_segmentation=disabled")
self.enable_correction = enable_correction
self.segmenter = SemanticSegmenter()
self.enable_semantic_segmentation = enable_semantic_segmentation
self.segmenter = None
self.corrector = None
# 初始化分段器
if enable_semantic_segmentation:
try:
from kb_workflow.srt.semantic_engine import SemanticSegmentationEngine
from kb_workflow.srt.semantic_engine import UnifiedSegmentationStrategy
from kb_workflow.deep_analyzer import SimpleAIClient
# 创建 AI 客户端
ai_client = SimpleAIClient()
if ai_client.api_key:
# 初始化缓存
cache = None
if enable_cache:
from kb_workflow.srt.cache import SemanticCache
cache = SemanticCache()
# 创建统一策略,传入 AI 客户端和缓存
strategy = UnifiedSegmentationStrategy(
ai_client=ai_client,
cache=cache
)
self.segmenter = SemanticSegmentationEngine(strategy=strategy)
logger.info(f"Semantic segmentation enabled (cache={'enabled' if cache else 'disabled'})")
else:
logger.info("AI API key not configured, using rule-based segmenter")
self.segmenter = SemanticSegmenter()
except Exception as e:
logger.warning(f"Failed to initialize semantic engine: {e}, using rule-based segmenter")
self.segmenter = SemanticSegmenter()
else:
self.segmenter = SemanticSegmenter()
# 延迟初始化纠错器
if enable_correction:
try:
@@ -102,27 +153,53 @@ class SRTProcessor(BaseProcessor):
segments = parse_srt_file(Path(input_data.srt_file))
logger.info(f"Parsed {len(segments)} segments")
# Step 2: 语义分段
# Step 2: 加载元数据(需要在分段之前加载,因为 LLM 分段需要元数据)
metadata = self._load_metadata(input_data.metadata_file)
# Step 3: 语义分段
logger.info("Segmenting subtitles into paragraphs")
paragraphs = self.segmenter.segment(segments)
if self.enable_semantic_segmentation:
# 使用 LLM 语义分段
from kb_workflow.srt.semantic_engine import SemanticSegmentationEngine
if isinstance(self.segmenter, SemanticSegmentationEngine):
# 返回 VideoSegment 列表(包含标题)
paragraphs = self.segmenter.segment(segments, metadata=metadata)
else:
# 规则分段返回纯文本列表
paragraphs = self.segmenter.segment(segments)
else:
# 规则分段返回纯文本列表
paragraphs = self.segmenter.segment(segments)
logger.info(f"Generated {len(paragraphs)} paragraphs")
# Step 3: ASR 纠错(可选)
# Step 4: ASR 纠错(可选)
corrected = False
if self.corrector and paragraphs:
logger.info("Applying ASR correction")
corrected_paragraphs = []
for para in paragraphs:
corrected_para = self.corrector.correct(para)
# 处理 VideoSegment 或纯文本
if hasattr(para, 'content'):
# VideoSegment 对象
content = para.content
corrected_content = self.corrector.correct(content)
# 创建新的 VideoSegment 对象(假设不可变)
from kb_workflow.srt.semantic_engine import VideoSegment
corrected_para = VideoSegment(
title=para.title,
content=corrected_content,
start_index=para.start_index,
end_index=para.end_index
)
else:
# 纯文本
corrected_para = self.corrector.correct(para)
corrected_paragraphs.append(corrected_para)
if corrected_para != para:
corrected = True
paragraphs = corrected_paragraphs
logger.info(f"ASR correction applied: {corrected}")
# Step 4: 加载元数据
metadata = self._load_metadata(input_data.metadata_file)
# Step 5: 生成 Markdown
logger.info(f"Generating Markdown: {input_data.output_file}")
tags = self._extract_tags(paragraphs)
@@ -133,6 +210,12 @@ class SRTProcessor(BaseProcessor):
tags=tags
)
# 转换 VideoSegment 为纯文本(用于 SRTOutput)
if paragraphs and hasattr(paragraphs[0], 'content'):
paragraphs_text = [para.content if hasattr(para, 'content') else para for para in paragraphs]
else:
paragraphs_text = paragraphs
# 记录完成状态
if self.state_manager:
state = self.state_manager.load()
@@ -144,7 +227,7 @@ class SRTProcessor(BaseProcessor):
return SRTOutput(
success=True,
output_file=str(input_data.output_file),
paragraphs=paragraphs,
paragraphs=paragraphs_text,
tags=tags,
corrected=corrected
)
@@ -190,14 +273,14 @@ class SRTProcessor(BaseProcessor):
return raw_metadata
def _extract_tags(self, paragraphs: List[str]) -> List[str]:
def _extract_tags(self, paragraphs: Union[List[str], List[Any]]) -> List[str]:
"""从段落中提取标签
简单实现:不使用 LLM,只返回默认标签。
未来可以增强为 LLM 提取。
Args:
paragraphs: 段落列表
paragraphs: 段落列表(可以是纯文本或 VideoSegment 对象)
Returns:
标签列表
@@ -210,7 +293,7 @@ class SRTProcessor(BaseProcessor):
self,
output_file: Path,
metadata: Dict[str, Any],
paragraphs: List[str],
paragraphs: Union[List[str], List[Any]], # List[str] 或 List[VideoSegment]
tags: List[str]
) -> None:
"""生成 Markdown 文件
@@ -230,12 +313,29 @@ class SRTProcessor(BaseProcessor):
# 构建内容
content_parts = [frontmatter, ""]
# 直接添加内容,不生成摘要部分
content_parts.append("## 内容")
content_parts.append("")
for para in paragraphs:
content_parts.append(para)
# 检查是否是 VideoSegment 类型(LLM 分段结果)
from kb_workflow.srt.semantic_engine import VideoSegment
is_semantic_segmentation = (
paragraphs and
hasattr(paragraphs[0], 'title') and
hasattr(paragraphs[0], 'content')
)
if is_semantic_segmentation:
# LLM 语义分段:包含标题和内容
for seg in paragraphs:
if seg.title:
content_parts.append(f"## {seg.title}")
content_parts.append("")
content_parts.append(seg.content)
content_parts.append("")
else:
# 规则分段:纯文本
content_parts.append("## 内容")
content_parts.append("")
for para in paragraphs:
content_parts.append(para)
content_parts.append("")
# 写入文件
output_file.write_text('\n'.join(content_parts), encoding='utf-8')
+8
View File
@@ -0,0 +1,8 @@
"""语义分段缓存模块"""
from kb_workflow.srt.cache.semantic_cache import (
SemanticCache,
compute_content_hash
)
__all__ = ['SemanticCache', 'compute_content_hash']
Binary file not shown.
+155
View File
@@ -0,0 +1,155 @@
"""语义分段缓存管理器
使用内容哈希(SHA256)作为缓存键,存储在本地文件系统。
功能:
- 计算内容的 SHA256 哈希作为缓存键
- 缓存 SegmentationResult 到本地文件系统
- 支持版本控制,便于未来格式变更
- 错误容错,缓存失败不影响主流程
"""
from __future__ import annotations
import hashlib
import json
import logging
from pathlib import Path
from typing import Optional
from pydantic import ValidationError
from kb_workflow.srt.semantic_engine import SegmentationResult
logger = logging.getLogger(__name__)
def compute_content_hash(content: str) -> str:
"""计算内容的 SHA256 哈希作为缓存键
Args:
content: 字幕内容
Returns:
SHA256 哈希值(64 字符的十六进制字符串)
Examples:
>>> hash1 = compute_content_hash("相同内容")
>>> hash2 = compute_content_hash("相同内容")
>>> hash1 == hash2
True
>>> len(hash1)
64
"""
return hashlib.sha256(content.encode('utf-8')).hexdigest()
class SemanticCache:
"""语义分段结果缓存管理器
使用内容哈希(SHA256)作为缓存键,存储在本地文件系统。
缓存格式:
- 文件命名: {sha256_hash}.json
- 文件内容: JSON 格式的 SegmentationResult + version 字段
- 缓存 TTL: 永久有效,手动清理
Attributes:
CACHE_VERSION: 缓存格式版本,用于未来兼容性
DEFAULT_CACHE_DIR: 默认缓存目录
Examples:
>>> cache = SemanticCache()
>>> result = cache.get(subtitle_content)
>>> if result is None:
... result = llm_segment(subtitle_content)
... cache.set(subtitle_content, result)
"""
CACHE_VERSION = "1.0"
DEFAULT_CACHE_DIR = Path(".planning/cache/semantic")
def __init__(self, cache_dir: Optional[Path] = None):
"""初始化缓存管理器
Args:
cache_dir: 缓存目录路径,默认为 .planning/cache/semantic/
"""
self.cache_dir = cache_dir or self.DEFAULT_CACHE_DIR
self.logger = logging.getLogger(__name__)
def get(self, content: str) -> Optional[SegmentationResult]:
"""从缓存读取分段结果
Args:
content: 字幕内容
Returns:
缓存的 SegmentationResult,如果不存在或读取失败则返回 None
Examples:
>>> cache = SemanticCache()
>>> result = cache.get("字幕内容")
>>> if result:
... print(f"从缓存读取: {result.video_type}")
"""
cache_key = compute_content_hash(content)
cache_file = self.cache_dir / f"{cache_key}.json"
if not cache_file.exists():
self.logger.debug(f"Cache miss: {cache_key}")
return None
try:
data = json.loads(cache_file.read_text(encoding='utf-8'))
# 验证版本
if data.get('version') != self.CACHE_VERSION:
self.logger.warning(
f"Cache version mismatch: {data.get('version')} != {self.CACHE_VERSION}"
)
return None
# 移除 version 字段,转换为 SegmentationResult
data.pop('version', None)
result = SegmentationResult(**data)
self.logger.debug(f"Cache hit: {cache_key}")
return result
except (json.JSONDecodeError, IOError, ValidationError) as e:
self.logger.warning(f"Failed to load cache: {e}")
return None
def set(self, content: str, result: SegmentationResult) -> None:
"""保存分段结果到缓存
Args:
content: 字幕内容
result: 分段结果
Examples:
>>> cache = SemanticCache()
>>> result = SegmentationResult(video_type="知识类", segments=[], actual_segment_count=0)
>>> cache.set("字幕内容", result)
"""
cache_key = compute_content_hash(content)
cache_file = self.cache_dir / f"{cache_key}.json"
try:
# 确保目录存在
self.cache_dir.mkdir(parents=True, exist_ok=True)
# 序列化为 JSON,添加 version 字段
data = result.model_dump()
data['version'] = self.CACHE_VERSION
cache_file.write_text(
json.dumps(data, ensure_ascii=False, indent=2),
encoding='utf-8'
)
self.logger.debug(f"Cache saved: {cache_key}")
except IOError as e:
self.logger.warning(f"Failed to save cache: {e}")
+853
View File
@@ -0,0 +1,853 @@
"""语义分段引擎
使用 LLM 实现智能视频字幕语义分段。
功能:
- 视频类型识别(知识类/故事类/访谈类/新闻类/vlog 等)
- 语义边界检测
- 内容完整性保护
- 主题标题生成
- 可扩展的分段策略架构
"""
from __future__ import annotations
import json
import logging
import re
from typing import List, Optional, Protocol
import requests.exceptions
from pydantic import BaseModel, Field, field_validator, ValidationError
logger = logging.getLogger(__name__)
# ============================================================================
# AI Client Protocol
# ============================================================================
class AIClientProtocol(Protocol):
"""AI 客户端协议(与 ASRCorrector 保持一致)"""
def generate(self, prompt: str, max_tokens: int = 16000,
disable_reasoning: bool = False) -> str:
"""生成文本"""
...
# ============================================================================
# Segmentation Strategy Pattern (Plan 13-06)
# ============================================================================
class SegmentationStrategy(Protocol):
"""分段策略接口
定义了分段策略的通用接口,支持未来扩展不同的分段策略。
Examples:
>>> strategy = UnifiedSegmentationStrategy()
>>> segments = strategy.segment(subtitle_segments, metadata)
Note:
遵守用户决策:Phase 13 实现统一策略,不区分视频类型。
"""
def segment(
self,
segments: List,
metadata: dict
) -> List[Union[str, 'VideoSegment']]:
"""对字幕分段进行语义分段
Args:
segments: 字幕分段列表(来自 parser.py 的 Segment 对象)
metadata: 视频元数据(title, duration 等)
Returns:
分段列表(可以是纯文本列表或 VideoSegment 对象列表)
"""
...
class UnifiedSegmentationStrategy:
"""统一分段策略
适用于所有视频类型(知识类、故事类、访谈类等)。
视频类型仅用于 Prompt 上下文,不改变分段策略。
遵守用户决策:无类型区分,使用统一 Prompt。
Attributes:
ai_client: AI 客户端(实现 AIClientProtocol)
"""
def __init__(
self,
ai_client: Optional[AIClientProtocol] = None,
fallback_segmenter: Optional['SemanticSegmenter'] = None,
cache: Optional['SemanticCache'] = None
):
"""初始化统一分段策略
Args:
ai_client: AI 客户端实例,如果为 None 则尝试创建 SimpleAIClient
fallback_segmenter: 已弃用,保留仅为向后兼容
cache: 缓存管理器,如果为 None 则不使用缓存
"""
self.ai_client = ai_client
self.fallback_segmenter = fallback_segmenter
self.cache = cache
# Lazy AI Client 初始化(与 ASRCorrector 相同模式)
if self.ai_client is None:
try:
from kb_workflow.deep_analyzer import SimpleAIClient
self.ai_client = SimpleAIClient()
if not self.ai_client.api_key:
logger.info("AI API key not configured")
self.ai_client = None
except Exception as e:
logger.warning(f"Failed to initialize AI client: {e}")
self.ai_client = None
@staticmethod
def _is_recoverable_error(error: Exception) -> bool:
"""判断错误是否可恢复
可恢复错误:网络错误、超时、限流、服务器错误(500/502/503/504)、
JSON 解析错误(JSONDecodeError, 非 ValidationError 的 ValueError)
不可恢复错误:其他 HTTP 错误(4xx)
注意:Pydantic ValidationError(如标题超长)现在被视为可恢复错误,
因为这是LLM生成内容的问题,应该允许重试。
Args:
error: 异常对象
Returns:
True 如果错误可恢复,False 否则
"""
# 注意:ValidationError 现在被视为可恢复错误
# 因为这可能是LLM偶然生成的内容问题,重试可能解决
# 网络层错误(可恢复)
if isinstance(error, requests.exceptions.ConnectionError):
return True
if isinstance(error, requests.exceptions.Timeout):
return True
# JSON 解析错误(可恢复 - 可能是 LLM 输出格式问题)
if isinstance(error, (json.JSONDecodeError, ValueError)):
return True
# HTTP 错误(根据状态码判断)
if isinstance(error, requests.exceptions.HTTPError):
status_code = error.response.status_code if hasattr(error, 'response') and error.response else None
if status_code in (429, 500, 502, 503, 504):
return True
# 其他 4xx 错误不可恢复
return False
# 其他错误不可恢复
return False
def segment(
self,
segments: List,
metadata: dict
) -> List['VideoSegment']:
"""对字幕分段进行语义分段
使用统一的 LLM Prompt 进行语义分段,不区分视频类型。
视频类型仅用于 Prompt 上下文。
Args:
segments: 字幕分段列表(来自 parser.py 的 Segment 对象)
metadata: 视频元数据(title, duration 等)
Returns:
VideoSegment 对象列表(包含标题和内容)
"""
# AI 不可用,直接报错
if self.ai_client is None:
raise RuntimeError(
"AI客户端未配置,无法进行LLM语义分段。请检查AI_API_KEY环境变量。"
)
# 合并字幕文本
content = " ".join(seg.text for seg in segments)
# 检查缓存(Plan 14-05: 缓存集成)
if self.cache is not None:
cached_result = self.cache.get(content)
if cached_result is not None:
logger.info("Using cached segmentation result")
return cached_result.segments
# 检查是否需要分块(Plan 14-04: 分块阈值 5000 字符)
if len(content) <= 5000:
# 短文本直接处理
video_segments = self._segment_single_chunk(content, metadata, segments)
else:
# 长文本分块处理
video_segments = self._segment_multiple_chunks(content, metadata, segments)
# 保存到缓存(Plan 14-05: 缓存结果)
if self.cache is not None:
# 构建完整的 SegmentationResult
result = SegmentationResult(
video_type=self._infer_video_type(metadata),
segments=video_segments,
actual_segment_count=len(video_segments)
)
self.cache.set(content, result)
logger.debug("Saved segmentation result to cache")
return video_segments
def _build_prompt(self, content: str, metadata: dict) -> str:
"""构建语义分段 Prompt
Args:
content: 字幕内容
metadata: 视频元数据
Returns:
构建好的 Prompt 字符串
"""
# 推断视频类型
video_type = self._infer_video_type(metadata)
title = metadata.get("title", "") or ""
# 构建 Prompt
total_chars = len(content)
prompt = f"""你是一个专业的视频内容分析师。请将以下字幕内容按语义分段。
【视频信息】
类型:{video_type}
标题:{title}
总字数:{total_chars}字
【字幕内容】
{content}
【分段要求】
1. 建议将内容分为 5-8 个段落(可根据语义完整性灵活调整)
2. 每个段落约 1000-2000 字(为保持语义完整性可以突破此范围)
3. 在话题转换处创建新分段,不要混入不同话题的内容
4. **重要**:保持句子完整性,分段边界应放在自然停顿处(句号。、问号?、感叹号!、省略号……等标点符号后)
- 基于语义停顿判断,不仅依赖标点符号
- 保持内容的连贯性和可读性
5. 保持论点完整性,不要在前提-结论结构中间截断
6. 为主题/章节类型的分段生成简洁标题(最多30字),论点/观点类型分段不加标题
7. **广告识别**:识别UP主的广告植入内容(包括但不限于"转转""京东""得物""淘宝""拼多多"等电商平台推广,以及其他明显的商业推广内容)
- 将广告内容单独分为一个段落
- 广告段落的 title 必须设为"广告"或"推广"
- 不要将广告内容混入正常内容段落中
【输出格式】
必须返回以下 JSON 格式(不要添加任何额外文本):
```json
{{
"video_type": "{video_type}",
"segments": [
{{
"title": "分段标题(如果此分段不需要标题则设为 null)",
"content": "分段内容",
"start_index": 0,
"end_index": 123
}}
],
"actual_segment_count": 6
}}
```
【注意事项】
- 优先保证语义完整性,不要为了凑数而强行截断
- 标题应简洁准确,如「机器学习概述」「梯度下降原理」
- 如果某个分段无法生成合适的标题(如过渡性内容),将 title 设为 null
- **广告识别提示**:常见的广告植入特征包括:
* 突然话题转换到商品推荐
* 提及"回收""卖""优惠""下单"等电商相关词汇
* 提及具体品牌名称(如转转、京东、得物等)
* 说话风格明显变化(如口语化的推销语气)
* 内容与视频主题无关的商品推荐"""
return prompt
def _infer_video_type(self, metadata: dict) -> str:
"""从元数据推断视频类型
Args:
metadata: 视频元数据,包含 title, category, tags 等字段
Returns:
推断出的视频类型,默认为"知识类"
Examples:
>>> strategy = UnifiedSegmentationStrategy()
>>> strategy._infer_video_type({"title": "Python教程"})
'知识类'
>>> strategy._infer_video_type({"category": "影视"})
'故事类'
"""
if not metadata:
return DEFAULT_VIDEO_TYPE
# 提取所有文本字段
title = metadata.get("title", "") or ""
category = metadata.get("category", "") or ""
tags = metadata.get("tags", []) or []
description = metadata.get("description", "") or ""
# 合并所有文本用于匹配
all_text = " ".join([title, category, description] + list(tags))
# 如果没有有效文本,返回默认类型
if not all_text or all_text.isspace():
return DEFAULT_VIDEO_TYPE
# 按优先级匹配类型关键词
for video_type, keywords in VIDEO_TYPE_KEYWORDS.items():
for keyword in keywords:
if keyword in all_text:
logger.debug(
f"Detected video type '{video_type}' "
f"from keyword '{keyword}'"
)
return video_type
# 未匹配到任何类型,返回默认
logger.debug("No specific video type detected, using default")
return DEFAULT_VIDEO_TYPE
def _parse_result(
self,
llm_output: str,
fallback_segments: List
) -> List[VideoSegment]:
"""解析 LLM 输出并验证
Args:
llm_output: LLM 原始输出
fallback_segments: 已弃用参数,保留仅为向后兼容
Returns:
VideoSegment 对象列表
Raises:
json.JSONDecodeError: JSON 解析失败
ValueError: 无法提取 JSON
ValidationError: Pydantic 验证失败
"""
# 提取 JSON
data = extract_json_from_llm_response(llm_output)
# Pydantic 验证
result = SegmentationResult(**data)
logger.info(
f"LLM 分段成功: 类型={result.video_type}, "
f"分段数={result.actual_segment_count}"
)
return result.segments
def _segment_single_chunk(
self,
content: str,
metadata: dict,
fallback_segments: List
) -> List[VideoSegment]:
"""处理单个文本块(不分块)
Args:
content: 字幕内容
metadata: 视频元数据
fallback_segments: 降级时使用的原始分段
Returns:
VideoSegment 对象列表
"""
# 构建 Prompt
prompt = self._build_prompt(content=content, metadata=metadata)
# 调用 LLM,带重试逻辑(最多 2 次尝试)
max_attempts = 2
last_error = None
last_llm_output = None
for attempt in range(max_attempts):
try:
llm_output = self.ai_client.generate(
prompt,
max_tokens=8000,
disable_reasoning=True # 分段不需要思考模式
)
# 解析和验证
video_segments = self._parse_result(
llm_output,
fallback_segments=fallback_segments
)
logger.info(f"LLM semantic segmentation: {len(video_segments)} segments")
return video_segments
except Exception as e:
is_recoverable = self._is_recoverable_error(e)
is_last_attempt = (attempt == max_attempts - 1)
# 可恢复错误且不是最后一次尝试:重试
if is_recoverable and not is_last_attempt:
logger.info(
f"LLM call failed (attempt {attempt + 1}/{max_attempts}): "
f"{type(e).__name__}: {e}, retrying..."
)
continue
# 最后一次尝试或不可恢复错误:直接抛出异常
error_type = type(e).__name__
# 为 HTTPError 提取更详细的信息
if isinstance(e, requests.exceptions.HTTPError) and hasattr(e, 'response') and e.response:
status_code = e.response.status_code
response_text = getattr(e.response, 'text', '') or ''
error_msg = f"HTTP {status_code}"
if response_text and isinstance(response_text, str):
error_msg += f" ({response_text[:100]})"
raise RuntimeError(
f"{error_type}: {error_msg}, LLM语义分段失败"
) from e
else:
error_msg = str(e) if str(e) else error_type
raise RuntimeError(
f"{error_type}: {error_msg}, LLM语义分段失败"
) from e
def _segment_multiple_chunks(
self,
content: str,
metadata: dict,
fallback_segments: List
) -> List[VideoSegment]:
"""处理多个文本块(分块)
Args:
content: 字幕内容
metadata: 视频元数据
fallback_segments: 降级时使用的原始分段
Returns:
VideoSegment 对象列表
"""
logger.info(f"Content too long ({len(content)} chars), splitting into chunks")
# 分块
chunks = self._split_into_chunks(content, max_chunk_size=5000)
logger.info(f"Split into {len(chunks)} chunks")
# 处理每个分块
chunk_results = []
for i, (chunk_text, offset) in enumerate(chunks, 1):
logger.info(f"Processing chunk {i}/{len(chunks)} (offset={offset}, length={len(chunk_text)})")
# 构建该分块的 prompt
chunk_metadata = metadata.copy()
chunk_metadata['chunk_info'] = f"第 {i}/{len(chunks)} 块"
prompt = self._build_prompt(content=chunk_text, metadata=chunk_metadata)
try:
# 调用 LLM
llm_output = self.ai_client.generate(prompt, max_tokens=8000, disable_reasoning=True)
segments = self._parse_result(llm_output, fallback_segments=fallback_segments)
chunk_results.append((segments, offset))
logger.info(f"Chunk {i} segmented successfully: {len(segments)} segments")
except Exception as e:
# 分块处理失败,直接抛出异常
raise RuntimeError(
f"分块 {i}/{len(chunks)} LLM语义分段失败: {type(e).__name__}: {e}"
) from e
# 合并结果
return self._merge_segment_results(chunk_results)
def _split_into_chunks(self, text: str, max_chunk_size: int = 5000) -> List[tuple[str, int]]:
"""按句子边界分割文本为多个块
Args:
text: 待分割的文本
max_chunk_size: 每块的最大字符数
Returns:
List of (chunk_text, offset) 元组,offset 是该块在原文中的起始位置
"""
# 按句子分割
sentences = []
current = ""
for char in text:
current += char
if char in '。!?\n':
sentences.append(current)
current = ""
# 添加最后一个不完整的句子
if current:
sentences.append(current)
# 分块
chunks = []
current_chunk = []
current_length = 0
current_offset = 0
for sentence in sentences:
sentence_len = len(sentence)
if current_length + sentence_len > max_chunk_size:
if current_chunk:
chunk_text = ''.join(current_chunk)
chunks.append((chunk_text, current_offset))
current_offset += len(chunk_text)
current_chunk = [sentence]
current_length = sentence_len
else:
current_chunk.append(sentence)
current_length += sentence_len
# 添加最后一个块
if current_chunk:
chunk_text = ''.join(current_chunk)
chunks.append((chunk_text, current_offset))
return chunks
def _merge_segment_results(
self,
chunk_results: List[tuple[List[VideoSegment], int]]
) -> List[VideoSegment]:
"""合并分块的分段结果
Args:
chunk_results: List of (segments, offset) 元组
Returns:
合并后的分段列表,修正 start_index 和 end_index 为相对于原文的位置
"""
all_segments = []
for segments, offset in chunk_results:
for seg in segments:
# 修正索引为相对于原文的位置
corrected_seg = VideoSegment(
title=seg.title,
content=seg.content,
start_index=seg.start_index + offset,
end_index=seg.end_index + offset
)
all_segments.append(corrected_seg)
return all_segments
def _fallback_chunk(self, chunk_text: str, offset: int) -> List[VideoSegment]:
"""对单个分块使用规则分段(已弃用)
此方法已弃用,不再被调用。如被调用将抛出异常。
Args:
chunk_text: 分块文本
offset: 该分块在原文中的起始位置
Returns:
VideoSegment 对象列表
Raises:
RuntimeError: 此方法已弃用
"""
raise RuntimeError("_fallback_chunk 方法已弃用,LLM语义分段失败将直接抛出异常")
# 转换为 VideoSegment,并设置正确的偏移量
segments = []
current_pos = offset
for para in paragraphs:
# 计算该分段在原文中的位置
seg = VideoSegment(
title=None,
content=para,
start_index=current_pos,
end_index=current_pos + len(para)
)
segments.append(seg)
current_pos += len(para)
return segments
# ============================================================================
# Pydantic Models
# ============================================================================
def extract_json_from_llm_response(response: str) -> dict:
"""从 LLM 响应中提取 JSON
处理以下情况:
- 纯 JSON
- 包裹在 ```json ``` 中的 JSON
- 前后包含额外说明文本的 JSON
Args:
response: LLM 响应文本
Returns:
解析后的 JSON 字典
Raises:
ValueError: 无法提取有效 JSON
"""
# 尝试直接解析
try:
return json.loads(response.strip())
except json.JSONDecodeError:
pass
# 尝试提取 ```json ``` 代码块
json_match = re.search(r'```json\s*(.*?)\s*```', response, re.DOTALL)
if json_match:
try:
return json.loads(json_match.group(1))
except json.JSONDecodeError:
pass
# 尝试提取任何 JSON 对象
json_match = re.search(r'\{.*\}', response, re.DOTALL)
if json_match:
try:
return json.loads(json_match.group())
except json.JSONDecodeError as e:
raise ValueError(f"无法从 LLM 响应中提取有效 JSON: {e}")
raise ValueError("LLM 响应中未找到 JSON 内容")
class VideoSegment(BaseModel):
"""视频分段
Attributes:
title: 分段标题(可选)
content: 分段内容(必填)
start_index: 起始字幕索引
end_index: 结束字幕索引
"""
title: Optional[str] = Field(
None,
description="分段标题,简洁描述型(最多30字)"
)
content: str = Field(
...,
description="分段内容,合并后的字幕文本"
)
start_index: int = Field(
...,
ge=0,
description="在原文中的起始字符位置"
)
end_index: int = Field(
...,
ge=0,
description="在原文中的结束字符位置"
)
@field_validator('title')
@classmethod
def validate_title_length(cls, v: Optional[str]) -> Optional[str]:
"""验证标题长度(最多30字)"""
if v is not None and len(v) > 30:
raise ValueError(f"标题长度不能超过30字,当前为{len(v)}字")
return v
model_config = {
"json_schema_extra": {
"examples": [
{
"title": "机器学习概述",
"content": "机器学习是人工智能的一个分支...",
"start_index": 1,
"end_index": 10
}
]
}
}
class SegmentationResult(BaseModel):
"""分段结果
Attributes:
video_type: 视频类型(知识类/故事类/访谈类/新闻类/vlog 等)
segments: 分段列表
actual_segment_count: 实际分段数量
"""
video_type: str = Field(
...,
description="识别出的视频类型"
)
segments: List[VideoSegment] = Field(
default_factory=list,
description="分段列表"
)
actual_segment_count: int = Field(
...,
ge=0,
description="实际分段数量"
)
model_config = {
"json_schema_extra": {
"examples": [
{
"video_type": "知识类",
"segments": [
{
"title": "机器学习概述",
"content": "...",
"start_index": 1,
"end_index": 10
}
],
"actual_segment_count": 5
}
]
}
}
# ============================================================================
# Video Type Detection
# ============================================================================
# 视频类型关键词映射
VIDEO_TYPE_KEYWORDS = {
"知识类": [
"教程", "课程", "教学", "入门", "基础", "进阶", "实战",
"编程", "开发", "技术", "学习", "教育", "培训", "讲座"
],
"故事类": [
"影视", "电影", "电视剧", "动漫", "动画", "小说", "故事",
"剧情", "短片", "纪录片"
],
"访谈类": [
"访谈", "对话", "采访", "专访", "聊天", "脱口秀", "播客"
],
"新闻类": [
"新闻", "报道", "资讯", "时事", "热点", "快讯"
],
"vlog": [
"vlog", "日常", "生活", "旅行", "美食", "探店",
"分享", "体验"
]
}
# 默认视频类型
DEFAULT_VIDEO_TYPE = "知识类"
# ============================================================================
# Semantic Segmentation Engine
# ============================================================================
class SemanticSegmentationEngine:
"""语义分段引擎(使用策略架构)
使用策略模式实现可扩展的分段架构。
Attributes:
strategy: 分段策略(实现 SegmentationStrategy 接口)
Examples:
>>> # 使用默认统一策略
>>> engine = SemanticSegmentationEngine()
>>> paragraphs = engine.segment(segments, metadata)
>>> # 使用自定义策略(未来扩展)
>>> custom_strategy = KnowledgeTypeStrategy()
>>> engine = SemanticSegmentationEngine(strategy=custom_strategy)
>>> paragraphs = engine.segment(segments, metadata)
Note:
Plan 13-06: 实现可扩展策略架构,Phase 13 使用统一策略。
"""
def __init__(
self,
strategy: Optional[SegmentationStrategy] = None,
fallback_segmenter: Optional['SemanticSegmenter'] = None,
cache: Optional['SemanticCache'] = None
):
"""初始化语义分段引擎
Args:
strategy: 分段策略实例,如果为 None 则使用统一策略
fallback_segmenter: 降级时使用的规则分段器(已弃用,保留兼容性)
cache: 缓存管理器
"""
# 默认使用统一策略
if strategy is None:
self.strategy = UnifiedSegmentationStrategy(
fallback_segmenter=fallback_segmenter,
cache=cache
)
else:
self.strategy = strategy
logger.debug(
f"SemanticSegmentationEngine initialized with strategy: "
f"{self.strategy.__class__.__name__}"
)
def _infer_video_type(self, metadata: dict) -> str:
"""从元数据推断视频类型(代理到策略)
Args:
metadata: 视频元数据
Returns:
推断出的视频类型
"""
# 如果策略有 _infer_video_type 方法,使用它
if hasattr(self.strategy, '_infer_video_type'):
return self.strategy._infer_video_type(metadata)
# 否则返回默认类型
return DEFAULT_VIDEO_TYPE
def _build_prompt(self, content: str, metadata: dict) -> str:
"""构建 Prompt(代理到策略)
Args:
content: 字幕内容
metadata: 视频元数据
Returns:
构建好的 Prompt
"""
# 如果策略有 _build_prompt 方法,使用它
if hasattr(self.strategy, '_build_prompt'):
return self.strategy._build_prompt(content, metadata)
# 否则返回基本 prompt
return f"Content: {content}\nMetadata: {metadata}"
def segment(
self,
segments: List,
metadata: dict
) -> List['VideoSegment']:
"""对字幕分段进行语义分段
使用当前配置的策略进行分段。
Args:
segments: 字幕分段列表(来自 parser.py 的 Segment 对象)
metadata: 视频元数据(title, duration 等)
Returns:
VideoSegment 对象列表(包含标题和内容)
"""
return self.strategy.segment(segments, metadata)