当前位置: 首页 > news >正文

Memoria-智能影记创新实训博客(三):故事生成功能接口实现与界面展示

Memoria-智能影记创新实训博客(三):故事生成功能接口实现与界面展示

博客主题:主线功能的实现
功能时间跨度:2026.04.13 - 2026.04.21(第7-8周)
进度总结:我已经完成并完善了图片打标,语义搜索,故事生成三大主线逻辑与界面实现,外加队友实现的时空聚类、人脸聚类以及整套视频生成流程,该app已经具备了任务书中的约60%的主线需求,后续会继续补齐推荐、数字相册模拟等功能。

1. 目标

和前两篇一样,这套功能仍然不把用户相册原图直接上传给云端大模型。当前实现里,DeepSeek 接收的是时间、地点、标签、OCR、caption 等结构化线索;如果需要直接看图,则优先走本地 VLM。

故事生成要解决的不是给一组图配一段文案,而是把用户挑出的照片整理成一条完整创作链路:

  • 先把照片从相册、语义搜索或聚类结果里选出来,组成一个可调整顺序的故事队列。
  • 再让用户配置主题、文案风格、故事模式、音乐和字幕等生成条件。
  • 按固定编排流程提取时间、地点、标签、OCR、caption 等线索,生成结构化故事并落库。
  • 最后进入结果页,让用户继续编辑文字、预览视频、生成数字相册。

2. 前期工作

故事生成建立在前面的打标与语义搜索能力之上。真正进入故事编排阶段的,是每张图已经沉淀下来的信息:

  • aiTags:提供画面主体和场景线索。
  • aiCaption:提供已有的图片描述。
  • ocrTags / ocrSummary:补充文字型画面内容。
  • 时间与地点:用于组织时间线和空间线索。
  • 语义搜索词:如果用户是从语义搜索结果里选图,原始查询会一起带入故事主题。

3. 选图与故事队列

故事链路的第一步不是写故事,而是先确定“哪些图进入故事”以及“这些图按什么顺序讲”。

当前代码里,照片主要从相册聚类/事件页、语义搜索结果页、创作页手动勾选这三类入口进入故事流程。

故事队列由StoryQueueService统一管理。它做了三件事:

  • 去重:同一张照片不会重复进入队列。
  • 保序:队列顺序默认是后续故事的顺序,用户可以手动拖拽调整。
  • 传上下文:如果照片来自语义搜索,semanticSearchQuery会和照片一起进入后续流程。
finaladdedCount=StoryQueueService().addPhotos(selectedEntities.map(StoryQueueService.mapPhotoEntityToQueuePhoto).toList(growable:false),semanticSearchQuery:_controller.text.trim(),);

队列页里,用户还能查看大图、移除照片、拖动排序、手动改写每张图的描述。这里的“手动描述”会覆盖默认 caption,直接参与后面的故事生成。实际界面展示如下:

4. 配置页:把选图变成生成请求

选图完成后,系统会进入ConfigPage,把用户输入整理成一个StoryGenerationRequest

界面展示如下,从上到下看,配置页实际上有 8 组信息。

这一页虽然选项很多,但逻辑很清楚:上半部分的“核心主题”和“副标题/切入点”决定故事要讲什么、从什么角度讲;中间的“画面比例”“发布平台”“配乐方案”决定结果更适合竖屏还是横屏、偏向哪类平台风格,以及后续视频使用 AI 配乐还是本地音乐;下半部分的“生成故事方式”和“文案模板”决定故事正文是直接基于标签生成,还是先用本地 VLM 补 caption 再交给 DeepSeek,同时控制最终文案更像热门表达、诗歌感、电影旁白还是治愈回忆;最下面的“自动生成视频台词”则继续补齐后续视频字幕。也就是说,这张配置页把“讲什么、怎么讲、讲完怎么展示”三件事都交代完整。

5. 生成主流程

真正的生成工作由StoryGenerationOrchestrator完成。它拆成 8 个步骤推进,界面展示如下:

它会先取出选中的PhotoEntity,如果用户来自故事队列就保留拖拽顺序,否则按时间排序;接着为每张图整理时间、地点、清洗后的aiTagsocrTags / ocrSummary、已有aiCaption和用户手动改写 caption,统一收束成可写作的素材对象。之后进入语义增强阶段:deepseekTags直接基于标签、OCR 和元数据写故事,localCaptionThenDeepseek会先均匀采样最多12张图片,用本地 VLM 补一轮 caption,再交给 DeepSeek 串成完整叙事。真正调用 DeepSeek 时,系统上传的不是原图,而是每张图片对应的结构化 JSON 线索,并要求模型只输出一个 JSON 对象,严格基于事实写作,保证sections数量与图片数量一致、每段只对应一张图,同时生成整篇storyhighlights。如果返回为空、不是合法 JSON,或者正文和分段都无效,系统就回退到本地保底逻辑,利用时间、地点、标签、caption 和亮点摘要拼出一段可用故事,再按图片数均分成多个 section。最后,标准化结果会被写成StoryEntity,其中content采用带![img](index)占位符的 Markdown,连同标题、副标题、图片 ID、画幅方向和发布平台一起入库,供后面的结果页、视频回忆和数字相册继续使用。

6. 结果展示、编辑与二次产出

结果页会先把StoryEntity里的 Markdown 重新解析成StorySection列表,再结合PhotoEntity里的最新图片信息补齐展示数据,形成图文并茂的故事。之后用户可以逐段编辑文字、保存修改、进入“播放回忆”,或者继续生成数字相册。界面展示如下:

7. 视频与后续扩展

故事页不是终点。当前代码在故事生成完成后,还会立即调用StoryVideoPreparationService

  • 生成配乐:如果启用了 AI 配乐,就先让 LLM 写音乐 prompt,再尝试生成音乐;失败时回退到预置音乐。
  • 生成字幕:如果开启自动字幕,就根据故事正文和图片描述生成逐图字幕;失败时回退到故事 section 文本或aiCaption

“故事生成”是后面视频回忆和数字相册的素材中台。

8. 总结

当前项目里的故事生成,已经形成了一条完整创作链路:先选图和排顺序,再配置主题、模式与模板,然后由编排器分步骤提取线索、生成结构化故事、落库保存,最后进入结果编辑、视频回忆和数字相册。

从代码实现看,这条链路最重要的特点有三个:用户可以明确控制素材和顺序;生成不是单次调用,而是完整编排流程;故事结果也不是终态,而是后续视频和数字相册的上游内容资产。

http://www.jsqmd.com/news/690171/

相关文章:

  • 高德地图API本地调试踩坑记:为什么官方demo能跑,我的代码就报错?
  • 突破硬件限制:OpenCore Legacy Patcher如何让2008-2017年Mac重获新生
  • PCA与t-SNE:数据降维可视化的核心技术与应用
  • Harness 中的熔断半开状态探测机制
  • 更强、更轻、更耐热:机器学习正帮我们设计“下一代超级合金”!
  • 世界读书日:华为阅读带读者开启阅读自由!
  • 别再硬编码了!用Unity Timeline+Playable实现GalGame对话系统(附完整项目)
  • VSCode 2026启动速度提升300%:实测验证的5个隐藏配置项与3个插件替代方案
  • centos 上没有安装telnet命令 ,如何测试到1个目标IP的 443端口是否open
  • 量子稳定器模拟器Sdim:高维量子纠错码研究新工具
  • 奥运羽毛球男单奖牌
  • easyRSA - Writeup by AI
  • 百度地图BMapGL鼠标绘制功能避坑指南:从GL版切回经典版的真实案例
  • uni-app弹窗进阶:用Vuex管理全局状态,实现一个支持多按钮回调的showToast
  • LTspice 3.3V 稳压二极管模型
  • 算法训练营第十一天|删除有序数组中的重复项 II
  • 5分钟掌握音乐格式转换:Unlock-Music浏览器解密工具完整指南
  • RAG系列:RAG核心技术原理解析
  • 2026年4月西安老酒回收机构估价能力权威排行盘点:西安剑南春回收,西安名酒回收,西安收老酒,实力盘点! - 优质品牌商家
  • VLC Android电视版和ChromeOS:3大核心优势与完整配置指南
  • Vue3 + wangEditor实战:如何像搭积木一样扩展一个自定义菜单(以“首行缩进”为例)
  • 告别信号模糊:手把手教你理解PCIe 3.0的动态均衡(含FIR滤波器与CTLE/DFE详解)
  • 如何彻底告别审稿焦虑:Elsevier Tracker让你的学术投稿进度一目了然
  • GB/T34944-2017 合规:Java 代码漏洞测试用例编写(附案例)
  • 时间序列预测中基线模型的重要性与实践
  • 解决QT配置Android时“Platfrom tools installed”等顽固错误的实战记录
  • 孕婴护理产品可以怎样来做一物一码防伪溯源呢
  • 沃虎连接器加速寿命测试(ALT)方法与其长期可靠性数据的关联解读
  • 保姆级教程:从零在Ubuntu 22.04 ARM版上配置SuperMap iServer服务并设置开机自启
  • 信息学奥赛刷题笔记:OpenJudge 1481 Maximum sum 的两种DP解法与避坑指南(附C++代码)