feat(ECR-012–016): 合规、题库、时辰刷新、头像、MBTI OEJTS 与埋点

落地输入合规、探索题库、报告日/时辰刷新、账号头像、OEJTS 量表,并补齐 H5 埋点与 Admin 漏斗;同步 ESS 工件、切至自建 Git、清理 GitHub Actions。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
jackyu66git
2026-08-13 01:27:58 +08:00
co-authored by Cursor
parent 13860bf1ef
commit 89756f65b4
227 changed files with 7405 additions and 1407 deletions
+14 -13
View File
@@ -15,6 +15,7 @@ import (
"github.com/yuxingu/digital-psychology/apps/api/internal/llm/deepseek"
"github.com/yuxingu/digital-psychology/apps/api/internal/model"
"github.com/yuxingu/digital-psychology/apps/api/internal/repository"
"github.com/yuxingu/digital-psychology/apps/api/internal/textsafe"
)
// FreeQuota is the number of assistant replies allowed without membership.
@@ -42,7 +43,11 @@ func (s *Service) CreateThread(ctx context.Context, userID uuid.UUID, in CreateT
return nil, errors.New("profile not found")
}
var scene *string
if sc := strings.TrimSpace(in.Scene); sc != "" {
if strings.TrimSpace(in.Scene) != "" {
sc, err := textsafe.Check(textsafe.Scene, in.Scene)
if err != nil {
return nil, err
}
scene = &sc
}
return s.Ask.CreateThread(ctx, userID, in.ProfileID, scene)
@@ -137,12 +142,10 @@ type SendResult struct {
// SendMessage stores user content, consumes quota, generates assistant reply.
func (s *Service) SendMessage(ctx context.Context, userID, threadID uuid.UUID, content string) (*SendResult, error) {
content = strings.TrimSpace(content)
if content == "" {
return nil, errors.New("content required")
}
if len([]rune(content)) > 2000 {
return nil, errors.New("content too long")
var err error
content, err = textsafe.Check(textsafe.AskContent, content)
if err != nil {
return nil, err
}
thread, err := s.Ask.GetThreadForUser(ctx, userID, threadID)
@@ -281,12 +284,10 @@ func (s *Service) StreamMessage(ctx context.Context, userID, threadID uuid.UUID,
if emit == nil {
return errors.New("emit required")
}
content = strings.TrimSpace(content)
if content == "" {
return errors.New("content required")
}
if len([]rune(content)) > 2000 {
return errors.New("content too long")
var err error
content, err = textsafe.Check(textsafe.AskContent, content)
if err != nil {
return err
}
thread, err := s.Ask.GetThreadForUser(ctx, userID, threadID)