122 lines
3.4 KiB
Go
122 lines
3.4 KiB
Go
package persona
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
|
|
app "haixun-backend/internal/library/errors"
|
|
"haixun-backend/internal/library/errors/code"
|
|
libviral "haixun-backend/internal/library/viral"
|
|
domai "haixun-backend/internal/model/ai/domain/usecase"
|
|
aiusecase "haixun-backend/internal/model/ai/usecase"
|
|
copydraftusecase "haixun-backend/internal/model/copy_draft/domain/usecase"
|
|
"haixun-backend/internal/svc"
|
|
"haixun-backend/internal/types"
|
|
)
|
|
|
|
type GeneratePersonaCopyDraftLogic struct {
|
|
ctx context.Context
|
|
svcCtx *svc.ServiceContext
|
|
}
|
|
|
|
func NewGeneratePersonaCopyDraftLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GeneratePersonaCopyDraftLogic {
|
|
return &GeneratePersonaCopyDraftLogic{ctx: ctx, svcCtx: svcCtx}
|
|
}
|
|
|
|
func (l *GeneratePersonaCopyDraftLogic) GeneratePersonaCopyDraft(
|
|
req *types.GeneratePersonaCopyDraftHandlerReq,
|
|
) (*types.GeneratePersonaCopyDraftData, error) {
|
|
tenantID, uid, err := actorFrom(l.ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
personaID := strings.TrimSpace(req.ID)
|
|
scanPostID := strings.TrimSpace(req.ScanPostID)
|
|
if scanPostID == "" {
|
|
return nil, app.For(code.Persona).InputMissingRequired("scan_post_id is required")
|
|
}
|
|
|
|
persona, err := l.svcCtx.Persona.Get(l.ctx, tenantID, uid, personaID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
post, err := l.svcCtx.ScanPost.GetForPersona(l.ctx, tenantID, uid, personaID, scanPostID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
credential, err := l.svcCtx.ThreadsAccount.ResolveMemberAiCredential(l.ctx, tenantID, uid)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
providerID, err := aiusecase.MapWorkerProvider(credential.Provider)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
result, err := l.svcCtx.AI.GenerateText(l.ctx, domai.GenerateRequest{
|
|
Provider: providerID,
|
|
Model: credential.Model,
|
|
Credential: domai.Credential{
|
|
APIKey: credential.APIKey,
|
|
},
|
|
System: libviral.BuildSystemPrompt(),
|
|
Messages: []domai.Message{
|
|
{
|
|
Role: "user",
|
|
Content: libviral.BuildUserPrompt(libviral.ReplicateInput{
|
|
TopicLabel: post.SearchTag,
|
|
TopicBrief: persona.Brief,
|
|
Persona: persona.Persona,
|
|
StyleProfile: persona.StyleProfile,
|
|
OriginalText: post.Text,
|
|
AuthorName: post.Author,
|
|
}),
|
|
},
|
|
},
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
parsed, err := libviral.ParseReplicateOutput(result.Text)
|
|
if err != nil {
|
|
return nil, app.For(code.AI).SvcThirdParty("仿寫 LLM 回傳無法解析:" + err.Error())
|
|
}
|
|
|
|
saved, err := l.svcCtx.CopyDraft.Create(l.ctx, copydraftusecase.CreateRequest{
|
|
TenantID: tenantID,
|
|
OwnerUID: uid,
|
|
PersonaID: personaID,
|
|
ScanPostID: scanPostID,
|
|
DraftType: "replicate",
|
|
Text: parsed.Text,
|
|
Angle: parsed.Angle,
|
|
Hook: parsed.Hook,
|
|
Rationale: parsed.Rationale,
|
|
ReferenceNotes: parsed.StructureNotes,
|
|
Sources: []string{post.Permalink},
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &types.GeneratePersonaCopyDraftData{
|
|
Draft: types.CopyDraftData{
|
|
ID: saved.ID,
|
|
PersonaID: saved.PersonaID,
|
|
ScanPostID: saved.ScanPostID,
|
|
DraftType: saved.DraftType,
|
|
Text: saved.Text,
|
|
Angle: saved.Angle,
|
|
Hook: saved.Hook,
|
|
Rationale: saved.Rationale,
|
|
ReferenceNotes: saved.ReferenceNotes,
|
|
Sources: saved.Sources,
|
|
Status: saved.Status,
|
|
CreateAt: saved.CreateAt,
|
|
},
|
|
Message: "已產出仿寫草稿",
|
|
}, nil
|
|
}
|