Refine member context profiling detail
This commit is contained in:
@@ -189,9 +189,13 @@ class ContextBuilder:
|
||||
meta = member_context.get("meta", {}) or {}
|
||||
topics = member_context.get("topics_of_interest", []) or []
|
||||
recent_focus = member_context.get("recent_focus", []) or []
|
||||
common_scenarios = ContextBuilder._stringify_items(meta.get("common_scenarios", []), 4)
|
||||
skills = ContextBuilder._stringify_items(meta.get("skill_profile", []), 5)
|
||||
problem_solving = ContextBuilder._stringify_items(meta.get("problem_solving_profile", []), 4)
|
||||
stable_traits = ContextBuilder._stringify_items(meta.get("stable_traits", []), 4)
|
||||
habits = ContextBuilder._stringify_items(meta.get("habit_patterns", []), 4)
|
||||
expression_profile = ContextBuilder._stringify_items(meta.get("expression_profile", []), 4)
|
||||
reply_entry = ContextBuilder._stringify_items(meta.get("reply_entry_profile", []), 4)
|
||||
reply_prefs = ContextBuilder._stringify_items(meta.get("long_term_reply_preferences", []), 4)
|
||||
recent_state = ContextBuilder._stringify_items(meta.get("recent_state", []), 4)
|
||||
reply_taboos = ContextBuilder._stringify_items(meta.get("reply_taboos", []), 3)
|
||||
@@ -201,9 +205,13 @@ class ContextBuilder:
|
||||
f"回复偏好:{member_context.get('response_style_hint', '')}".strip(),
|
||||
f"长期主题:{', '.join(topics[:5])}" if topics else "",
|
||||
f"近期关注:{', '.join(recent_focus[:4])}" if recent_focus else "",
|
||||
f"常见发言场景:{common_scenarios}" if common_scenarios else "",
|
||||
f"技能侧重点:{skills}" if skills else "",
|
||||
f"处理问题方式:{problem_solving}" if problem_solving else "",
|
||||
f"稳定特征:{stable_traits}" if stable_traits else "",
|
||||
f"习惯模式:{habits}" if habits else "",
|
||||
f"表达标记:{expression_profile}" if expression_profile else "",
|
||||
f"有效接话点:{reply_entry}" if reply_entry else "",
|
||||
f"长期回复偏好:{reply_prefs}" if reply_prefs else "",
|
||||
f"近期状态:{recent_state}" if recent_state else "",
|
||||
f"气质倾向:{meta.get('temperament_tendency', '')}".strip(),
|
||||
|
||||
@@ -67,10 +67,14 @@
|
||||
3. 请先按 wxid 汇总该成员全天发言,再提取结果。
|
||||
4. 即使成员发言以短句为主,只要样本量足够,也必须尽量提炼:
|
||||
- topics
|
||||
- discussion_scenarios
|
||||
- skill_signals
|
||||
- problem_solving_signals
|
||||
- value_preferences
|
||||
- habit_signals
|
||||
- expression_markers
|
||||
- engagement_traits
|
||||
- reply_entry_points
|
||||
- social_role
|
||||
- temperament_signal
|
||||
- summary_text
|
||||
@@ -88,8 +92,10 @@
|
||||
"wxid": "成员wxid",
|
||||
"display_name": "显示名",
|
||||
"topics": ["主题1"],
|
||||
"discussion_scenarios": ["场景1"],
|
||||
"identity_clues": ["身份线索1"],
|
||||
"skill_signals": ["技能信号1"],
|
||||
"problem_solving_signals": ["处理方式1"],
|
||||
"family_signals": ["家庭线索1"],
|
||||
"life_stage_signals": ["阶段线索1"],
|
||||
"value_preferences": ["价值偏好1"],
|
||||
@@ -97,7 +103,9 @@
|
||||
"message_pattern": "一句中文",
|
||||
"response_style_hint": "一句中文",
|
||||
"habit_signals": ["习惯1"],
|
||||
"expression_markers": ["表达标记1"],
|
||||
"engagement_traits": ["参与特征1"],
|
||||
"reply_entry_points": ["接话点1"],
|
||||
"decision_style": "一句中文",
|
||||
"social_role": "一句中文",
|
||||
"reply_taboos": ["避坑1"],
|
||||
|
||||
@@ -149,10 +149,12 @@ class MemberDigestService:
|
||||
normalized = {}
|
||||
list_keys = {
|
||||
"topics", "identity_clues", "skill_signals", "family_signals", "life_stage_signals",
|
||||
"value_preferences", "habit_signals", "engagement_traits", "reply_taboos",
|
||||
"discussion_scenarios", "problem_solving_signals", "value_preferences", "habit_signals",
|
||||
"expression_markers", "engagement_traits", "reply_entry_points", "reply_taboos",
|
||||
"representative_messages", "stable_topics", "identity_traits", "skill_profile",
|
||||
"family_profile", "life_stage_profile", "value_profile", "stable_traits",
|
||||
"habit_patterns", "reply_preferences", "long_term_topics", "long_term_reply_preferences",
|
||||
"problem_solving_profile", "family_profile", "life_stage_profile", "value_profile",
|
||||
"stable_traits", "habit_patterns", "expression_profile", "reply_entry_profile",
|
||||
"reply_preferences", "long_term_topics", "long_term_reply_preferences", "common_scenarios",
|
||||
"phase_state", "recent_state"
|
||||
}
|
||||
for key, value in item.items():
|
||||
|
||||
351
plugins/member_context/member_context.yml
Normal file
351
plugins/member_context/member_context.yml
Normal file
@@ -0,0 +1,351 @@
|
||||
app:
|
||||
description: 按群和日期提取群成员日画像,输出严格 JSON,供 member_context 插件直接消费
|
||||
icon: 🤖
|
||||
icon_background: '#E0F2FE'
|
||||
mode: workflow
|
||||
name: member_context
|
||||
use_icon_as_answer_icon: false
|
||||
dependencies:
|
||||
- current_identifier: null
|
||||
type: marketplace
|
||||
value:
|
||||
marketplace_plugin_unique_identifier: langgenius/openai_api_compatible:0.0.27@f9ce3ff5e28f09931a3a7fca59add2d09590408f7e9a3d701b10c77a60249719
|
||||
version: null
|
||||
kind: app
|
||||
version: 0.5.0
|
||||
workflow:
|
||||
conversation_variables: []
|
||||
environment_variables: []
|
||||
features:
|
||||
file_upload:
|
||||
allowed_file_extensions:
|
||||
- .TXT
|
||||
allowed_file_types:
|
||||
- document
|
||||
allowed_file_upload_methods:
|
||||
- local_file
|
||||
- remote_url
|
||||
enabled: false
|
||||
fileUploadConfig:
|
||||
audio_file_size_limit: 50
|
||||
batch_count_limit: 5
|
||||
file_size_limit: 15
|
||||
image_file_batch_limit: 10
|
||||
image_file_size_limit: 10
|
||||
single_chunk_attachment_limit: 10
|
||||
video_file_size_limit: 100
|
||||
workflow_file_upload_limit: 10
|
||||
image:
|
||||
enabled: false
|
||||
number_limits: 3
|
||||
transfer_methods:
|
||||
- local_file
|
||||
- remote_url
|
||||
number_limits: 3
|
||||
opening_statement: ''
|
||||
retriever_resource:
|
||||
enabled: false
|
||||
sensitive_word_avoidance:
|
||||
enabled: false
|
||||
speech_to_text:
|
||||
enabled: false
|
||||
suggested_questions: []
|
||||
suggested_questions_after_answer:
|
||||
enabled: false
|
||||
text_to_speech:
|
||||
enabled: false
|
||||
language: ''
|
||||
voice: ''
|
||||
graph:
|
||||
edges:
|
||||
- data:
|
||||
isInIteration: false
|
||||
isInLoop: false
|
||||
sourceType: start
|
||||
targetType: llm
|
||||
id: start-source-llm-target
|
||||
selected: false
|
||||
source: start_node
|
||||
sourceHandle: source
|
||||
target: llm_node
|
||||
targetHandle: target
|
||||
type: custom
|
||||
zIndex: 0
|
||||
- data:
|
||||
isInIteration: false
|
||||
isInLoop: false
|
||||
sourceType: llm
|
||||
targetType: end
|
||||
id: llm-source-end-target
|
||||
selected: false
|
||||
source: llm_node
|
||||
sourceHandle: source
|
||||
target: end_node
|
||||
targetHandle: target
|
||||
type: custom
|
||||
zIndex: 0
|
||||
- data:
|
||||
isInIteration: false
|
||||
isInLoop: false
|
||||
sourceType: llm
|
||||
targetType: llm
|
||||
id: llm_node-fail-branch-1775115372864-target
|
||||
source: llm_node
|
||||
sourceHandle: fail-branch
|
||||
target: '1775115372864'
|
||||
targetHandle: target
|
||||
type: custom
|
||||
zIndex: 0
|
||||
- data:
|
||||
isInLoop: false
|
||||
sourceType: llm
|
||||
targetType: end
|
||||
id: 1775115372864-source-end_node-target
|
||||
source: '1775115372864'
|
||||
sourceHandle: source
|
||||
target: end_node
|
||||
targetHandle: target
|
||||
type: custom
|
||||
zIndex: 0
|
||||
nodes:
|
||||
- data:
|
||||
desc: ''
|
||||
selected: false
|
||||
title: 开始
|
||||
type: start
|
||||
variables:
|
||||
- label: query
|
||||
max_length: 120000
|
||||
options: []
|
||||
required: false
|
||||
type: paragraph
|
||||
variable: query
|
||||
- label: chatroom_id
|
||||
max_length: 128
|
||||
options: []
|
||||
required: true
|
||||
type: text-input
|
||||
variable: chatroom_id
|
||||
- label: digest_date
|
||||
max_length: 32
|
||||
options: []
|
||||
required: true
|
||||
type: text-input
|
||||
variable: digest_date
|
||||
- label: member_labels
|
||||
max_length: 50000
|
||||
options: []
|
||||
required: true
|
||||
type: paragraph
|
||||
variable: member_labels
|
||||
- label: compressed_chat
|
||||
max_length: 200000
|
||||
options: []
|
||||
required: true
|
||||
type: paragraph
|
||||
variable: compressed_chat
|
||||
height: 213
|
||||
id: start_node
|
||||
position:
|
||||
x: 0
|
||||
y: 0
|
||||
positionAbsolute:
|
||||
x: 0
|
||||
y: 0
|
||||
selected: false
|
||||
sourcePosition: right
|
||||
targetPosition: left
|
||||
type: custom
|
||||
width: 242
|
||||
- data:
|
||||
context:
|
||||
enabled: false
|
||||
variable_selector: []
|
||||
desc: ''
|
||||
error_strategy: fail-branch
|
||||
model:
|
||||
completion_params:
|
||||
temperature: 0.2
|
||||
mode: chat
|
||||
name: gpt-5.4-mini
|
||||
provider: langgenius/openai_api_compatible/openai_api_compatible
|
||||
prompt_template:
|
||||
- id: system_prompt_member_context
|
||||
role: system
|
||||
text: "你是微信群后台的成员日行为证据提取器。\n\n任务:\n根据给定的一天群聊记录,只按 wxid 识别成员,输出每个成员当天的结构化行为观察。\n\
|
||||
\n关键规则:\n1. wxid 是唯一标识。display_name 仅用于展示,不用于身份判定。\n2. 每个 wxid 最终只能输出一条记录,严禁重复输出同一个\
|
||||
\ wxid。\n3. 请先按 wxid 汇总该成员全天发言,再提取结果。\n4. 即使成员发言以短句为主,只要样本量足够,也必须尽量提炼:\n\
|
||||
\ - topics\n - discussion_scenarios\n - skill_signals\n - problem_solving_signals\n\
|
||||
\ - value_preferences\n - habit_signals\n - expression_markers\n\
|
||||
\ - engagement_traits\n - reply_entry_points\n - social_role\n\
|
||||
\ - temperament_signal\n - summary_text\n5. identity_clues、family_signals、life_stage_signals\
|
||||
\ 没有明确公开证据时允许为空。\n6. 不允许因为“短句较多”就统一输出空数组和通用摘要。\n7. 不做心理诊断、不做隐私猜测、不把玩笑当事实。\n\
|
||||
8. 只能输出候选成员列表中的 wxid。\n9. topics 更偏向反复出现的关注方向;discussion_scenarios 更偏向什么情境下会发言;skill_signals\
|
||||
\ 更偏向能力表现;problem_solving_signals 更偏向怎么处理问题;value_preferences 更偏向判断偏好;social_role 更偏向当天在群里的实际作用。\n\
|
||||
10. expression_markers 记录可观察的表达标记,如常用句式、口头禅、是否爱列步骤/贴日志;reply_entry_points 记录什么样的接话方式最容易接住他。\n\
|
||||
11. 输出前自行去重,同一个 wxid 只保留一条最完整结果。\n\n输出要求:\n- 只输出严格 JSON,不要 markdown,不要解释,不要前后缀。\n\
|
||||
- 输出格式:\n{\n \"members\": [\n {\n \"wxid\": \"成员wxid\",\n \
|
||||
\ \"display_name\": \"显示名\",\n \"topics\": [\"主题1\"],\n \"discussion_scenarios\"\
|
||||
: [\"场景1\"],\n \"identity_clues\": [\"身份线索1\"],\n \"skill_signals\"\
|
||||
: [\"技能信号1\"],\n \"problem_solving_signals\": [\"处理方式1\"],\n \
|
||||
\ \"family_signals\": [\"家庭线索1\"],\n \"life_stage_signals\": [\"\
|
||||
阶段线索1\"],\n \"value_preferences\": [\"价值偏好1\"],\n \"interaction_style\"\
|
||||
: \"一句中文\",\n \"message_pattern\": \"一句中文\",\n \"response_style_hint\"\
|
||||
: \"一句中文\",\n \"habit_signals\": [\"习惯1\"],\n \"expression_markers\"\
|
||||
: [\"表达标记1\"],\n \"engagement_traits\": [\"参与特征1\"],\n \"reply_entry_points\"\
|
||||
: [\"接话点1\"],\n \"decision_style\": \"一句中文\",\n \"social_role\"\
|
||||
: \"一句中文\",\n \"reply_taboos\": [\"避坑1\"],\n \"temperament_signal\"\
|
||||
: \"一句中文\",\n \"summary_text\": \"不超过100字\",\n \"representative_messages\"\
|
||||
: [\"原话1\", \"原话2\"],\n \"confidence\": 0.95\n }\n ]\n}\n\n字段约束:\n\
|
||||
- topics、discussion_scenarios、skill_signals、problem_solving_signals、value_preferences、habit_signals、expression_markers、engagement_traits、reply_entry_points\
|
||||
\ 最多 4 个\n- identity_clues、family_signals、life_stage_signals 最多 3 个\n\
|
||||
- reply_taboos 最多 3 个\n- representative_messages 最多 3 条\n- 如果某成员样本明显不足,可以不输出该成员\n"
|
||||
- id: user_prompt_member_context
|
||||
role: user
|
||||
text: '群ID: {{#start_node.chatroom_id#}}
|
||||
|
||||
日期: {{#start_node.digest_date#}}
|
||||
|
||||
|
||||
候选成员:
|
||||
|
||||
{{#start_node.member_labels#}}
|
||||
|
||||
|
||||
压缩后的群聊记录:
|
||||
|
||||
{{#start_node.compressed_chat#}}
|
||||
|
||||
'
|
||||
retry_config:
|
||||
max_retries: 3
|
||||
retry_enabled: true
|
||||
retry_interval: 1000
|
||||
selected: false
|
||||
title: 成员画像提取
|
||||
type: llm
|
||||
variables: []
|
||||
vision:
|
||||
enabled: false
|
||||
height: 154
|
||||
id: llm_node
|
||||
position:
|
||||
x: 342
|
||||
y: 30
|
||||
positionAbsolute:
|
||||
x: 342
|
||||
y: 30
|
||||
selected: false
|
||||
sourcePosition: right
|
||||
targetPosition: left
|
||||
type: custom
|
||||
width: 242
|
||||
- data:
|
||||
desc: ''
|
||||
outputs:
|
||||
- value_selector:
|
||||
- llm_node
|
||||
- text
|
||||
variable: text
|
||||
selected: false
|
||||
title: 结束
|
||||
type: end
|
||||
height: 88
|
||||
id: end_node
|
||||
position:
|
||||
x: 1066
|
||||
y: 52
|
||||
positionAbsolute:
|
||||
x: 1066
|
||||
y: 52
|
||||
selected: false
|
||||
sourcePosition: right
|
||||
targetPosition: left
|
||||
type: custom
|
||||
width: 242
|
||||
- data:
|
||||
context:
|
||||
enabled: false
|
||||
variable_selector: []
|
||||
default_value:
|
||||
- key: text
|
||||
type: string
|
||||
value: '{"members": []}'
|
||||
error_strategy: default-value
|
||||
model:
|
||||
completion_params:
|
||||
temperature: 0.7
|
||||
mode: chat
|
||||
name: grok-4-fast
|
||||
provider: langgenius/openai_api_compatible/openai_api_compatible
|
||||
prompt_template:
|
||||
- id: c5ee983e-d6e0-4790-ac3b-f4e097013b70
|
||||
role: system
|
||||
text: "你是微信群后台的成员日行为证据提取器。\n\n任务:\n根据给定的一天群聊记录,只按 wxid 识别成员,输出每个成员当天的结构化行为观察。\n\
|
||||
\n关键规则:\n1. wxid 是唯一标识。display_name 仅用于展示,不用于身份判定。\n2. 每个 wxid 最终只能输出一条记录,严禁重复输出同一个\
|
||||
\ wxid。\n3. 请先按 wxid 汇总该成员全天发言,再提取结果。\n4. 即使成员发言以短句为主,只要样本量足够,也必须尽量提炼:\n\
|
||||
\ - topics\n - discussion_scenarios\n - skill_signals\n - problem_solving_signals\n\
|
||||
\ - value_preferences\n - habit_signals\n - expression_markers\n\
|
||||
\ - engagement_traits\n - reply_entry_points\n - social_role\n\
|
||||
\ - temperament_signal\n - summary_text\n5. identity_clues、family_signals、life_stage_signals\
|
||||
\ 没有明确公开证据时允许为空。\n6. 不允许因为“短句较多”就统一输出空数组和通用摘要。\n7. 不做心理诊断、不做隐私猜测、不把玩笑当事实。\n\
|
||||
8. 只能输出候选成员列表中的 wxid。\n9. topics 更偏向反复出现的关注方向;discussion_scenarios 更偏向什么情境下会发言;skill_signals\
|
||||
\ 更偏向能力表现;problem_solving_signals 更偏向怎么处理问题;value_preferences 更偏向判断偏好;social_role 更偏向当天在群里的实际作用。\n\
|
||||
10. expression_markers 记录可观察的表达标记,如常用句式、口头禅、是否爱列步骤/贴日志;reply_entry_points 记录什么样的接话方式最容易接住他。\n\
|
||||
11. 输出前自行去重,同一个 wxid 只保留一条最完整结果。\n\n输出要求:\n- 只输出严格 JSON,不要 markdown,不要解释,不要前后缀。\n\
|
||||
- 输出格式:\n{\n \"members\": [\n {\n \"wxid\": \"成员wxid\",\n \
|
||||
\ \"display_name\": \"显示名\",\n \"topics\": [\"主题1\"],\n \"discussion_scenarios\"\
|
||||
: [\"场景1\"],\n \"identity_clues\": [\"身份线索1\"],\n \"skill_signals\"\
|
||||
: [\"技能信号1\"],\n \"problem_solving_signals\": [\"处理方式1\"],\n \
|
||||
\ \"family_signals\": [\"家庭线索1\"],\n \"life_stage_signals\": [\"\
|
||||
阶段线索1\"],\n \"value_preferences\": [\"价值偏好1\"],\n \"interaction_style\"\
|
||||
: \"一句中文\",\n \"message_pattern\": \"一句中文\",\n \"response_style_hint\"\
|
||||
: \"一句中文\",\n \"habit_signals\": [\"习惯1\"],\n \"expression_markers\"\
|
||||
: [\"表达标记1\"],\n \"engagement_traits\": [\"参与特征1\"],\n \"reply_entry_points\"\
|
||||
: [\"接话点1\"],\n \"decision_style\": \"一句中文\",\n \"social_role\"\
|
||||
: \"一句中文\",\n \"reply_taboos\": [\"避坑1\"],\n \"temperament_signal\"\
|
||||
: \"一句中文\",\n \"summary_text\": \"不超过100字\",\n \"representative_messages\"\
|
||||
: [\"原话1\", \"原话2\"],\n \"confidence\": 0.95\n }\n ]\n}\n\n字段约束:\n\
|
||||
- topics、discussion_scenarios、skill_signals、problem_solving_signals、value_preferences、habit_signals、expression_markers、engagement_traits、reply_entry_points\
|
||||
\ 最多 4 个\n- identity_clues、family_signals、life_stage_signals 最多 3 个\n\
|
||||
- reply_taboos 最多 3 个\n- representative_messages 最多 3 条\n- 如果某成员样本明显不足,可以不输出该成员\n"
|
||||
- id: 2df6d4ce-4e40-42a9-85f3-184075da24c7
|
||||
role: user
|
||||
text: '群ID: {{#start_node.chatroom_id#}}
|
||||
|
||||
日期: {{#start_node.digest_date#}}
|
||||
|
||||
|
||||
候选成员:
|
||||
|
||||
{{#start_node.member_labels#}}
|
||||
|
||||
|
||||
压缩后的群聊记录:
|
||||
|
||||
{{#start_node.compressed_chat#}}
|
||||
|
||||
'
|
||||
selected: true
|
||||
title: 异常分支
|
||||
type: llm
|
||||
vision:
|
||||
enabled: false
|
||||
height: 124
|
||||
id: '1775115372864'
|
||||
position:
|
||||
x: 704
|
||||
y: 132
|
||||
positionAbsolute:
|
||||
x: 704
|
||||
y: 132
|
||||
selected: true
|
||||
sourcePosition: right
|
||||
targetPosition: left
|
||||
type: custom
|
||||
width: 242
|
||||
viewport:
|
||||
x: 210
|
||||
y: 340
|
||||
zoom: 0.7
|
||||
rag_pipeline_variables: []
|
||||
@@ -162,10 +162,14 @@ workflow:
|
||||
3. 请先按 wxid 汇总该成员全天发言,再提取结果。
|
||||
4. 即使成员发言以短句为主,只要样本量足够,也必须尽量提炼:
|
||||
- topics
|
||||
- discussion_scenarios
|
||||
- skill_signals
|
||||
- problem_solving_signals
|
||||
- value_preferences
|
||||
- habit_signals
|
||||
- expression_markers
|
||||
- engagement_traits
|
||||
- reply_entry_points
|
||||
- social_role
|
||||
- temperament_signal
|
||||
- summary_text
|
||||
@@ -173,8 +177,9 @@ workflow:
|
||||
6. 不允许因为“短句较多”就统一输出空数组和通用摘要。
|
||||
7. 不做心理诊断、不做隐私猜测、不把玩笑当事实。
|
||||
8. 只能输出候选成员列表中的 wxid。
|
||||
9. topics 更偏向反复出现的关注方向;skill_signals 更偏向能力表现;value_preferences 更偏向判断偏好;social_role 更偏向当天在群里的实际作用。
|
||||
10. 输出前自行去重,同一个 wxid 只保留一条最完整结果。
|
||||
9. topics 更偏向反复出现的关注方向;discussion_scenarios 更偏向什么情境下会发言;skill_signals 更偏向能力表现;problem_solving_signals 更偏向怎么处理问题;value_preferences 更偏向判断偏好;social_role 更偏向当天在群里的实际作用。
|
||||
10. expression_markers 记录可观察的表达标记,如常用句式、口头禅、是否爱列步骤/贴日志;reply_entry_points 记录什么样的接话方式最容易接住他。
|
||||
11. 输出前自行去重,同一个 wxid 只保留一条最完整结果。
|
||||
|
||||
输出要求:
|
||||
- 只输出严格 JSON,不要 markdown,不要解释,不要前后缀。
|
||||
@@ -185,8 +190,10 @@ workflow:
|
||||
"wxid": "成员wxid",
|
||||
"display_name": "显示名",
|
||||
"topics": ["主题1"],
|
||||
"discussion_scenarios": ["场景1"],
|
||||
"identity_clues": ["身份线索1"],
|
||||
"skill_signals": ["技能信号1"],
|
||||
"problem_solving_signals": ["处理方式1"],
|
||||
"family_signals": ["家庭线索1"],
|
||||
"life_stage_signals": ["阶段线索1"],
|
||||
"value_preferences": ["价值偏好1"],
|
||||
@@ -194,7 +201,9 @@ workflow:
|
||||
"message_pattern": "一句中文",
|
||||
"response_style_hint": "一句中文",
|
||||
"habit_signals": ["习惯1"],
|
||||
"expression_markers": ["表达标记1"],
|
||||
"engagement_traits": ["参与特征1"],
|
||||
"reply_entry_points": ["接话点1"],
|
||||
"decision_style": "一句中文",
|
||||
"social_role": "一句中文",
|
||||
"reply_taboos": ["避坑1"],
|
||||
@@ -207,7 +216,7 @@ workflow:
|
||||
}
|
||||
|
||||
字段约束:
|
||||
- topics、skill_signals、value_preferences、habit_signals、engagement_traits 最多 4 个
|
||||
- topics、discussion_scenarios、skill_signals、problem_solving_signals、value_preferences、habit_signals、expression_markers、engagement_traits、reply_entry_points 最多 4 个
|
||||
- identity_clues、family_signals、life_stage_signals 最多 3 个
|
||||
- reply_taboos 最多 3 个
|
||||
- representative_messages 最多 3 条
|
||||
|
||||
@@ -21,8 +21,10 @@ class MemberContextPromptBuilder:
|
||||
"\"wxid\":\"成员wxid\","
|
||||
"\"display_name\":\"成员显示名\","
|
||||
"\"topics\":[\"主题1\"],"
|
||||
"\"discussion_scenarios\":[\"场景1\"],"
|
||||
"\"identity_clues\":[\"身份线索1\"],"
|
||||
"\"skill_signals\":[\"技能信号1\"],"
|
||||
"\"problem_solving_signals\":[\"处理方式1\"],"
|
||||
"\"family_signals\":[\"家庭线索1\"],"
|
||||
"\"life_stage_signals\":[\"阶段线索1\"],"
|
||||
"\"value_preferences\":[\"价值偏好1\"],"
|
||||
@@ -30,7 +32,9 @@ class MemberContextPromptBuilder:
|
||||
"\"message_pattern\":\"一句中文\","
|
||||
"\"response_style_hint\":\"一句中文\","
|
||||
"\"habit_signals\":[\"信号1\"],"
|
||||
"\"expression_markers\":[\"表达标记1\"],"
|
||||
"\"engagement_traits\":[\"特征1\"],"
|
||||
"\"reply_entry_points\":[\"接话点1\"],"
|
||||
"\"decision_style\":\"一句中文\","
|
||||
"\"social_role\":\"一句中文,描述当天在群中的角色表现\","
|
||||
"\"reply_taboos\":[\"避坑1\"],"
|
||||
@@ -43,15 +47,17 @@ class MemberContextPromptBuilder:
|
||||
"}\n"
|
||||
"要求:\n"
|
||||
"1. 只输出当天真正参与发言且能看出明确行为信号的成员;发言极少的人可以不输出。\n"
|
||||
"2. 每个成员的 topics、identity_clues、skill_signals、family_signals、life_stage_signals、value_preferences、habit_signals、engagement_traits 最多4个,reply_taboos 最多3个。\n"
|
||||
"2. 每个成员的 topics、discussion_scenarios、identity_clues、skill_signals、problem_solving_signals、family_signals、life_stage_signals、value_preferences、habit_signals、expression_markers、engagement_traits、reply_entry_points 最多4个,reply_taboos 最多3个。\n"
|
||||
"3. representative_messages 只保留最能代表当天表达方式的短句,最多3条。\n"
|
||||
"4. 必须严格使用候选成员列表中的 wxid 和显示名。\n"
|
||||
"5. identity_clues、family_signals、life_stage_signals 只能写公开聊天中出现的线索,不可把弱线索写成确定事实。\n"
|
||||
"6. skill_signals 重点提炼成员解决问题、提供信息、组织表达、专业能力等信号。\n"
|
||||
"7. social_role 只描述当天在群里的角色表现,例如:问题提出者、信息补充者、气氛调节者、组织推进者。\n"
|
||||
"8. topics 更偏向持续关注的话题方向;habit_signals 更偏向重复表达或互动习惯;engagement_traits 更偏向参与方式。\n"
|
||||
"9. value_preferences 只记录公开表达出的偏好,如效率优先、成本敏感、谨慎验证、乐于助人,不要写抽象大词。\n"
|
||||
"10. summary_text 应是后台观察摘要,不要写成对用户说的话。\n"
|
||||
"8. topics 更偏向持续关注的话题方向;discussion_scenarios 更偏向他通常在什么情境下发言,如求助排错、补充经验、分享资源、接梗互动。\n"
|
||||
"9. problem_solving_signals 要写得具体,比如先确认现象再给步骤、倾向贴链接/文档、会直接给结论和执行项,不要只写'善于解决问题'。\n"
|
||||
"10. expression_markers 记录可观察的表达标记,如常用句式、口头禅、是否爱列步骤/贴截图/贴日志;reply_entry_points 记录什么样的接话方式最容易接住他。\n"
|
||||
"11. value_preferences 只记录公开表达出的偏好,如效率优先、成本敏感、谨慎验证、乐于助人,不要写抽象大词。\n"
|
||||
"12. summary_text 应是后台观察摘要,不要写成对用户说的话。\n"
|
||||
f"群ID: {chatroom_id}\n"
|
||||
f"日期: {digest_date}\n"
|
||||
"候选成员:\n" + "\n".join(member_labels[:80]) + "\n"
|
||||
@@ -68,13 +74,17 @@ class MemberContextPromptBuilder:
|
||||
"period_key": item.get("period_key"),
|
||||
"summary_text": item.get("summary_text", ""),
|
||||
"topics": structured.get("topics") or structured.get("stable_topics") or structured.get("long_term_topics") or [],
|
||||
"discussion_scenarios": structured.get("discussion_scenarios") or structured.get("common_scenarios") or [],
|
||||
"identity_clues": structured.get("identity_clues") or structured.get("identity_traits") or [],
|
||||
"skill_signals": structured.get("skill_signals") or structured.get("skill_profile") or [],
|
||||
"problem_solving_signals": structured.get("problem_solving_signals") or structured.get("problem_solving_profile") or [],
|
||||
"family_signals": structured.get("family_signals") or structured.get("family_profile") or [],
|
||||
"life_stage_signals": structured.get("life_stage_signals") or structured.get("life_stage_profile") or [],
|
||||
"value_preferences": structured.get("value_preferences") or structured.get("value_profile") or [],
|
||||
"habit_signals": structured.get("habit_signals") or structured.get("habit_patterns") or [],
|
||||
"expression_markers": structured.get("expression_markers") or structured.get("expression_profile") or [],
|
||||
"engagement_traits": structured.get("engagement_traits") or structured.get("stable_traits") or [],
|
||||
"reply_entry_points": structured.get("reply_entry_points") or structured.get("reply_entry_profile") or [],
|
||||
"reply_preferences": structured.get("reply_preferences") or structured.get("long_term_reply_preferences") or [],
|
||||
"social_role": structured.get("social_role") or structured.get("group_role") or "",
|
||||
"decision_style": structured.get("decision_style") or structured.get("decision_profile") or "",
|
||||
@@ -87,13 +97,17 @@ class MemberContextPromptBuilder:
|
||||
schema = (
|
||||
"{"
|
||||
"\"stable_topics\":[\"主题1\"],"
|
||||
"\"common_scenarios\":[\"场景1\"],"
|
||||
"\"identity_traits\":[\"身份特征1\"],"
|
||||
"\"skill_profile\":[\"技能画像1\"],"
|
||||
"\"problem_solving_profile\":[\"处理方式1\"],"
|
||||
"\"family_profile\":[\"家庭线索1\"],"
|
||||
"\"life_stage_profile\":[\"阶段线索1\"],"
|
||||
"\"value_profile\":[\"价值偏好1\"],"
|
||||
"\"stable_traits\":[\"特征1\"],"
|
||||
"\"habit_patterns\":[\"习惯1\"],"
|
||||
"\"expression_profile\":[\"表达标记1\"],"
|
||||
"\"reply_entry_profile\":[\"接话点1\"],"
|
||||
"\"reply_preferences\":[\"偏好1\"],"
|
||||
"\"group_role\":\"一句中文\","
|
||||
"\"decision_profile\":\"一句中文\","
|
||||
@@ -108,13 +122,17 @@ class MemberContextPromptBuilder:
|
||||
schema = (
|
||||
"{"
|
||||
"\"long_term_topics\":[\"主题1\"],"
|
||||
"\"common_scenarios\":[\"场景1\"],"
|
||||
"\"identity_traits\":[\"身份特征1\"],"
|
||||
"\"skill_profile\":[\"技能画像1\"],"
|
||||
"\"problem_solving_profile\":[\"处理方式1\"],"
|
||||
"\"family_profile\":[\"家庭线索1\"],"
|
||||
"\"life_stage_profile\":[\"阶段线索1\"],"
|
||||
"\"value_profile\":[\"价值偏好1\"],"
|
||||
"\"stable_traits\":[\"特征1\"],"
|
||||
"\"habit_patterns\":[\"习惯1\"],"
|
||||
"\"expression_profile\":[\"表达标记1\"],"
|
||||
"\"reply_entry_profile\":[\"接话点1\"],"
|
||||
"\"long_term_reply_preferences\":[\"偏好1\"],"
|
||||
"\"group_role\":\"一句中文\","
|
||||
"\"decision_profile\":\"一句中文\","
|
||||
@@ -136,9 +154,11 @@ class MemberContextPromptBuilder:
|
||||
"2. 只有多个下级摘要反复出现的特征,才允许写进 stable_traits / habit_patterns / long_term_reply_preferences。\n"
|
||||
"3. recent_state / phase_state 只描述当前阶段状态,不要冒充长期人格。\n"
|
||||
"4. identity_traits、family_profile、life_stage_profile 只能保留反复出现的公开线索,不可编造事实。\n"
|
||||
"5. skill_profile 要优先提炼稳定出现的能力、专业方向、擅长处理的问题类型。\n"
|
||||
"6. group_role 描述其在群中的长期角色位置,decision_profile 描述其决策与判断风格。\n"
|
||||
"7. value_profile 需要优先保留真正反复出现的判断偏好,如效率优先、成本敏感、风险谨慎、愿意分享。\n"
|
||||
"5. common_scenarios 要总结这个人通常会在什么场景下参与,problem_solving_profile 要总结其典型处理问题方式,尽量具体到行为动作。\n"
|
||||
"6. skill_profile 要优先提炼稳定出现的能力、专业方向、擅长处理的问题类型。\n"
|
||||
"7. expression_profile 要保留反复出现的表达标记,如先说结论、爱列步骤、常贴原话/日志;reply_entry_profile 要总结适合接话的切入点。\n"
|
||||
"8. group_role 描述其在群中的长期角色位置,decision_profile 描述其决策与判断风格。\n"
|
||||
"9. value_profile 需要优先保留真正反复出现的判断偏好,如效率优先、成本敏感、风险谨慎、愿意分享。\n"
|
||||
f"成员: {display_name} ({wxid})\n"
|
||||
f"群ID: {chatroom_id}\n"
|
||||
f"周期: {period_key}\n"
|
||||
@@ -164,13 +184,17 @@ class MemberContextPromptBuilder:
|
||||
"\"response_style_hint\":\"一句中文\","
|
||||
"\"topics_of_interest\":[\"主题1\"],"
|
||||
"\"recent_focus\":[\"近期主题1\"],"
|
||||
"\"common_scenarios\":[\"场景1\"],"
|
||||
"\"identity_traits\":[\"身份线索1\"],"
|
||||
"\"skill_profile\":[\"技能画像1\"],"
|
||||
"\"problem_solving_profile\":[\"处理方式1\"],"
|
||||
"\"family_profile\":[\"家庭线索1\"],"
|
||||
"\"life_stage_profile\":[\"阶段线索1\"],"
|
||||
"\"value_profile\":[\"价值偏好1\"],"
|
||||
"\"stable_traits\":[\"长期特征1\"],"
|
||||
"\"habit_patterns\":[\"习惯1\"],"
|
||||
"\"expression_profile\":[\"表达标记1\"],"
|
||||
"\"reply_entry_profile\":[\"接话点1\"],"
|
||||
"\"long_term_reply_preferences\":[\"偏好1\"],"
|
||||
"\"group_role\":\"一句中文\","
|
||||
"\"decision_profile\":\"一句中文\","
|
||||
@@ -186,9 +210,10 @@ class MemberContextPromptBuilder:
|
||||
"2. recent_focus、recent_state 更依赖最近周级和日级。\n"
|
||||
"3. summary_text 要像后台备注,不要明显暴露在给用户做画像。\n"
|
||||
"4. identity_traits、family_profile、life_stage_profile 必须写成公开线索或长期观察,不得伪造事实。\n"
|
||||
"5. skill_profile 要尽量覆盖专业能力、问题解决能力、表达组织能力、资源协调能力等维度。\n"
|
||||
"6. group_role 要描述其在群中的角色定位,decision_profile 要描述其决策/判断方式。\n"
|
||||
"7. 如果月级与周级证据不足,宁可少写,也不要把短期状态写成长期人格。\n"
|
||||
"5. common_scenarios、problem_solving_profile、expression_profile、reply_entry_profile 要尽量写具体行为,不要只写抽象人格词。\n"
|
||||
"6. skill_profile 要尽量覆盖专业能力、问题解决能力、表达组织能力、资源协调能力等维度。\n"
|
||||
"7. group_role 要描述其在群中的角色定位,decision_profile 要描述其决策/判断方式。\n"
|
||||
"8. 如果月级与周级证据不足,宁可少写,也不要把短期状态写成长期人格。\n"
|
||||
f"成员: {display_name} ({wxid})\n"
|
||||
f"群ID: {chatroom_id}\n"
|
||||
"月级摘要:\n" + ("\n".join(monthly_lines) or "暂无")
|
||||
|
||||
@@ -130,10 +130,18 @@ class MemberContextService:
|
||||
monthly_structured + weekly_structured + daily_structured,
|
||||
["identity_traits", "identity_clues"], limit=5
|
||||
),
|
||||
"common_scenarios": self._extract_scored_items(
|
||||
monthly_structured + weekly_structured + daily_structured,
|
||||
["common_scenarios", "discussion_scenarios"], limit=5
|
||||
),
|
||||
"skill_profile": self._extract_scored_items(
|
||||
monthly_structured + weekly_structured + daily_structured,
|
||||
["skill_profile", "skill_signals"], limit=6
|
||||
),
|
||||
"problem_solving_profile": self._extract_scored_items(
|
||||
monthly_structured + weekly_structured + daily_structured,
|
||||
["problem_solving_profile", "problem_solving_signals"], limit=5
|
||||
),
|
||||
"family_profile": self._extract_scored_items(
|
||||
monthly_structured + weekly_structured + daily_structured,
|
||||
["family_profile", "family_signals"], limit=4
|
||||
@@ -153,6 +161,14 @@ class MemberContextService:
|
||||
monthly_structured + weekly_structured + daily_structured,
|
||||
["habit_patterns", "habit_signals"], limit=self.stable_max_items
|
||||
),
|
||||
"expression_profile": self._extract_scored_items(
|
||||
monthly_structured + weekly_structured + daily_structured,
|
||||
["expression_profile", "expression_markers"], limit=5
|
||||
),
|
||||
"reply_entry_profile": self._extract_scored_items(
|
||||
monthly_structured + weekly_structured + daily_structured,
|
||||
["reply_entry_profile", "reply_entry_points"], limit=4
|
||||
),
|
||||
"long_term_reply_preferences": self._extract_scored_items(
|
||||
monthly_structured + weekly_structured, ["long_term_reply_preferences", "reply_preferences"], limit=4
|
||||
),
|
||||
@@ -538,12 +554,16 @@ class MemberContextService:
|
||||
"confidence": max(0.0, min(1.0, confidence)),
|
||||
"meta": {
|
||||
"identity_traits": norm_list(data.get("identity_traits"), 5),
|
||||
"common_scenarios": norm_list(data.get("common_scenarios"), 5),
|
||||
"skill_profile": norm_list(data.get("skill_profile"), 6),
|
||||
"problem_solving_profile": norm_list(data.get("problem_solving_profile"), 5),
|
||||
"family_profile": norm_list(data.get("family_profile"), 4),
|
||||
"life_stage_profile": norm_list(data.get("life_stage_profile"), 4),
|
||||
"value_profile": norm_list(data.get("value_profile"), 5),
|
||||
"stable_traits": norm_list(data.get("stable_traits"), self.stable_max_items),
|
||||
"habit_patterns": norm_list(data.get("habit_patterns"), self.stable_max_items),
|
||||
"expression_profile": norm_list(data.get("expression_profile"), 5),
|
||||
"reply_entry_profile": norm_list(data.get("reply_entry_profile"), 4),
|
||||
"long_term_reply_preferences": norm_list(data.get("long_term_reply_preferences"), 4),
|
||||
"group_role": str(data.get("group_role", "")).strip(),
|
||||
"decision_profile": str(data.get("decision_profile", "")).strip(),
|
||||
@@ -586,11 +606,21 @@ class MemberContextService:
|
||||
meta.get("identity_traits", []),
|
||||
current_context.get("confidence", 0) * 0.75,
|
||||
)
|
||||
merged_common_scenario_scores = self._merge_scored_items(
|
||||
existing_meta.get("common_scenario_scores", {}),
|
||||
meta.get("common_scenarios", []),
|
||||
current_context.get("confidence", 0) * 0.85,
|
||||
)
|
||||
merged_skill_scores = self._merge_scored_items(
|
||||
existing_meta.get("skill_profile_scores", {}),
|
||||
meta.get("skill_profile", []),
|
||||
current_context.get("confidence", 0) * 0.85,
|
||||
)
|
||||
merged_problem_solving_scores = self._merge_scored_items(
|
||||
existing_meta.get("problem_solving_profile_scores", {}),
|
||||
meta.get("problem_solving_profile", []),
|
||||
current_context.get("confidence", 0) * 0.9,
|
||||
)
|
||||
merged_family_scores = self._merge_scored_items(
|
||||
existing_meta.get("family_profile_scores", {}),
|
||||
meta.get("family_profile", []),
|
||||
@@ -606,6 +636,16 @@ class MemberContextService:
|
||||
meta.get("value_profile", []),
|
||||
current_context.get("confidence", 0) * 0.75,
|
||||
)
|
||||
merged_expression_scores = self._merge_scored_items(
|
||||
existing_meta.get("expression_profile_scores", {}),
|
||||
meta.get("expression_profile", []),
|
||||
current_context.get("confidence", 0) * 0.95,
|
||||
)
|
||||
merged_reply_entry_scores = self._merge_scored_items(
|
||||
existing_meta.get("reply_entry_profile_scores", {}),
|
||||
meta.get("reply_entry_profile", []),
|
||||
current_context.get("confidence", 0),
|
||||
)
|
||||
merged_reply_pref_scores = self._merge_scored_items(
|
||||
existing_meta.get("long_term_reply_preference_scores", {}),
|
||||
meta.get("long_term_reply_preferences", []),
|
||||
@@ -621,32 +661,48 @@ class MemberContextService:
|
||||
meta["stable_trait_scores"] = merged_trait_scores
|
||||
meta["habit_pattern_scores"] = merged_habit_scores
|
||||
meta["identity_trait_scores"] = merged_identity_scores
|
||||
meta["common_scenario_scores"] = merged_common_scenario_scores
|
||||
meta["skill_profile_scores"] = merged_skill_scores
|
||||
meta["problem_solving_profile_scores"] = merged_problem_solving_scores
|
||||
meta["family_profile_scores"] = merged_family_scores
|
||||
meta["life_stage_profile_scores"] = merged_life_stage_scores
|
||||
meta["value_profile_scores"] = merged_value_scores
|
||||
meta["expression_profile_scores"] = merged_expression_scores
|
||||
meta["reply_entry_profile_scores"] = merged_reply_entry_scores
|
||||
meta["long_term_reply_preference_scores"] = merged_reply_pref_scores
|
||||
meta["temperament_tendency_scores"] = merged_temperament_scores
|
||||
meta["identity_traits"] = self._top_scored_items(merged_identity_scores, limit=5)
|
||||
meta["common_scenarios"] = self._top_scored_items(merged_common_scenario_scores, limit=5)
|
||||
meta["skill_profile"] = self._top_scored_items(merged_skill_scores, limit=6)
|
||||
meta["problem_solving_profile"] = self._top_scored_items(merged_problem_solving_scores, limit=5)
|
||||
meta["family_profile"] = self._top_scored_items(merged_family_scores, limit=4)
|
||||
meta["life_stage_profile"] = self._top_scored_items(merged_life_stage_scores, limit=4)
|
||||
meta["value_profile"] = self._top_scored_items(merged_value_scores, limit=5)
|
||||
meta["stable_traits"] = self._top_scored_items(merged_trait_scores, limit=self.stable_max_items)
|
||||
meta["habit_patterns"] = self._top_scored_items(merged_habit_scores, limit=self.stable_max_items)
|
||||
meta["expression_profile"] = self._top_scored_items(merged_expression_scores, limit=5)
|
||||
meta["reply_entry_profile"] = self._top_scored_items(merged_reply_entry_scores, limit=4)
|
||||
meta["long_term_reply_preferences"] = self._top_scored_items(merged_reply_pref_scores, limit=4)
|
||||
temperament = self._top_scored_items(merged_temperament_scores, limit=1)
|
||||
meta["temperament_tendency"] = temperament[0] if temperament else meta.get("temperament_tendency", "")
|
||||
if not meta["identity_traits"]:
|
||||
meta["identity_traits"] = (existing_meta.get("identity_traits") or [])[:5]
|
||||
if not meta["common_scenarios"]:
|
||||
meta["common_scenarios"] = (existing_meta.get("common_scenarios") or [])[:5]
|
||||
if not meta["skill_profile"]:
|
||||
meta["skill_profile"] = (existing_meta.get("skill_profile") or [])[:6]
|
||||
if not meta["problem_solving_profile"]:
|
||||
meta["problem_solving_profile"] = (existing_meta.get("problem_solving_profile") or [])[:5]
|
||||
if not meta["family_profile"]:
|
||||
meta["family_profile"] = (existing_meta.get("family_profile") or [])[:4]
|
||||
if not meta["life_stage_profile"]:
|
||||
meta["life_stage_profile"] = (existing_meta.get("life_stage_profile") or [])[:4]
|
||||
if not meta["value_profile"]:
|
||||
meta["value_profile"] = (existing_meta.get("value_profile") or [])[:5]
|
||||
if not meta["expression_profile"]:
|
||||
meta["expression_profile"] = (existing_meta.get("expression_profile") or [])[:5]
|
||||
if not meta["reply_entry_profile"]:
|
||||
meta["reply_entry_profile"] = (existing_meta.get("reply_entry_profile") or [])[:4]
|
||||
meta["group_role"] = meta.get("group_role") or existing_meta.get("group_role") or ""
|
||||
meta["decision_profile"] = meta.get("decision_profile") or existing_meta.get("decision_profile") or ""
|
||||
meta["engagement_traits"] = (meta.get("engagement_traits") or existing_meta.get("engagement_traits") or [])[:4]
|
||||
@@ -706,6 +762,13 @@ class MemberContextService:
|
||||
)
|
||||
if preferences:
|
||||
return "更适合:" + "、".join(preferences[:3])
|
||||
entry_points = self._extract_scored_items(
|
||||
monthly_structured + weekly_structured + daily_structured,
|
||||
["reply_entry_profile", "reply_entry_points"],
|
||||
limit=3,
|
||||
)
|
||||
if entry_points:
|
||||
return "优先从这些点接话:" + "、".join(entry_points[:3])
|
||||
return "保持自然口语化,结论和解释尽量平衡"
|
||||
|
||||
def _calc_digest_confidence(self, monthly_digests: List[Dict], weekly_digests: List[Dict],
|
||||
@@ -745,12 +808,18 @@ class MemberContextService:
|
||||
if meta.get("temperament_tendency"):
|
||||
label = "长期沟通倾向" if meta.get("stable_ready") else "阶段性沟通倾向"
|
||||
parts.append(f"{label}:{meta.get('temperament_tendency')}")
|
||||
if meta.get("common_scenarios"):
|
||||
parts.append(f"常见场景:{'、'.join(meta.get('common_scenarios')[:3])}")
|
||||
if meta.get("problem_solving_profile"):
|
||||
parts.append(f"处理方式:{'、'.join(meta.get('problem_solving_profile')[:3])}")
|
||||
if meta.get("stable_traits"):
|
||||
parts.append(f"长期特征:{'、'.join(meta.get('stable_traits')[:3])}")
|
||||
if meta.get("identity_traits"):
|
||||
parts.append(f"身份线索:{'、'.join(meta.get('identity_traits')[:2])}")
|
||||
if meta.get("skill_profile"):
|
||||
parts.append(f"技能画像:{'、'.join(meta.get('skill_profile')[:3])}")
|
||||
if meta.get("expression_profile"):
|
||||
parts.append(f"表达标记:{'、'.join(meta.get('expression_profile')[:3])}")
|
||||
if meta.get("value_profile"):
|
||||
parts.append(f"判断偏好:{'、'.join(meta.get('value_profile')[:2])}")
|
||||
if meta.get("habit_patterns"):
|
||||
|
||||
Reference in New Issue
Block a user