修改后端数据库结构:
- photos表移除album_id字段,新增文件名字段、新增照片时间字段
- 文件名默认使用照片上传时的文件名,允许用户在上传后修改文件名
- 照片时间提取:从照片的元数据中提取照片的拍摄时间,存储在照片时间字段中,如果元数据中没有拍摄时间,则默认使用照片上传时的时间
- 新增album_photos表,用于存储照片与相册的多对多关系,一张照片可能对应多个相册,一个相册里面有多张照片
- album_photos表结构:
- id: 主键
- album_id: 相册ID,外键引用albums表
- photo_id: 照片ID,外键引用photos表
- created_at: 创建时间
- photo_metadata表,修改camera_info 为exif_info字段,用于存储照片的相机信息,位置信息包括两种,一种是经纬度,一种是人类可读的地址信息(如城市、街道等,需要从第三方API获取,暂时保留接口后续扩展),把地址信息返回给前端展示
- 修改前后端对应的crud代码和api接口完全对应
修改后端数据库结构的具体实施方案:
photos表结构调整:
- 移除album_id字段
- 新增filename字段:VARCHAR(255),存储照片文件名
- 新增photo_time字段:TIMESTAMP,存储照片拍摄时间
- 实现逻辑:
- 文件名处理:上传时自动填充原始文件名,提供API接口供用户修改
- 照片时间处理:优先从EXIF元数据中提取DateTimeOriginal字段,若无则根据文件名提取时间(格式如20230815_123456,20230815等多种格式),若文件名也没有时间信息,则使用当前系统时间
新增album_photos关联表:
- 表结构:
- id: INT PRIMARY KEY AUTO_INCREMENT
- album_id: INT NOT NULL,外键约束REFERENCES albums(id)
- photo_id: INT NOT NULL,外键约束REFERENCES photos(id)
- created_at: TIMESTAMP DEFAULT CURRENT_TIMESTAMP
- 创建复合唯一索引(album_id, photo_id)防止重复关联
- 表结构:
photo_metadata表修改:
- 重命名camera_info为exif_info:TEXT,存储完整的EXIF元数据
- 新增location字段:JSON,存储结构化的位置信息
- 包含:latitude(浮点数), longitude(浮点数), formatted_address(字符串)
- 保留location_api字段:VARCHAR(255),为后续地址解析API预留
API接口调整:
- 照片相关接口:
- 上传接口:返回包含filename的完整照片信息
- 更新接口:支持修改filename
- 查询接口:返回照片关联的所有相册ID列表
- 相册相关接口:
- 添加/移除照片:操作album_photos表
- 查询相册照片:联合查询photos和album_photos表
- 照片相关接口:
前后端协调:
- 更新API文档和TypeScript类型定义
- 前端需要适配:
- 照片上传流程调整
- 相册管理界面支持多对多关系
- 照片详情页显示EXIF信息和位置数据
将PhotosPage.vue和AlbumDetail.vue中的照片展示功能重构为公共组件模块,实现以下具体优化方案:
组件提取要求:
- 创建名为PhotoGallery.vue的公共组件
- 提取两页面共用的照片展示布局、样式和交互逻辑
- 保留各自页面的特殊业务逻辑差异点
性能优化方案
- 实现虚拟滚动(Virtual Scrolling)技术
- 添加图片懒加载(Lazy Loading)功能
- 采用响应式图片(Responsive Images)方案
- 实现图片预加载(Preloading)策略
- 添加加载状态占位图(Placeholder)
接口设计
- 定义统一的props接口:
- photos:
Array<Photo> (必传) - loading: Boolean
- layoutType: 'grid' | 'masonry' (默认'grid')
- 其他定制化参数
实现步骤
- 分析两页面现有功能差异点
- 抽象公共逻辑到PhotoGallery组件
- 在两页面中替换原有实现
- 添加性能优化功能
- 编写单元测试
质量要求
- 保持原有功能100%兼容
- 首屏加载性能提升30%以上
- 滚动流畅度达到60FPS
- 内存占用减少20%
- 支持无障碍访问
重构PhotosPage.vue和PhotoGallery.vue组件,实现以下功能改进
在批量选择功能中新增"保存到本地"选项
- 添加一个保存按钮或菜单项,点击后可将选中的图片批量下载到用户设备
- 实现文件下载功能,确保支持多文件同时下载
- 添加下载进度提示和完成通知
将批量选择功能迁移到公共组件PhotoGallery.vue:
- 提取PhotosPage.vue中的批量选择相关代码
- 在PhotoGallery.vue中实现通用的批量选择逻辑
- 通过props接收配置参数,通过events触发父组件操作
- 确保样式和交互行为与原有功能一致
修改删除选项动作
- 在全部照片中为删除选项
- 在相册中查看时将"删除"选项改为"从相册中移除"
- 更新相关提示信息和确认对话框文案
技术要求:
- 保持原有功能的完整性和性能
- 确保组件间的数据流清晰
前端新增设置页面,可以设置图片文件夹的位置,新增重建索引选项,扫描文件夹里的所有图片,更新数据库索引 用户上传的图片会被保存到指定的文件夹中,新增的图片会被自动索引到数据库中,新增的图片默认采用原始文件名,按年月组织两层文件夹结构,2025年8月15日上传的图片会被保存到2025/08/原始文件名.jpg,如果文件名重复,会在文件名后添加序号, 用户也可以自己手动往文件夹里复制照片文件,此时不要修改用户自己的文件目录结构,只需要在设置页面中点击重建索引,即可将新增的照片索引到数据库中。 生成中等尺寸和小尺寸的缩略图,缩略图统一保存在thumbnails文件夹中,取uuid的前四位采用两层文件夹结构,例如uuid为1234-5678-90ab-cdef的中等尺寸缩略图会被保存到12/34/1234-5678-90ab-cdef.jpg,小尺寸缩略图会被保存到12/34/1234-5678-90ab-cdef-thumb.jpg
albums表新增cover字段,用于存储相册的封面照片,封面照片默认采用相册中的第一张照片,用户也可以在相册详情页手动设置封面照片。
开发一个完整的前端设置页面,包含以下详细功能实现:
图片存储设置功能
- 提供文件夹路径选择器,允许用户设置图片存储根目录
- 实现路径验证功能,确保用户选择的目录可读写
- 保存路径配置到应用配置中
自动索引功能
- 实现文件监听服务,实时监测指定文件夹的新增文件
- 对于用户上传的图片
- 按照"年/月/原始文件名"的结构自动组织存储
- 处理文件名冲突:自动添加序号(如"filename(1).jpg")
- 记录完整的文件存储路径到数据库
- 对于手动复制到存储路径下的图片或文件夹:保留原始目录结构,仅更新数据库索引
缩略图生成系统:
- 自动生成两种尺寸缩略图:
- 中等尺寸:长边800px,质量80%
- 小尺寸:长边300px,质量75%
- 采用UUID前四位进行两级目录分片存储
- 缩略图命名规范:
- 中等尺寸:
[uuid前2位]/[第3-4位]/[完整uuid].jpg - 小尺寸:
[uuid前2位]/[第3-4位]/[完整uuid]-thumb.jpg
- 中等尺寸:
- 自动生成两种尺寸缩略图:
相册封面管理系统:
- albums表新增cover字段,存储封面照片ID
- 默认逻辑:使用相册中创建时间最早的照片作为封面
- 提供用户界面:
- 在相册详情页显示当前封面
- 允许用户从相册照片中选择新封面
- 保存用户选择到数据库
重建索引功能:
- 在设置页面提供"重建索引"按钮
- 实现全目录扫描功能:
- 递归遍历图片文件夹
- 对比数据库记录,识别新增/删除的图片
- 生成差异报告
- 提供进度显示和完成通知
技术要求:
- 添加操作日志记录所有索引变更
测试要求:
- 验证各种文件名冲突场景的处理
- 测试不同规模文件夹的索引性能
- 验证缩略图生成质量和存储路径正确性
- 测试封面切换功能的稳定性
现有的存储结构是用户可以选择一个文件夹,后端扫描文件夹中的图片,并生成缩略图,缩略图保存在主目录下的thumbnails文件夹中 目标功能:
- 初始化的时候有一个主目录,存储用户上传的图片,缩略图存在主目录下的thumbnails文件夹中
- 用户可以添加若干个其他目录,这些目录下的图片也会被索引到数据库中,缩略图也会保存在主目录下的thumbnails文件夹中
- 移除目录,删除数据库中对应的图片数据及其缩略图 修改代码:
- 完善前后端接口
- 以及前端设置Ui(Setting.vue)
- 实现目录管理UI组件
- 包含目录添加表单、目录列表展示
- 支持目录删除操作确认
- 显示目录扫描状态和图片统计
- 后端代码(indexer.py,settings.py、storage.py)
优化照片显示功能: 新增全部照片数据api,用于获取相册中全部照片的数据,例如照片个数,时间跨度等信息,用于在前端显示相册的统计信息和时间轴,方便直接跳转到某个时间。 后端不再返回给前端完整照片路径,而是返回照片的可访问url,前端根据url显示照片。现在返回的是完整路径,前端无法直接显示,需要修改前端代码。 新增视频的缩略图生成功能,视频的缩略图保存在主目录下的thumbnails文件夹中,命名规则与图片相同。 实现视频的播放功能,用户可以在相册中查看视频,并点击播放按钮播放视频。
优化照片显示功能的具体实现方案如下:
新增相册统计API接口,用于获取相册中全部照片的数据,例如照片个数,时间跨度等信息,用于在前端显示相册的统计信息和时间轴,方便直接跳转到某个时间。
- 返回数据应包括:
- 文件总数
- 时间范围
- 等其他前端需要的数据
- 返回数据应包括:
媒体URL访问改造:
- 修改现有照片获取接口,将返回的完整文件路径改为可公开访问的URL
- 实现媒体访问控制器,处理媒体请求并返回正确的文件流
视频缩略图生成功能:
- 在媒体上传时自动生成视频缩略图
- 实现缩略图生成服务,支持常见视频格式
视频播放功能实现:
- 前端集成视频播放器组件(如video.js)
- 实现播放控制界面,包括:
- 播放/暂停按钮
- 进度条
- 音量控制
- 全屏功能
- 支持移动端触摸控制
前端改造要求:
- 重构媒体显示组件,适配新的URL格式
- 优化媒体加载性能,实现懒加载
- 根据统计信息,提前生成时间轴,可以直接跳转到某个时间点的照片或视频。
性能优化:
- 实现媒体缓存策略
- 优化缩略图生成性能
整理一下前后端api接口:
后端获取相册列表返回的schema中cover改成Photo,前端可以直接渲染封面图 class Album(AlbumBase): id: UUID create_time: datetime
改成Photo结构
cover: Optional[UUID] = None
photos: List[Photo] = [] # Can be heavy if included by default.
class Config: from_attributes = True 前端根据修改结果渲染相册
albums表新增相册类型type字段,用于区分用户相册和条件相册。新增相册中项目个数字段num_photos,用于存储相册中照片的个数。
- 修改相册时,更新num_photos字段。
前端取消conditionalAlbums和userAlbums,只使用从后端返回的albums,前端根据albums渲染相册列表。
优化前后端API接口规范:
- 相册列表接口改进:
- 后端修改Album schema结构:python
class Album(AlbumBase): id: UUID create_time: datetime # 将cover字段类型从UUID改为完整的Photo对象 cover: Optional[Photo] = None type: str # 新增相册类型字段 num_photos: int # 新增照片数量字段 class Config: from_attributes = True - 前端直接使用返回的cover.thumbnail_url渲染相册封面图
- 移除前端原有的conditionalAlbums和userAlbums区分逻辑,统一使用后端返回的albums列表
- 数据库表结构变更:
- albums表新增字段:
- type: VARCHAR(20) NOT NULL # 存储相册类型(user/conditional)
- num_photos: INTEGER DEFAULT 0 # 存储相册中照片数量
- 实现相册照片数量自动更新机制:
- 当照片被添加/删除时触发num_photos字段更新
- 批量操作时确保num_photos的原子性更新
- 前端渲染要求:
- 根据album.type字段区分显示不同图标/样式
- 使用album.num_photos显示相册照片数量
- 封面图直接使用album.cover.thumbnail_url渲染
- 移除所有conditionalAlbums/userAlbums相关的前端状态管理逻辑
- 接口兼容性:
- 确保修改后的接口保持向后兼容
- 为type和num_photos字段设置合理的默认值
- 更新API文档和前端类型定义
优化所有图片(PhotosPage.vue)和相册图片(Albumdetail.vue)时间轴跳转功能,现有的跳转逻辑是从images列表里查找对应的日期并跳转,实际上images列表可能并没有加载,可以直接从timeline_stats.timeline列表里查找对应的日期并跳转。 timeline_stats.timeline里有count字段,记录了每个月的照片数量,跳转过去可以先生成占位元素然后再加载缩略图。 另外优化时间轴的显示,不是每个月都有照片,只有有照片的月份才显示在时间轴上。
优化PhotosPage.vue和Albumdetail.vue组件中的时间轴跳转功能,具体改进要求如下:
跳转逻辑优化:
- 不再依赖images列表进行日期查找跳转
- 改为直接从timeline_stats.timeline列表中查找目标日期
- 利用timeline_stats.timeline中的count字段信息进行跳转
加载机制改进:
- 跳转时先根据count字段生成对应数量的占位元素
- 在占位元素生成后异步加载实际缩略图
- 实现平滑的加载过渡效果
- 跳转之后向上和向下滚动均能流畅加载
时间轴显示优化:
- 只显示包含照片的月份(count > 0的月份)
- 隐藏没有照片的月份条目
- 确保时间轴布局在过滤后仍然保持正确
性能要求:
- 减少不必要的DOM操作
- 实现懒加载机制
- 添加加载状态指示器
兼容性要求:
- 保持与现有功能的向后兼容
- 确保在两种视图(PhotosPage和Albumdetail)中表现一致
- 处理边界情况(如空列表、无效日期等)
不需要一下子给所有照片都生成占位符,而是在跳转时根据count字段生成对应数量的占位元素,跳转位置当页、上一页都生成占位符,例如每次加载50张图片,跳转到第352个时加载352-50到352+50的占位符,以便在滚动到目标位置时能够及时加载缩略图。
修复bug: 现在每组月份只有前50个能加载图片,后面的不会跟着鼠标滚动同步加载
优化图片懒加载机制,实现按需生成占位符元素,具体要求如下:
动态占位符生成策略:
- 仅在页面跳转时生成当前视窗范围内的占位符,而不是一下子加载所有占位符(这样会占用大量内存)
- 生成范围为 [当前页码-50, 当前页码+50]
- 示例:跳转到第352项时,生成302-402项的占位符
滚动加载修复:
- 监听滚动位置动态加载可视区域及缓冲区的图片
- 现在仅能加载每组前50张图片,后面不会随着鼠标滚动加载
性能优化要求:
- 实现平滑的占位符到图片的过渡效果
- 添加加载状态指示器
- 内存管理:卸载不可见区域的图片资源
边界情况处理:
- 处理列表开头和结尾的特殊情况
- 添加错误重试机制
- 支持快速跳转时的取消和重新请求
测试要求:
- 验证各种跳转场景下的占位符生成
- 测试快速连续滚动时的性能表现
- 检查内存占用是否合理
目前还存在以下几个bug:
- 跳转到指定日期时有时候会跳转到错误的位置
- 滚动到目标位置时有时候会卡顿,尤其是向上滚动时,会出现图片位置变化造成页面闪烁
- 跳转到指定日期之后,再滚动到目标位置时,会出现图片位置变化造成页面闪烁
- 跳转到指定日期之后有时候无法向上滚动,只能向下滚动,多滚动几次才行
- 内存占用过高,尤其是在快速跳转和滚动时
时间轴跳转很精确,没问题了,现在还存在以下几个问题:
- 跳转到指定日期之后,再向上滚动会持续请求后端数据,从而造成加载卡顿和页面闪烁:
INFO: 127.0.0.1:63997 - "GET /photos?skip=1791&limit=50 HTTP/1.1" 200 OK
INFO: 127.0.0.1:61390 - "GET /photos?skip=1792&limit=50 HTTP/1.1" 200 OK
INFO: 127.0.0.1:51455 - "GET /photos?skip=1793&limit=50 HTTP/1.1" 200 OK
INFO: 127.0.0.1:51456 - "GET /photos?skip=1794&limit=50 HTTP/1.1" 200 OK
INFO: 127.0.0.1:62381 - "GET /photos?skip=1796&limit=50 HTTP/1.1" 200 OK
INFO: 127.0.0.1:62380 - "GET /photos?skip=1795&limit=50 HTTP/1.1" 200 OK
INFO: 127.0.0.1:54748 - "GET /photos?skip=1797&limit=50 HTTP/1.1" 200 OK
INFO: 127.0.0.1:51570 - "GET /photos?skip=1798&limit=50 HTTP/1.1" 200 OK
INFO: 127.0.0.1:52327 - "GET /photos?skip=1800&limit=50 HTTP/1.1" 200 OK
INFO: 127.0.0.1:56020 - "GET /photos?skip=1799&limit=50 HTTP/1.1" 200 OK
INFO: 127.0.0.1:64173 - "GET /photos?skip=1801&limit=50 HTTP/1.1" 200 OK
INFO: 127.0.0.1:64174 - "GET /photos?skip=1802&limit=50 HTTP/1.1" 200 OK
INFO: 127.0.0.1:50635 - "GET /photos?skip=1803&limit=50 HTTP/1.1" 200 OK
INFO: 127.0.0.1:65375 - "GET /photos?skip=1804&limit=50 HTTP/1.1" 200 OK
INFO: 127.0.0.1:65113 - "GET /photos?skip=1806&limit=50 HTTP/1.1" 200 OK
INFO: 127.0.0.1:65112 - "GET /photos?skip=1805&limit=50 HTTP/1.1" 200 OK
INFO: 127.0.0.1:62368 - "GET /photos?skip=1807&limit=50 HTTP/1.1" 200 OK
INFO: 127.0.0.1:62369 - "GET /photos?skip=1808&limit=50 HTTP/1.1" 200 OK
INFO: 127.0.0.1:50315 - "GET /photos?skip=1809&limit=50 HTTP/1.1" 200 OK
INFO: 127.0.0.1:51112 - "GET /photos?skip=1810&limit=50 HTTP/1.1" 200 OK
INFO: 127.0.0.1:49224 - "GET /photos?skip=1811&limit=50 HTTP/1.1" 200 OK
INFO: 127.0.0.1:49225 - "GET /photos?skip=1812&limit=50 HTTP/1.1" 200 OK
INFO: 127.0.0.1:59604 - "GET /photos?skip=1813&limit=50 HTTP/1.1" 200 OK
INFO: 127.0.0.1:65190 - "GET /photos?skip=1814&limit=50 HTTP/1.1" 200 OK
INFO: 127.0.0.1:65191 - "GET /photos?skip=1815&limit=50 HTTP/1.1" 200 OK
INFO: 127.0.0.1:55057 - "GET /photos?skip=1816&limit=50 HTTP/1.1" 200 OK- 跳转到指定日期之后再向上滚动,会由于新增图片导致已有图片位置变化,从而造成页面闪烁
- 可能的解决办法:一次性加载该组所有占位符,而不是增量加载,这样就不会出现位置变化的问题,可能会导致内存占用增加
- 未来考虑按天分组加载图片,而不是按月份分组,这样可以减少占位符数量,提高性能
对于正方形布局,现在的显示效果已经好多了,但是瀑布流布局下,默认的占位符大小跟图片大小不一致,导致在加载图片时会出现占位符大小变化的问题,从而造成页面闪烁。 从后端返回的图片数据中,包含了图片的宽度和高度,我们可以根据这些数据来动态设置占位符的大小,从而避免占位符大小变化的问题。 可以修改后端read_all_photos接口,前端按组一次性获取所有图片数据,包括图片的宽度和高度,然后根据这些数据来动态设置占位符的大小。前端根据需要渲染占位符和加载图片时,根据图片的宽度和高度来设置占位符的宽度和高度,从而避免占位符大小变化的问题。
优化瀑布流布局下的图片加载体验,通过以下具体步骤实现占位符尺寸与图片实际尺寸的精确匹配:
后端接口改造要求:
- 修改read_all_photos接口,支持按日期分组获取图片数据
前端实现规范:
- 现在是按月分组,改成按天分组
- 对于正方形布局,现在的显示效果已经好多了,但是瀑布流布局下,默认的占位符大小跟图片大小不一致,导致在加载图片时会出现占位符大小变化的问题,从而造成页面闪烁。从后端返回的图片数据中,包含了图片的宽度和高度,我们可以根据这些数据来动态设置占位符的大小,从而避免占位符大小变化的问题。
- 瀑布流布局下,固定图片高度为占位符高度,宽度根据图片比例动态计算(设置最小宽度),从而保持占位符与图片的宽高比一致。
性能优化要求:
- 实现防抖处理,避免频繁DOM操作导致的回流重绘
- 对移动端适配:根据设备像素比动态调整显示尺寸
质量验证标准:
- 瀑布流布局下占位符必须保持与最终图片相同的宽高比
- 页面滚动过程中不允许出现任何可见的布局跳动
- 图片加载过程应实现平滑过渡效果
修改PhotoGallery.vue动态加载逻辑,timelineStats已经包含精确的某一天的照片数量,滚动的时候从后端直接获取某一天的全部照片元数据,前端根据页面滚动位置动态渲染要显示的照片,而不是现在这样根据偏移量从后端取数据
重构PhotoGallery.vue组件的动态加载逻辑,实现以下改进:
数据获取机制:
- 利用现有的timelineStats数据(包含精确的每日照片数量统计)
- 当用户滚动到特定日期区域时,向后台请求该日期的完整照片元数据
- 废弃原有的基于偏移量的数据获取方式
前端渲染优化:
- 根据当前视窗位置计算需要显示的日期范围
- 仅渲染当前可视区域及前后缓冲区的照片
- 实现照片的虚拟滚动,保持高性能渲染
性能要求:
- 确保滚动流畅,无卡顿现象
- 首次加载时间不超过500ms
- 内存占用控制在合理范围内
存在的bug:
- 有时候滚动条滚到底时无法加载更多照片
- 第一次跳转指定日期,会因为该日期的照片还未获取,导致无法加载该日期的照片,二次跳转才能加载该日期的照片
# 高性能动态加载相册整体设计方案
## 一、设计目标
1. 核心体验:支持按天维度的时间轴精准跳转,滚动过程无缝丝滑,无卡顿、无断层;
2. 性能目标:最小化内存占用(仅保留可视区核心资源)、降低网络开销(按需加载数据/图片)、避免滚动卡顿(减少重排重绘);
3. 扩展性:适配单日海量图片(千级以上)、响应式布局(移动端/PC端)、异常场景兜底。
## 二、核心设计原则
1. **按天聚合**:以“天”为最小数据/渲染单元,适配时间轴核心诉求;
2. **分层按需**:数据分“元数据/详情数据”、资源分“可视区/非可视区”,仅加载当前必要内容;
3. **虚拟渲染**:仅渲染可视区±预加载范围的DOM,彻底减少内存占用;
4. **三级缓存**:内存缓存、本地缓存、浏览器图片缓存,减少重复请求;
5. **预加载+懒加载**:滚动预加载邻近数据,图片仅加载可视区资源,平衡体验与性能。
## 三、数据层设计
### 1. 数据结构分层
| 数据类型 | 核心内容 | 用途 | 加载策略 |
|------------------|--------------------------------------------------------------------------|--------------------------|------------------------------|
| 时间轴概览数据 | 日期(YYYY-MM-DD)、当日图片总数、是否有更多数据 | 渲染时间轴、估算占位高度 | 首屏一次性加载(可按时间范围分段) |
| 单日图片元数据 | 图片ID、缩略图URL(多尺寸适配)、宽高比、拍摄时间、原图URL | 渲染图片容器、计算高度 | 按日期+分页加载,仅加载可视区日期 |
| 图片详情数据 | EXIF信息、拍摄地点、图片描述等 | 点击查看详情时展示 | 按需触发,点击后加载 |
### 2. 缓存策略
| 缓存层级 | 缓存内容 | 有效期 | 清理策略 |
|----------------|-----------------------------------|--------------|------------------------------|
| 内存缓存 | 已加载的日期元数据、可视区DOM状态 | 页面生命周期 | 页面卸载/切换时清空 |
| 本地缓存 | 时间轴数据、单日元数据(JSON) | 1天 | 缓存过期/数据更新时覆盖 |
| 浏览器图片缓存 | 缩略图、原图 | 7天 | 依赖HTTP缓存头(Cache-Control) |
## 四、前端架构设计
### 1. 整体模块划分
| 模块名称 | 核心职责 |
|------------------|--------------------------------------------------------------------------|
| 状态管理模块 | 维护全局状态(时间轴数据、已加载单日数据、可视区范围、滚动位置等) |
| 虚拟滚动核心模块 | 预计算总高度、监听滚动、计算可视区范围、渲染/销毁可视区DOM |
| 时间轴联动模块 | 渲染时间轴、绑定点击跳转、高亮当前日期、同步滚动状态 |
| 数据加载模块 | 按需加载/预加载单日数据、分页加载单日海量数据、缓存管理、请求中断控制 |
| 图片懒加载模块 | 监听图片可视状态、加载/释放图片资源、占位符/兜底图处理 |
| 异常处理模块 | 接口失败重试、图片加载失败兜底、缓存失效处理、内存泄漏防范 |
### 2. 布局架构
采用“时间轴区 + 虚拟滚动容器区”的双区域布局:
- 时间轴区:横向/纵向展示所有有图片的日期,支持点击跳转,高亮当前可视区日期;
- 虚拟滚动容器区:核心由“占位符容器”+“可视区内容容器”组成:
- 占位符容器:设置总高度(所有日期高度之和),模拟完整滚动条;
- 可视区内容容器:绝对定位,仅渲染可视区±预加载范围的日期内容,随滚动动态更新位置和内容。
## 五、核心功能实现逻辑
### 1. 初始化流程
1. 加载时间轴概览数据(优先读本地缓存);
2. 预计算所有日期的占位高度(基于图片总数估算,加载后修正);
3. 初始化虚拟滚动容器,设置占位符总高度;
4. 加载初始数据(当前日期±1天),渲染初始可视区内容;
5. 绑定滚动监听、时间轴点击事件。
### 2. 时间轴跳转逻辑
1. 点击时间轴日期,计算该日期在虚拟滚动容器中的偏移高度;
2. 调用平滑滚动API跳转到目标偏移高度;
3. 预加载目标日期及邻近日期的元数据(未加载时);
4. 高亮当前跳转的日期,取消其他日期高亮。
### 3. 虚拟滚动核心流程
1. **预计算高度**:初始化/数据加载后,计算每个日期的总高度(基于图片宽高比+间距),汇总为全局总高度;
2. **滚动监听**:通过`requestAnimationFrame`监听滚动,计算可视区范围(滚动位置±预加载偏移);
3. **可视区计算**:遍历所有日期,筛选出落在可视区范围内的日期;
4. **内容渲染**:批量渲染可视区日期的DOM(仅渲染该日期内可视区的图片容器),销毁超出范围的DOM;
5. **位置校准**:调整可视区内容容器的定位,与滚动位置对齐,保证滚动视觉连贯。
### 4. 单日海量图片处理逻辑
1. **元数据不分页**:单日图片从后端加载全部元数据,前端按需加载,避免全选或取消全选某一天全部照片的时候缺失未加载的数据;
2. **图片懒加载**:单日内部图片仅加载可视区的,非可视区图片保留懒加载标记,滚动到对应位置再加载;
### 5. 预加载与懒加载协同
1. **数据预加载**:滚动时预加载可视区前后N个日期的元数据(如前后1天),避免滚动到新日期时空白;
2. **图片懒加载**:通过IntersectionObserver监听图片可视状态,仅加载进入可视区的图片;
3. **预加载防抖**:避免滚动时频繁触发预加载请求,设置防抖阈值(如50ms);
4. **离屏资源释放**:滚动离开可视区过远的图片,清空src(替换为透明占位图),释放内存。
## 六、性能优化策略
### 1. 内存占用优化
- 仅渲染可视区±预加载范围的DOM,销毁远距区DOM;
- 单日元数据分页加载,避免一次性加载千级元数据;
- 离屏图片释放资源,仅保留可视区图片的有效src;
- 页面卸载时清空内存缓存、取消监听/观察者,避免内存泄漏。
### 2. 滚动流畅性优化
- 滚动事件设置`passive: true`,避免阻塞滚动;
- 所有DOM操作/计算逻辑包裹在`requestAnimationFrame`中;
- 预计算所有高度,滚动时仅做范围判断,不实时计算DOM尺寸;
- 滚动容器开启硬件加速(CSS transform),避免布局抖动;
- 避免使用`float`/`fixed`等高性能损耗的CSS属性,图片容器用`will-change`提示浏览器优化。
### 3. 网络加载优化
- 缩略图使用适配尺寸(如移动端300px宽、PC端600px宽),减少图片体积;
- 接口请求使用AbortController中断无效请求(如快速滚动时取消已触发的预加载);
- 预加载仅触发邻近日期,避免一次性发起大量请求;
- 利用HTTP缓存头优化图片缓存,减少重复下载。
## 七、体验优化策略
1. **加载占位**:数据/图片加载时展示骨架屏/占位图,避免空白;
2. **无缝滚动**:时间轴跳转使用平滑滚动API,滚动过程无卡顿;
3. **响应式适配**:窗口大小变化时,重新计算图片宽度/日期高度,适配不同设备;
4. **错误兜底**:接口请求失败自动重试(最多3次),图片加载失败显示兜底图;
5. **交互反馈**:时间轴跳转/图片加载时给出轻量动效反馈,提升感知流畅度。
## 八、技术选型建议
### 1. 原生开发
- 核心依赖:IntersectionObserver(图片懒加载)、requestAnimationFrame(滚动优化)、AbortController(请求中断);
- 无需额外依赖,轻量化,适合对体积要求高的场景。
### 2. 框架开发
| 框架 | 核心推荐库 | 优势 |
|------------|--------------------------------|--------------------------|
| Vue 3 | vue-virtual-scroller(虚拟滚动)、@vueuse/core(懒加载/监听) | 生态完善,虚拟滚动支持动态高度 |
## 九、异常处理设计
1. **数据加载失败**:接口请求失败后,3秒内自动重试(最多3次),仍失败则显示“重新加载”按钮;
2. **图片加载失败**:替换为兜底图,点击可重新加载原图;
3. **缓存失效**:本地缓存过期/数据不一致时,自动重新请求最新数据;
4. **滚动异常**:滚动位置超出范围时,自动校准到有效范围;
5. **内存泄漏防范**:页面卸载时取消所有监听、观察者,清空内存缓存。重构PhotoGallery.vue和AlbumTimeline.vue组件,优化内存占用和滚动流畅性。 已知数据:
- 时间轴数据(精确到天),包含日期和对应照片数量
- 照片元数据(包括ID、日期、宽高)
- 后端返回的是排序后的数据,前端不用再次排序 具体要求:
- timeline时间轴(精确到天)充当滚动条,点击日期跳转到指定位置
- 提前根据时间轴数据和当前布局,估算每月的总高度(基于图片宽高比+间距+标题),汇总为全局总高度
- 按月份分组生成占位符,每个占位符高度为对应月份的总高度 2. 对于可视窗口对应的当前月份(可能有多个),按天分组渲染
- 前端每次从后端获取一个月的全部数据
- 计算当前可视窗口包含的图片行数为hn,每行的图片个数为wn
- 则最多渲染(hn+2+2)*wn个图片,hn+2(前面两行)+2(后面两行)
- 触发更新的条件是有新的行进入窗口或者移出窗口
- 如果这(hn+2+2)*wn个图片包含多个月份则,需要获取新的数据,把该月对应的占位符替换成实际图片
- 对于其他月份,用div组件占位,高度为对应月份的总高度
重构PhotoGallery.vue和AlbumTimeline.vue组件,实现以下优化方案以降低内存占用并提升滚动流畅性:
时间轴组件(AlbumTimeline.vue)实现要求:
- 基于精确到天的时间轴数据(包含日期和对应照片数量)实现可点击的日期导航
- 点击特定日期时,平滑滚动到对应位置
- 时间轴样式需清晰展示日期分布密度
内存优化方案: a) 预计算布局:
- 根据图片元数据(ID、日期、宽高)和当前布局参数(间距、标题高度)
- 计算每个月份的总高度(基于图片宽高比+间距+标题)
- 生成全局高度映射表,用于虚拟滚动计算
b) 虚拟滚动实现:
- 按月份分组生成占位div,高度为预计算的月份总高度
- 仅渲染可视窗口及缓冲区的月份内容(hn+2+2行)
- 动态计算可视窗口包含的图片行数(hn)和每行图片数(wn)
- 维护当前渲染的图片范围为(hn+2+2)*wn
数据加载策略:
- 当新行进入可视窗口时触发更新
- 如果所需图片跨越多个月份,则:
- 从后端获取对应月份的全部数据
- 将月份占位符替换为实际图片内容
- 移出可视窗口的月份内容恢复为占位div
性能优化措施:
- 实现高效的滚动事件节流处理
- 添加IntersectionObserver监听元素进出可视区域
- 对图片加载实现懒加载和缓存策略
- 确保滚动位置计算精确到像素级别
组件通信:
- 在PhotoGallery和AlbumTimeline之间建立高效的数据同步机制
- 确保时间轴点击和图片滚动位置保持同步
- 实现平滑的滚动动画效果
错误处理:
- 添加数据加载失败的重试机制
- 处理边缘情况(如无数据月份)
- 确保布局计算时的容错处理
有一些几个问题需要解决:
- 月份对应的占位符或者实际图片的个数是不变的,例如一共有15个月,则页面上必须固定有15个元素,只是页面上显示的月份用实际的图片布局替代占位符,移除页面的月份改为占位符
- 现有的判断是否有新的行进入可视窗口无效,不能触发更新,需要在滚动事件中判断是否有新的行进入可视窗口
- 现在并没有从后端获取当月的全部数据
- 可以重构albumStore.ts,移除不需要的内容,添加需要的变量
优化一下数据结构:
- 照片画廊(PhotoGallery.vue)
- 虚拟占位按月份分组
- 当前显示的月份分组内按天再次分组渲染照片,支持虚拟滚动
- 预计算每个月份的总高度,用于滚动定位
- 动态计算当前可视窗口包含的图片行数(hn)和每行图片数(wn)
- 维护当前渲染的图片范围为(hn+2+2)*wn
- 当新行进入可视窗口时触发更新,新增或移除渲染的照片用于释放内存
## 详细设计
### 数据结构
```typescript
interface Photo {
id: number;
date: string; // 格式为YYYY-MM-DD
width: number;
height: number;
}
---
性能优化:
1. 必要的接口改成异步,例如照片缩略图接口
2. 缩略图路径改为全局变量,没必要每次都去数据库里查找,更新的时候只需要更新全局变量即可,然后再写入数据库
---
存在的问题:
1. 拖动滚动条的时候会触发更新,但是如果拖动的速度过快,会导致更新次数过多,从而前端展示性能还行,就是会向后端持续请求缩略图,导致后端压力增大
2. 似乎目前并没有实现懒加载,而是直接请求某组所有的缩略图,导致性能下降
3. 大量缩略图请求时延在300ms左右,经测试瓶颈不在后端,而是前端大量并发请求阻塞导致的
---
优化Ui以及数据结构:
1. 适配相册与照片画廊功能
- 相册列表(AlbumList.vue)
- 显示用户所有相册,每个相册包含名称、创建时间、照片数量等信息
- 支持创建新相册、重命名相册、删除相册等操作
- 相册详情(AlbumDetail.vue)
- 显示选中相册的所有照片
2. albumStore.ts将相册和照片相关的功能区分开,分别写到albumStore.ts和photoStore.ts,以减少单个文件大小
3. 照片画廊(PhotoGallery.vue)
- 支持按天批量选择照片,移除按月份批量选择
- 每组的header显示完整的年月日,例如2023-08-01,全选的时候日期左侧显示选中按钮,点击可以全选和取消全选
- 选择之后下方显示功能栏,包含下载,全选,取消选择等功能
- 在相册中AlbumDetail.vue增加移除相册的选项
- 在照片中增加删除照片的选项
- 移除或者删除的时候添加提醒框,确认操作
---
优化图片扫描性能:
1. 采用多线程或者异步协程来扫描文件夹,提高扫描效率。
2. 对扫描到的图片文件进行并行处理,减少io等待时间,尽可能合并相同的iO操作,避免重复io操作。
3. 采用任务队列机制,将图片处理任务分发到多个worker线程或者进程中并行处理,提高处理效率。
4. 数据库新增批量插入删除接口,用于批量处理照片数据,减少io操作次数。
5. 优先处理图片缩略图,先在前端加载出来,减少前端等待时间,提升用户体验。
6. 后续还要新增功能,包括地理信息的提取和存储,以及图片的分类和识别,AI功能等耗时任务,要为新增的耗时任务留接口,方便后续扩展和维护。
7. 任务完成后及时释放资源,减少内存占用
8. 提供任务状态查询接口,用户可以查询图片处理任务的状态,包括缩略图构建、元数据提取、分类识别等。
9. 前端对接任务状态查询接口(Settings.vue),实时展示任务处理进度,提升用户体验。
---
图片新增位置信息功能:
1. 新增位置信息字段,包括经度、纬度、城市、省份、国家等。
2. 后端在接收图片时,解析位置信息,将其存储到数据库中。
3. 提供查询接口,用户可以根据位置信息查询图片,例如查询某个城市的所有图片。
4. 后续可以新增地图展示功能,用户可以在地图上查看所有上传的图片位置。
5. 前端设置页面使用侧边导航栏,方便用户切换不同功能模块(后端可以不用实现,先在前端展示)。
1. 用户管理模块:包括用户注册、登录、权限管理等功能(功能暂时不用实现)。
2. 任务管理模块:查看当前后台运行的任务,包括图片处理任务、元数据提取任务等,用户可以取消正在运行的任务,新建新的任务等(后端接口暂时没有实现)。
3. 设置模块:包括系统参数设置、用户偏好设置等。
4. 外部图库管理模块:用户可以添加外部图库作为图片数据源。
图片新增位置信息功能详细实现方案:
1. 数据库与字段设计:
- 在元数据表中新增以下位置信息字段:
* 经度(longitude):DECIMAL(10,7) 类型
* 纬度(latitude):DECIMAL(10,7) 类型
* 城市(city):VARCHAR(100) 类型
* 省份(province):VARCHAR(100) 类型
* 国家(country):VARCHAR(100) 类型
* 详细地址(address):TEXT 类型(可选)
2. 后端功能实现:
- 图片元数据增强:
* 实现位置信息解析逻辑,将GPS坐标转换为可读的地理位置信息
* 将解析后的位置信息与图片元数据一起存储到数据库
- 查询接口开发:
* 实现按地理位置查询的API,支持以下查询条件:
- 按城市/省份/国家筛选
- 按地理坐标范围筛选(矩形区域)
- 按距离某点的半径范围筛选
* 返回结果应包含图片基本信息及位置数据
3. 前端设置页SettingsPage.vue功能规划:
- 侧边导航栏实现:
* 用户管理模块:预留界面布局,标注"待实现"状态
* 任务管理模块:
- 展示任务列表界面框架
- 实现任务状态模拟展示功能
- 操作按钮置灰处理,提示"后端接口待实现"
* 设置模块:构建基础设置表单框架
* 外部图库管理:设计添加外部图库的界面流程
4. 后续扩展规划:
- 地图可视化功能:
* 实现聚类标记显示
* 支持点击标记查看图片缩略图
* 添加地图筛选控件
- 任务管理后端对接:
* 定义任务状态查询API
* 实现任务取消接口
* 开发新任务创建接口
5. 技术注意事项:
- 数据库设计需添加空间索引以提高地理查询效率
- 预留足够扩展性以便后续添加更多位置相关功能
新增任务:
1. 重建缩略图:
- 新增任务类型:"重建缩略图"
- 任务描述:重新生成所有图片的缩略图,用于在相册中展示。
- 触发条件:用户手动请求。
- 任务参数:
* 可选:指定要重建缩略图的图片范围(例如,仅对新上传的图片、最近一个月的图片或所有图片)
- 任务执行流程:
1. 查询数据库中所有图片记录。
2. 对于每个图片记录,检查是否存在对应的缩略图文件。
3. 如果不存在缩略图文件,调用图片处理库生成缩略图。
4. 将生成的缩略图保存到指定目录。
- 任务完成条件:所有图片的缩略图都已成功重建。
2. 重建元数据:
- 新增任务类型:"重建元数据"
- 任务描述:重新提取所有图片的元数据,包括位置信息、拍摄时间等。
- 触发条件:用户手动请求。
- 任务参数:
* 可选:指定要重建元数据的图片范围(例如,仅对新上传的图片、最近一个月的图片或所有图片)
- 任务执行流程:
1. 查询数据库中所有图片记录。
2. 提取元数据,将提取的元数据保存到数据库中。
3. 更新元数据信息
- 任务完成条件:所有图片的元数据都已成功重建。
3. 前端对应任务接口,并显示任务进度(Settings.vue)
- 在任务管理模块,展示当前运行的任务列表。
- 每个任务项显示任务类型、描述、触发条件、参数、状态(运行中/已完成/失败)、进度条。
- 提供取消任务按钮,调用后端接口取消任务。
- 新增新建任务按钮,调用后端接口创建新任务。
模块拆分:
1. 前端模块(Settings.vue):
- 将每个设置项拆分为独立的组件(放到settings文件夹下),包括用户管理模块、任务管理模块、设置模块、外部图库管理模块。
- 每个组件负责展示自己的设置项,以及处理用户操作(如点击取消任务按钮)。
2. 后端模块(task_manager.py):
- 将不同的任务类型(如重建缩略图、重建元数据)拆分为独立的文件,每个文件负责处理对应类型的任务。
- 每个函数或类负责处理对应类型的任务,包括任务创建、取消、查询、执行等。
- 任务执行时,根据任务类型调用相应的函数或类。
修改接口参数:
1. 把按年月日筛选的照片接口改成按起始时间和结束时间筛选
1. 新增参数:start_time(起始时间)、end_time(结束时间)
2. 时间格式:YYYY-MM-DD HH:MM:SS
3. 起始时间和结束时间可以为空
2. 修改前端对应接口
3. 任务完成情况:数据库新增失败个数
4. 前端显示失败个数(Settings.vue)
性能优化:
前端loadPhotosByMonth函数不再一次性获取所有照片,而是分页加载,使用skip和limit参数,按需加载数据。
优化前端性能:重构loadPhotosByMonth函数实现分页加载功能,具体要求如下:
1. 修改函数签名,增加skip和limit参数:
- skip: 表示要跳过的记录数
- limit: 表示每次加载的照片数量
2. 实现分页逻辑:
- 默认加载第一页数据(skip=0)
- 每次滚动到页面底部时自动加载下一页
- 使用防抖技术控制请求频率
- 直到当月数据全部加载完成
3. 后端API适配:
- 确保后端API支持skip和limit参数
- 返回数据包含总记录数和当前页数据
4. 时间轴组件AlbumTimeline.vue适配移动端,现在存在的bug是移动端无法实现点击跳转
对现有项目的前后端框架进行全面技术分析,并产出以下专业设计文档(放在doc文件夹下):
1. 架构设计文档
- 绘制当前系统的整体架构图(包括前端、后端、数据库等组件)
- 详细说明各层架构的技术选型及版本信息
- 各个文件夹/文件/模块的作用、功能
2. 前端框架分析文档
- 详细拆解前端技术栈(框架、UI库、构建工具等)
- 绘制前端组件层级关系图
- 分析性能指标和优化空间
3. 后端框架分析文档
- 详细说明后端技术栈(语言、框架、中间件等)
- 绘制服务模块划分和调用关系图
- 分析API设计规范和接口文档现状
4. 完善README.md文档
1. 补充项目功能、特色、部署要求等说明
要求:
- 所有文档采用标准技术文档格式
- 包含必要的图表
数据库字段优化:
1. photo_metadata表
1. 新增字段:district(区县)
2. 删除字段:location、tags、faces
2. 新增人脸识别功能和标签功能
### 一、人脸身份表(face_identities)
**作用**:聚合同一用户下属于“同一个人”的人脸,定义身份名称(如“妈妈”“张三”),符合现有表名复数命名习惯
| 字段名 | 字段类型 | 字段说明 |
|-------------------|-------------------------|--------------------------------------------|
| id | UUID | 主键,人脸身份唯一标识 |
| identity_name | String(50) | 身份名称(如“妈妈”“同事A”) |
| default_face_id | UUID | 外键,关联faces.id,该身份的默认人脸头像 |
| create_time | DateTime | 身份创建时间,默认当前时间 |
| update_time | DateTime | 身份更新时间,默认当前时间 |
| is_deleted | Boolean | 软删除标记,默认False(未删除) |
### 二、人脸信息表(faces)
**作用**:存储单张照片中检测到的人脸特征、位置等核心信息,对应单个人脸的原始数据
| 字段名 | 字段类型 | 字段说明 |
|-----------------------|-------------------------|--------------------------------------------|
| id | UUID | 主键,人脸信息唯一标识 |
| photo_id | UUID | 外键,关联photos.id,归属照片,级联删除 |
| face_identity_id | UUID | 外键,关联face_identities.id,关联的人脸身份 |
| face_feature | JSON/Text | 人脸特征向量(序列化存储,如JSON数组) |
| face_rect | JSON | 人脸矩形框坐标,格式:{"x1":数值,"y1":数值,"x2":数值,"y2":数值} |
| face_confidence | DECIMAL(5,4) | 人脸检测置信度(0-1,越高越准确) |
| recognize_confidence | DECIMAL(5,4) | 匹配到人脸身份的置信度(0-1,可选) |
| create_time | DateTime | 人脸信息创建时间,默认当前时间 |
| update_time | DateTime | 人脸信息更新时间,默认当前时间 |
| is_deleted | Boolean | 软删除标记,默认False(未删除) |
### 三、照片标签表(photo_tags)
**作用**:存储用户自定义的照片标签名称(字典表),避免重复创建,适配“给整张照片打标签”的需求
| 字段名 | 字段类型 | 字段说明 |
|-------------------|-------------------------|--------------------------------------------|
| id | UUID | 主键,标签唯一标识 |
| tag_name | String(50) | 标签名称(如“旅游”“2025春节”“风景”) |
| create_time | DateTime | 标签创建时间,默认当前时间 |
| update_time | DateTime | 标签更新时间,默认当前时间 |
| is_deleted | Boolean | 软删除标记,默认False(未删除) |
### 四、照片标签关联表(photo_tag_relations)
**作用**:实现照片与标签的多对多关联,参考现有`album_photos`的结构设计
| 字段名 | 字段类型 | 字段说明 |
|-------------------|-------------------------|--------------------------------------------|
| id | Integer | 主键,自增,关联记录唯一标识 |
| photo_id | UUID | 外键,关联photos.id,归属照片,级联删除 |
| tag_id | UUID | 外键,关联photo_tags.id,归属标签,级联删除|
| created_at | DateTime | 关联创建时间,默认当前时间 |
| is_deleted | Boolean | 软删除标记,默认False(未删除) |
| 约束 | UniqueConstraint | 联合唯一约束:photo_id + tag_id,避免同一照片重复绑定同一标签 |
3. /photos 接口新增筛选参数:
1. 按人脸id查询照片
2. 按标签id查询照片
实现人脸识别接口:
1. 放在./package/ai/文件夹下,作为单独的服务提供ai能力
2. 使用fastapi实现接口,使用8001端口
3. 未来还要实现的功能:
1. OCR
2. 物体识别、图片分类
3. 票据识别
开发一个基于FastAPI的人脸识别微服务接口,具体要求如下:
1. 项目结构:
- 代码实现必须放置在./package/ai/目录下
- 作为独立的AI能力服务模块进行开发
2. 接口实现:
- 使用FastAPI框架开发RESTful API
- 服务运行在8001端口
- 必须包含以下标准接口:
* POST /face-recognition 人脸识别主接口
* GET /health-check 服务健康检查
* GET /version 服务版本查询
3. 功能要求:
- 人脸识别接口需支持:
* 接收图片文件上传(支持JPG/PNG格式)
* 返回人脸位置坐标和特征数据
* 人脸识别采用InsightFace模型
* 错误处理和输入验证
- 代码需预留扩展接口用于未来功能:
* OCR文本识别
* 物体识别与图片分类
* 票据识别专用接口
4. 扩展性设计:
- 采用模块化设计便于添加新AI功能
- 接口路由需按功能分类组织
- 预留配置系统用于不同AI模型切换
server模块任务模块优化:
1. 标记已经处理完成的photo为已处理状态,重启之后可以跳过已经完成的照片,提高效率(可以在photos表里新增字段,要区分不同的任务类型,例如缩略图构建、元数据处理、人脸识别、OCR等还要扩展以后可能新增的功能)
2. 新增任务类型为“人脸识别”的任务管理接口
1. 调用ai模块的人脸识别接口,获取人脸位置坐标和特征数据
2. 存储人脸信息到数据库中,包括人脸id、照片id、人脸位置坐标、特征数据等
前端增加人脸识别任务接口,调用server模块的任务管理接口,新增一个任务类型为“人脸识别”的任务。
后端优化:
1. server启动的时候检查数据库是否存在,如果不存在则创建数据库
2. faces表中特征向量使用VECTOR存储,数据库使用的是pgvector已经支持向量了
3. 单张图片人脸特征之后,检索聚类,自动将人脸分类到不同的类中,暂时命名为“未命名”
1. 关联face_identities.id 字段,将人脸特征向量关联到具体的人脸身份
2. 每个类中人脸特征向量的数量超过阈值(例如10张),则将该类命名为“未命名”
4. 新增face相关的api
1. 查询人物列表
2. 查询人物的照片列表
3. 删除人物
4. 重命名人物
5. 合并人物
bug修复:
1. force=True的时候每次重启server,自动未完成任务的时候都会重新处理,导致重复处理
前端功能:
1. 新增人脸识别相关的Ui,显示人物列表
1. 支持删除人物
2. 支持重命名人物
3. 支持把多个人脸合并为一个人物
2. 新增根据人物显示照片的界面
后端优化技术方案:
1. 人脸特征向量存储优化
- 修改faces表结构,将特征向量字段类型改为VECTOR(512)
- 为特征向量字段创建IVFFlat或HNSW索引(根据实际数据量选择)
1. 自动人脸聚类功能
- 实现单张图片处理后的实时聚类算法:
* 使用余弦相似度计算(阈值设为0.6)
* 采用DBSCAN聚类算法(eps=0.5, min_samples=3)
- 身份关联逻辑:
* 自动关联face_identities.id字段
* 新聚类统一标记为"未命名"
* 实现聚类数量阈值检测(可配置,默认10张)
1. 人脸相关API开发
- 实现以下RESTful接口:
1. GET /api/faces/identities - 分页查询人物列表(每页20条)
2. GET /api/faces/identities/{id}/photos - 获取指定人物的照片列表
3. DELETE /api/faces/identities/{id} - 软删除人物记录
4. PUT /api/faces/identities/{id}/name - 人物重命名
5. POST /api/faces/identities/merge - 人物合并(需验证合并逻辑)
Bug修复:
1. 任务重复处理问题,force=True的时候每次重启server,自动未完成任务的时候都会重新处理,导致重复处理
前端功能需求:
1. 人脸识别UI组件
- 开发人物列表视图:
* 分页显示人物卡片(含缩略图)
* 实现以下交互功能:
- 人物删除(二次确认)
- 人物重命名(实时保存)
- 多选合并(拖拽支持)
- 采用响应式设计(支持移动端)
1. 人物照片展示界面
- 开发照片墙视图
优化前端Ui:
1. /album 相册列表界面
1. 页面分为两部分
1. 顶部为智能相册列表
1. 展示用户创建的智能相册,例如“最近照片”、“人物相册”、“位置”等
2. 点击之后,跳转到对应的相册界面
2. 下面为自定义相册列表,与现有的保持一致
优化前端Ui:
1. PeopleDetail.vue
1. 显示时间轴、支持时间轴跳转
2. 整体显示内容与相册界面保持一致,只是批量选择功能不一样,相册中是批量移出相册,这里变成批量从人物中移除照片
3. 增加批量选择功能,用户可以选中多个照片进行操作(例如从人物中移除照片、设为封面等)(复用AlbumDetail.vue里的逻辑)
优化/faces接口:
1. FaceIdentitySchema中cover_photo字段增加属性,face_rect,用于存储封面照片的人脸位置坐标
2. 优化查询性能,减少循环查询
3. 完善每个api的文档,包括请求参数、响应体、错误码等
前端修改:
1. PeopleDetail.vue中,显示封面照片时,根据face_rect坐标裁剪显示
后端优化:
1. 新增全局配置项,用于存储一些全局的配置,例如AI的api地址、图片存储路径等
1. 删除app_settings表,所有配置项都存储在全局配置项中
2. 以JSON格式存储配置项,存在本地文件中
3. 记录配置项的版本,方便后续升级
2. 提高导入、导出配置项的接口
1. 新增POST /api/settings/import 接口,用于导入配置项
2. 新增GET /api/settings/export 接口,用于导出配置项
3. 前端settings.vue中,新增导入、导出配置项的按钮
配置项优化:
1. 把所有的配置项都统一的Python对象中,方便后续扩展和维护,而不是放在不同的文件里,把JSON格式的配置项转换为Python对象,方便后续使用,更新之后把Python对象转成JSON文件存储。
例如:
```python
class AppSettings:
def __init__(self, **kwargs):
self.ai_api_url = kwargs.get('ai_api_url', 'http://localhost:8000')
self.photo_storage_path = kwargs.get('photo_storage_path', './uploads')
self.external_directories = kwargs.get('external_directories', [])- 新增人脸识别配置项
- 新增face_recognition_threshold,用于设置人脸识别的阈值,默认0.6
- 新增face_recognition_min_photos,用于设置一个人物最少需要的照片数量,默认5
- 新增修改配置项的接口
- 新增修改配置项的前端界面
配置项优化:
- 配置项按类别分组:
- AI相关配置项
- ai_api_url - AI API的URL地址
- 人脸识别相关配置
- OCR相关配置
- 其他AI相关配置项(后续扩展)
- 存储相关配置项
- photo_storage_path
- external_directories
- 图片设置:
- 缩略图配置
- 预览图配置
- 其他配置
- 回收站相关配置(待实现)
- 其他配置
- AI相关配置项
- 前端优化
- 新增配置项的导入、导出功能
- 按类别分组展示配置项
优化任务管理模块:
- 用户添加或者移除外部图库目录时,需要重新扫描目录,更新数据库中的照片记录,重建索引需要扫描全部的目录
- 扫描目录时,需要立即创建缩略图,预览图,照片时间,照片路径等,而不是等用户请求时才创建(这一步应尽可能快的处理完成,用户可以快速看到新添加的照片)
- 扫描目录时新增后台任务:
- 处理元数据,地理位置识别等,高优先级
- 识别人物,创建人物记录,低优先级
- 其他后台任务(后续扩展)
前端对应修改:
- 任务管理模块:
- 按任务类别分组显示(例如当前一共有3个任务类别:扫描文件夹,处理元数据、识别人物):
- 任务类型、已完成个数、待完成个数、任务状态
- 不需要显示任务详情
- 用户可以暂停、继续某一类任务,暂停之后自动执行其他未完成任务
- 按任务类别分组显示(例如当前一共有3个任务类别:扫描文件夹,处理元数据、识别人物):
优化前端Ui:
- 任务管理模块:
- 显示任务的优先级,按任务优先级排序
- 待处理任务为0时,状态显示已完成
- 已完成任务为0时,状态显示等待中 后端优化:
- 设置任务对应的默认优先级映射,统一管理任务的优先级,后续还会有其他任务类型,每个任务类型有不同的默认优先级
- 任务完成之后即使释放资源,关闭任务的线程,减少内存占用
- 新增任务管理设置TaskSettings:
- 任务最大并发数,默认3个任务并发执行
- 其他任务相关参数(后续扩展)
优化设置模块:
- 图片设置新增:
- 缩略图大小,默认250p(可选项:250p、480p、720p、1080p)
- 预览图大小,默认1440p(可选项:720p、1080p、1440p、2160p)
- 其他图片相关配置(后续扩展)
- AI相关使用的图片默认使用预览图,而不是原始照片,这样可以减少AI处理的图片大小,提高处理速度(预览图不存在时使用原图)。
ai服务:
- 服务启动时默认不加载模型资源,使用的时候再加载
- 监控ai服务的运行情况,长时间不用时自动释放资源,有请求时再加载
- requirements.txt添加torch依赖,区分cpu和gpu版本
- 新增OCR模块,使用paddleocr,识别照片中的文字
优化ai服务:
- 模型动态加载机制,把模块import放到加载函数中,避免服务启动时就加载所有模块,占用内存(例如paddleocr模块,import之后就占用很大内存)
- 模型释放时,在释放模型的同时也释放相关的资源,例如paddleocr模块的模型资源,清理import进来的模块
- 其他可能优化资源占用的方案
bug修复:
- default_face_id外键依赖问题:
- 问题描述:当删除一个人脸记录(faces表的一条数据)时,人物记录的default_face_id外键会设置为空,导致人物封面显示为空
- 修复方案:在删除人脸记录时,先判断该人脸是否是人物的默认人脸,如果是,则需要更新人物记录的default_face_id为其他人脸记录的id(如果有的话),如果不是,则直接删除该人脸记录
- crud模块新增face.py:
- 增加人脸识别相关的crud接口,将人脸识别相关的操作都写到face.py中,例如添加人脸记录、删除人脸记录、更新人脸记录、查询人脸记录等
- 包括:tasks模块,api接口查询模块等
优化任务管理模块:
- 不再统计已完成任务的个数,只统计待完成任务的个数,任务完成后删除任务记录,防止表膨胀
- 新建任务(例如:扫描文件夹、处理元数据、识别人物等)时,需要为每一张照片创建一个任务记录,任务类型为新建任务的类型,而不是只有一个任务记录
- 启动时,自动扫描待完成任务,处理每个任务,任务处理完成后删除任务记录
前端对应修改:
- 不再显示已完成个数,只显示待处理任务数
新增OCR功能:
- 新增OCR任务,创建新的图片时,自动为该图片创建一个OCR任务,任务类型为OCR(业务逻辑同人脸识别)
- 调用ai服务中的OCR接口/ocr/predict,识别照片中的文字 @router.post("/predict", response_model=OCRResponse, summary="OCR Prediction") async def ocr_predict(file: UploadFile = File(...)): """ Perform OCR prediction on the uploaded image file.
- file: The image file to perform OCR on. Returns: OCRResponse: The OCR results and images.
- dataInfo: Additional information about the OCR process.
- ocrResults: The OCR results, including pruned results and images.
- prunedResult: The pruned OCR result, containing the detected text and other relevant information.
- rec_texts: (List[str]) 文本识别结果列表,仅包含置信度超过text_rec_score_thresh的文本
- rec_scores: (List[float]) 文本识别的置信度列表,已按text_rec_score_thresh过滤
- rec_polys: (List[List[int]]) 经过置信度过滤的文本检测框列表,文本检测的多边形框列表。每个检测框由4个顶点坐标构成的int数组表示,数组shape为(4, 2),数据类型为int16
- rec_boxes: (List[List[int]]) 检测框的矩形边界框列表,每个元素为一个4个整数的列表,分别表示矩形框的[x_min, y_min, x_max, y_max]坐标,其中(x_min, y_min)为左上角坐标,(x_max, y_max)为右下角坐标
- ocrImage: The image of the OCR result.
- docPreprocessingImage: The image of the document preprocessing step.
- inputImage: The original input image. """
- prunedResult: The pruned OCR result, containing the detected text and other relevant information.
- file: The image file to perform OCR on. Returns: OCRResponse: The OCR results and images.
- 新增OCR相关的表(每个文本框对应一个OCR记录):
id- 主键,自增整数photo_id- 外键,引用photos表的id字段,关联到对应的照片记录(创建索引)text- 文本字段,存储OCR识别的文本内容(创建索引,用于搜索)text_score- 浮点数字段,存储OCR识别的文本置信度polygon- 多边形字段,存储OCR识别的文本框坐标(json格式,例如:[[x1,y1],[x2,y2],[x3,y3],[x4,y4]],表示文本框的4个顶点坐标,使用0-1的小数存储相对坐标)(用于在照片中绘制文本框)- 其他可能需要的字段
前端对应修改:
- 任务模块:
- 新增OCR任务类型,显示OCR任务的进度和状态
- 用户可以在任务列表中暂停、继续、创建新的OCR任务(同人脸识别任务)
新增文字识别相关功能:
- 后端新增OCR相关接口,包括根据照片id查询OCR记录、根据照片id删除OCR记录等
- 前端新增OCR模块,用户可以在照片详情页查看OCR识别的文字,以及在照片中绘制文本框
开发完整的文字识别(OCR)功能模块,具体实现要求如下:
后端开发:
- 实现OCR相关接口:
- 创建
/api/ocr接口:根据照片ID查询OCR识别记录,返回识别结果、置信度、文本位置坐标等信息 - 创建
/api/ocr/{photo_id}接口:根据照片ID删除对应的OCR识别记录 - 接口给出详细注释文档
- 创建
前端开发:
- 在照片详情页新增OCR功能区域(PhotoLightbox.vue):
- 显示OCR识别出的文字内容
- 在照片上叠加显示识别出的文本框,使用半透明高亮效果
- 支持文本框点击交互,点击后显示对应文字的识别详情
- 实现响应式设计,适配不同屏幕尺寸
前端Ui优化:
- 顶部按钮只保留缩小、放大、下载、删除、详情、更多六个个按钮,其他按钮都放到“更多”中(例如:文字识别、添加到相册等)
- 文字识别结果单独显示在一个区域,而不是在照片详细信息中,不需要显示置信度
- 图片详细信息新增图片宽高、图片大小等信息
- 点击查看文件EXIF信息弹出EXIF详情弹窗,显示照片的拍摄时间、相机型号、曝光时间、ISO值、焦距等信息,去除“详细信息”
- 布局与给出的图片类似
bug修复(PhotoLightbox.vue):
- 点击“更多”按钮后直接退出了,没有显示菜单选项
- 查看EXIF信息对话框,以表格形式显示EXIF信息,每个EXIF项占一行,左侧为EXIF标签,右侧为对应值
- 图片显示比例不对,不是原始比例
## 首页设计:
### 一、整体视觉风格
- **布局原则**:上下流式布局,卡片化设计,所有可点击区域触控尺寸≥44×44px(符合移动端交互规范),间距统一(内边距16px,卡片间距12px)。
### 二、页面结构与模块详情
#### 1. 顶部导航栏(固定悬浮,高度56px)
| 区域 | 视觉样式 | 交互细节 |
|------------|--------------------------------------------------------------------------|------------------------------|
| 左侧 | 标题:“相册概览”,字体18px,#333,粗体 | 无交互 |
| 右侧 | 2个线性图标:搜索(24px)、设置(24px),颜色#666;点击后图标变色为#4A90E2 | 点击搜索→弹出搜索框;点击设置→进入概览自定义页面 |
| 背景 | 纯白色,底部1px浅灰分割线(#EEEEEE) | 下滑时导航栏透明度渐变(0.9→1) |
#### 2. 核心基础概览区(置顶,占页面1/4)
**布局**:横向滚动卡片组(适配多卡片,小屏也可改为2列网格),卡片圆角8px,背景#F5F5F5,内边距16px,单卡片尺寸:140×80px。
| 卡片项 | 视觉样式(从上到下) | 交互细节 |
|--------------|--------------------------------------------------------------------------------------|------------------------------|
| 总媒体数卡片 | 图标:📸 24px #4A90E2 → 数字:“12,893” 20px 粗体 #333 → 文字:“照片+视频” 12px #666 | 点击→跳转“全部媒体”列表页 |
| 最近更新卡片 | 图标:🆕 24px #FF9500 → 数字:“28” 20px 粗体 #333 → 文字:“今日新增” 12px #666 | 点击→跳转“最近添加”相册 |
| 存储空间卡片 | 图标:💾 24px #666 → 数字:“128.5GB” 20px 粗体 #333 → 文字:“占用空间” 12px #666 | 点击→弹出存储分布弹窗(照片/视频占比环形图) |
#### 3. 人脸维度特色区(核心差异化模块,占页面1/5)
**布局**:独立模块,顶部标题栏+内容区,背景白色,圆角8px,外间距上下12px。
| 子区域 | 视觉样式 | 交互细节 |
|--------------|--------------------------------------------------------------------------|------------------------------|
| 模块标题栏 | 左侧文字:“人脸相册” 16px 粗体 #333 → 右侧小字:“28位已识别” 12px #4A90E2 | 点击右侧文字→跳转“全部人物”相册 |
| 高频人物Top3 | 横向滚动头像栏:<br>• 每个项:圆形头像(40×40px,圆角50%)→ 下方文字:“小明 1,258张” 12px #666<br>• 项间距8px,左侧16px padding | 点击头像/文字→跳转该人物专属相册 |
| 待处理提示 | 浅橙背景(#FFF7E8)圆角6px,内边距8px:<br>图标❓ 16px #FF9500 → 文字:“5位待确认人脸 / 326张未识别照片” 12px #666 → 右侧按钮:“快速标注” 12px #FF9500(无底色,边框1px #FF9500,圆角4px) | 点击“快速标注”→跳转人脸标注页面 |
#### 4. 内容维度统计区(折叠面板,默认收起,占页面1/6)
**布局**:折叠式卡片,顶部可点击展开/收起,背景#F5F5F5,圆角8px。
| 子区域 | 视觉样式 | 交互细节 |
|--------------|--------------------------------------------------------------------------|------------------------------|
| 折叠标题栏 | 左侧文字:“内容细分” 16px #333 → 右侧图标:↓/↑ 20px #666(展开/收起切换) | 点击→展开/收起内容区 |
| 展开后内容 | 分2列展示,每行:图标+文字+数字<br>📷 照片:11,568(普通:9,872/截图:1,256)<br>🎬 视频:1,325(短视频:1,180/长视频:145)<br>🏞️ 风景:2,150 / 🍜 美食:1,876 | 点击任意行→跳转对应分类相册 |
#### 5. 时间维度可视化区(轻量化图表,占页面1/5)
**布局**:白色背景卡片,圆角8px,内边距16px,顶部标题+下方图表+标注。
| 子区域 | 视觉样式 | 交互细节 |
|--------------|--------------------------------------------------------------------------|------------------------------|
| 模块标题 | “拍摄时光” 16px 粗体 #333 → 右侧小字:“2025年占42%” 12px #666 | 无 |
| 年度分布图表 | 环形图(直径100px):<br>• 2025:#4A90E2(42%)<br>• 2024:#67C23A(35%)<br>• 2023:#909399(23%)<br>图表右侧文字标注(12px #666) | 点击环形图某部分→跳转对应年度相册 |
| 月度高峰提示 | 浅蓝背景(#E8F4F8)圆角6px,内边距8px:“2025年10月(国庆)拍摄最多:1,258张” 12px #333 | 点击→跳转该月度相册 |
#### 6. 实用工具区(底部模块,占页面1/6)
**布局**:2列网格卡片,单卡片尺寸:160×60px,圆角8px,背景#F5F5F5,内边距12px。
| 工具卡片 | 视觉样式 | 交互细节 |
|--------------|--------------------------------------------------------------------------|------------------------------|
| 清理冗余 | 图标🧹 20px #FF9500 → 文字:“清理重复照片(89张)” 12px #333 → 按钮:“一键清理” 10px #FFF(背景#FF9500,圆角4px) | 点击按钮→进入重复照片清理页 |
| 空间优化 | 图标📱 20px #4A90E2 → 文字:“优化存储空间” 12px #333 → 文字标注:“可省1.2GB” 10px #666 | 点击→进入空间优化页面 |
#### 7. 底部操作栏(固定,高度48px)
| 区域 | 视觉样式 | 交互细节 |
|------------|--------------------------------------------------------------------------|------------------------------|
| 左侧 | 文字:“自定义展示” 14px #4A90E2 | 点击→弹出弹窗,勾选/取消要展示的统计项(如隐藏“存储空间”“时间分布”) |
| 右侧 | 图标:刷新 20px #666 | 点击→刷新所有统计数据(加载中显示转圈动画) |
### 三、交互与动效细节
1. **懒加载**:页面初始化时仅加载“核心基础概览区”“人脸维度区”,滑动到对应区域时再加载“内容统计区”“时间可视化区”,图表加载时显示骨架屏(灰色占位);
2. **过渡动效**:
- 卡片点击:轻微缩放(0.98倍)+ 背景色渐变(#F5F5F5→#E8F4F8);
- 折叠面板展开/收起:高度渐变(300ms缓动);
- 图表加载:环形图从0到100%渐入绘制;
3. **适配性**:
- 小屏手机(≤4.7英寸):核心概览区改为1列网格,人脸Top3改为纵向排列;
- 深色模式:自动切换色调(背景#1C1C1E,文字#E5E5E5,卡片#2C2C2E,主色#5BA4F4);
4. **反馈提示**:
- 数据加载中:对应区域显示转圈加载动画(24px,#4A90E2);
- 无数据时:如无未识别人脸,“待处理提示”替换为“✅ 所有人脸已识别” 12px #67C23A;
- 操作成功:顶部toast提示(如“数据刷新成功”,背景#67C23A,文字#FFF,显示2秒)。
### 四、视觉层次优先级
1. 第一层级(最突出):核心概览区的数字(如12,893、28)、人脸Top3的头像;
2. 第二层级:模块标题(如“人脸相册”“拍摄时光”)、操作按钮(一键清理、快速标注);
3. 第三层级:辅助文字(如“今日新增”“可省1.2GB”)、图表标注;
4. 第四层级:分割线、占位符、次要提示文字。
## 后端对应实现
1. 实现首页前端对应api接口
2. 模块结构与现有的保持一致,schemas、crud模块单独抽离出来,保持代码的可维护性和可扩展性。
3. 前端和后端数据交互格式保持一致
## 性能优化
server当前任务管理器里的任务执行是采用异步执行的,但是与主线程是在同一个线程里,任务通常是CPU密集型,执行后台任务时会阻塞主线程,导致api响应延迟。
采用独立的进程来处理后台任务,不要影响主线程的执行。
## 性能优化方案:后台任务进程分离
### 当前问题分析
1. 当前系统采用异步方式执行后台任务,但仍在主线程中运行
2. 后台任务例如GPS元数据处理、人脸识别聚类等主要为CPU密集型计算任务
3. 任务执行期间会导致主线程阻塞,影响API响应速度
4. 现有架构无法充分利用多核CPU资源
### 优化目标
1. 将后台任务从主线程中完全分离
2. 确保后台任务执行不影响API响应性能
3. 提高系统整体吞吐量和资源利用率
### 技术实施方案
1. 采用多进程架构设计:
- 主进程:专门处理API请求和快速响应
- 工作进程:独立进程池处理CPU密集型后台任务
前端预览优化:
1. 新增查看原图选项,PhotoLightbox.vue默认加载预览图(image.preview),当用户点击查看大图时,再加载高清图(image.url)。
2. 详细信息栏,人脸信息显示头像,faces_identities中的cover_photo.face_rect是人脸在图片中的位置,用这个位置绘制一个头像,框住人脸。
"faces_identities": [
{
"id": "907088b3-7af3-47db-a9ce-71907a265f42",
"identity_name": "未命名",
"default_face_id": 4059,
"face_count": 1,
"cover_photo": {
"photo_id": "4607ba63-c053-45b0-922e-05c07ccc26f4",
"width": 1440,
"height": 1080,
"face_rect": [
572.5159912109375,
271.5009460449219,
800.9171752929688,
588.9747314453125
]
},
"cover": {
"file_type": "image",
"size": 8670200,
"width": 6528,
"height": 4896,
"duration": 0.0,
"filename": "IMG_20240729_071841.jpg",
"photo_time": "2024-07-29T07:18:41",
"id": "4607ba63-c053-45b0-922e-05c07ccc26f4",
"upload_time": "2025-12-22T15:26:00.580725"
}
}
]实现位置相册查看功能:
- 前端src/views/album新增位置相关的视图
- 支持按city和province视图切换
- 每个位置展示一个卡片,包含封面、位置名称、照片数量
- 后端新增位置相关的api接口
- 按city和province查询位置列表
- 按位置查询照片列表
bug修复:
- 修复按位置查询照片列表时,不显示照片
- 某个位置可能有上万张图片,注意性能
位置相册新增在地图上显示相册热力图 /api/medias/geojson?level=city接口可以获取对应的城市geojson数据 /api/medias/geojson?level=province接口可以获取对应的省份geojson数据
在位置相册功能中新增地图热力图展示功能,实现以下具体需求:
数据获取:
- 调用/api/medias/geojson接口获取地理数据
- 支持两种数据粒度:
- 城市级数据:通过?level=city参数获取
- 省级数据:通过?level=province参数获取
热力图实现:
- 基于获取的geojson数据生成可视化热力图
- 热力图应准确反映相册照片的地理分布密度
- 支持不同缩放级别下的热力图动态调整
交互功能:
- 实现地图缩放时自动切换数据层级(城市/省份)
- 添加点击事件查看具体位置的照片集
- 支持热力图透明度调节控件
样式规范:
- 热力图配色方案需符合产品设计规范
- 确保在不同主题模式下正常显示
- 添加图例说明热力强度
位置相册视图选项,保存到全局配置,避免路由切换之后丢失 实现位置相册视图选项的持久化存储功能,将用户选择的视图模式(如网格视图、列表视图等)保存到应用的全局配置中。具体要求如下:
- 在Vuex或Pinia等状态管理工具中创建专用模块存储视图配置
- 当用户切换视图选项时,立即将当前选择保存到全局状态
- 同时将配置持久化到localStorage或cookie中,确保页面刷新后仍能恢复
- 在路由切换时通过导航守卫检查并保持视图状态一致性
- 组件初始化时自动从全局配置读取并应用上次保存的视图选项
- 提供默认视图选项作为fallback方案
确保该功能与现有路由系统无缝集成,且不会影响其他全局状态的管理。需要添加相应的单元测试验证状态持久化和恢复的逻辑正确性。
完善文档
- 新增用户指南,详细介绍相册功能、使用方法和操作流程。
- 增加开发者文档
- 完善package下的README.md文件,添加使用说明、安装依赖、运行项目等内容
bug修复: server/main.py中通过后台进程启动了一个TaskManager示例, # Start Worker Process # Start a separate process for background tasks # This process will run the TaskManager loop worker_process = multiprocessing.Process(target=run_worker, daemon=True) worker_process.start() 但是主线程中还有很多地方使用了TaskManager.get_instance(),这会导致单例冲突,从而导致任务异常。
修改方案,主线程的TaskManager单独拿出来,只负责创建新任务、查询任务状态 后台线程负责监控任务并执行任务
优化任务管理TaskWorker模块:
- 提供快速模式(允许同时运行不同优先级的任务),例如一些任务扫描文件夹(优先级10),一些任务处理元数据(优先级5),一些任务处理(人脸识别、OCR识别优先级1)
- 扫描文件夹是io密集型任务,元数据处理是CPU密集型任务,人脸识别、OCR识别也是iO密集型任务(人脸识别、OCR识别本身是调用其他api服务,需要等待服务返回结果)
- 快速模式下尽可能利用CPU、内存,避免io密集型任务阻塞其他任务的执行。
- 注意内存占用,避免同时运行太多任务导致内存不足。
- 任务结束之后及时释放资源
- 前端提高快速模式切换按钮,用户可以在快速模式和正常模式之间切换
bug修复:
- TaskManagement.vue没有快速模式选项
- server的TaskManager是独立的守护进程,不能创建子进程,使用多进程会报错
bug修复:
文档完善: 给出任务管理模块的设计文档(放到docs目录下),包括但不限于以下几个方面:
- 任务管理整体架构
- 生产者消费者是如何协同的
- 任务的优先级是如何实现的
- 任务的状态是如何管理的
- 消费者拿到任务之后是如何分配执行的
- 哪些任务是并发执行的,哪些任务是顺序执行的
- 任务执行过程中出现异常的处理机制
- 怎么优化可以尽可能的提高性能
AI服务新增图片分类功能: 输入一张图片,返回图片的分类结果(可能有多个),分类结果包括但不限于以下几个类别:
- 人物
- 动物
- 自然场景
- 建筑
- 滑雪
- 运动
- 其他
为AI服务开发一个图片分类功能模块,具体要求如下:
- 功能需求:
- 接收用户上传的图片文件(支持常见格式:JPG/PNG/WebP等),支持选择中文和英文分类标签(默认中文)
- 对图片内容进行分析识别
- 返回图片可能属于的多个分类标签及其置信度
- 分类类别体系:
- 人物(包括单人、多人、人像特写等)
- 动物(包含宠物、野生动物等)
- 自然场景(山水、森林、海洋等自然景观)
- 建筑(房屋、桥梁、城市景观等人工建筑)
- 滑雪(包含滑雪场景、滑雪装备等)
- 运动(各类体育活动和运动场景)
- 其他(不属于上述类别的其他内容)
- 技术实现要求:
- 使用深度学习模型进行图片分类,使用预训练的模型,选择合适的模型
- 支持多标签分类(一张图片可同时属于多个类别)
- 每个分类结果需附带置信度分数(0-1范围)
- 响应时间控制在500ms以内
- 输出格式:
- 返回JSON格式结果
- 包含top 3最可能的分类结果
- 每个结果包含类别名称和置信度
分类优化,把分类放到一个单独的JSON文件中,做成可配置的,用户可以根据需要添加、删除、修改分类类别。提供api接口, 新增一些生活中常见的标签或者场景
图片分类的接口增加分类的个数,默认返回top 3个分类结果。
模型注册的时候增加模型释放资源的函数,确保在模型不再使用时及时释放资源。
图片分类的接口增加一个参数,用于指定返回的分类的精度,分为正常和精确,默认为精确。
- 正常精度使用第一个prompt
- 精确精度使用所有prompt
功能实现,新增照片的标签功能: server端:
- photo_tag_relations表,新增置信度字段,用于存储照片标签的置信度(0-1范围)1表示手动添加,<1表示模型识别生成的
- 新增api接口,用于新增照片的标签、查询照片的标签、删除照片的标签
- 把crud操作放到一个单独的文件中,用于管理照片标签的关系
前端:
- 照片详情页面,用户可以查看照片的所有标签,可以手动添加、删除标签
架构优化,模块拆分 前端:
- PhotoLightbox.vue组件,将 Sidebar (Metadata) 拆分成一个单独的组件,用于显示照片的详细信息(标签、元数据等)
- PhotoLightbox.vue组件,将OCR Panel (Separate)拆分成一个单独的组件,用于显示照片的OCR识别结果
调整AI服务的图片分类功能:
- AI服务使用SentenceTransformer来实现图片分类功能
- 返回结果增加图片的embedded向量,用于后续的图片相似度比较
server功能新增:
- 新增图片向量表,用于存储图片的embedding向量,用于后续的图片相似性搜索,以文搜图等功能
- 向量使用postgresql的向量类型,建立合适的索引,postgresql已安装vector插件
- 新增一个任务,用于处理图片的分类任务,将分类结果存储到photo_tag_relations表中,将图片的embedding向量存储到图片向量表中
实现服务器功能扩展,具体包含以下两个主要模块:
图片向量存储系统:
- 在PostgreSQL数据库中创建专门的图片向量表,表结构包含:
- 图片ID(主键)
- 图片embedding向量(使用pgvector插件的vector类型)
- 创建时间戳
- 其他必要元数据字段
- 为向量字段建立高效的索引(建议使用IVFFlat或HNSW索引)
- 现有的数据库已正确安装并配置pgvector插件
- 实现向量插入和更新接口
- 支持后续的向量相似性搜索功能(以文搜图、以图搜图等)
- 在PostgreSQL数据库中创建专门的图片向量表,表结构包含:
图片分类任务:
- 创建任务处理流程:
- 将分类结果写入photo_tag_relations表
- 生成图片embedding向量并存入图片向量表
- 实现任务状态监控和错误处理机制
- 确保与现有系统的数据一致性
- 提供任务执行日志和统计信息
- 创建任务处理流程:
前端功能适配
- 任务列表新增图片分类任务的状态显示
- 新建任务时,新增图片分类任务的选项