* 用户详情优化
* 用户详情优化
* 用户详情优化
* 用户详情优化
* 读取的接口,去掉全局锁
* 输出数组
* 反思优化1.0(优化隐私输出、时间检索)
* 反思优化1.0(优化隐私输出、时间检索)
* 反思优化1.0(优化隐私输出、时间检索)
* 反思优化测试接口
* 反思优化测试接口
* 读取接口内层嵌套BUG修复
* 读取接口内层嵌套BUG修复
* 读取接口内层嵌套BUG修复
* 读取接口内层嵌套BUG修复
* 读取接口内层嵌套BUG修复
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 把group_id替换end_user_id
* 把group_id替换end_user_id_
* 把group_id替换end_user_id_
* config_config替换成memory_config
* config_config替换成memory_config
* [fix]Fix the memory interface to use end_user_id.
* config_config替换成memory_config
* config_config替换成memory_config
* config_config替换成memory_config
* config_id字段改成UUID
* config_id字段改成UUID
* config_id字段改成UUID
* config_id字段改成UUID,与develop校对恢复
* 检查项目,修复group_id的遗留问题
* 检查项目,修复group_id的遗留问题
* Fix/interface home (#182)
* [fix]Fix the interface for statistics of recent activities and applications
* [changes]Modify the code based on the AI review
1.Use the boolean auxiliary methods provided by SQLAlchemy instead of using == True in the is_active filter.
2.The calculation of the "PROJECT_ROOT" has now been hardcoded with five levels of nested os.path.dirname calls.
* [fix]Fix the interface for statistics of recent activities and applications
* [changes]Modify the code based on the AI review
1.Use the boolean auxiliary methods provided by SQLAlchemy instead of using == True in the is_active filter.
2.The calculation of the "PROJECT_ROOT" has now been hardcoded with five levels of nested os.path.dirname calls.
* Fix/optimize inerface (#183)
* [changes]Optimize the time consumption of the "/end_users" interface
* [fix]Optimize the time consumption of the "/hot_memory_tags" interface
* [changes]Optimize the time consumption of the "/end_users" interface
* [fix]Optimize the time consumption of the "/hot_memory_tags" interface
* [changes]Improve the code based on AI review
* Fix/memory mcp2 1 (#184)
* 优化快速检索的回复内容
* 优化快速检索的回复内容
* Fix/memory mcp2 1 (#185)
* 优化快速检索的回复内容
* 优化快速检索的回复内容
* 路径的BUG修复
* 路径的BUG修复
* 路径的BUG修复
* 路径的BUG修复
* 路径的BUG修复
* Fix/memory mcp2 1 (#188)
* 优化快速检索的回复内容
* 优化快速检索的回复内容
* 路径的BUG修复
* 路径的BUG修复
* 路径的BUG修复
* 路径的BUG修复
* 路径的BUG修复
* LLM生存缺少config_id认证,修复BUG
* LLM生存缺少config_id认证,修复BUG
* LLM生存缺少config_id认证,修复BUG
* 解决冲突
* 解决冲突
* feat(home page): version description update
* Fix/memory mcp2 1 (#190)
* 优化快速检索的回复内容
* 优化快速检索的回复内容
* 路径的BUG修复
* 路径的BUG修复
* 路径的BUG修复
* 路径的BUG修复
* 路径的BUG修复
* LLM生存缺少config_id认证,修复BUG
* LLM生存缺少config_id认证,修复BUG
* LLM生存缺少config_id认证,修复BUG
* 深度检索优化,搜索不到数据/提问的概念过于蘑菇,以引导的方式继续提问
* 深度检索优化,搜索不到数据/提问的概念过于蘑菇,以引导的方式继续提问
* 深度检索优化,搜索不到数据/提问的概念过于蘑菇,以引导的方式继续提问
* end_user_id清理干净
* end_user_id清理干净
* 修复遗留合并BUG
* 修复遗留合并BUG
* 修复遗留合并BUG
* 修复遗留合并BUG
* feat(web): memory related interface parameter transfer adjustment
* 感知meta_data字段BUG修复
* Fix/memory bug fix (#171)
* feat(sandbox): add Python 3 code execution sandbox support
* feat(workflow): emit SSE events for node exception output
* perf(sandbox): optimize code encryption handling
* perf(workflow): update standard node output structure
* [add] migration script
* [modify] migration script
* feat(web): add workflow runtime info
* fix(web): handleSSE bugfix
* fix(sandbox): prevent imports from being blocked when network is disabled
* user_id->现实为config_id_old
* user_id->显示为config_id_old传输
* Fix/memory bug fix (#199)
* 图谱数据量限制数量去掉
* 图谱数据量限制数量去掉
* 图谱数据量限制数量去掉
* 用户详情优化
* 用户详情优化
* 用户详情优化
* 用户详情优化
* 用户详情优化
* 用户详情优化
* 读取的接口,去掉全局锁
* 输出数组
* 反思优化1.0(优化隐私输出、时间检索)
* 反思优化1.0(优化隐私输出、时间检索)
* 反思优化1.0(优化隐私输出、时间检索)
* 反思优化测试接口
* 反思优化测试接口
* 读取接口内层嵌套BUG修复
* 读取接口内层嵌套BUG修复
* 读取接口内层嵌套BUG修复
* 读取接口内层嵌套BUG修复
* 读取接口内层嵌套BUG修复
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 把group_id替换end_user_id
* 把group_id替换end_user_id_
* 把group_id替换end_user_id_
* config_config替换成memory_config
* config_config替换成memory_config
* [fix]Fix the memory interface to use end_user_id.
* config_config替换成memory_config
* config_config替换成memory_config
* config_config替换成memory_config
* config_id字段改成UUID
* config_id字段改成UUID
* config_id字段改成UUID
* config_id字段改成UUID,与develop校对恢复
* 检查项目,修复group_id的遗留问题
* 检查项目,修复group_id的遗留问题
* 解决冲突
* 解决冲突
* end_user_id清理干净
* end_user_id清理干净
* 修复遗留合并BUG
* 修复遗留合并BUG
* 修复遗留合并BUG
* 修复遗留合并BUG
* 感知meta_data字段BUG修复
* user_id->现实为config_id_old
* user_id->显示为config_id_old传输
---------
Co-authored-by: lanceyq <1982376970@qq.com>
* user_id->显示为config_id_old传输
* feat(web): update read_all_config select valueKey
* user_id->显示为config_id_old传输
* feat(workflow): Add a new node for executing code
* fix(web): KnowledgeConfigModal bugfix
* fix(web): iteration's variable add parameter-extractor node
* fix(sandbox): treat non-zero exit codes as errors instead of relying only on stderr
* Fix/memory bug fix (#200)
* 图谱数据量限制数量去掉
* 图谱数据量限制数量去掉
* 图谱数据量限制数量去掉
* 用户详情优化
* 用户详情优化
* 用户详情优化
* 用户详情优化
* 用户详情优化
* 用户详情优化
* 读取的接口,去掉全局锁
* 输出数组
* 反思优化1.0(优化隐私输出、时间检索)
* 反思优化1.0(优化隐私输出、时间检索)
* 反思优化1.0(优化隐私输出、时间检索)
* 反思优化测试接口
* 反思优化测试接口
* 读取接口内层嵌套BUG修复
* 读取接口内层嵌套BUG修复
* 读取接口内层嵌套BUG修复
* 读取接口内层嵌套BUG修复
* 读取接口内层嵌套BUG修复
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 把group_id替换end_user_id
* 把group_id替换end_user_id_
* 把group_id替换end_user_id_
* config_config替换成memory_config
* config_config替换成memory_config
* [fix]Fix the memory interface to use end_user_id.
* config_config替换成memory_config
* config_config替换成memory_config
* config_config替换成memory_config
* config_id字段改成UUID
* config_id字段改成UUID
* config_id字段改成UUID
* config_id字段改成UUID,与develop校对恢复
* 检查项目,修复group_id的遗留问题
* 检查项目,修复group_id的遗留问题
* 解决冲突
* 解决冲突
* end_user_id清理干净
* end_user_id清理干净
* 修复遗留合并BUG
* 修复遗留合并BUG
* 修复遗留合并BUG
* 修复遗留合并BUG
* 感知meta_data字段BUG修复
* user_id->现实为config_id_old
* user_id->显示为config_id_old传输
* user_id->显示为config_id_old传输
* user_id->显示为config_id_old传输
---------
Co-authored-by: lanceyq <1982376970@qq.com>
* Refactor/benchmark test (#196)
* [changes]refactor locomo_test
* [fix]Fix the circular import of ModelParameters
* [changes]The benchmark test can run stably.
* [fix]Complete end-to-end LoCoMo repair
* [fix]Complete the end-to-end longmemeval and memsciqa fixes
* [changes]Complete the benchmark test description document to ensure that the configuration parameters take effect.
* [changes]refactor locomo_test
* [fix]Fix the circular import of ModelParameters
* [changes]The benchmark test can run stably.
* [fix]Complete end-to-end LoCoMo repair
* [fix]Complete the end-to-end longmemeval and memsciqa fixes
* [changes]Complete the benchmark test description document to ensure that the configuration parameters take effect.
* [changes]Benchmark test adaptation for end_user_id
* [changes]refactor locomo_test
* [fix]Fix the circular import of ModelParameters
* [changes]The benchmark test can run stably.
* [fix]Complete end-to-end LoCoMo repair
* [fix]Complete the end-to-end longmemeval and memsciqa fixes
* [changes]Complete the benchmark test description document to ensure that the configuration parameters take effect.
* [fix]Complete the end-to-end longmemeval and memsciqa fixes
* [changes]Complete the benchmark test description document to ensure that the configuration parameters take effect.
* [changes]Benchmark test adaptation for end_user_id
* [modify] migration script
* delete benchmark-test (#204)
* Refactor: Move evaluation folder to redbear-mem-benchmark submodule
* [changes]Restore .gitmodules
* feat(web): workflow add code node
* 检查需要更改的格式问题
* Fix/redbear benchmark (#205)
* Refactor: Move evaluation folder to redbear-mem-benchmark submodule
* [changes]Update submodule reference
* Refactor: Move evaluation folder to redbear-mem-benchmark submodule
* [changes]Update submodule reference
* Remove duplicate evaluation submodule, use redbear-mem-benchmark instead
* Fix/memory bug fix (#207)
* 图谱数据量限制数量去掉
* 图谱数据量限制数量去掉
* 图谱数据量限制数量去掉
* 用户详情优化
* 用户详情优化
* 用户详情优化
* 用户详情优化
* 用户详情优化
* 用户详情优化
* 读取的接口,去掉全局锁
* 输出数组
* 反思优化1.0(优化隐私输出、时间检索)
* 反思优化1.0(优化隐私输出、时间检索)
* 反思优化1.0(优化隐私输出、时间检索)
* 反思优化测试接口
* 反思优化测试接口
* 读取接口内层嵌套BUG修复
* 读取接口内层嵌套BUG修复
* 读取接口内层嵌套BUG修复
* 读取接口内层嵌套BUG修复
* 读取接口内层嵌套BUG修复
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 把group_id替换end_user_id
* 把group_id替换end_user_id_
* 把group_id替换end_user_id_
* config_config替换成memory_config
* config_config替换成memory_config
* [fix]Fix the memory interface to use end_user_id.
* config_config替换成memory_config
* config_config替换成memory_config
* config_config替换成memory_config
* config_id字段改成UUID
* config_id字段改成UUID
* config_id字段改成UUID
* config_id字段改成UUID,与develop校对恢复
* 检查项目,修复group_id的遗留问题
* 检查项目,修复group_id的遗留问题
* 解决冲突
* 解决冲突
* end_user_id清理干净
* end_user_id清理干净
* 修复遗留合并BUG
* 修复遗留合并BUG
* 修复遗留合并BUG
* 修复遗留合并BUG
* 感知meta_data字段BUG修复
* user_id->现实为config_id_old
* user_id->显示为config_id_old传输
* user_id->显示为config_id_old传输
* user_id->显示为config_id_old传输
* 检查需要更改的格式问题
---------
Co-authored-by: lanceyq <1982376970@qq.com>
* fix(web): remove URI decode and encode
* [add] plugin system and base sso module
* 修复宿主列表获取memory_config_idBUG
* Fix/memory bug fix (#209)
* 图谱数据量限制数量去掉
* 图谱数据量限制数量去掉
* 图谱数据量限制数量去掉
* 用户详情优化
* 用户详情优化
* 用户详情优化
* 用户详情优化
* 用户详情优化
* 用户详情优化
* 读取的接口,去掉全局锁
* 输出数组
* 反思优化1.0(优化隐私输出、时间检索)
* 反思优化1.0(优化隐私输出、时间检索)
* 反思优化1.0(优化隐私输出、时间检索)
* 反思优化测试接口
* 反思优化测试接口
* 读取接口内层嵌套BUG修复
* 读取接口内层嵌套BUG修复
* 读取接口内层嵌套BUG修复
* 读取接口内层嵌套BUG修复
* 读取接口内层嵌套BUG修复
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 把group_id替换end_user_id
* 把group_id替换end_user_id_
* 把group_id替换end_user_id_
* config_config替换成memory_config
* config_config替换成memory_config
* [fix]Fix the memory interface to use end_user_id.
* config_config替换成memory_config
* config_config替换成memory_config
* config_config替换成memory_config
* config_id字段改成UUID
* config_id字段改成UUID
* config_id字段改成UUID
* config_id字段改成UUID,与develop校对恢复
* 检查项目,修复group_id的遗留问题
* 检查项目,修复group_id的遗留问题
* 解决冲突
* 解决冲突
* end_user_id清理干净
* end_user_id清理干净
* 修复遗留合并BUG
* 修复遗留合并BUG
* 修复遗留合并BUG
* 修复遗留合并BUG
* 感知meta_data字段BUG修复
* user_id->现实为config_id_old
* user_id->显示为config_id_old传输
* user_id->显示为config_id_old传输
* user_id->显示为config_id_old传输
* 检查需要更改的格式问题
* 修复宿主列表获取memory_config_idBUG
---------
Co-authored-by: lanceyq <1982376970@qq.com>
* [modify] file local server url
* [add] migration script
* fix(workflow): fix activation and branch control issues in streaming output
* fix(workflow): fix function cache not taking effect and potential list index overflow
* style(workflow): enforce PEP8 style and remove redundant imports
* fix(workflow): fix streaming output error when variable is not a string
* [fix]remove aspose-slides
* perf(workflow): enhance streaming output node activation performance
* feat(workflow): store token usage in message table
* feat(web): add PageEmpty component
* feat(web): add PageTabs component
* perf(workflow): make memory configuration backward compatible
* feat(web): update model management
* config_id做映射
* config_id做映射
* Fix/memory bug fix (#211)
* 图谱数据量限制数量去掉
* 图谱数据量限制数量去掉
* 图谱数据量限制数量去掉
* 用户详情优化
* 用户详情优化
* 用户详情优化
* 用户详情优化
* 用户详情优化
* 用户详情优化
* 读取的接口,去掉全局锁
* 输出数组
* 反思优化1.0(优化隐私输出、时间检索)
* 反思优化1.0(优化隐私输出、时间检索)
* 反思优化1.0(优化隐私输出、时间检索)
* 反思优化测试接口
* 反思优化测试接口
* 读取接口内层嵌套BUG修复
* 读取接口内层嵌套BUG修复
* 读取接口内层嵌套BUG修复
* 读取接口内层嵌套BUG修复
* 读取接口内层嵌套BUG修复
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 把group_id替换end_user_id
* 把group_id替换end_user_id_
* 把group_id替换end_user_id_
* config_config替换成memory_config
* config_config替换成memory_config
* [fix]Fix the memory interface to use end_user_id.
* config_config替换成memory_config
* config_config替换成memory_config
* config_config替换成memory_config
* config_id字段改成UUID
* config_id字段改成UUID
* config_id字段改成UUID
* config_id字段改成UUID,与develop校对恢复
* 检查项目,修复group_id的遗留问题
* 检查项目,修复group_id的遗留问题
* 解决冲突
* 解决冲突
* end_user_id清理干净
* end_user_id清理干净
* 修复遗留合并BUG
* 修复遗留合并BUG
* 修复遗留合并BUG
* 修复遗留合并BUG
* 感知meta_data字段BUG修复
* user_id->现实为config_id_old
* user_id->显示为config_id_old传输
* user_id->显示为config_id_old传输
* user_id->显示为config_id_old传输
* 检查需要更改的格式问题
* 修复宿主列表获取memory_config_idBUG
* config_id做映射
* config_id做映射
---------
Co-authored-by: lanceyq <1982376970@qq.com>
* feat(web): getModelListUrl add is_active param
* config_id做映射+1
* config_id做映射+1
* config_id做映射+1
* feat(web): remove file url replace
* Fix/memory bug fix (#212)
* 图谱数据量限制数量去掉
* 图谱数据量限制数量去掉
* 图谱数据量限制数量去掉
* 用户详情优化
* 用户详情优化
* 用户详情优化
* 用户详情优化
* 用户详情优化
* 用户详情优化
* 读取的接口,去掉全局锁
* 输出数组
* 反思优化1.0(优化隐私输出、时间检索)
* 反思优化1.0(优化隐私输出、时间检索)
* 反思优化1.0(优化隐私输出、时间检索)
* 反思优化测试接口
* 反思优化测试接口
* 读取接口内层嵌套BUG修复
* 读取接口内层嵌套BUG修复
* 读取接口内层嵌套BUG修复
* 读取接口内层嵌套BUG修复
* 读取接口内层嵌套BUG修复
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 把group_id替换end_user_id
* 把group_id替换end_user_id_
* 把group_id替换end_user_id_
* config_config替换成memory_config
* config_config替换成memory_config
* [fix]Fix the memory interface to use end_user_id.
* config_config替换成memory_config
* config_config替换成memory_config
* config_config替换成memory_config
* config_id字段改成UUID
* config_id字段改成UUID
* config_id字段改成UUID
* config_id字段改成UUID,与develop校对恢复
* 检查项目,修复group_id的遗留问题
* 检查项目,修复group_id的遗留问题
* 解决冲突
* 解决冲突
* end_user_id清理干净
* end_user_id清理干净
* 修复遗留合并BUG
* 修复遗留合并BUG
* 修复遗留合并BUG
* 修复遗留合并BUG
* 感知meta_data字段BUG修复
* user_id->现实为config_id_old
* user_id->显示为config_id_old传输
* user_id->显示为config_id_old传输
* user_id->显示为config_id_old传输
* 检查需要更改的格式问题
* 修复宿主列表获取memory_config_idBUG
* config_id做映射
* config_id做映射
* config_id做映射+1
* config_id做映射+1
* config_id做映射+1
---------
Co-authored-by: lanceyq <1982376970@qq.com>
* feat(model and app statistic): 1. Optimize the model list; 2. Increase the model combination; 3. Add a model square; 4. Add application management statistics
* feat(web): model logo update
* 应用层memory_content->memory_config
* fix(web): correct spelling
* 应用层memory_content->memory_config
* 应用层memory_content->memory_config
* Fix/memory bug fix (#215)
* 图谱数据量限制数量去掉
* 图谱数据量限制数量去掉
* 图谱数据量限制数量去掉
* 用户详情优化
* 用户详情优化
* 用户详情优化
* 用户详情优化
* 用户详情优化
* 用户详情优化
* 读取的接口,去掉全局锁
* 输出数组
* 反思优化1.0(优化隐私输出、时间检索)
* 反思优化1.0(优化隐私输出、时间检索)
* 反思优化1.0(优化隐私输出、时间检索)
* 反思优化测试接口
* 反思优化测试接口
* 读取接口内层嵌套BUG修复
* 读取接口内层嵌套BUG修复
* 读取接口内层嵌套BUG修复
* 读取接口内层嵌套BUG修复
* 读取接口内层嵌套BUG修复
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 把group_id替换end_user_id
* 把group_id替换end_user_id_
* 把group_id替换end_user_id_
* config_config替换成memory_config
* config_config替换成memory_config
* [fix]Fix the memory interface to use end_user_id.
* config_config替换成memory_config
* config_config替换成memory_config
* config_config替换成memory_config
* config_id字段改成UUID
* config_id字段改成UUID
* config_id字段改成UUID
* config_id字段改成UUID,与develop校对恢复
* 检查项目,修复group_id的遗留问题
* 检查项目,修复group_id的遗留问题
* 解决冲突
* 解决冲突
* end_user_id清理干净
* end_user_id清理干净
* 修复遗留合并BUG
* 修复遗留合并BUG
* 修复遗留合并BUG
* 修复遗留合并BUG
* 感知meta_data字段BUG修复
* user_id->现实为config_id_old
* user_id->显示为config_id_old传输
* user_id->显示为config_id_old传输
* user_id->显示为config_id_old传输
* 检查需要更改的格式问题
* 修复宿主列表获取memory_config_idBUG
* config_id做映射
* config_id做映射
* config_id做映射+1
* config_id做映射+1
* config_id做映射+1
* 应用层memory_content->memory_config
* 应用层memory_content->memory_config
* 应用层memory_content->memory_config
---------
Co-authored-by: lanceyq <1982376970@qq.com>
* feat(model and app statistic): 1. Optimize the model list; 2. Increase the model combination; 3. Add a model square; 4. Add application management statistics
* fix(web): model loading update
* 统一字段为config_id_old
* 统一字段为config_id_old
* feat(model and app statistic): 1. Optimize the model list; 2. Increase the model combination; 3. Add a model square; 4. Add application management statistics
* 统一字段为config_id_old
* 统一字段为config_id_old
* memory_content暂时不修改
* memory_content暂时不修改
* Fix/memory bug fix (#217)
* 图谱数据量限制数量去掉
* 图谱数据量限制数量去掉
* 图谱数据量限制数量去掉
* 用户详情优化
* 用户详情优化
* 用户详情优化
* 用户详情优化
* 用户详情优化
* 用户详情优化
* 读取的接口,去掉全局锁
* 输出数组
* 反思优化1.0(优化隐私输出、时间检索)
* 反思优化1.0(优化隐私输出、时间检索)
* 反思优化1.0(优化隐私输出、时间检索)
* 反思优化测试接口
* 反思优化测试接口
* 读取接口内层嵌套BUG修复
* 读取接口内层嵌套BUG修复
* 读取接口内层嵌套BUG修复
* 读取接口内层嵌套BUG修复
* 读取接口内层嵌套BUG修复
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
* 把group_id替换end_user_id
* 把group_id替换end_user_id_
* 把group_id替换end_user_id_
* config_config替换成memory_config
* config_config替换成memory_config
* [fix]Fix the memory interface to use end_user_id.
* config_config替换成memory_config
* config_config替换成memory_config
* config_config替换成memory_config
* config_id字段改成UUID
* config_id字段改成UUID
* config_id字段改成UUID
* config_id字段改成UUID,与develop校对恢复
* 检查项目,修复group_id的遗留问题
* 检查项目,修复group_id的遗留问题
* 解决冲突
* 解决冲突
* end_user_id清理干净
* end_user_id清理干净
* 修复遗留合并BUG
* 修复遗留合并BUG
* 修复遗留合并BUG
* 修复遗留合并BUG
* 感知meta_data字段BUG修复
* user_id->现实为config_id_old
* user_id->显示为config_id_old传输
* user_id->显示为config_id_old传输
* user_id->显示为config_id_old传输
* 检查需要更改的格式问题
* 修复宿主列表获取memory_config_idBUG
* config_id做映射
* config_id做映射
* config_id做映射+1
* config_id做映射+1
* config_id做映射+1
* 应用层memory_content->memory_config
* 应用层memory_content->memory_config
* 应用层memory_content->memory_config
* 统一字段为config_id_old
* 统一字段为config_id_old
* 统一字段为config_id_old
* 统一字段为config_id_old
* memory_content暂时不修改
* memory_content暂时不修改
---------
Co-authored-by: lanceyq <1982376970@qq.com>
* feat(web): add app statistics
* fix(workflow): fix streaming output issues with multi-output End nodes
End nodes with multiple output segments could cause cursor errors or leave some
segments inactive, resulting in incorrect final outputs.
Unified _emit_active_chunks and _update_scope_activate to ensure all segments
are activated in order and streamed correctly.
* feat(web): add apps statistics api
* fix(web): agent's knowledge_bases bugfix
* Revert "feat(web): update read_all_config select valueKey"
This reverts commit 46f0f3cee9.
* [add] migrations script
* perf(workflow): make memory write node backward-compatible and defer config validation
* 旧数据兼容
* 旧数据兼容
* 旧数据兼容
* 旧数据兼容
* fix(web): model bugfix
* fix(web): model bugfix
* 提交遗漏 (#228)
* [fix] chat api for workflow
* [fix] web search set for v1 api
* fix(web): model bugfix
* fix(web): model list remove is_active
* fix(model): bug fix
* [add]migration script
* [fix] api
* [fix] api
* fix(web): model bugfix
* fix(model): the model type does not allow modification, delete tts and speech2text type
* fix(model): bug fix
* 遗漏的历史映射
* 遗漏的历史映射
* 遗漏的历史映射
* Add/develop memory (#239)
* 遗漏的历史映射
* 遗漏的历史映射
* 遗漏的历史映射
* 遗漏的历史映射
* 遗漏的历史映射
* feat(web): model ui update
* feat(web): model ui update
* Add/develop memory (#243)
* 遗漏的历史映射
* 遗漏的历史映射
* fix(model): bug fix
* feat(web): model ui update
* Add/develop memory (#247)
* 遗漏的历史映射
* 遗漏的历史映射
* 遗漏的历史映射
* 遗漏的历史映射
* 遗漏的历史映射
* 遗漏的历史映射
* 遗漏的历史映射
* 遗漏的历史映射
* 遗漏的历史映射
* [modify] migration script
* [add] migration script
* fix(web): change form message
* fix(web): the memoryContent field is compatible with numbers and strings
* feat(web): code node hidden
* fix(model):
1. create a basic model to check if the name and provider are duplicated.
2. The result shows error models because the provider created API Keys for all matching models.
---------
Co-authored-by: lixinyue <2569494688@qq.com>
Co-authored-by: lanceyq <1982376970@qq.com>
Co-authored-by: yujiangping <yujiangping@taofen8.com>
Co-authored-by: 乐力齐 <162269739+lanceyq@users.noreply.github.com>
Co-authored-by: lixinyue11 <94037597+lixinyue11@users.noreply.github.com>
Co-authored-by: yingzhao <zhaoyingyz@126.com>
Co-authored-by: Timebomb2018 <18868801967@163.com>
Co-authored-by: Mark <zhuwenhui5566@163.com>
Co-authored-by: zhaoying <yzhao96@best-inc.com>
Co-authored-by: Eternity <1533512157@qq.com>
Co-authored-by: lixiangcheng1 <lixiangcheng1@wanda.cn>
794 lines
30 KiB
Python
794 lines
30 KiB
Python
from typing import List, Optional
|
||
|
||
from app.celery_app import celery_app
|
||
from app.core.error_codes import BizCode
|
||
from app.core.logging_config import get_api_logger
|
||
from app.core.rag.llm.cv_model import QWenCV
|
||
from app.core.response_utils import fail, success
|
||
from app.db import get_db
|
||
from app.dependencies import cur_workspace_access_guard, get_current_user
|
||
from app.models import ModelApiKey
|
||
from app.models.user_model import User
|
||
from app.core.memory.agent.utils.session_tools import SessionService
|
||
from app.core.memory.agent.utils.redis_tool import store
|
||
from app.repositories import knowledge_repository, WorkspaceRepository
|
||
from app.schemas.memory_agent_schema import UserInput, Write_UserInput
|
||
from app.schemas.response_schema import ApiResponse
|
||
from app.services import task_service, workspace_service
|
||
from app.services.memory_agent_service import MemoryAgentService
|
||
from app.services.model_service import ModelConfigService
|
||
from dotenv import load_dotenv
|
||
from fastapi import APIRouter, Depends, File, Form, Query, UploadFile,Header
|
||
from sqlalchemy.orm import Session
|
||
from starlette.responses import StreamingResponse
|
||
|
||
load_dotenv()
|
||
api_logger = get_api_logger()
|
||
|
||
memory_agent_service = MemoryAgentService()
|
||
|
||
router = APIRouter(
|
||
prefix="/memory",
|
||
tags=["Memory"],
|
||
)
|
||
|
||
|
||
@router.get("/health/status", response_model=ApiResponse)
|
||
async def get_health_status(
|
||
current_user: User = Depends(get_current_user)
|
||
):
|
||
"""
|
||
Get latest health status written by Celery periodic task
|
||
|
||
Returns health status information from Redis cache
|
||
"""
|
||
api_logger.info("Health status check requested")
|
||
try:
|
||
result = await memory_agent_service.get_health_status()
|
||
return success(data=result["status"])
|
||
except Exception as e:
|
||
api_logger.error(f"Health status check failed: {str(e)}")
|
||
return fail(BizCode.SERVICE_UNAVAILABLE, "健康状态查询失败", str(e))
|
||
|
||
|
||
@router.get("/download_log")
|
||
async def download_log(
|
||
log_type: str = Query("file", regex="^(file|transmission)$", description="日志类型: file=完整文件, transmission=实时流式传输"),
|
||
current_user: User = Depends(get_current_user)
|
||
):
|
||
"""
|
||
Download or stream agent service log file
|
||
|
||
log_type: str = Query("file", regex="^(file|transmission)$",
|
||
description="日志类型: file=完整文件, transmission=实时流式传输"),
|
||
current_user: User = Depends(get_current_user)
|
||
|
||
Args:
|
||
log_type: Log retrieval mode
|
||
- "file": Returns complete log file content in single response (default)
|
||
- "transmission": Real-time streaming of log content using Server-Sent Events
|
||
|
||
Returns:
|
||
- file mode: ApiResponse with log content
|
||
- transmission mode: StreamingResponse with SSE
|
||
"""
|
||
api_logger.info(f"Log download requested with log_type={log_type}")
|
||
|
||
# Validate log_type parameter (FastAPI Query regex already validates, but explicit check for clarity)
|
||
if log_type not in ["file", "transmission"]:
|
||
api_logger.warning(f"Invalid log_type parameter: {log_type}")
|
||
return fail(
|
||
BizCode.BAD_REQUEST,
|
||
"无效的log_type参数",
|
||
"log_type必须是'file'或'transmission'"
|
||
)
|
||
|
||
# Route to appropriate mode
|
||
if log_type == "file":
|
||
# File mode: Return complete log file content
|
||
try:
|
||
log_content = memory_agent_service.get_log_content()
|
||
return success(data=log_content)
|
||
except ValueError as e:
|
||
api_logger.warning(f"Log content issue: {str(e)}")
|
||
return fail(BizCode.FILE_NOT_FOUND, str(e))
|
||
except Exception as e:
|
||
api_logger.error(f"Log reading failed: {str(e)}")
|
||
return fail(BizCode.FILE_READ_ERROR, "日志读取失败", str(e))
|
||
|
||
else: # log_type == "transmission"
|
||
# Transmission mode: Stream log content using SSE
|
||
try:
|
||
api_logger.info("Starting SSE log streaming")
|
||
return StreamingResponse(
|
||
memory_agent_service.stream_log_content(),
|
||
media_type="text/event-stream",
|
||
headers={
|
||
"Cache-Control": "no-cache",
|
||
"Connection": "keep-alive",
|
||
"X-Accel-Buffering": "no" # Disable nginx buffering
|
||
}
|
||
)
|
||
except Exception as e:
|
||
api_logger.error(f"Failed to start log streaming: {str(e)}")
|
||
return fail(BizCode.INTERNAL_ERROR, "启动日志流式传输失败", str(e))
|
||
|
||
|
||
@router.post("/writer_service", response_model=ApiResponse)
|
||
@cur_workspace_access_guard()
|
||
async def write_server(
|
||
user_input: Write_UserInput,
|
||
db: Session = Depends(get_db),
|
||
current_user: User = Depends(get_current_user)
|
||
):
|
||
"""
|
||
Write service endpoint - processes write operations synchronously
|
||
|
||
Args:
|
||
user_input: Write request containing message and end_user_id
|
||
|
||
Returns:
|
||
Response with write operation status
|
||
"""
|
||
config_id = user_input.config_id
|
||
workspace_id = current_user.current_workspace_id
|
||
api_logger.info(f"Write service: workspace_id={workspace_id}, config_id={config_id}")
|
||
|
||
# 获取 storage_type,如果为 None 则使用默认值
|
||
storage_type = workspace_service.get_workspace_storage_type(
|
||
db=db,
|
||
workspace_id=workspace_id,
|
||
user=current_user
|
||
)
|
||
if storage_type is None: storage_type = 'neo4j'
|
||
user_rag_memory_id = ''
|
||
|
||
# 如果 storage_type 是 rag,必须确保有有效的 user_rag_memory_id
|
||
if storage_type == 'rag':
|
||
if workspace_id:
|
||
knowledge = knowledge_repository.get_knowledge_by_name(
|
||
db=db,
|
||
name="USER_RAG_MERORY",
|
||
workspace_id=workspace_id
|
||
)
|
||
if knowledge:
|
||
user_rag_memory_id = str(knowledge.id)
|
||
else:
|
||
api_logger.warning(f"未找到名为 'USER_RAG_MERORY' 的知识库,workspace_id: {workspace_id},将使用 neo4j 存储")
|
||
storage_type = 'neo4j'
|
||
else:
|
||
api_logger.warning("workspace_id 为空,无法使用 rag 存储,将使用 neo4j 存储")
|
||
storage_type = 'neo4j'
|
||
|
||
api_logger.info(f"Write service requested for group {user_input.end_user_id}, storage_type: {storage_type}, user_rag_memory_id: {user_rag_memory_id}")
|
||
try:
|
||
messages_list = memory_agent_service.get_messages_list(user_input)
|
||
result = await memory_agent_service.write_memory(
|
||
user_input.end_user_id,
|
||
messages_list,
|
||
config_id,
|
||
db,
|
||
storage_type,
|
||
user_rag_memory_id
|
||
)
|
||
|
||
return success(data=result, msg="写入成功")
|
||
except BaseException as e:
|
||
# Handle ExceptionGroup from TaskGroup (Python 3.11+) or BaseExceptionGroup
|
||
if hasattr(e, 'exceptions'):
|
||
error_messages = [f"{type(sub_e).__name__}: {str(sub_e)}" for sub_e in e.exceptions]
|
||
detailed_error = "; ".join(error_messages)
|
||
api_logger.error(f"Write operation error (TaskGroup): {detailed_error}", exc_info=True)
|
||
return fail(BizCode.INTERNAL_ERROR, "写入失败", detailed_error)
|
||
api_logger.error(f"Write operation error: {str(e)}", exc_info=True)
|
||
return fail(BizCode.INTERNAL_ERROR, "写入失败", str(e))
|
||
|
||
|
||
@router.post("/writer_service_async", response_model=ApiResponse)
|
||
@cur_workspace_access_guard()
|
||
async def write_server_async(
|
||
user_input: Write_UserInput,
|
||
db: Session = Depends(get_db),
|
||
current_user: User = Depends(get_current_user)
|
||
):
|
||
"""
|
||
Async write service endpoint - enqueues write processing to Celery
|
||
|
||
Args:
|
||
user_input: Write request containing message and end_user_id
|
||
|
||
Returns:
|
||
Task ID for tracking async operation
|
||
Use GET /memory/write_result/{task_id} to check task status and get result
|
||
"""
|
||
config_id = user_input.config_id
|
||
workspace_id = current_user.current_workspace_id
|
||
api_logger.info(f"Async write service: workspace_id={workspace_id}, config_id={config_id}")
|
||
|
||
# 获取 storage_type,如果为 None 则使用默认值
|
||
storage_type = workspace_service.get_workspace_storage_type(
|
||
db=db,
|
||
workspace_id=workspace_id,
|
||
user=current_user
|
||
)
|
||
if storage_type is None: storage_type = 'neo4j'
|
||
user_rag_memory_id = ''
|
||
if workspace_id:
|
||
|
||
knowledge = knowledge_repository.get_knowledge_by_name(
|
||
db=db,
|
||
name="USER_RAG_MERORY",
|
||
workspace_id=workspace_id
|
||
)
|
||
if knowledge: user_rag_memory_id = str(knowledge.id)
|
||
api_logger.info(f"Async write: storage_type={storage_type}, user_rag_memory_id={user_rag_memory_id}")
|
||
try:
|
||
# 获取标准化的消息列表
|
||
messages_list = memory_agent_service.get_messages_list(user_input)
|
||
|
||
task = celery_app.send_task(
|
||
"app.core.memory.agent.write_message",
|
||
args=[user_input.end_user_id, messages_list, config_id, storage_type, user_rag_memory_id]
|
||
)
|
||
api_logger.info(f"Write task queued: {task.id}")
|
||
|
||
return success(data={"task_id": task.id}, msg="写入任务已提交")
|
||
except Exception as e:
|
||
api_logger.error(f"Async write operation failed: {str(e)}")
|
||
return fail(BizCode.INTERNAL_ERROR, "写入失败", str(e))
|
||
|
||
|
||
@router.post("/read_service", response_model=ApiResponse)
|
||
@cur_workspace_access_guard()
|
||
async def read_server(
|
||
user_input: UserInput,
|
||
db: Session = Depends(get_db),
|
||
current_user: User = Depends(get_current_user)
|
||
):
|
||
"""
|
||
Read service endpoint - processes read operations synchronously
|
||
|
||
search_switch values:
|
||
- "0": Requires verification
|
||
- "1": No verification, direct split
|
||
- "2": Direct answer based on context
|
||
|
||
Args:
|
||
user_input: Read request with message, history, search_switch, and end_user_id
|
||
|
||
Returns:
|
||
Response with query answer
|
||
"""
|
||
config_id = user_input.config_id
|
||
workspace_id = current_user.current_workspace_id
|
||
|
||
storage_type = workspace_service.get_workspace_storage_type(
|
||
db=db,
|
||
workspace_id=workspace_id,
|
||
user=current_user
|
||
)
|
||
if storage_type is None: storage_type = 'neo4j'
|
||
user_rag_memory_id = ''
|
||
if workspace_id:
|
||
|
||
knowledge = knowledge_repository.get_knowledge_by_name(
|
||
db=db,
|
||
name="USER_RAG_MERORY",
|
||
workspace_id=workspace_id
|
||
)
|
||
if knowledge:
|
||
user_rag_memory_id = str(knowledge.id)
|
||
|
||
api_logger.info(f"Read service: group={user_input.end_user_id}, storage_type={storage_type}, user_rag_memory_id={user_rag_memory_id}, workspace_id={workspace_id}")
|
||
try:
|
||
result = await memory_agent_service.read_memory(
|
||
user_input.end_user_id,
|
||
user_input.message,
|
||
user_input.history,
|
||
user_input.search_switch,
|
||
config_id,
|
||
db,
|
||
storage_type,
|
||
user_rag_memory_id
|
||
)
|
||
if str(user_input.search_switch) == "2":
|
||
retrieve_info = result['answer']
|
||
history = await SessionService(store).get_history(user_input.end_user_id, user_input.end_user_id, user_input.end_user_id)
|
||
query = user_input.message
|
||
|
||
# 调用 memory_agent_service 的方法生成最终答案
|
||
result['answer'] = await memory_agent_service.generate_summary_from_retrieve(
|
||
end_user_id=user_input.end_user_id,
|
||
retrieve_info=retrieve_info,
|
||
history=history,
|
||
query=query,
|
||
config_id=config_id,
|
||
db=db
|
||
)
|
||
if "信息不足,无法回答" in result['answer']:
|
||
result['answer']=retrieve_info
|
||
return success(data=result, msg="回复对话消息成功")
|
||
except BaseException as e:
|
||
# Handle ExceptionGroup from TaskGroup (Python 3.11+) or BaseExceptionGroup
|
||
if hasattr(e, 'exceptions'):
|
||
error_messages = [f"{type(sub_e).__name__}: {str(sub_e)}" for sub_e in e.exceptions]
|
||
detailed_error = "; ".join(error_messages)
|
||
api_logger.error(f"Read operation error (TaskGroup): {detailed_error}", exc_info=True)
|
||
return fail(BizCode.INTERNAL_ERROR, "回复对话消息失败", detailed_error)
|
||
api_logger.error(f"Read operation error: {str(e)}", exc_info=True)
|
||
return fail(BizCode.INTERNAL_ERROR, "回复对话消息失败", str(e))
|
||
|
||
|
||
@router.post("/file", response_model=ApiResponse)
|
||
async def file_update(
|
||
files: List[UploadFile] = File(..., description="要上传的文件"),
|
||
model_id:str = Form(..., description="模型ID"),
|
||
metadata: Optional[str] = Form(None, description="文件元数据 (JSON格式)"),
|
||
current_user: User = Depends(get_current_user)
|
||
):
|
||
"""
|
||
文件上传接口 - 支持图片识别
|
||
|
||
Args:
|
||
files: 上传的文件列表
|
||
metadata: 文件元数据(可选)
|
||
current_user: 当前用户
|
||
|
||
Returns:
|
||
文件处理结果
|
||
"""
|
||
|
||
db_gen = get_db() # get_db 通常是一个生成器
|
||
db = next(db_gen)
|
||
api_logger.info(f"File upload requested, file count: {len(files)}")
|
||
config = ModelConfigService.get_model_by_id(db=db, model_id=model_id)
|
||
apiConfig: ModelApiKey = config.api_keys[0]
|
||
file_content = []
|
||
try:
|
||
for file in files:
|
||
api_logger.debug(f"Processing file: {file.filename}, content_type: {file.content_type}")
|
||
content = await file.read()
|
||
|
||
if file.content_type and file.content_type.startswith("image/"):
|
||
vision_model = QWenCV(
|
||
key=apiConfig.api_key,
|
||
model_name=apiConfig.model_name,
|
||
lang="Chinese",
|
||
base_url=apiConfig.api_base
|
||
)
|
||
description, token_count = vision_model.describe(content)
|
||
file_content.append(description)
|
||
api_logger.info(f"Image processed: {file.filename}, tokens: {token_count}")
|
||
else:
|
||
api_logger.warning(f"Unsupported file type: {file.content_type}")
|
||
file_content.append(f"[不支持的文件类型: {file.content_type}]")
|
||
|
||
result_text = ';'.join(file_content)
|
||
api_logger.info(f"File processing completed, result length: {len(result_text)}")
|
||
|
||
return success(data=result_text, msg="转换文本成功")
|
||
|
||
except Exception as e:
|
||
api_logger.error(f"File processing failed: {str(e)}", exc_info=True)
|
||
return fail(BizCode.INTERNAL_ERROR, "转换文本失败", str(e))
|
||
|
||
|
||
@router.post("/read_service_async", response_model=ApiResponse)
|
||
@cur_workspace_access_guard()
|
||
async def read_server_async(
|
||
user_input: UserInput,
|
||
db: Session = Depends(get_db),
|
||
current_user: User = Depends(get_current_user)
|
||
):
|
||
config_id = user_input.config_id
|
||
workspace_id = current_user.current_workspace_id
|
||
api_logger.info(f"Async read service: workspace_id={workspace_id}, config_id={config_id}")
|
||
|
||
# 获取 storage_type,如果为 None 则使用默认值
|
||
storage_type = workspace_service.get_workspace_storage_type(
|
||
db=db,
|
||
workspace_id=workspace_id,
|
||
user=current_user
|
||
)
|
||
if storage_type is None: storage_type = 'neo4j'
|
||
user_rag_memory_id = ''
|
||
if workspace_id:
|
||
|
||
knowledge = knowledge_repository.get_knowledge_by_name(
|
||
db=db,
|
||
name="USER_RAG_MERORY",
|
||
workspace_id=workspace_id
|
||
)
|
||
if knowledge: user_rag_memory_id = str(knowledge.id)
|
||
api_logger.info(f"Async read: storage_type={storage_type}, user_rag_memory_id={user_rag_memory_id}")
|
||
try:
|
||
task = celery_app.send_task(
|
||
"app.core.memory.agent.read_message",
|
||
args=[user_input.end_user_id, user_input.message, user_input.history, user_input.search_switch,
|
||
config_id, storage_type, user_rag_memory_id]
|
||
)
|
||
api_logger.info(f"Read task queued: {task.id}")
|
||
|
||
return success(data={"task_id": task.id}, msg="查询任务已提交")
|
||
except Exception as e:
|
||
api_logger.error(f"Async read operation failed: {str(e)}")
|
||
return fail(BizCode.INTERNAL_ERROR, "回复对话消息失败", str(e))
|
||
|
||
|
||
@router.get("/read_result/", response_model=ApiResponse)
|
||
async def get_read_task_result(
|
||
task_id: str,
|
||
current_user: User = Depends(get_current_user)
|
||
):
|
||
"""
|
||
Get the status and result of an async read task
|
||
|
||
Args:
|
||
task_id: Celery task ID returned from /read_service_async
|
||
|
||
Returns:
|
||
Task status and result if completed
|
||
|
||
Response format:
|
||
- PENDING: Task is waiting to be executed
|
||
- STARTED: Task has started
|
||
- SUCCESS: Task completed successfully, returns result
|
||
- FAILURE: Task failed, returns error message
|
||
"""
|
||
api_logger.info(f"Read task status check requested for task {task_id}")
|
||
try:
|
||
result = task_service.get_task_memory_read_result(task_id)
|
||
status = result.get("status")
|
||
|
||
if status == "SUCCESS":
|
||
# 任务成功完成
|
||
task_result = result.get("result", {})
|
||
if isinstance(task_result, dict):
|
||
# 新格式:包含详细信息
|
||
return success(
|
||
data={
|
||
"result": task_result.get("result"),
|
||
"end_user_id": task_result.get("end_user_id"),
|
||
"elapsed_time": task_result.get("elapsed_time"),
|
||
"task_id": task_id
|
||
},
|
||
msg="查询任务已完成"
|
||
)
|
||
else:
|
||
# 旧格式:直接返回结果
|
||
return success(data=task_result, msg="查询任务已完成")
|
||
|
||
elif status == "FAILURE":
|
||
# 任务失败
|
||
error_info = result.get("result", "Unknown error")
|
||
if isinstance(error_info, dict):
|
||
error_msg = error_info.get("error", str(error_info))
|
||
else:
|
||
error_msg = str(error_info)
|
||
return fail(BizCode.INTERNAL_ERROR, "查询任务失败", error_msg)
|
||
|
||
elif status in ["PENDING", "STARTED"]:
|
||
# 任务进行中
|
||
return success(
|
||
data={
|
||
"status": status,
|
||
"task_id": task_id,
|
||
"message": "任务处理中,请稍后查询"
|
||
},
|
||
msg="查询任务处理中"
|
||
)
|
||
else:
|
||
# 未知状态
|
||
return success(
|
||
data={
|
||
"status": status,
|
||
"task_id": task_id
|
||
},
|
||
msg=f"任务状态: {status}"
|
||
)
|
||
|
||
except Exception as e:
|
||
api_logger.error(f"Read task status check failed: {str(e)}", exc_info=True)
|
||
return fail(BizCode.INTERNAL_ERROR, "任务状态查询失败", str(e))
|
||
|
||
|
||
@router.get("/write_result/", response_model=ApiResponse)
|
||
async def get_write_task_result(
|
||
task_id: str,
|
||
current_user: User = Depends(get_current_user)
|
||
):
|
||
"""
|
||
Get the status and result of an async write task
|
||
|
||
Args:
|
||
task_id: Celery task ID returned from /writer_service_async
|
||
|
||
Returns:
|
||
Task status and result if completed
|
||
|
||
Response format:
|
||
- PENDING: Task is waiting to be executed
|
||
- STARTED: Task has started
|
||
- SUCCESS: Task completed successfully, returns result
|
||
- FAILURE: Task failed, returns error message
|
||
"""
|
||
api_logger.info(f"Write task status check requested for task {task_id}")
|
||
try:
|
||
result = task_service.get_task_memory_write_result(task_id)
|
||
status = result.get("status")
|
||
|
||
if status == "SUCCESS":
|
||
# 任务成功完成
|
||
task_result = result.get("result", {})
|
||
if isinstance(task_result, dict):
|
||
# 新格式:包含详细信息
|
||
return success(
|
||
data={
|
||
"result": task_result.get("result"),
|
||
"end_user_id": task_result.get("end_user_id"),
|
||
"elapsed_time": task_result.get("elapsed_time"),
|
||
"task_id": task_id
|
||
},
|
||
msg="写入任务已完成"
|
||
)
|
||
else:
|
||
# 旧格式:直接返回结果
|
||
return success(data=task_result, msg="写入任务已完成")
|
||
|
||
elif status == "FAILURE":
|
||
# 任务失败
|
||
error_info = result.get("result", "Unknown error")
|
||
if isinstance(error_info, dict):
|
||
error_msg = error_info.get("error", str(error_info))
|
||
else:
|
||
error_msg = str(error_info)
|
||
return fail(BizCode.INTERNAL_ERROR, "写入任务失败", error_msg)
|
||
|
||
elif status in ["PENDING", "STARTED"]:
|
||
# 任务进行中
|
||
return success(
|
||
data={
|
||
"status": status,
|
||
"task_id": task_id,
|
||
"message": "任务处理中,请稍后查询"
|
||
},
|
||
msg="写入任务处理中"
|
||
)
|
||
else:
|
||
# 未知状态
|
||
return success(
|
||
data={
|
||
"status": status,
|
||
"task_id": task_id
|
||
},
|
||
msg=f"任务状态: {status}"
|
||
)
|
||
|
||
except Exception as e:
|
||
api_logger.error(f"Write task status check failed: {str(e)}", exc_info=True)
|
||
return fail(BizCode.INTERNAL_ERROR, "任务状态查询失败", str(e))
|
||
|
||
|
||
@router.post("/status_type", response_model=ApiResponse)
|
||
async def status_type(
|
||
user_input: Write_UserInput,
|
||
db: Session = Depends(get_db),
|
||
current_user: User = Depends(get_current_user)
|
||
):
|
||
"""
|
||
Determine the type of user message (read or write)
|
||
|
||
Args:
|
||
user_input: Request containing user message and end_user_id
|
||
|
||
Returns:
|
||
Type classification result
|
||
"""
|
||
api_logger.info(f"Status type check requested for group {user_input.end_user_id}")
|
||
try:
|
||
# 获取标准化的消息列表
|
||
messages_list = memory_agent_service.get_messages_list(user_input)
|
||
|
||
# 将消息列表转换为字符串用于分类
|
||
# 只取最后一条用户消息进行分类
|
||
last_user_message = ""
|
||
for msg in reversed(messages_list):
|
||
if msg.get('role') == 'user':
|
||
last_user_message = msg.get('content', '')
|
||
break
|
||
|
||
if not last_user_message:
|
||
# 如果没有用户消息,使用所有消息的内容
|
||
last_user_message = " ".join([msg.get('content', '') for msg in messages_list])
|
||
|
||
result = await memory_agent_service.classify_message_type(
|
||
last_user_message,
|
||
user_input.config_id,
|
||
db
|
||
)
|
||
return success(data=result)
|
||
except Exception as e:
|
||
api_logger.error(f"Message type classification failed: {str(e)}")
|
||
return fail(BizCode.INTERNAL_ERROR, "类型判断失败", str(e))
|
||
|
||
|
||
# ==================== 新增的三个接口路由 ====================
|
||
|
||
@router.get("/stats/types", response_model=ApiResponse)
|
||
async def get_knowledge_type_stats_api(
|
||
end_user_id: Optional[str] = Query(None, description="用户ID(可选)"),
|
||
only_active: bool = Query(True, description="仅统计有效记录(status=1)"),
|
||
current_user: User = Depends(get_current_user)
|
||
):
|
||
"""
|
||
统计当前空间下各知识库类型的数量,包含 General | Web | Third-party | Folder | memory。
|
||
会对缺失类型补 0,返回字典形式。
|
||
可选按状态过滤。
|
||
- 知识库类型根据当前用户的 current_workspace_id 过滤
|
||
- memory 是 Neo4j 中 Chunk 的数量,根据 end_user_id (end_user_id) 过滤
|
||
- 如果用户没有当前工作空间或未提供 end_user_id,对应的统计返回 0
|
||
"""
|
||
api_logger.info(f"Knowledge type stats requested for workspace_id: {current_user.current_workspace_id}, end_user_id: {end_user_id}")
|
||
try:
|
||
from app.db import get_db
|
||
|
||
# 获取数据库会话
|
||
db_gen = get_db()
|
||
db = next(db_gen)
|
||
|
||
# 调用service层函数
|
||
result = await memory_agent_service.get_knowledge_type_stats(
|
||
end_user_id=end_user_id,
|
||
only_active=only_active,
|
||
current_workspace_id=current_user.current_workspace_id,
|
||
db=db
|
||
)
|
||
|
||
return success(data=result, msg="获取知识库类型统计成功")
|
||
except Exception as e:
|
||
api_logger.error(f"Knowledge type stats failed: {str(e)}")
|
||
return fail(BizCode.INTERNAL_ERROR, "获取知识库类型统计失败", str(e))
|
||
|
||
|
||
@router.get("/analytics/hot_memory_tags/by_user", response_model=ApiResponse)
|
||
async def get_hot_memory_tags_by_user_api(
|
||
end_user_id: Optional[str] = Query(None, description="用户ID(可选)"),
|
||
language_type: str = Header(default="zh", alias="X-Language-Type"),
|
||
limit: int = Query(20, description="返回标签数量限制"),
|
||
current_user: User = Depends(get_current_user),
|
||
db: Session=Depends(get_db),
|
||
):
|
||
"""
|
||
获取指定用户的热门记忆标签
|
||
|
||
返回格式:
|
||
[
|
||
{"name": "标签名", "frequency": 频次},
|
||
...
|
||
]
|
||
"""
|
||
|
||
workspace_id=current_user.current_workspace_id
|
||
workspace_repo = WorkspaceRepository(db)
|
||
workspace_models = workspace_repo.get_workspace_models_configs(workspace_id)
|
||
|
||
if workspace_models:
|
||
model_id = workspace_models.get("llm", None)
|
||
else:
|
||
model_id = None
|
||
|
||
api_logger.info(f"Hot memory tags by user requested: end_user_id={end_user_id}")
|
||
try:
|
||
result = await memory_agent_service.get_hot_memory_tags_by_user(
|
||
end_user_id=end_user_id,
|
||
language_type=language_type,
|
||
model_id=model_id,
|
||
limit=limit
|
||
)
|
||
return success(data=result, msg="获取热门记忆标签成功")
|
||
except Exception as e:
|
||
api_logger.error(f"Hot memory tags by user failed: {str(e)}")
|
||
return fail(BizCode.INTERNAL_ERROR, "获取热门记忆标签失败", str(e))
|
||
|
||
|
||
@router.get("/analytics/user_profile", response_model=ApiResponse)
|
||
async def get_user_profile_api(
|
||
end_user_id: Optional[str] = Query(None, description="用户ID(可选)"),
|
||
db: Session = Depends(get_db),
|
||
current_user: User = Depends(get_current_user)
|
||
):
|
||
"""
|
||
获取用户详情,包含:
|
||
- name: 用户名字(直接使用 end_user_id)
|
||
- tags: 3个用户特征标签(从语句和实体中LLM总结)
|
||
- hot_tags: 4个热门记忆标签
|
||
|
||
返回格式:
|
||
{
|
||
"name": "用户名",
|
||
"tags": ["产品设计师", "旅行爱好者", "摄影发烧友"],
|
||
"hot_tags": [
|
||
{"name": "标签1", "frequency": 10},
|
||
{"name": "标签2", "frequency": 8},
|
||
...
|
||
]
|
||
}
|
||
"""
|
||
api_logger.info(f"User profile requested: end_user_id={end_user_id}, current_user={current_user.id}")
|
||
try:
|
||
result = await memory_agent_service.get_user_profile(
|
||
end_user_id=end_user_id,
|
||
current_user_id=str(current_user.id),
|
||
db=db
|
||
)
|
||
return success(data=result, msg="获取用户详情成功")
|
||
except Exception as e:
|
||
api_logger.error(f"User profile failed: {str(e)}")
|
||
return fail(BizCode.INTERNAL_ERROR, "获取用户详情失败", str(e))
|
||
|
||
|
||
# @router.get("/docs/api", response_model=ApiResponse)
|
||
# async def get_api_docs_api(
|
||
# file_path: Optional[str] = Query(None, description="API文档文件路径,不传则使用默认路径")
|
||
# ):
|
||
# """
|
||
# Get parsed API documentation (Public endpoint - no authentication required)
|
||
|
||
# Args:
|
||
# file_path: Optional path to API docs file. If None, uses default path.
|
||
|
||
# Returns:
|
||
# Parsed API documentation including title, meta info, and sections
|
||
# """
|
||
# api_logger.info(f"API docs requested, file_path: {file_path or 'default'}")
|
||
# try:
|
||
# result = await memory_agent_service.get_api_docs(file_path)
|
||
|
||
# if result.get("success"):
|
||
# return success(msg=result["msg"], data=result["data"])
|
||
# else:
|
||
# return fail(
|
||
# code=BizCode.BAD_REQUEST,
|
||
# msg=result["msg"],
|
||
# error=result.get("data", {}).get("error", result.get("error_code", ""))
|
||
# )
|
||
# except Exception as e:
|
||
# api_logger.error(f"API docs retrieval failed: {str(e)}")
|
||
# return fail(BizCode.INTERNAL_ERROR, "API文档获取失败", str(e))
|
||
|
||
|
||
@router.get("/end_user/{end_user_id}/connected_config", response_model=ApiResponse)
|
||
async def get_end_user_connected_config(
|
||
end_user_id: str,
|
||
db: Session = Depends(get_db),
|
||
current_user: User = Depends(get_current_user)
|
||
):
|
||
"""
|
||
获取终端用户关联的记忆配置
|
||
|
||
通过以下流程获取配置:
|
||
1. 根据 end_user_id 获取用户的 app_id
|
||
2. 获取该应用的最新发布版本
|
||
3. 从发布版本的 config 字段中提取 memory_config_id
|
||
|
||
Args:
|
||
end_user_id: 终端用户ID
|
||
|
||
Returns:
|
||
包含 memory_config_id 和相关信息的响应
|
||
"""
|
||
from app.services.memory_agent_service import (
|
||
get_end_user_connected_config as get_config,
|
||
)
|
||
|
||
api_logger.info(f"Getting connected config for end_user: {end_user_id}")
|
||
|
||
try:
|
||
result = get_config(end_user_id, db)
|
||
return success(data=result, msg="获取终端用户关联配置成功")
|
||
except ValueError as e:
|
||
api_logger.warning(f"End user config not found: {str(e)}")
|
||
return fail(BizCode.NOT_FOUND, str(e))
|
||
except Exception as e:
|
||
api_logger.error(f"Failed to get end user connected config: {str(e)}", exc_info=True)
|
||
return fail(BizCode.INTERNAL_ERROR, "获取终端用户关联配置失败", str(e)) |