🔄 卡若AI 同步 2026-02-27 05:21 | 更新:水桥平台对接、运营中枢工作台 | 排除 >20MB: 14 个
This commit is contained in:
@@ -48,6 +48,7 @@ python3 "/Users/karuo/Documents/个人/卡若AI/02_卡人(水)/水桥_平台
|
|||||||
2. 写入前校验标题月份;不匹配拒绝写入。
|
2. 写入前校验标题月份;不匹配拒绝写入。
|
||||||
3. 写入后打开对应月份文档。
|
3. 写入后打开对应月份文档。
|
||||||
4. 默认登记内容包含:目标进度、卡点、下一步、运营登记说明。
|
4. 默认登记内容包含:目标进度、卡点、下一步、运营登记说明。
|
||||||
|
5. **TNTWF 格式**:仅 **W(工作)** 和 **F(反馈)** 有复选框;T(目标)、N(过程)、T(思考) 为纯文本,无勾选框。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -93,7 +93,15 @@ python3 "/Users/karuo/Documents/个人/卡若AI/02_卡人(水)/水桥_平台
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7. 推荐填写模板
|
## 7. TNTWF 格式与复选框规则
|
||||||
|
|
||||||
|
- **T(目标)、N(过程)、T(思考)**:纯文本,无复选框。
|
||||||
|
- **W(工作)、F(反馈)**:任务列表,带复选框,可勾选完成。
|
||||||
|
- 覆盖已有日志:`write_today_0227.py --overwrite` 或脚本支持 `--overwrite` 时使用。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. 推荐填写模板
|
||||||
|
|
||||||
- 今日主题:卡若AI / 接口 / 网站 / 运营报表
|
- 今日主题:卡若AI / 接口 / 网站 / 运营报表
|
||||||
- 完成度:例如 `55%`
|
- 完成度:例如 `55%`
|
||||||
@@ -103,7 +111,7 @@ python3 "/Users/karuo/Documents/个人/卡若AI/02_卡人(水)/水桥_平台
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 8. 故障排查
|
## 9. 故障排查
|
||||||
|
|
||||||
- 提示 Token 失败:先重新执行一次,触发静默刷新
|
- 提示 Token 失败:先重新执行一次,触发静默刷新
|
||||||
- 写入失败(字段校验):缩短单条文本长度后重试
|
- 写入失败(字段校验):缩短单条文本长度后重试
|
||||||
@@ -111,7 +119,7 @@ python3 "/Users/karuo/Documents/个人/卡若AI/02_卡人(水)/水桥_平台
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 9. 关联文件
|
## 10. 关联文件
|
||||||
|
|
||||||
- 子技能:`02_卡人(水)/水桥_平台对接/飞书管理/卡若的飞书日志_SKILL.md`
|
- 子技能:`02_卡人(水)/水桥_平台对接/飞书管理/卡若的飞书日志_SKILL.md`
|
||||||
- 主技能:`02_卡人(水)/水桥_平台对接/飞书管理/SKILL.md`
|
- 主技能:`02_卡人(水)/水桥_平台对接/飞书管理/SKILL.md`
|
||||||
|
|||||||
@@ -204,21 +204,23 @@ def build_blocks(date_str, tasks):
|
|||||||
'style': {'done': False, 'align': 1}}})
|
'style': {'done': False, 'align': 1}}})
|
||||||
blocks.append({'block_type': 2, 'text': {'elements': [{'text_run': {'content': '{'}}], 'style': {}}})
|
blocks.append({'block_type': 2, 'text': {'elements': [{'text_run': {'content': '{'}}], 'style': {}}})
|
||||||
|
|
||||||
# TNTWF格式,标注清楚
|
# TNTWF格式:仅 W(工作) F(反馈) 有复选框,T/N/T 为纯文本
|
||||||
labels = [
|
labels = [
|
||||||
('T', 't_targets', '目标'),
|
('T', 't_targets', '目标', False),
|
||||||
('N', 'n_process', '过程'),
|
('N', 'n_process', '过程', False),
|
||||||
('T', 't_thoughts', '思考'),
|
('T', 't_thoughts', '思考', False),
|
||||||
('W', 'w_work', '工作'),
|
('W', 'w_work', '工作', True),
|
||||||
('F', 'f_feedback', '反馈')
|
('F', 'f_feedback', '反馈', True)
|
||||||
]
|
]
|
||||||
|
for label, key, name, use_todo in labels:
|
||||||
for label, key, name in labels:
|
|
||||||
items = task.get(key, [])
|
items = task.get(key, [])
|
||||||
if items:
|
if items:
|
||||||
blocks.append({'block_type': 2, 'text': {'elements': [{'text_run': {'content': f'{label} ({name})', 'text_element_style': {'bold': True}}}], 'style': {}}})
|
blocks.append({'block_type': 2, 'text': {'elements': [{'text_run': {'content': f'{label} ({name})', 'text_element_style': {'bold': True}}}], 'style': {}}})
|
||||||
for item in items:
|
for item in items:
|
||||||
blocks.append({'block_type': 17, 'todo': {'elements': [{'text_run': {'content': item}}], 'style': {'done': False}}})
|
if use_todo:
|
||||||
|
blocks.append({'block_type': 17, 'todo': {'elements': [{'text_run': {'content': item}}], 'style': {'done': False}}})
|
||||||
|
else:
|
||||||
|
blocks.append({'block_type': 2, 'text': {'elements': [{'text_run': {'content': item}}], 'style': {}}})
|
||||||
|
|
||||||
blocks.append({'block_type': 2, 'text': {'elements': [{'text_run': {'content': '}'}}], 'style': {}}})
|
blocks.append({'block_type': 2, 'text': {'elements': [{'text_run': {'content': '}'}}], 'style': {}}})
|
||||||
blocks.append({'block_type': 2, 'text': {'elements': [{'text_run': {'content': ''}}], 'style': {}}})
|
blocks.append({'block_type': 2, 'text': {'elements': [{'text_run': {'content': ''}}], 'style': {}}})
|
||||||
@@ -246,8 +248,39 @@ def resolve_wiki_token_for_date(date_str, explicit_wiki_token=None):
|
|||||||
return CONFIG['MONTH_WIKI_TOKENS'][month]
|
return CONFIG['MONTH_WIKI_TOKENS'][month]
|
||||||
return CONFIG['WIKI_TOKEN']
|
return CONFIG['WIKI_TOKEN']
|
||||||
|
|
||||||
def write_log(token, date_str=None, tasks=None, wiki_token=None):
|
def _find_date_section_block_ids(blocks, date_str, doc_id):
|
||||||
"""写入日志(倒序插入:新日期在最上面)"""
|
"""找到某日期区块的 block_id 列表(用于覆盖删除)"""
|
||||||
|
date_re = re.compile(r'\d+\s*月\s*\d+\s*日')
|
||||||
|
start_i = None
|
||||||
|
for i, block in enumerate(blocks):
|
||||||
|
for key in ['heading4', 'text']:
|
||||||
|
if key in block:
|
||||||
|
for el in block[key].get('elements', []):
|
||||||
|
c = el.get('text_run', {}).get('content', '')
|
||||||
|
if date_str in c:
|
||||||
|
start_i = i
|
||||||
|
break
|
||||||
|
if start_i is not None:
|
||||||
|
break
|
||||||
|
if start_i is None:
|
||||||
|
return []
|
||||||
|
# 从 start_i 向后收集,直到遇到下一个日期标题
|
||||||
|
ids = []
|
||||||
|
for i in range(start_i, len(blocks)):
|
||||||
|
b = blocks[i]
|
||||||
|
bid = b.get('block_id')
|
||||||
|
if not bid:
|
||||||
|
continue
|
||||||
|
# 若遇下一个日期 heading4,停止
|
||||||
|
if i > start_i and 'heading4' in b:
|
||||||
|
for el in b.get('heading4', {}).get('elements', []):
|
||||||
|
if date_re.search(el.get('text_run', {}).get('content', '')):
|
||||||
|
return ids
|
||||||
|
ids.append(bid)
|
||||||
|
return ids
|
||||||
|
|
||||||
|
def write_log(token, date_str=None, tasks=None, wiki_token=None, overwrite=False):
|
||||||
|
"""写入日志(倒序插入:新日期在最上面);overwrite=True 时先删后写"""
|
||||||
headers = {'Authorization': f'Bearer {token}', 'Content-Type': 'application/json'}
|
headers = {'Authorization': f'Bearer {token}', 'Content-Type': 'application/json'}
|
||||||
|
|
||||||
if not date_str or not tasks:
|
if not date_str or not tasks:
|
||||||
@@ -264,27 +297,58 @@ def write_log(token, date_str=None, tasks=None, wiki_token=None):
|
|||||||
doc_id = node['obj_token']
|
doc_id = node['obj_token']
|
||||||
doc_title = node.get('title', '')
|
doc_title = node.get('title', '')
|
||||||
|
|
||||||
# 防串月:日期月份与文档标题不一致时拒绝写入
|
# 防串月
|
||||||
month = parse_month_from_date_str(date_str)
|
month = parse_month_from_date_str(date_str)
|
||||||
if month and f"{month}月" not in doc_title:
|
if month and f"{month}月" not in doc_title:
|
||||||
print(f"❌ 月份校验失败:{date_str} 不应写入《{doc_title}》")
|
print(f"❌ 月份校验失败:{date_str} 不应写入《{doc_title}》")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# 获取blocks检查日期是否存在
|
|
||||||
r = requests.get(f"https://open.feishu.cn/open-apis/docx/v1/documents/{doc_id}/blocks",
|
r = requests.get(f"https://open.feishu.cn/open-apis/docx/v1/documents/{doc_id}/blocks",
|
||||||
headers=headers, params={'page_size': 500}, timeout=30)
|
headers=headers, params={'document_revision_id': -1, 'page_size': 500}, timeout=30)
|
||||||
blocks = r.json().get('data', {}).get('items', [])
|
blk_data = r.json().get('data', {})
|
||||||
|
blocks = blk_data.get('items', [])
|
||||||
|
|
||||||
# 检查是否已存在
|
# 检查是否已存在
|
||||||
|
exists = False
|
||||||
for block in blocks:
|
for block in blocks:
|
||||||
for key in ['heading4', 'text']:
|
for key in ['heading4', 'text']:
|
||||||
if key in block:
|
if key in block:
|
||||||
for el in block[key].get('elements', []):
|
for el in block[key].get('elements', []):
|
||||||
if 'text_run' in el and date_str in el['text_run'].get('content', ''):
|
if 'text_run' in el and date_str in el['text_run'].get('content', ''):
|
||||||
print(f"✅ {date_str} 日志已存在,无需重复写入")
|
exists = True
|
||||||
return True
|
break
|
||||||
|
if exists:
|
||||||
|
break
|
||||||
|
|
||||||
# 找插入位置(倒序:插入到"本月最重要的任务"标题后,即第一个位置)
|
if exists and overwrite:
|
||||||
|
to_del = _find_date_section_block_ids(blocks, date_str, doc_id)
|
||||||
|
if to_del:
|
||||||
|
try:
|
||||||
|
for i in range(0, len(to_del), 20):
|
||||||
|
batch = to_del[i:i+20]
|
||||||
|
body = {"requests": [{"block_id": bid} for bid in batch]}
|
||||||
|
rd = requests.post(f"https://open.feishu.cn/open-apis/docx/v1/documents/{doc_id}/blocks/batch_delete",
|
||||||
|
headers=headers, json=body, timeout=30)
|
||||||
|
try:
|
||||||
|
j = rd.json()
|
||||||
|
except Exception:
|
||||||
|
j = {}
|
||||||
|
if j.get('code') != 0:
|
||||||
|
print(f"⚠️ 覆盖删除失败: {j.get('msg', rd.text[:80])},请手动删飞书中 {date_str} 后重试")
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
r = requests.get(f"https://open.feishu.cn/open-apis/docx/v1/documents/{doc_id}/blocks",
|
||||||
|
headers=headers, params={'document_revision_id': -1, 'page_size': 500}, timeout=30)
|
||||||
|
blocks = r.json().get('data', {}).get('items', [])
|
||||||
|
exists = False
|
||||||
|
except Exception as e:
|
||||||
|
print(f"⚠️ 覆盖删除异常: {e},请手动删飞书中 {date_str} 后重试")
|
||||||
|
|
||||||
|
if exists:
|
||||||
|
print(f"✅ {date_str} 日志已存在,无需重复写入(可用 --overwrite 覆盖)")
|
||||||
|
return True
|
||||||
|
|
||||||
|
# 找插入位置(倒序:插入到"本月最重要的任务"标题后)
|
||||||
insert_index = 1
|
insert_index = 1
|
||||||
for i, block in enumerate(blocks):
|
for i, block in enumerate(blocks):
|
||||||
if block.get('parent_id') == doc_id and 'heading2' in block:
|
if block.get('parent_id') == doc_id and 'heading2' in block:
|
||||||
|
|||||||
@@ -24,19 +24,19 @@ def build_tasks_0227():
|
|||||||
"events": ["一人公司Agent", "玩值电竞", "重要未完成项", "飞书日志迭代"],
|
"events": ["一人公司Agent", "玩值电竞", "重要未完成项", "飞书日志迭代"],
|
||||||
"quadrant": "重要紧急",
|
"quadrant": "重要紧急",
|
||||||
"t_targets": [
|
"t_targets": [
|
||||||
"一人公司Agent→视频切片/文章/直播/小程序/朋友圈/聚合 (5%)",
|
"一人公司Agent→视频切片/文章/直播/小程序/朋友圈/聚合 (5%) 【自2月17日迭代】",
|
||||||
"玩值电竞→Docker部署与功能推进 (第二) (25%)",
|
"玩值电竞→Docker部署与功能推进 (第二) (25%) 【自2月17日迭代】",
|
||||||
"卡若AI 4项优化→减重+收口+规则+输出+护栏 (执行中)",
|
"卡若AI 4项优化→减重+收口+规则+输出+护栏 (执行中)",
|
||||||
"飞书日志→每日迭代+进度百分比更新 (100%)",
|
"飞书日志→每日迭代+进度百分比更新 (100%)",
|
||||||
],
|
],
|
||||||
"n_process": [
|
"n_process": [
|
||||||
"【一人公司】视频切片分发、文章全网、每日直播、小程序、朋友圈→聚合平台",
|
"【一人公司】视频切片分发、文章全网、每日直播、小程序、朋友圈→聚合平台",
|
||||||
"【玩值电竞】Docker 3001,MongoDB wanzhi_esports,持续迭代",
|
"【玩值电竞】Docker 3001,MongoDB wanzhi_esports,持续迭代",
|
||||||
"【重要未完成】卡若AI优化、书小程序、玉宁直播等持续迭代",
|
"【重要未完成】卡若AI优化、书小程序、玉宁直播等 自2月17日持续迭代",
|
||||||
"【昨日2月26】卡若AI 56%、一场创业实验→永平、GitHub yongpxu-soul",
|
"【昨日2月26】卡若AI 56%、一场创业实验→永平、GitHub yongpxu-soul",
|
||||||
],
|
],
|
||||||
"t_thoughts": [
|
"t_thoughts": [
|
||||||
"一人公司第一、玩值电竞第二;重要未完成项加入今日迭代",
|
"一人公司第一、玩值电竞第二;未完成进度自2月17日迭代至今日",
|
||||||
],
|
],
|
||||||
"w_work": ["一人公司Agent", "玩值电竞", "卡若AI优化", "飞书日志登记"],
|
"w_work": ["一人公司Agent", "玩值电竞", "卡若AI优化", "飞书日志登记"],
|
||||||
"f_feedback": [
|
"f_feedback": [
|
||||||
@@ -50,9 +50,14 @@ def build_tasks_0227():
|
|||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
import argparse
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("--overwrite", action="store_true", help="覆盖已有当日日志")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
date_str = "2月27日"
|
date_str = "2月27日"
|
||||||
print("=" * 50)
|
print("=" * 50)
|
||||||
print(f"📝 写入飞书日志:{date_str}")
|
print(f"📝 写入飞书日志:{date_str}" + (" [覆盖]" if args.overwrite else ""))
|
||||||
print("=" * 50)
|
print("=" * 50)
|
||||||
|
|
||||||
token = get_token_silent()
|
token = get_token_silent()
|
||||||
@@ -62,7 +67,7 @@ def main():
|
|||||||
|
|
||||||
tasks = build_tasks_0227()
|
tasks = build_tasks_0227()
|
||||||
target_wiki_token = resolve_wiki_token_for_date(date_str)
|
target_wiki_token = resolve_wiki_token_for_date(date_str)
|
||||||
ok = write_log(token, date_str, tasks, target_wiki_token)
|
ok = write_log(token, date_str, tasks, target_wiki_token, overwrite=args.overwrite)
|
||||||
if ok:
|
if ok:
|
||||||
open_result(target_wiki_token)
|
open_result(target_wiki_token)
|
||||||
print(f"✅ {date_str} 日志写入成功")
|
print(f"✅ {date_str} 日志写入成功")
|
||||||
|
|||||||
@@ -165,3 +165,4 @@
|
|||||||
| 2026-02-26 00:31:13 | 🔄 卡若AI 同步 2026-02-26 00:31 | 更新:水桥平台对接、运营中枢工作台 | 排除 >20MB: 14 个 |
|
| 2026-02-26 00:31:13 | 🔄 卡若AI 同步 2026-02-26 00:31 | 更新:水桥平台对接、运营中枢工作台 | 排除 >20MB: 14 个 |
|
||||||
| 2026-02-26 00:43:29 | 🔄 卡若AI 同步 2026-02-26 00:43 | 更新:运营中枢工作台 | 排除 >20MB: 14 个 |
|
| 2026-02-26 00:43:29 | 🔄 卡若AI 同步 2026-02-26 00:43 | 更新:运营中枢工作台 | 排除 >20MB: 14 个 |
|
||||||
| 2026-02-26 16:43:05 | 🔄 卡若AI 同步 2026-02-26 16:41 | 更新:金仓、水桥平台对接、卡木、运营中枢工作台 | 排除 >20MB: 14 个 |
|
| 2026-02-26 16:43:05 | 🔄 卡若AI 同步 2026-02-26 16:41 | 更新:金仓、水桥平台对接、卡木、运营中枢工作台 | 排除 >20MB: 14 个 |
|
||||||
|
| 2026-02-27 05:06:58 | 🔄 卡若AI 同步 2026-02-27 05:06 | 更新:水桥平台对接、运营中枢工作台 | 排除 >20MB: 14 个 |
|
||||||
|
|||||||
@@ -168,3 +168,4 @@
|
|||||||
| 2026-02-26 00:31:13 | 成功 | 成功 | 🔄 卡若AI 同步 2026-02-26 00:31 | 更新:水桥平台对接、运营中枢工作台 | 排除 >20MB: 14 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
|
| 2026-02-26 00:31:13 | 成功 | 成功 | 🔄 卡若AI 同步 2026-02-26 00:31 | 更新:水桥平台对接、运营中枢工作台 | 排除 >20MB: 14 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
|
||||||
| 2026-02-26 00:43:29 | 成功 | 成功 | 🔄 卡若AI 同步 2026-02-26 00:43 | 更新:运营中枢工作台 | 排除 >20MB: 14 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
|
| 2026-02-26 00:43:29 | 成功 | 成功 | 🔄 卡若AI 同步 2026-02-26 00:43 | 更新:运营中枢工作台 | 排除 >20MB: 14 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
|
||||||
| 2026-02-26 16:43:05 | 成功 | 成功 | 🔄 卡若AI 同步 2026-02-26 16:41 | 更新:金仓、水桥平台对接、卡木、运营中枢工作台 | 排除 >20MB: 14 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
|
| 2026-02-26 16:43:05 | 成功 | 成功 | 🔄 卡若AI 同步 2026-02-26 16:41 | 更新:金仓、水桥平台对接、卡木、运营中枢工作台 | 排除 >20MB: 14 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
|
||||||
|
| 2026-02-27 05:06:58 | 成功 | 成功 | 🔄 卡若AI 同步 2026-02-27 05:06 | 更新:水桥平台对接、运营中枢工作台 | 排除 >20MB: 14 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
|
||||||
|
|||||||
Reference in New Issue
Block a user