feat: 重构成员画像为日周月分层沉淀链路并增强后台摘要能力
本次提交围绕成员画像插件进行了较大升级,核心目标是把原来偏单次、偏近期的成员交互摘要,升级为可随时间沉淀的分层画像能力。 主要功能变更如下: 1. 新增成员分层摘要存储表 t_member_digest,并提供对应的数据库操作层,支持按成员、按群、按摘要类型(daily/weekly/monthly)持久化周期性摘要结果。 2. 在 member_context 插件内新增 MemberDigestService,把画像生成拆分为日摘要、周摘要、月摘要三级处理流程,再由最终画像服务消费这些分层摘要,减少直接反复处理大量原始消息带来的成本和失真。 3. 新增提示词构建模块,分别为日级观察、周级归纳、月级归纳以及最终画像整理提供独立提示词,强调中性、克制、避免敏感推断,并将长期特征与近期状态明确分层。 4. 重写成员最终画像生成逻辑,优先基于日/周/月摘要融合出长期特征、习惯模式、长期回复偏好、近期状态等信息,再用 AI 对分层摘要做最终整理,避免仅依赖近 30 天消息得出偏短期结论。 5. 保留并增强长期画像融合逻辑,通过打分、衰减和重复证据累积,使长期特征随着时间逐步稳定,而不会被单次刷新完全覆盖。 6. 在消息存储层补充成员按时间增量获取、按活跃日期统计、按天取消息等查询方法,为后续分层摘要生成提供数据支撑。 7. 扩展 member_context 插件配置,增加日级摘要消息上限、日摘要最小消息数、单次回填的日摘要数量上限、最终画像使用的日/周/月摘要数量等参数,便于在准确性和系统负载之间做平衡。 8. 后台成员摘要详情页新增长期沟通倾向、长期特征、习惯模式、长期回复偏好、近期状态、历史样本数、分层摘要数量等展示字段,方便观察画像沉淀程度。 9. 优化后台查看成员摘要接口逻辑:首次打开如果还没有摘要,不再同步阻塞生成,而是返回未就绪状态,配合后台手动异步刷新,降低页面卡顿和接口阻塞风险。 10. 增强刷新日志,单成员和群级刷新会输出当前刷新模式以及日/周/月摘要数量,便于排查画像构建进度。 11. 调整当前日、当前周、当前月摘要的重算逻辑,确保新增日摘要写入后,本周和本月摘要不会长期停留在旧版本。 本次提交后,成员画像能力从“基于近期样本的单层摘要”升级为“基于时间沉淀的分层画像管线”,为后续把画像稳定接入 AI 自动回复上下文打下基础,同时尽量保持现有群权限控制和后台异步刷新方式不变。
This commit is contained in:
@@ -260,9 +260,13 @@ def api_group_member_context(roomid, wxid):
|
||||
if not server.member_context_service.is_group_enabled(roomid):
|
||||
return jsonify({"success": False, "error": "该群未启用成员交互摘要功能"}), 403
|
||||
context = server.member_context_db.get_member_context(roomid, wxid)
|
||||
if not context:
|
||||
context = server.member_context_service.refresh_member_context(roomid, wxid)
|
||||
return jsonify({"success": True, "data": {"context": context}})
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"data": {
|
||||
"context": context,
|
||||
"ready": bool(context)
|
||||
}
|
||||
})
|
||||
except Exception as e:
|
||||
logger.error(f"获取群成员交互摘要失败: {e}")
|
||||
return jsonify({"success": False, "error": str(e)}), 500
|
||||
|
||||
@@ -262,19 +262,58 @@
|
||||
<el-button size="mini" type="success" @click="refreshMemberContext">刷新摘要</el-button>
|
||||
</div>
|
||||
|
||||
<el-empty
|
||||
v-if="!memberContextLoading && !memberContext"
|
||||
description="暂无后台摘要,可手动刷新后稍等查看。">
|
||||
</el-empty>
|
||||
|
||||
<el-descriptions :column="1" border v-if="memberContext">
|
||||
<el-descriptions-item label="互动强度">{% raw %}{{ memberContext.activity_level || '-' }}{% endraw %}</el-descriptions-item>
|
||||
<el-descriptions-item label="表达特征">{% raw %}{{ memberContext.message_pattern || '-' }}{% endraw %}</el-descriptions-item>
|
||||
<el-descriptions-item label="互动风格">{% raw %}{{ memberContext.interaction_style || '-' }}{% endraw %}</el-descriptions-item>
|
||||
<el-descriptions-item label="性格倾向(长期观察)">{% raw %}{{ ((memberContext.meta || {}).temperament_tendency) || '-' }}{% endraw %}</el-descriptions-item>
|
||||
<el-descriptions-item label="回复建议">{% raw %}{{ memberContext.response_style_hint || '-' }}{% endraw %}</el-descriptions-item>
|
||||
<el-descriptions-item label="观察跨度">
|
||||
{% raw %}{{ ((memberContext.meta || {}).observation_days || 0) }}{% endraw %} 天
|
||||
<el-tag
|
||||
v-if="(memberContext.meta || {}).stable_ready"
|
||||
size="mini"
|
||||
type="success"
|
||||
class="context-tag">
|
||||
已进入长期画像
|
||||
</el-tag>
|
||||
<el-tag
|
||||
v-else
|
||||
size="mini"
|
||||
type="info"
|
||||
class="context-tag">
|
||||
仍在积累
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="长期关注">
|
||||
<el-tag v-for="item in (memberContext.topics_of_interest || [])" :key="item" size="mini" class="context-tag">{% raw %}{{ item }}{% endraw %}</el-tag>
|
||||
<span v-if="!(memberContext.topics_of_interest || []).length">-</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="长期特征">
|
||||
<el-tag v-for="item in (((memberContext.meta || {}).stable_traits) || [])" :key="item" size="mini" type="warning" class="context-tag">{% raw %}{{ item }}{% endraw %}</el-tag>
|
||||
<span v-if="!((((memberContext.meta || {}).stable_traits) || []).length)">-</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="习惯模式">
|
||||
<el-tag v-for="item in (((memberContext.meta || {}).habit_patterns) || [])" :key="item" size="mini" type="info" class="context-tag">{% raw %}{{ item }}{% endraw %}</el-tag>
|
||||
<span v-if="!((((memberContext.meta || {}).habit_patterns) || []).length)">-</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="长期回复偏好">
|
||||
<el-tag v-for="item in (((memberContext.meta || {}).long_term_reply_preferences) || [])" :key="item" size="mini" type="success" class="context-tag">{% raw %}{{ item }}{% endraw %}</el-tag>
|
||||
<span v-if="!((((memberContext.meta || {}).long_term_reply_preferences) || []).length)">-</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="近期话题">
|
||||
<el-tag v-for="item in (memberContext.recent_focus || [])" :key="item" size="mini" type="success" class="context-tag">{% raw %}{{ item }}{% endraw %}</el-tag>
|
||||
<span v-if="!(memberContext.recent_focus || []).length">-</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="近期状态">
|
||||
<el-tag v-for="item in (((memberContext.meta || {}).recent_state) || [])" :key="item" size="mini" type="primary" class="context-tag">{% raw %}{{ item }}{% endraw %}</el-tag>
|
||||
<span v-if="!((((memberContext.meta || {}).recent_state) || []).length)">-</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="显著特征">
|
||||
<el-tag v-for="item in ((memberContext.meta || {}).engagement_traits || [])" :key="item" size="mini" type="warning" class="context-tag">{% raw %}{{ item }}{% endraw %}</el-tag>
|
||||
<span v-if="!(((memberContext.meta || {}).engagement_traits || []).length)">-</span>
|
||||
@@ -285,6 +324,13 @@
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="摘要说明">{% raw %}{{ memberContext.summary_text || '-' }}{% endraw %}</el-descriptions-item>
|
||||
<el-descriptions-item label="样本消息">{% raw %}{{ memberContext.source_message_count || 0 }}{% endraw %}</el-descriptions-item>
|
||||
<el-descriptions-item label="历史样本">{% raw %}{{ ((memberContext.meta || {}).history_message_count) || 0 }}{% endraw %}</el-descriptions-item>
|
||||
<el-descriptions-item label="摘要层级">
|
||||
日 {% raw %}{{ ((memberContext.meta || {}).digest_daily_count) || 0 }}{% endraw %}
|
||||
/ 周 {% raw %}{{ ((memberContext.meta || {}).digest_weekly_count) || 0 }}{% endraw %}
|
||||
/ 月 {% raw %}{{ ((memberContext.meta || {}).digest_monthly_count) || 0 }}{% endraw %}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="累计刷新">{% raw %}{{ ((memberContext.meta || {}).profile_iterations) || 0 }}{% endraw %}</el-descriptions-item>
|
||||
<el-descriptions-item label="最后更新">{% raw %}{{ memberContext.last_profiled_at || '-' }}{% endraw %}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user