Просмотр исходного кода

fix search_posts overview details

guantao 17 часов назад
Родитель
Сommit
fb0f6415ca
2 измененных файлов с 123 добавлено и 85 удалено
  1. 67 23
      agent/tools/builtin/search.py
  2. 56 62
      examples/plan/xiaocong/analysis.json

+ 67 - 23
agent/tools/builtin/search.py

@@ -14,6 +14,7 @@ import base64
 import io
 import json
 import math
+import textwrap
 from enum import Enum
 from typing import Any, Dict, List, Optional
 
@@ -98,17 +99,33 @@ async def _build_collage(posts: List[Dict[str, Any]]) -> Optional[str]:
     canvas = Image.new("RGB", (canvas_w, canvas_h), BG_COLOR)
     draw = ImageDraw.Draw(canvas)
 
-    # 尝试加载字体
-    try:
-        font_title = ImageFont.truetype("msyh.ttc", 16)
-        font_index = ImageFont.truetype("msyh.ttc", 32)
-    except Exception:
+    # 尝试加载字体(跨平台中文支持)
+    font_title = None
+    font_index = None
+
+    # 按优先级尝试不同平台的中文字体
+    font_candidates = [
+        "msyh.ttc",           # Windows 微软雅黑
+        "simhei.ttf",         # Windows 黑体
+        "simsun.ttc",         # Windows 宋体
+        "/System/Library/Fonts/PingFang.ttc",  # macOS 苹方
+        "/usr/share/fonts/truetype/droid/DroidSansFallbackFull.ttf",  # Linux
+        "/usr/share/fonts/truetype/wqy/wqy-microhei.ttc",  # Linux WenQuanYi
+        "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc",  # Linux Noto
+    ]
+
+    for font_path in font_candidates:
         try:
-            font_title = ImageFont.truetype("arial.ttf", 16)
-            font_index = ImageFont.truetype("arial.ttf", 32)
+            font_title = ImageFont.truetype(font_path, 16)
+            font_index = ImageFont.truetype(font_path, 32)
+            break
         except Exception:
-            font_title = ImageFont.load_default()
-            font_index = font_title
+            continue
+
+    # 如果都失败,使用默认字体(可能不支持中文)
+    if not font_title:
+        font_title = ImageFont.load_default()
+        font_index = font_title
 
     for item, img in valid:
         idx = item["index"]
@@ -117,22 +134,47 @@ async def _build_collage(posts: List[Dict[str, Any]]) -> Optional[str]:
         x = PADDING + col * cell_w
         y = PADDING + row * cell_h
 
-        # 缩放封面图
-        thumb = img.resize((THUMB_WIDTH, THUMB_HEIGHT), Image.LANCZOS)
-        canvas.paste(thumb, (x, y))
-
-        # 左上角写序号(带背景)
-        index_text = f" {idx} "
+        # 等比缩放封面图,保持原始比例,居中放置
+        scale = min(THUMB_WIDTH / img.width, THUMB_HEIGHT / img.height)
+        new_w = int(img.width * scale)
+        new_h = int(img.height * scale)
+        thumb = img.resize((new_w, new_h), Image.LANCZOS)
+        offset_x = x + (THUMB_WIDTH - new_w) // 2
+        offset_y = y + (THUMB_HEIGHT - new_h) // 2
+        canvas.paste(thumb, (offset_x, offset_y))
+
+        # 左上角写序号(带背景),固定大小,跟随图片位置
+        index_text = str(idx)
+        idx_x = offset_x
+        idx_y = offset_y + 4
+        box_size = 52
+        draw.rectangle([idx_x, idx_y, idx_x + box_size, idx_y + box_size], fill=INDEX_COLOR)
+        # 序号居中绘制
         bbox = draw.textbbox((0, 0), index_text, font=font_index)
         tw, th = bbox[2] - bbox[0], bbox[3] - bbox[1]
-        # 增加背景块的 padding,确保完全覆盖数字
-        pad_x, pad_y = 8, 6
-        draw.rectangle([x, y, x + tw + pad_x * 2, y + th + pad_y * 2], fill=INDEX_COLOR)
-        draw.text((x + pad_x, y + pad_y), index_text, fill=(255, 255, 255), font=font_index)
-
-        # 写标题
-        title_text = _truncate_text(item["title"], max_len=16)
-        draw.text((x, y + THUMB_HEIGHT + 6), title_text, fill=TEXT_COLOR, font=font_title)
+        text_x = idx_x + (box_size - tw) // 2
+        text_y = idx_y + (box_size - th) // 2
+        draw.text((text_x, text_y), index_text, fill=(255, 255, 255), font=font_index)
+
+        # 写标题(完整显示,按像素宽度自动换行)
+        title = item["title"] or ""
+        if title:
+            words = list(title)  # 逐字符拆分,兼容中英文
+            lines = []
+            current_line = ""
+            for ch in words:
+                test_line = current_line + ch
+                bbox_line = draw.textbbox((0, 0), test_line, font=font_title)
+                if bbox_line[2] - bbox_line[0] > THUMB_WIDTH:
+                    if current_line:
+                        lines.append(current_line)
+                    current_line = ch
+                else:
+                    current_line = test_line
+            if current_line:
+                lines.append(current_line)
+            for line_i, line in enumerate(lines):
+                draw.text((x, y + THUMB_HEIGHT + 6 + line_i * 22), line, fill=TEXT_COLOR, font=font_title)
 
     # 转 base64
     buf = io.BytesIO()
@@ -264,6 +306,8 @@ async def search_posts(
                 "title": post.get("title"),
                 "body_text": body[:100] + ("..." if len(body) > 100 else ""),
                 "like_count": post.get("like_count"),
+                "collect_count": post.get("collect_count"),
+                "comment_count": post.get("comment_count"),
                 "channel": post.get("channel"),
                 "link": post.get("link"),
                 "content_type": post.get("content_type"),

+ 56 - 62
examples/plan/xiaocong/analysis.json

@@ -2,99 +2,93 @@
   "category": {
     "name": "AI 知识科普笔记风格海报",
     "traits": [
-      "拟物化笔记本场景呈现(螺旋笔记本框架、边缘纹理、阴影)",
-      "结构化排版与导视(居中堆叠、虚线分隔、层级列表)",
-      "语义化色彩高亮(荧光笔触、彩色字体标记关键术语)",
-      "手绘装饰与卡通图标(星星、花朵、笑脸等涂鸦元素)",
-      "知识可视化图表(将抽象算法逻辑具象化为可视矩阵)",
-      "拟真纸张纹理(带褶皱纹理的信纸、横线笔记本纸张)"
+      "拟真纸张与笔记本实体作为视觉载体",
+      "手绘装饰与卡通图标中和科技主题枯燥感",
+      "结构化排版与导视建立清晰视觉秩序",
+      "语义化色彩高亮建立信息层级",
+      "知识可视化图表将抽象概念具象化"
     ],
     "ai_challenges": [
-      "纸张纹理的真实感还原(褶皱、横线、虚线边框的自然度)",
-      "手绘装饰的自然笔触感(避免过于规整的 AI 生成痕迹)",
-      "文字与背景的融合度(荧光笔触效果、彩色字体的边缘处理)",
-      "立体装饰元素的透视一致性(回形针的立体感、阴影方向)",
-      "知识图表的数据准确性与视觉美观的平衡"
+      "纸张纹理与褶皱的真实感还原(避免塑料感)",
+      "手绘元素的自然笔触与不规则边缘(避免过于规整)",
+      "文字与背景的融合度(避免浮于表面)",
+      "多层元素的空间关系与阴影处理(避免扁平化)",
+      "色彩高亮的透明度与笔触边缘模糊效果"
     ],
-    "reasoning": "基于 index.md 明确这是'AI 知识科普笔记风格海报的解构数据',制作亮点.md 定义了 6 组视觉亮点聚类(3 实质 +3 形式),制作点.md 按权重排序了 3 个核心元素。该品类的核心特征是将数字化知识内容包装在物理笔记本的视觉容器中,通过拟物化设计增强阅读代入感。"
+    "reasoning": "基于制作亮点.md 中 6 组视觉亮点聚类(3 个实质 +3 个形式),以及制作点.md 中权重排序(核心英文单词 87.3、背景 59.2、回形针装饰 48.7),判断该品类为'AI 知识科普笔记风格海报',核心特征是用拟真笔记本场景包装科技知识内容"
   },
   "highlight": [
     {
-      "name": "拟真纸张与笔记本实体",
-      "description": "必须高度还原带褶皱纹理的信纸和螺旋活页笔记本的真实触感,包括纸张的横线纹理、边缘虚线边框、螺旋装订孔的细节,以及纸张因使用产生的自然褶皱和阴影变化。",
-      "reasoning": "这是实质亮点中权重最高的物理基础元素,构成画面的视觉容器。如果纸张纹理过于平滑或规则,会失去'手写笔记'的生活气息,导致整体风格失真。"
+      "name": "拟真纸张纹理与褶皱",
+      "description": "米白色纸张背景(RGB:245,245,235)带有横向浅灰色细线、不规则褶皱和轻微脏污感,模拟真实笔记本纸张的物理质感",
+      "reasoning": "制作亮点中'拟真纸张与笔记本实体'聚类描述强调'真实触感的书写介质',制作点中'背景'权重 59.2 且出现在 3 张图片中,是视觉基础;做不好会导致画面缺乏真实感、一眼假"
     },
     {
       "name": "核心英文单词的视觉突出",
-      "description": "页面中心的大号英文单词必须位于彩色背景块上,字体颜色突出、尺寸明显大于正文,形成视觉焦点。背景块的颜色需与整体色彩体系协调且具有足够的对比度。",
-      "reasoning": "制作点中权重 87.3 的最高优先级元素,是每张图的核心信息载体。如果文字不够突出或背景块融合度差,会导致信息层级混乱,读者无法快速捕捉核心概念。"
+      "description": "页面中心位置的大号英文单词(如'Embedding',约 90-100pt),采用粗体无衬线字体,颜色突出(蓝色 RGB:60,140,220 或黑色),位于彩色背景块或视觉焦点位置",
+      "reasoning": "制作点中'核心英文单词'权重 87.3 为最高,出现在全部 4 张图片的段落中(段落 1.3.3、2.2.2、3.2.2、4.2.2),是每张图的视觉焦点和信息核心"
     },
     {
-      "name": "语义化色彩高亮体系",
-      "description": "模拟学生笔记的荧光笔触和彩色字体,对关键术语进行视觉强调。色彩使用需建立清晰的信息层级(如定义用黄色、公式用蓝色、重点用粉色),且高亮边缘需有自然的笔触过渡。",
-      "reasoning": "形式亮点中的信息导视核心,权重体现在制作点的背景元素(59.2)中。如果色彩高亮过于均匀或缺乏层次,会失去笔记的真实感,降低信息传达效率。"
+      "name": "手绘装饰元素的自然笔触",
+      "description": "星星、花朵、笑脸等手绘涂鸦元素,具有不规则边缘和自然笔触感,颜色柔和(粉色五角星、黄色四角星、四瓣花朵),分布在画面四角作为装饰",
+      "reasoning": "制作亮点中'手绘装饰与卡通图标'聚类描述强调'中和科技主题的枯燥感',在 img_1 中明确出现于左上角和右下角,是营造轻松氛围的关键元素"
     },
     {
-      "name": "手绘装饰与卡通图标的自然分布",
-      "description": "星星、花朵、笑脸及各类卡通小图标需以手绘涂鸦风格散布在画面中,笔触需有自然的不规则感,分布需疏密有致,中和科技主题的枯燥感但不干扰主要内容阅读。",
-      "reasoning": "实质亮点中的氛围调节元素,是区分'模板化设计'与'真实笔记'的关键。如果装饰元素过于规整或分布均匀,会暴露 AI 生成的痕迹。"
+      "name": "结构化排版与层级导视",
+      "description": "居中堆叠的标题层级(主标题→副标题→核心词)、虚线分隔、列表缩进、表格对齐等排版手段,建立严谨清晰的视觉秩序",
+      "reasoning": "制作亮点中'结构化排版与导视'聚类描述强调'将复杂信息拆解为易于消化的模块',在 img_2 中体现为问题标题序号 + 正文 + 表格的层级结构"
     },
     {
-      "name": "知识可视化图表的准确性",
-      "description": "将抽象算法逻辑(如 Embedding 的分词到向量转化)具象化为可视矩阵数据,图表结构需准确反映技术逻辑,同时保持与整体笔记风格的视觉一致性(手写标注、彩色箭头等)。",
-      "reasoning": "实质亮点中的教育解释核心,是内容专业性的体现。如果图表结构错误或视觉风格割裂,会同时损害内容可信度和整体美观度。"
+      "name": "语义化色彩高亮标记",
+      "description": "模拟荧光笔触的彩色标记(如粉色涂抹区域 RGB:255,180,200、蓝色高亮文字#4682B4),用于强调关键术语,边缘模糊具有手绘感",
+      "reasoning": "制作亮点中'语义化色彩高亮'聚类描述强调'建立清晰的信息层级',在 img_1 中体现为'AI 知识点'下方的粉色涂抹,在 img_2 中体现为关键术语的蓝色高亮"
     },
     {
-      "name": "拟物化场景的透视一致性",
-      "description": "螺旋笔记本框架、回形针装饰、纸张阴影需保持统一的透视角度和光源方向。回形针的立体感需通过高光和阴影正确呈现,螺旋装订孔需符合透视变形规律。",
-      "reasoning": "形式亮点中的沉浸感基础,影响整体画面的真实度。如果透视不一致(如回形针阴影方向与纸张阴影矛盾),会产生视觉违和感。"
+      "name": "拟物化装饰元素(回形针/螺旋圈)",
+      "description": "页面边缘的蓝色或黄色回形针形状装饰(具有立体感和阴影),或螺旋笔记本的环形结构边缘,增强场景真实感",
+      "reasoning": "制作点中'回形针装饰'权重 48.7,出现在 img_2、img_3、img_4 中(段落 2.2.1、3.2.1、4.2.1),是营造'实体笔记本'场景感的关键道具"
     }
   ],
   "baseline": [
     {
-      "name": "纸张纹理的基本质感",
-      "description": "背景必须呈现笔记本纸张的基本特征:横线纹理、虚线边框、适当的纸张颜色(米白或淡黄)。不能是纯色背景或过于光滑的数码质感。",
-      "why_critical": "这是笔记风格的物理基础,做不好会直接导致'一眼假'。如果背景是纯色或纹理过于规则,会失去手写笔记的生活气息,整体风格崩塌。",
-      "reasoning": "制作点中'背景'元素权重 59.2,且在 3 张图中都有出现(段落 2.1、3.1、4.1)。index.md 明确将'拟真纸张与笔记本实体'列为首要实质亮点。"
+      "name": "纸张纹理的真实感",
+      "description": "背景必须呈现纸张特有的微纹理、横向细线和自然褶皱,颜色为米白色系,避免纯色或塑料质感",
+      "why_critical": "做不好会导致画面失去'笔记'的核心场景感,看起来像普通 PPT 或海报而非手写笔记,一眼假",
+      "reasoning": "制作点中'背景'权重 59.2 且是全部图片的基础层(段落 1.1、2.1、3.1、4.1),制作亮点中'拟真纸张与笔记本实体'和'拟物化笔记场景呈现'两个聚类都强调物理质感"
     },
     {
-      "name": "核心文字的清晰可读性",
-      "description": "中心英文单词必须清晰可读,字体大小明显大于正文,与背景色块有足够对比度。不能出现文字模糊、颜色融合或尺寸不足的问题。",
-      "why_critical": "这是信息传达的核心载体,权重 87.3 为最高。如果文字不清晰或不够突出,读者无法快速理解核心概念,内容失去教育价值。",
-      "reasoning": "制作点中'核心英文单词'权重最高(87.3),且在 4 张图中都有出现。这是内容功能性的底线要求。"
+      "name": "文字与背景的融合度",
+      "description": "文字必须与纸张背景有适当的融合效果(轻微阴影、透明度调整),避免浮于表面的贴图感",
+      "why_critical": "做不好会导致文字看起来是后期添加的数码字体,破坏'手写笔记'的真实感",
+      "reasoning": "制作表中文字字体多为'手写风格'字体,且与背景纹理共同出现,需要视觉融合;AI 生成常见问题是文字过于清晰锐利"
     },
     {
-      "name": "回形针装饰的基本形态",
-      "description": "页面边缘的蓝色回形针需呈现基本立体形态,有明确的金属质感和阴影。不能是扁平色块或形态扭曲。",
-      "why_critical": "这是增强拟物感的关键装饰元素,权重 48.7。如果回形针过于扁平或形态错误,会破坏整体场景的真实感,暴露 AI 生成痕迹。",
-      "reasoning": "制作点中'回形针装饰'在 3 张图中出现(段落 2.2.1、3.2.1、4.2.1),是拟物化场景的重要组成部分。"
+      "name": "手绘元素的不规则性",
+      "description": "星星、花朵、涂抹区域等手绘元素必须具有不规则边缘和自然变化,避免几何完美和重复图案",
+      "why_critical": "做不好会导致装饰元素看起来像素材库贴图,失去'手绘'的亲切感和真实感",
+      "reasoning": "制作亮点中'手绘装饰与卡通图标'强调'手绘涂鸦元素',制作表中描述'不规则的粉色涂抹区域,边缘模糊,模拟手绘涂抹效果'"
     },
     {
-      "name": "排版结构的基本秩序",
-      "description": "内容需呈现居中堆叠、虚线分隔、层级列表的基本排版秩序。不能出现元素杂乱堆砌、层级混乱或对齐不一致的问题。",
-      "why_critical": "这是信息可读性的基础,对应'结构化排版与导视'亮点。如果排版混乱,会降低阅读体验,损害知识传达效率。",
-      "reasoning": "制作亮点中明确将'结构化排版与导视'列为形式亮点,index.md 提到'严谨清晰的视觉秩序'是该风格的核心特征。"
+      "name": "色彩高亮的透明度与边缘模糊",
+      "description": "荧光笔触效果必须具有半透明感和边缘模糊过渡,模拟真实荧光笔在纸张上的渗透效果",
+      "why_critical": "做不好会导致高亮区域看起来像纯色块填充,失去'荧光笔标记'的真实感",
+      "reasoning": "制作表中'涂抹颜色'描述为'粉色,边缘模糊,模拟手绘涂抹效果',透明度是关键参数"
     },
     {
-      "name": "色彩体系的基本协调",
-      "description": "整体色彩需保持协调,荧光笔触和彩色字体需建立基本层次。不能出现色彩冲突、饱和度过高或层次混乱的问题。",
-      "why_critical": "这是视觉美观的底线,对应'语义化色彩高亮'亮点。如果色彩混乱,会产生视觉疲劳,降低内容专业感。",
-      "reasoning": "制作亮点中'语义化色彩高亮'被定义为建立信息层级的形式手段,是笔记风格的重要特征。"
+      "name": "多层元素的空间关系",
+      "description": "回形针、螺旋圈等装饰元素必须与纸张有正确的遮挡关系和阴影投射,体现前后空间层次",
+      "why_critical": "做不好会导致画面扁平化,失去'实体笔记本'的立体感和场景沉浸感",
+      "reasoning": "制作点中'回形针装饰'描述为'具有立体感',制作亮点中'拟物化笔记场景呈现'强调'边缘纹理和阴影处理'"
     }
   ],
   "requirement_summary": [
-    "【品类定位】AI 知识科普笔记风格海报,需将数字化知识内容包装在物理笔记本的视觉容器中",
-    "【核心亮点 1】拟真纸张纹理:横线、虚线边框、褶皱阴影的自然还原",
-    "【核心亮点 2】核心英文单词:大号字体 + 彩色背景块,形成视觉焦点(权重 87.3)",
-    "【核心亮点 3】语义化色彩高亮:荧光笔触 + 彩色字体建立信息层级",
-    "【核心亮点 4】手绘装饰:星星、花朵、笑脸等涂鸦的自然分布和笔触感",
-    "【核心亮点 5】知识可视化图表:准确反映技术逻辑且保持手写风格",
-    "【核心亮点 6】拟物化透视:螺旋框架、回形针、阴影的透视一致性",
-    "【下限 1】纸张基本质感:不能是纯色或光滑数码背景",
-    "【下限 2】文字清晰可读:核心单词必须突出且清晰",
-    "【下限 3】回形针立体感:不能是扁平色块",
-    "【下限 4】排版秩序:居中堆叠、虚线分隔、层级清晰",
-    "【下限 5】色彩协调:避免冲突和层次混乱",
-    "【AI 挑战】纸张纹理真实感、手绘笔触自然度、文字背景融合度、立体装饰透视一致性、图表准确性与美观平衡"
+    "生成米白色纸张纹理背景(RGB:245,245,235),带有横向浅灰色细线、不规则褶皱和轻微脏污感",
+    "在页面中心位置生成大号英文单词(90-100pt,粗体无衬线字体),颜色突出(蓝色或黑色)",
+    "添加手绘风格的装饰元素(星星、花朵、笑脸),具有不规则边缘和自然笔触感,分布于画面四角",
+    "实现结构化排版:标题层级(主标题→副标题→核心词)居中堆叠,正文左对齐,表格居中对齐",
+    "添加语义化色彩高亮:荧光笔触效果(半透明、边缘模糊)用于强调关键术语",
+    "添加拟物化装饰元素(回形针或螺旋圈),具有立体感和正确阴影,与纸张有遮挡关系",
+    "确保文字与背景融合(轻微阴影、透明度调整),避免浮于表面的贴图感",
+    "所有手绘元素避免几何完美和重复图案,体现自然变化"
   ]
 }