项目名称: 智能影记 - Memoria
团队名称: Mnemosyne
时间节点: 2026年5月11日 - 2026年5月17日

一、 本周工作概述:赋予“骨架”以“灵魂”

在实训的前六周,我个人的工作重心一直集中在底层的基建上:瀑布流性能调优、音频节拍解析、以及打通基于 RepaintBoundary 和 MediaCodec 的端侧视频软硬件导出管线。

随着视听链路的彻底闭环,“智能影记”的工程骨架已经搭建完毕。本周,我的任务是从“能用”向“好用”和“好看”进阶。我主要负责了两个全新模块的开发:

  1. 渲染特效引擎扩充:利用 Flutter 原生绘制(CustomPaint / Shader)实现故障风(Glitch)、暗角、胶片噪点等电影级视听特效。

  2. AI 记忆助理:开发全局悬浮的 AI 聊天系统,并赋予其调用本地向量数据库“找图”的能力。

二、 视听特效引擎:基于原生 UI 树的“所见即所得”

在给视频加特效时,常规的做法是在后处理阶段拼写极其冗长复杂的 FFmpeg filter_complex 命令。但我意识到,既然上周我已经打通了通过 RepaintBoundary 抓取屏幕内存像素的管线,那么我完全可以把特效直接写在 Flutter 的 UI 树里! 这不仅能实现“所见即所得”的实时预览,开发效率也远超手写 FFmpeg 滤镜。

1. 赛博朋克:故障风(Glitch Effect)的完美复刻

为了配合高 BPM(如摇滚、电子乐)的强节拍转场,我实现了一个动态的 GlitchEffect。我没有使用第三方库,而是直接模拟了 GLSL Shader 中的色差与画面撕裂逻辑:

// 截取自 glitch_effect.dart 核心逻辑
Widget build(BuildContext context) {
  // 1. 红色通道偏移 (向左移),模拟画面撕裂与色散
  Widget redChannel = Transform.translate(
    offset: Offset(-rgbOffset, 0), // rgbOffset 随音频能量值波动
    child: Opacity(
      opacity: 0.4 * intensity.clamp(0.0, 1.0),
      child: ColorFiltered(
        colorFilter: const ColorFilter.mode(Colors.red, BlendMode.modulate),
        child: child, // 原始图片帧
      ),
    ),
  );

  // 2. 故障条带层 (横向切割错位)
  Widget glitchBand = ClipPath(
    clipper: _GlitchBandClipper(bandTop, bandHeight),
    child: Transform.translate(
      offset: Offset(bandShift, 0),
      child: child, // 撕裂部分依然是原图的高清切片
    ),
  );
  
  return Stack(children: [child, redChannel, glitchBand]);
}

当音乐的 RMS 能量达到峰值时,触发该组件,画面瞬间产生红蓝边缘色散与横向断层,视觉冲击力极强。

2. 电影感静态滤镜

为了让随手拍出的照片在生成的视频中具有“大片质感”,我使用 RadialGradient 叠加 BlendMode 实现了暗角(Vignette)效果,将视觉焦点强制聚拢在画面中央;同时,利用极细微的 Timer 驱动实现了胶片噪点(Film Grain)的随机闪烁,极大提升了视频的整体调色质感。

三、 AI Agent 交互:跨越自然语言与本地 SQL 的桥梁

“智能影记”不仅仅是一个视频剪辑器,它更应该是用户的回忆管家。为此,我本周从零搭建了名为 MemoryAssistantOverlay 的全局悬浮交互系统。

这绝不是一个简单的聊天框,我引入了类似 Agent(智能体)的 Tool-use(工具调用) 机制。

1. System Prompt 劫持与意图识别

我对接了 DeepSeek API,并在 ChatService 中注入了极其苛刻的系统提示词,强制大模型在检测到用户的“寻图意图”时,输出特定格式的 JSON Action:

// 截取自 chat_service.dart
static const String _systemPrompt = '''
你叫 Memoria,是一个极具同理心、文艺且专业的“生活记忆导演”。
[核心工作流]:
1. 如果用户只是闲聊,用像“王家卫电影旁白”一样温暖富有诗意的语言回复。
2. 如果用户的输入表达了寻找照片的意图,你必须在回复的末尾,附加指令:
[ACTION_START] {"search": "核心搜索词"} [ACTION_END]
例如:"我想看海边的照片",回复:"海风总能带走烦恼... [ACTION_START] {"search": "海边, 沙滩"} [ACTION_END]"
''';

2. 前台正则表达式解析与动态 UI 渲染

当 ChatPage 接收到服务器的数据流时,我通过正则表达式拦截 [ACTION_START] 与 [ACTION_END] 之间的内容,并阻止其在 UI 上显示。取而代之的,是触发底层相册的 API 检索:

// 伪代码逻辑:拦截指令并触发本地查询
final match = RegExp(r'\[ACTION_START\](.*?)\[ACTION_END\]').firstMatch(aiResponse);
if (match != null) {
  final jsonStr = match.group(1)!;
  final searchKeyword = jsonDecode(jsonStr)['search'];
  
  // 触发底层的本地相册查询
  final matchedPhotos = await photoService.searchLocalDatabase(searchKeyword);
  
  // 将找到的照片路径注入到当前的消息实体中
  currentMessage.relatedPhotoPaths = matchedPhotos.map((p) => p.path).toList();
}

3. Isar 持久化与相册混合流展示

为了让这种体验更加完美,我修改了 ChatMessage 数据实体,在对话记录中增加了 List? relatedPhotoPaths 字段。得益于 Isar 数据库的支持,用户的每一段闲聊,以及 AI 为用户翻找出的本地照片记录,都被永久且安全地固化在了本地。

现在,用户点开悬浮球,不仅可以得到一段充满情绪价值的文字安慰,AI 还会直接在对话流中把相关的旧照片以圆角卡片的形式呈现出来。这才是“智能影记”的终极形态。

四、 本周总结与后续展望

本周是产品体验发生质变的一周。将炫酷的 Shader 动效挂载到视频渲染管线,让成片质量有了肉眼可见的提升;而具备 Tool-use 能力的 AI 聊天助手,则让 App 从一个纯工具变成了具有同理心的数字陪伴者。

下周计划:
项目即将进入最后的打磨阶段。接下来我将主要负责:

  • iOS端UI细节适配:虽然底层队友完成了 iOS 的架构移植,但在刘海屏/灵动岛区域仍有部分安全区需要我进行适配。

  • 离屏渲染:继续优化导出体验,将导出流程完全放进后台的 Isolate 中,确保前台聊天与导出的并发流畅性。

  • 整体应用测试:开始进行边界条件(极端分辨率图片、无网环境)的异常抛出与兜底处理。

期待 Memoria 最终的完美绽放!

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐