feat: add RelationInsight API and wire H5 relation/profile pages
Second P1 growth engine: compare two profiles, gate full tips behind deep-access mock payment, and list personal archives on /profile. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
// Package relation builds 关系理解 content from two birth-based portraits.
|
||||
package relation
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/yuxingu/digital-psychology/apps/api/internal/portrait"
|
||||
)
|
||||
|
||||
// Output is free summary + gated detail.
|
||||
type Output struct {
|
||||
Summary map[string]any
|
||||
Detail map[string]any
|
||||
}
|
||||
|
||||
// Build compares two profiles' exploration styles (lexicon-safe copy).
|
||||
func Build(aBirth, bBirth time.Time, aName, bName string) Output {
|
||||
if aName == "" {
|
||||
aName = "我"
|
||||
}
|
||||
if bName == "" {
|
||||
bName = "TA"
|
||||
}
|
||||
pa := portrait.Build(aBirth, aName)
|
||||
pb := portrait.Build(bBirth, bName)
|
||||
aLabel := str(pa.Summary["headline"])
|
||||
bLabel := str(pb.Summary["headline"])
|
||||
aKeys := strSlice(pa.Summary["keywords"])
|
||||
bKeys := strSlice(pb.Summary["keywords"])
|
||||
|
||||
summary := map[string]any{
|
||||
"title": "关系理解·基础",
|
||||
"me_style": aLabel,
|
||||
"other_style": bLabel,
|
||||
"me_keywords": aKeys,
|
||||
"other_keywords": bKeys,
|
||||
"diff_one_liner": fmt.Sprintf("%s更偏内在节奏,%s的表达方式不同——差异可以成为互补,而不是对立。", aName, bName),
|
||||
"share_hint": "了解彼此的沟通方式,查看关系理解",
|
||||
}
|
||||
detail := map[string]any{
|
||||
"title": "相处建议·完整分析",
|
||||
"communication": []string{
|
||||
fmt.Sprintf("%s:先讲清楚事实与需要,再谈感受。", aName),
|
||||
fmt.Sprintf("%s:先确认被听见,再进入方案讨论。", bName),
|
||||
"冲突时约定「复述对方一句」再回应,降低误解。",
|
||||
},
|
||||
"interaction": []string{
|
||||
"用「我观察到…我需要…」代替指责句式。",
|
||||
"每周留一次轻松同步:最近什么在消耗/滋养这段关系。",
|
||||
},
|
||||
"maintenance": []string{
|
||||
"差异标签不是评分,而是协作说明书。",
|
||||
"重要决定前,双方各写三点顾虑再合并。",
|
||||
},
|
||||
"me_behavior": str(pa.Detail["behavior_pattern"]),
|
||||
"other_behavior": str(pb.Detail["behavior_pattern"]),
|
||||
}
|
||||
return Output{Summary: summary, Detail: detail}
|
||||
}
|
||||
|
||||
func str(v any) string {
|
||||
s, _ := v.(string)
|
||||
return s
|
||||
}
|
||||
|
||||
func strSlice(v any) []string {
|
||||
arr, ok := v.([]string)
|
||||
if ok {
|
||||
return arr
|
||||
}
|
||||
raw, ok := v.([]any)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
out := make([]string, 0, len(raw))
|
||||
for _, x := range raw {
|
||||
if s, ok := x.(string); ok {
|
||||
out = append(out, s)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
Reference in New Issue
Block a user