fix frontend
This commit is contained in:
parent
fcc76911bb
commit
e41c1f96a2
|
|
@ -1,6 +1,6 @@
|
|||
# 只保留會重複打的指令;其餘直接 go / migrate。
|
||||
|
||||
.PHONY: build test gen-api tidy migrate-up migrate-down
|
||||
.PHONY: build test test-integration gen-api tidy migrate-up migrate-down
|
||||
|
||||
build:
|
||||
go build -o bin/gateway .
|
||||
|
|
@ -9,6 +9,16 @@ build:
|
|||
test:
|
||||
go test ./...
|
||||
|
||||
# M1–M5 integration gates
|
||||
test-integration:
|
||||
go test ./internal/module/member/usecase/ ./internal/middleware/ \
|
||||
./internal/module/threads/... ./internal/module/job/... ./internal/module/appnotif/... \
|
||||
./internal/module/usage/... ./internal/module/ai/... ./internal/module/search/... \
|
||||
./internal/module/permission/... ./internal/module/studio/... \
|
||||
./internal/module/inspire/... ./internal/module/scout/... \
|
||||
./internal/logic/extension/ ./internal/logic/media/ \
|
||||
-count=1 -timeout 180s
|
||||
|
||||
# 改 generate/api/*.api 後執行;handler 勿手寫
|
||||
gen-api:
|
||||
goctl api go -api generate/api/gateway.api -dir . -style go_zero --home generate/goctl
|
||||
|
|
|
|||
|
|
@ -1,21 +1,49 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"apps/backend/internal/config"
|
||||
"apps/backend/internal/module/ai"
|
||||
appnotifRepo "apps/backend/internal/module/appnotif/repository"
|
||||
appnotifUC "apps/backend/internal/module/appnotif/usecase"
|
||||
fsDomain "apps/backend/internal/module/filestorage/domain"
|
||||
"apps/backend/internal/module/filestorage/noop"
|
||||
"apps/backend/internal/module/filestorage/s3store"
|
||||
jobDomain "apps/backend/internal/module/job/domain"
|
||||
jobRepo "apps/backend/internal/module/job/repository"
|
||||
jobUC "apps/backend/internal/module/job/usecase"
|
||||
memberDomain "apps/backend/internal/module/member/domain"
|
||||
memberRepo "apps/backend/internal/module/member/repository"
|
||||
scoutRepo "apps/backend/internal/module/scout/repository"
|
||||
scoutUC "apps/backend/internal/module/scout/usecase"
|
||||
studioPublish "apps/backend/internal/module/studio/publish"
|
||||
studioRepo "apps/backend/internal/module/studio/repository"
|
||||
studioUC "apps/backend/internal/module/studio/usecase"
|
||||
threadsDomain "apps/backend/internal/module/threads/domain"
|
||||
threadsProv "apps/backend/internal/module/threads/provider"
|
||||
threadsRepo "apps/backend/internal/module/threads/repository"
|
||||
threadsUC "apps/backend/internal/module/threads/usecase"
|
||||
usageDomain "apps/backend/internal/module/usage/domain"
|
||||
usageRepo "apps/backend/internal/module/usage/repository"
|
||||
usageUC "apps/backend/internal/module/usage/usecase"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/conf"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
// Independent worker binary (A-03). M0 stub: config load + heartbeat log only.
|
||||
// Outbox/job runners land in M2/M4 (T133/T169).
|
||||
// Worker:demo + threads_token_renew + persona_analyze_* + outbox publish
|
||||
//
|
||||
// cd apps/backend && go build -o bin/worker ./cmd/worker
|
||||
// ./bin/worker -f etc/gateway.yaml
|
||||
func main() {
|
||||
configFile := flag.String("f", "etc/gateway.yaml", "config file")
|
||||
flag.Parse()
|
||||
|
|
@ -25,31 +53,319 @@ func main() {
|
|||
c.ApplyEnv()
|
||||
|
||||
workerID := c.Worker.ID
|
||||
if workerID == "" {
|
||||
workerID = "worker-1"
|
||||
if workerID == "" || workerID == "worker-1" || workerID == "worker-local-1" {
|
||||
workerID = "demo-worker-1"
|
||||
}
|
||||
interval := time.Duration(c.Worker.PollIntervalMs) * time.Millisecond
|
||||
if interval <= 0 {
|
||||
interval = 2 * time.Second
|
||||
}
|
||||
|
||||
logx.Infof("haixun worker stub started id=%s interval=%s (no publish yet)", workerID, interval)
|
||||
fmt.Printf("worker stub running id=%s (Ctrl+C to stop)\n", workerID)
|
||||
appN := appnotifUC.New(appnotifRepo.NewMonStore(c.Mongo.URI, c.Mongo.Database))
|
||||
jobs := jobUC.New(jobRepo.NewMonStore(c.Mongo.URI, c.Mongo.Database))
|
||||
jobs.Notifier = appN
|
||||
|
||||
secret := c.Auth.AccessSecret
|
||||
if secret == "" {
|
||||
secret = "dev-token-secret"
|
||||
}
|
||||
var provider threadsDomain.Provider
|
||||
if strings.TrimSpace(c.Platform.ThreadsAppId) != "" && strings.TrimSpace(c.Platform.ThreadsAppSecret) != "" {
|
||||
provider = threadsProv.NewMeta(c.Platform.ThreadsAppId, c.Platform.ThreadsAppSecret)
|
||||
logx.Info("worker threads: meta provider")
|
||||
} else {
|
||||
provider = &threadsProv.FakeProvider{}
|
||||
logx.Info("worker threads: fake provider")
|
||||
}
|
||||
threadsSvc := threadsUC.New(threadsRepo.NewMonStore(c.Mongo.URI, c.Mongo.Database), provider, secret)
|
||||
threadsSvc.Renew = jobs
|
||||
|
||||
// usage + AI keys(與 gateway 對齊,persona LLM 需真 key)
|
||||
members := memberRepo.NewMoncStore(c.Mongo.URI, c.Mongo.Database, c.CacheRedis)
|
||||
keyRes := &usageUC.SettingsResolver{
|
||||
Members: members,
|
||||
PlatformAI: c.Platform.AIKey,
|
||||
PlatformXAI: c.Platform.XAIKey,
|
||||
PlatformOpenCode: c.Platform.OpenCodeKey,
|
||||
PlatformExa: c.Platform.ExaKey,
|
||||
}
|
||||
if keyRes.PlatformAI == "" && keyRes.PlatformXAI == "" && keyRes.PlatformOpenCode == "" {
|
||||
keyRes.PlatformAI = "fake-platform-ai"
|
||||
logx.Info("worker usage: no platform AI keys — fake-platform-ai for quota only")
|
||||
}
|
||||
usageSvc := usageUC.New(usageRepo.NewMonStore(c.Mongo.URI, c.Mongo.Database), keyRes)
|
||||
aiRegistry := ai.NewRegistry()
|
||||
|
||||
// Outbox/scout 發文:有 Meta 憑證則真 Threads Graph,否則 Fake(單元測試用)
|
||||
var pub studioPublish.Transport
|
||||
if strings.TrimSpace(c.Platform.ThreadsAppId) != "" && strings.TrimSpace(c.Platform.ThreadsAppSecret) != "" {
|
||||
pub = studioPublish.NewMeta("https://graph.threads.net")
|
||||
logx.Info("worker studio: meta publish transport (real Threads)")
|
||||
} else {
|
||||
pub = studioPublish.NewFake()
|
||||
logx.Info("worker studio: fake publish transport (no Threads app credentials)")
|
||||
}
|
||||
studio := studioUC.New(studioRepo.NewMonStore(c.Mongo.URI, c.Mongo.Database), pub)
|
||||
studio.Accounts = threadsSvc
|
||||
studio.Usage = usageSvc
|
||||
studio.AI = &ai.FakeClient{}
|
||||
studio.AIRegistry = aiRegistry
|
||||
studio.Keys = &workerAIKeys{Members: members, Resolver: keyRes}
|
||||
// 發文暫存圖:Meta 發成功後刪 temp/*
|
||||
store := workerStorage(c)
|
||||
studio.Storage = store
|
||||
studio.StoragePublicBase = strings.TrimSpace(c.ObjectStorage.PublicBaseURL)
|
||||
|
||||
scoutSvc := scoutUC.New(scoutRepo.NewMonStore(c.Mongo.URI, c.Mongo.Database))
|
||||
scoutSvc.Settings = &workerDevMode{Members: members}
|
||||
scoutSvc.Transport = pub
|
||||
scoutSvc.Accounts = threadsSvc
|
||||
studio.Crawler = scoutSvc
|
||||
// worker 執行 job 本體,不經 API 再入列
|
||||
studio.Jobs = nil
|
||||
|
||||
logx.Infof("haixun worker started id=%s interval=%s (demo + token_renew + persona_analyze + compose_mimic + outbox)", workerID, interval)
|
||||
fmt.Printf("worker running id=%s interval=%s (Ctrl+C to stop)\n", workerID, interval)
|
||||
|
||||
sig := make(chan os.Signal, 1)
|
||||
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
|
||||
|
||||
tick := time.NewTicker(interval)
|
||||
defer tick.Stop()
|
||||
|
||||
ctx := context.Background()
|
||||
for {
|
||||
select {
|
||||
case <-sig:
|
||||
logx.Infof("worker %s shutting down", workerID)
|
||||
return
|
||||
case t := <-tick.C:
|
||||
// Health heartbeat only — no job/outbox processing in M0.
|
||||
logx.Infof("worker %s heartbeat at %s", workerID, t.UTC().Format(time.RFC3339))
|
||||
case <-tick.C:
|
||||
// 1) claim one due job
|
||||
j, err := jobs.ClaimNext(ctx, workerID)
|
||||
if err == nil {
|
||||
switch j.TemplateType {
|
||||
case "", jobDomain.TemplateDemo:
|
||||
logx.Infof("worker %s demo job %s", workerID, j.ID)
|
||||
if _, err := jobs.RunDemoToSuccess(ctx, j.ID); err != nil {
|
||||
logx.Errorf("worker %s job %s failed: %v", workerID, j.ID, err)
|
||||
_, _ = jobs.FailJob(ctx, j.ID, err.Error())
|
||||
} else {
|
||||
logx.Infof("worker %s job %s succeeded", workerID, j.ID)
|
||||
}
|
||||
case jobDomain.TemplateThreadsTokenRenew:
|
||||
logx.Infof("worker %s token renew job %s account=%s", workerID, j.ID, j.RefID)
|
||||
if err := runTokenRenew(ctx, jobs, threadsSvc, j); err != nil {
|
||||
logx.Errorf("worker %s renew %s failed: %v", workerID, j.ID, err)
|
||||
_, _ = jobs.FailJob(ctx, j.ID, err.Error())
|
||||
} else {
|
||||
logx.Infof("worker %s renew %s ok", workerID, j.ID)
|
||||
}
|
||||
case jobDomain.TemplatePersonaAnalyzeAccount, jobDomain.TemplatePersonaAnalyzeText:
|
||||
logx.Infof("worker %s persona analyze job %s type=%s persona=%s", workerID, j.ID, j.TemplateType, j.RefID)
|
||||
if err := runPersonaAnalyze(ctx, jobs, studio, j); err != nil {
|
||||
logx.Errorf("worker %s persona %s failed: %v", workerID, j.ID, err)
|
||||
_, _ = jobs.FailJob(ctx, j.ID, err.Error())
|
||||
} else {
|
||||
logx.Infof("worker %s persona %s ok", workerID, j.ID)
|
||||
}
|
||||
case jobDomain.TemplateComposeMimic:
|
||||
logx.Infof("worker %s compose_mimic job %s", workerID, j.ID)
|
||||
if err := runComposeMimic(ctx, jobs, studio, j); err != nil {
|
||||
logx.Errorf("worker %s compose_mimic %s failed: %v", workerID, j.ID, err)
|
||||
_, _ = jobs.FailJob(ctx, j.ID, err.Error())
|
||||
} else {
|
||||
logx.Infof("worker %s compose_mimic %s ok", workerID, j.ID)
|
||||
}
|
||||
case jobDomain.TemplatePlayGenerateScript:
|
||||
logx.Infof("worker %s play_generate_script job %s play=%s", workerID, j.ID, j.RefID)
|
||||
if err := runPlayGenerateScript(ctx, jobs, studio, j); err != nil {
|
||||
logx.Errorf("worker %s play_generate_script %s failed: %v", workerID, j.ID, err)
|
||||
_, _ = jobs.FailJob(ctx, j.ID, err.Error())
|
||||
} else {
|
||||
logx.Infof("worker %s play_generate_script %s ok", workerID, j.ID)
|
||||
}
|
||||
default:
|
||||
logx.Infof("worker %s unknown template %s job %s — fail", workerID, j.TemplateType, j.ID)
|
||||
_, _ = jobs.FailJob(ctx, j.ID, "unknown template: "+j.TemplateType)
|
||||
}
|
||||
}
|
||||
// 2) outbox due steps
|
||||
n, err := studio.ProcessDueSteps(ctx, 0)
|
||||
if err != nil {
|
||||
logx.Errorf("worker %s outbox tick: %v", workerID, err)
|
||||
} else if n > 0 {
|
||||
logx.Infof("worker %s outbox published %d step(s)", workerID, n)
|
||||
}
|
||||
// 3) 終態任務超過 2 天自動清除
|
||||
if purged, err := jobs.PurgeExpiredTerminal(ctx); err != nil {
|
||||
logx.Errorf("worker %s purge jobs: %v", workerID, err)
|
||||
} else if purged > 0 {
|
||||
logx.Infof("worker %s purged %d expired terminal job(s)", workerID, purged)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func runTokenRenew(ctx context.Context, jobs *jobUC.Service, threads *threadsUC.Service, j *jobDomain.Job) error {
|
||||
if j.RefID == "" {
|
||||
return fmt.Errorf("缺少帳號 ref_id")
|
||||
}
|
||||
_, _ = jobs.MarkRunningProgress(ctx, j.ID, 15, "定期延長 Threads token · 準備中")
|
||||
_, _ = jobs.MarkRunningProgress(ctx, j.ID, 40, "定期延長 Threads token · 向平台刷新中")
|
||||
acc, err := threads.Refresh(ctx, j.OwnerUID, j.RefID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, _ = jobs.MarkRunningProgress(ctx, j.ID, 75, "定期延長 Threads token · 排程下一次")
|
||||
// 下次再約 30 天
|
||||
next := jobDomain.NowNano() + jobDomain.DefaultTokenRenewDelayNs
|
||||
if acc != nil && acc.SessionExpiresAt > 0 {
|
||||
early := acc.SessionExpiresAt - int64(30*24*time.Hour)
|
||||
if early > jobDomain.NowNano() {
|
||||
next = early
|
||||
}
|
||||
}
|
||||
_ = jobs.ScheduleTokenRenew(ctx, j.OwnerUID, j.RefID, next)
|
||||
_, _ = jobs.MarkRunningProgress(ctx, j.ID, 90, "定期延長 Threads token · 寫入完成")
|
||||
_, err = jobs.SucceedJob(ctx, j.ID, "定期延長完成 · 已排程約 30 天後再執行")
|
||||
return err
|
||||
}
|
||||
|
||||
func runPersonaAnalyze(ctx context.Context, jobs *jobUC.Service, studio *studioUC.Service, j *jobDomain.Job) error {
|
||||
if j.RefID == "" {
|
||||
return fmt.Errorf("缺少人設 ref_id")
|
||||
}
|
||||
startSum := "人設分析 · 文字分析中…"
|
||||
if j.TemplateType == jobDomain.TemplatePersonaAnalyzeAccount {
|
||||
startSum = "人設分析 · 爬取公開貼文 + AI 分析中…(可離開頁面)"
|
||||
}
|
||||
_, _ = jobs.MarkRunningProgress(ctx, j.ID, 10, startSum)
|
||||
|
||||
err := studio.ExecutePersonaAnalyzeJob(ctx, j.TemplateType, j.OwnerUID, j.RefID, j.Payload, func(pct int, sum string) {
|
||||
if pct < 10 {
|
||||
pct = 10
|
||||
}
|
||||
if pct > 95 {
|
||||
pct = 95
|
||||
}
|
||||
_, _ = jobs.MarkRunningProgress(ctx, j.ID, pct, sum)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = jobs.SucceedJob(ctx, j.ID, "人設分析完成 · 已寫入指紋/範本")
|
||||
return err
|
||||
}
|
||||
|
||||
func runPlayGenerateScript(ctx context.Context, jobs *jobUC.Service, studio *studioUC.Service, j *jobDomain.Job) error {
|
||||
var pl jobUC.PlayGenerateScriptPayload
|
||||
if err := json.Unmarshal([]byte(j.Payload), &pl); err != nil {
|
||||
return fmt.Errorf("invalid play_generate_script payload: %w", err)
|
||||
}
|
||||
playID := strings.TrimSpace(pl.PlayID)
|
||||
if playID == "" {
|
||||
playID = strings.TrimSpace(j.RefID)
|
||||
}
|
||||
if playID == "" {
|
||||
return fmt.Errorf("empty play_id")
|
||||
}
|
||||
_, _ = jobs.MarkRunningProgress(ctx, j.ID, 15, "劇本產文 · 準備 AI(一次產全部)…")
|
||||
llmCtx, cancel := context.WithTimeout(ctx, 4*time.Minute)
|
||||
defer cancel()
|
||||
_, _ = jobs.MarkRunningProgress(ctx, j.ID, 40, "劇本產文 · 呼叫模型中(可離開頁面)…")
|
||||
n, err := studio.GeneratePlayScript(llmCtx, j.OwnerUID, playID, pl.OnlyEmpty)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pl.Filled = n
|
||||
body, _ := json.Marshal(pl)
|
||||
_, _ = jobs.MarkRunningProgress(ctx, j.ID, 90, fmt.Sprintf("劇本產文 · 已寫入 %d 步…", n))
|
||||
_, err = jobs.SucceedJobWithPayload(ctx, j.ID, fmt.Sprintf("劇本產文完成 · 已填 %d 步,請回互回方案查看", n), string(body))
|
||||
return err
|
||||
}
|
||||
|
||||
func runComposeMimic(ctx context.Context, jobs *jobUC.Service, studio *studioUC.Service, j *jobDomain.Job) error {
|
||||
var pl jobUC.ComposeMimicPayload
|
||||
if err := json.Unmarshal([]byte(j.Payload), &pl); err != nil {
|
||||
return fmt.Errorf("invalid compose_mimic payload: %w", err)
|
||||
}
|
||||
if strings.TrimSpace(pl.SourceText) == "" {
|
||||
return fmt.Errorf("empty source_text")
|
||||
}
|
||||
_, _ = jobs.MarkRunningProgress(ctx, j.ID, 15, "仿寫貼文 · 準備 AI…")
|
||||
// worker 不綁 gateway 120s;給模型較長時間(reasoning 模型需要)
|
||||
llmCtx, cancel := context.WithTimeout(ctx, 4*time.Minute)
|
||||
defer cancel()
|
||||
_, _ = jobs.MarkRunningProgress(ctx, j.ID, 35, "仿寫貼文 · 呼叫模型中(可離開頁面)…")
|
||||
text, err := studio.Mimic(llmCtx, j.OwnerUID, pl.SourceText, pl.PersonaID, pl.StructureNotes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, _ = jobs.MarkRunningProgress(ctx, j.ID, 90, "仿寫貼文 · 寫入結果…")
|
||||
pl.ResultText = text
|
||||
body, _ := json.Marshal(pl)
|
||||
_, err = jobs.SucceedJobWithPayload(ctx, j.ID, "仿寫完成 · 已可套用到正文", string(body))
|
||||
return err
|
||||
}
|
||||
|
||||
// workerAIKeys — 與 gateway studioAIKeys 對齊
|
||||
type workerAIKeys struct {
|
||||
Members memberDomain.Repository
|
||||
Resolver *usageUC.SettingsResolver
|
||||
}
|
||||
|
||||
func (k *workerAIKeys) ResolveAI(ctx context.Context, ownerUID int64) (provider, model, apiKey string, err error) {
|
||||
st, err := k.Members.GetSettings(ctx, ownerUID)
|
||||
if err != nil || st == nil {
|
||||
st = memberDomain.DefaultSettings(ownerUID)
|
||||
}
|
||||
// 完全依會員 AI 設定(provider / model / key),不寫死模型
|
||||
provider = ai.NormalizeProvider(st.Provider)
|
||||
model = strings.TrimSpace(st.Model)
|
||||
if model == "" {
|
||||
return provider, "", "", fmt.Errorf("請到設定選擇 AI 模型")
|
||||
}
|
||||
if k.Resolver != nil {
|
||||
_, key, rerr := k.Resolver.ResolveKey(ctx, ownerUID, usageDomain.MeterAICopy)
|
||||
if rerr == nil && strings.TrimSpace(key) != "" {
|
||||
return provider, model, key, nil
|
||||
}
|
||||
}
|
||||
if key := st.KeyForProvider(provider); key != "" {
|
||||
return provider, model, key, nil
|
||||
}
|
||||
return provider, model, "", fmt.Errorf("no AI key(請到設定填寫 Key,或確認平台已配置)")
|
||||
}
|
||||
|
||||
type workerDevMode struct {
|
||||
Members memberDomain.Repository
|
||||
}
|
||||
|
||||
func (d *workerDevMode) DevModeEnabled(ctx context.Context, uid int64) (bool, error) {
|
||||
if d == nil || d.Members == nil {
|
||||
return false, nil
|
||||
}
|
||||
st, err := d.Members.GetSettings(ctx, uid)
|
||||
if err != nil || st == nil {
|
||||
return false, nil
|
||||
}
|
||||
return st.DevModeEnabled, nil
|
||||
}
|
||||
|
||||
func workerStorage(c config.Config) fsDomain.Storage {
|
||||
os := c.ObjectStorage
|
||||
if strings.TrimSpace(os.Endpoint) == "" {
|
||||
logx.Info("worker storage: disabled (no endpoint)")
|
||||
return noop.New()
|
||||
}
|
||||
s, err := s3store.New(s3store.Config{
|
||||
Endpoint: os.Endpoint, Region: os.Region, Bucket: os.Bucket,
|
||||
AccessKey: os.AccessKey, SecretKey: os.SecretKey,
|
||||
UsePathStyle: os.UsePathStyle, PublicBaseURL: os.PublicBaseURL,
|
||||
})
|
||||
if err != nil {
|
||||
logx.Errorf("worker storage init failed: %v", err)
|
||||
return noop.New()
|
||||
}
|
||||
logx.Infof("worker storage: minio/s3 bucket=%s (ephemeral publish images cleanup enabled)", os.Bucket)
|
||||
return s
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@
|
|||
Name: haixun-gateway
|
||||
Host: 0.0.0.0
|
||||
Port: 8888
|
||||
Timeout: 30000
|
||||
# AI 產文/試產可能超過 30s;過短會 503 且前端拿不到結果
|
||||
Timeout: 120000
|
||||
MaxBytes: 104857600
|
||||
|
||||
Log:
|
||||
|
|
@ -32,14 +33,23 @@ Auth:
|
|||
RefreshSecret: "change-me-refresh-secret"
|
||||
RefreshExpire: 604800
|
||||
|
||||
# 平台預設 key(所有會員可用;會員在設定頁填的 BYOK 優先)
|
||||
# 也可用環境變數覆寫:PLATFORM_XAI_KEY / PLATFORM_OPENCODE_KEY / PLATFORM_EXA_KEY / PLATFORM_AI_KEY
|
||||
Platform:
|
||||
# xAI(api.x.ai)— 人設 LLM、文案等
|
||||
XAIKey: "xai-TtmPWVAz1CdssptRetj9iOFSdSG2LZDffEOTKzIiDmVSDqUL62lVdDladlQIXAwoeHtowWraVqYuHzl1"
|
||||
# 相容舊名:XAIKey 空時會用 AIKey
|
||||
AIKey: ""
|
||||
ExaKey: ""
|
||||
ThreadsAppId: ""
|
||||
ThreadsAppSecret: ""
|
||||
# OpenCode Go(opencode.ai/zen/go)
|
||||
OpenCodeKey: "sk-sJkJVG2Q3tQEGqgl4cCy10QCVnrHpvuzR8RuE2eTuvruXiVNromsQ7zo6db0Ssj1"
|
||||
# Exa 網搜
|
||||
ExaKey: "5d9af9b2-a847-4295-a110-f666049e1073"
|
||||
ThreadsAppId: "2733369680379930"
|
||||
ThreadsAppSecret: "31db4afdd8e348d75d76dee8fb9a42d3"
|
||||
|
||||
Worker:
|
||||
ID: "worker-local-1"
|
||||
# demo-worker 預設 id(cmd/worker 若見 worker-local-1 會改成 demo-worker-1)
|
||||
ID: "demo-worker-1"
|
||||
PollIntervalMs: 2000
|
||||
|
||||
Bcrypt:
|
||||
|
|
@ -62,7 +72,7 @@ OAuth:
|
|||
# 正式 Mailgun SMTP 例:
|
||||
# Host: smtp.mailgun.org Port: 587
|
||||
# User: postmaster@YOUR_DOMAIN Password: <API SMTP password>
|
||||
# DevExposeCode: false
|
||||
# DevExposeCode: false試產
|
||||
#
|
||||
# env 覆寫:MAIL_SMTP_* 或 HAIXUN_SMTP_*(舊名相容)
|
||||
Mail:
|
||||
|
|
@ -77,7 +87,7 @@ Mail:
|
|||
|
||||
# 前端 origin:重設信連結 + 預設 logo URL(/brand-mark.jpg)
|
||||
# 遠端 dev:https://threads-tool-dev.30cm.net
|
||||
PublicWebBase: "http://127.0.0.1:5173"
|
||||
PublicWebBase: "https://threads-tool-dev.30cm.net"
|
||||
|
||||
# 郵件品牌(hermes 模板;LogoURL 空 = PublicWebBase/brand-mark.jpg)
|
||||
Brand:
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ func main() {
|
|||
|
||||
ctx := svc.NewServiceContext(c)
|
||||
handler.RegisterHandlers(server, ctx)
|
||||
// 靈感 SSE stream(goctl 不生成 streaming handler)
|
||||
handler.RegisterInspireStream(server, ctx)
|
||||
|
||||
logx.Infof("haixun gateway %s:%d pid=%d", c.Host, c.Port, os.Getpid())
|
||||
fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
syntax = "v1"
|
||||
|
||||
// ST-16: extension zip download (authenticated member)
|
||||
@server (
|
||||
jwt: Auth
|
||||
group: extension
|
||||
prefix: /api/v1/extension
|
||||
middleware: AuthJWT
|
||||
)
|
||||
service gateway {
|
||||
@handler DownloadExtensionZip
|
||||
get /download returns (Empty)
|
||||
}
|
||||
|
|
@ -13,3 +13,11 @@ import "auth.api"
|
|||
import "admin.api"
|
||||
import "settings.api"
|
||||
import "media.api"
|
||||
import "threads.api"
|
||||
import "jobs.api"
|
||||
import "notifications.api"
|
||||
import "usage.api"
|
||||
import "proxy.api"
|
||||
import "extension.api"
|
||||
import "studio.api"
|
||||
import "m5.api"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,59 @@
|
|||
syntax = "v1"
|
||||
|
||||
type (
|
||||
JobPublic {
|
||||
Id string `json:"id"`
|
||||
TemplateType string `json:"template_type"`
|
||||
Status string `json:"status"`
|
||||
ProgressSummary string `json:"progress_summary"`
|
||||
ProgressPercent int `json:"progress_percent"`
|
||||
Error string `json:"error,optional"`
|
||||
// 業務關聯(例:threads 帳號 id、人設 id)
|
||||
RefId string `json:"ref_id,optional"`
|
||||
// 任務 payload JSON(例:{"username":"x"})
|
||||
Payload string `json:"payload,optional"`
|
||||
// 排程執行時間 unix ns;0=立刻可領
|
||||
RunAfter int64 `json:"run_after,optional"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
UpdatedAt int64 `json:"updated_at"`
|
||||
CompletedAt int64 `json:"completed_at,optional"`
|
||||
}
|
||||
|
||||
JobListData {
|
||||
List []JobPublic `json:"list"`
|
||||
}
|
||||
|
||||
JobIdPath {
|
||||
Id string `path:"id"`
|
||||
}
|
||||
)
|
||||
|
||||
@server (
|
||||
jwt: Auth
|
||||
group: jobs
|
||||
prefix: /api/v1/jobs
|
||||
middleware: AuthJWT
|
||||
)
|
||||
service gateway {
|
||||
@handler ListJobs
|
||||
get / returns (JobListData)
|
||||
|
||||
@handler GetJob
|
||||
get /:id (JobIdPath) returns (JobPublic)
|
||||
|
||||
// 手動刪除任務(執行中不可刪;終態/已排程可刪)
|
||||
@handler DeleteJob
|
||||
delete /:id (JobIdPath) returns (OkData)
|
||||
}
|
||||
|
||||
// 管理員:產生 demo/測試任務(由 demo-worker 消費)
|
||||
@server (
|
||||
jwt: Auth
|
||||
group: jobs
|
||||
prefix: /api/v1/jobs
|
||||
middleware: AuthJWT,AdminAuth
|
||||
)
|
||||
service gateway {
|
||||
@handler StartDemoJob
|
||||
post /demo returns (JobPublic)
|
||||
}
|
||||
|
|
@ -0,0 +1,465 @@
|
|||
syntax = "v1"
|
||||
|
||||
// M5: inspire + research + media image + scout
|
||||
|
||||
type (
|
||||
// --- Inspire ---
|
||||
TrendPublic {
|
||||
Id string `json:"id"`
|
||||
Kind string `json:"kind"`
|
||||
Label string `json:"label"`
|
||||
Summary string `json:"summary"`
|
||||
Heat int `json:"heat"`
|
||||
Keywords []string `json:"keywords"`
|
||||
Samples []string `json:"samples"`
|
||||
SourceLabel string `json:"source_label"`
|
||||
ObservedAt int64 `json:"observed_at"`
|
||||
}
|
||||
TrendListData {
|
||||
List []TrendPublic `json:"list"`
|
||||
}
|
||||
InspireElementPublic {
|
||||
Id string `json:"id"`
|
||||
Kind string `json:"kind"`
|
||||
Title string `json:"title"`
|
||||
Body string `json:"body"`
|
||||
RefId string `json:"ref_id,optional"`
|
||||
Reusable bool `json:"reusable"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
UpdatedAt int64 `json:"updated_at"`
|
||||
}
|
||||
InspireElementListData {
|
||||
List []InspireElementPublic `json:"list"`
|
||||
}
|
||||
InspireElementSaveReq {
|
||||
Id string `json:"id,optional"`
|
||||
Kind string `json:"kind,optional"`
|
||||
Title string `json:"title"`
|
||||
Body string `json:"body"`
|
||||
RefId string `json:"ref_id,optional"`
|
||||
Reusable bool `json:"reusable,optional"`
|
||||
}
|
||||
InspireElementIdPath {
|
||||
Id string `path:"id"`
|
||||
}
|
||||
InspireDraftPublic {
|
||||
Title string `json:"title,optional"`
|
||||
Body string `json:"body"`
|
||||
}
|
||||
InspireMessagePublic {
|
||||
Id string `json:"id"`
|
||||
Role string `json:"role"`
|
||||
Text string `json:"text"`
|
||||
Draft InspireDraftPublic `json:"draft,optional"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
}
|
||||
InspireSessionPublic {
|
||||
Id string `json:"id"`
|
||||
Title string `json:"title,optional"`
|
||||
Messages []InspireMessagePublic `json:"messages"`
|
||||
PinnedElementIds []string `json:"pinned_element_ids"`
|
||||
CreatedAt int64 `json:"created_at,optional"`
|
||||
UpdatedAt int64 `json:"updated_at"`
|
||||
}
|
||||
// 列表摘要(不含完整 messages)
|
||||
InspireSessionSummaryPublic {
|
||||
Id string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Preview string `json:"preview"`
|
||||
MessageCount int `json:"message_count"`
|
||||
UpdatedAt int64 `json:"updated_at"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
Active bool `json:"active"`
|
||||
}
|
||||
InspireSessionListData {
|
||||
List []InspireSessionSummaryPublic `json:"list"`
|
||||
}
|
||||
InspireSessionIdPath {
|
||||
Id string `path:"id"`
|
||||
}
|
||||
InspireSessionCreateReq {
|
||||
Title string `json:"title,optional"`
|
||||
}
|
||||
InspireChatReq {
|
||||
Message string `json:"message"`
|
||||
PinnedIds []string `json:"pinned_ids,optional"`
|
||||
Mode string `json:"mode,optional"` // chat|generate
|
||||
PersonaId string `json:"persona_id,optional"`
|
||||
SessionId string `json:"session_id,optional"` // 空 = active
|
||||
// generate 專用:待改寫素材(鎖定內容);空則拒絕產文
|
||||
Material string `json:"material,optional"`
|
||||
}
|
||||
InspireChatData {
|
||||
Session InspireSessionPublic `json:"session"`
|
||||
Messages []InspireMessagePublic `json:"messages"`
|
||||
}
|
||||
// 觀測:與送出相同的 prompt 組裝(不呼叫 AI、不計費)
|
||||
InspirePromptPreviewReq {
|
||||
Message string `json:"message,optional"`
|
||||
PinnedIds []string `json:"pinned_ids,optional"`
|
||||
Mode string `json:"mode,optional"` // chat|generate
|
||||
PersonaId string `json:"persona_id,optional"`
|
||||
SessionId string `json:"session_id,optional"`
|
||||
Material string `json:"material,optional"`
|
||||
}
|
||||
InspirePromptPinnedPublic {
|
||||
Id string `json:"id"`
|
||||
Kind string `json:"kind"`
|
||||
Title string `json:"title"`
|
||||
Body string `json:"body"`
|
||||
}
|
||||
InspirePromptBlockPublic {
|
||||
Title string `json:"title"`
|
||||
Body string `json:"body"`
|
||||
}
|
||||
InspirePromptPreviewData {
|
||||
Prompt string `json:"prompt"`
|
||||
Mode string `json:"mode"`
|
||||
Sections []string `json:"sections"`
|
||||
Blocks []InspirePromptBlockPublic `json:"blocks"`
|
||||
Fingerprint string `json:"fingerprint"`
|
||||
CharCount int `json:"char_count"`
|
||||
RuneCount int `json:"rune_count"`
|
||||
Pinned []InspirePromptPinnedPublic `json:"pinned"`
|
||||
Note string `json:"note,optional"`
|
||||
}
|
||||
ResearchSearchReq {
|
||||
Query string `json:"query"`
|
||||
}
|
||||
ResearchHitPublic {
|
||||
Id string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Snippet string `json:"snippet"`
|
||||
Url string `json:"url"`
|
||||
Summary string `json:"summary,optional"`
|
||||
LearnPoints []string `json:"learn_points,optional"`
|
||||
ReplyHooks []string `json:"reply_hooks,optional"`
|
||||
SourceLabel string `json:"source_label,optional"`
|
||||
}
|
||||
ResearchSearchData {
|
||||
List []ResearchHitPublic `json:"list"`
|
||||
}
|
||||
GenerateImageReq {
|
||||
Prompt string `json:"prompt"`
|
||||
}
|
||||
GenerateImageData {
|
||||
Id string `json:"id"`
|
||||
Url string `json:"url"`
|
||||
Prompt string `json:"prompt"`
|
||||
}
|
||||
|
||||
// --- Scout ---
|
||||
BrandPublic {
|
||||
Id string `json:"id"`
|
||||
DisplayName string `json:"display_name"`
|
||||
Brief string `json:"brief"`
|
||||
TargetAudience string `json:"target_audience,optional"`
|
||||
Goals string `json:"goals,optional"`
|
||||
}
|
||||
BrandListData {
|
||||
List []BrandPublic `json:"list"`
|
||||
}
|
||||
BrandSaveReq {
|
||||
Id string `json:"id,optional"`
|
||||
DisplayName string `json:"display_name"`
|
||||
Brief string `json:"brief,optional"`
|
||||
TargetAudience string `json:"target_audience,optional"`
|
||||
Goals string `json:"goals,optional"`
|
||||
}
|
||||
BrandIdPath {
|
||||
Id string `path:"id"`
|
||||
}
|
||||
BrandActiveData {
|
||||
Id string `json:"id"`
|
||||
}
|
||||
BrandSetActiveReq {
|
||||
Id string `json:"id"`
|
||||
}
|
||||
ProductPublic {
|
||||
Id string `json:"id"`
|
||||
BrandId string `json:"brand_id"`
|
||||
Label string `json:"label"`
|
||||
ProductContext string `json:"product_context"`
|
||||
MatchTags []string `json:"match_tags"`
|
||||
PainPoints []string `json:"pain_points"`
|
||||
PlacementUrl string `json:"placement_url,optional"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
UpdatedAt int64 `json:"updated_at"`
|
||||
}
|
||||
ProductListData {
|
||||
List []ProductPublic `json:"list"`
|
||||
}
|
||||
ProductSaveReq {
|
||||
Id string `json:"id,optional"`
|
||||
BrandId string `json:"brand_id"`
|
||||
Label string `json:"label"`
|
||||
ProductContext string `json:"product_context,optional"`
|
||||
MatchTags []string `json:"match_tags,optional"`
|
||||
PainPoints []string `json:"pain_points,optional"`
|
||||
PlacementUrl string `json:"placement_url,optional"`
|
||||
}
|
||||
ProductIdPath {
|
||||
Id string `path:"id"`
|
||||
}
|
||||
ProductListReq {
|
||||
BrandId string `form:"brand_id,optional"`
|
||||
}
|
||||
ImportProductReq {
|
||||
Url string `json:"url"`
|
||||
}
|
||||
ImportProductData {
|
||||
Label string `json:"label"`
|
||||
ProductContext string `json:"product_context"`
|
||||
PainPoints []string `json:"pain_points"`
|
||||
MatchTags []string `json:"match_tags"`
|
||||
PlacementUrl string `json:"placement_url"`
|
||||
SourceNote string `json:"source_note"`
|
||||
}
|
||||
ScoutBriefReq {
|
||||
Intent string `json:"intent"`
|
||||
BrandId string `json:"brand_id,optional"`
|
||||
ProductId string `json:"product_id,optional"`
|
||||
Purpose string `json:"purpose,optional"`
|
||||
Deep bool `json:"deep,optional"`
|
||||
}
|
||||
ScoutBriefPublic {
|
||||
Intent string `json:"intent"`
|
||||
Mode string `json:"mode"`
|
||||
BrandId string `json:"brand_id,optional"`
|
||||
ProductId string `json:"product_id,optional"`
|
||||
ProductLabel string `json:"product_label,optional"`
|
||||
Pains []string `json:"pains"`
|
||||
Tags []string `json:"tags"`
|
||||
Periphery []string `json:"periphery"`
|
||||
ScanTerms []string `json:"scan_terms"`
|
||||
PlacementNote string `json:"placement_note,optional"`
|
||||
ResponseStance string `json:"response_stance,optional"`
|
||||
ThemeKey string `json:"theme_key,optional"`
|
||||
ThemeLabel string `json:"theme_label,optional"`
|
||||
ProductContext string `json:"product_context,optional"`
|
||||
}
|
||||
ScoutScanReq {
|
||||
Brief ScoutBriefPublic `json:"brief"`
|
||||
}
|
||||
ScoutPostPublic {
|
||||
Id string `json:"id"`
|
||||
BrandId string `json:"brand_id,optional"`
|
||||
Author string `json:"author"`
|
||||
Text string `json:"text"`
|
||||
SearchTag string `json:"search_tag"`
|
||||
Opportunity string `json:"opportunity"`
|
||||
OutreachStatus string `json:"outreach_status"`
|
||||
DraftText string `json:"draft_text,optional"`
|
||||
Score int `json:"score"`
|
||||
MatchedProductId string `json:"matched_product_id,optional"`
|
||||
MatchedProductLabel string `json:"matched_product_label,optional"`
|
||||
MatchReason string `json:"match_reason,optional"`
|
||||
ScoutMode string `json:"scout_mode,optional"`
|
||||
IntentSnippet string `json:"intent_snippet,optional"`
|
||||
ThemeKey string `json:"theme_key,optional"`
|
||||
ThemeLabel string `json:"theme_label,optional"`
|
||||
ScanPath string `json:"scan_path,optional"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
}
|
||||
ScoutPostListData {
|
||||
List []ScoutPostPublic `json:"list"`
|
||||
}
|
||||
ScoutPostListReq {
|
||||
BrandId string `form:"brand_id,optional"`
|
||||
}
|
||||
ScoutPostIdPath {
|
||||
Id string `path:"id"`
|
||||
}
|
||||
ScoutDraftPathReq {
|
||||
Id string `path:"id"`
|
||||
PersonaId string `json:"persona_id,optional"`
|
||||
}
|
||||
ScoutSendPathReq {
|
||||
Id string `path:"id"`
|
||||
Text string `json:"text,optional"`
|
||||
AccountId string `json:"account_id,optional"`
|
||||
}
|
||||
ScoutThemePath {
|
||||
ThemeKey string `path:"themeKey"`
|
||||
}
|
||||
ScoutHomeworkPublic {
|
||||
ThemeKey string `json:"theme_key"`
|
||||
ThemeLabel string `json:"theme_label"`
|
||||
Purpose string `json:"purpose"`
|
||||
Brief ScoutBriefPublic `json:"brief"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
}
|
||||
ScoutHomeworkListData {
|
||||
List []ScoutHomeworkPublic `json:"list"`
|
||||
}
|
||||
ScoutHomeworkSaveReq {
|
||||
ThemeKey string `json:"theme_key"`
|
||||
ThemeLabel string `json:"theme_label"`
|
||||
Purpose string `json:"purpose,optional"`
|
||||
Brief ScoutBriefPublic `json:"brief"`
|
||||
}
|
||||
ScoutCrawlerSessionReq {
|
||||
Token string `json:"token"`
|
||||
}
|
||||
)
|
||||
|
||||
@server (
|
||||
jwt: Auth
|
||||
group: inspire
|
||||
prefix: /api/v1/inspire
|
||||
middleware: AuthJWT
|
||||
)
|
||||
service gateway {
|
||||
@handler ListTrends
|
||||
get /trends returns (TrendListData)
|
||||
|
||||
@handler RefreshTrends
|
||||
post /trends/refresh returns (TrendListData)
|
||||
|
||||
@handler ListInspireElements
|
||||
get /elements returns (InspireElementListData)
|
||||
|
||||
@handler SaveInspireElement
|
||||
post /elements (InspireElementSaveReq) returns (InspireElementPublic)
|
||||
|
||||
@handler RemoveInspireElement
|
||||
delete /elements/:id (InspireElementIdPath) returns (OkData)
|
||||
|
||||
@handler GetInspireSession
|
||||
get /session returns (InspireSessionPublic)
|
||||
|
||||
@handler ClearInspireSession
|
||||
post /session/clear returns (InspireSessionPublic)
|
||||
|
||||
@handler ListInspireSessions
|
||||
get /sessions returns (InspireSessionListData)
|
||||
|
||||
@handler CreateInspireSession
|
||||
post /sessions (InspireSessionCreateReq) returns (InspireSessionPublic)
|
||||
|
||||
@handler GetInspireSessionById
|
||||
get /sessions/:id (InspireSessionIdPath) returns (InspireSessionPublic)
|
||||
|
||||
@handler ActivateInspireSession
|
||||
post /sessions/:id/activate (InspireSessionIdPath) returns (InspireSessionPublic)
|
||||
|
||||
@handler DeleteInspireSession
|
||||
delete /sessions/:id (InspireSessionIdPath) returns (InspireSessionPublic)
|
||||
|
||||
@handler InspireChat
|
||||
post /chat (InspireChatReq) returns (InspireChatData)
|
||||
|
||||
@handler InspirePromptPreview
|
||||
post /prompt-preview (InspirePromptPreviewReq) returns (InspirePromptPreviewData)
|
||||
}
|
||||
|
||||
@server (
|
||||
jwt: Auth
|
||||
group: research
|
||||
prefix: /api/v1/research
|
||||
middleware: AuthJWT
|
||||
)
|
||||
service gateway {
|
||||
@handler ResearchSearch
|
||||
post /search (ResearchSearchReq) returns (ResearchSearchData)
|
||||
}
|
||||
|
||||
@server (
|
||||
jwt: Auth
|
||||
group: media
|
||||
prefix: /api/v1/media
|
||||
middleware: AuthJWT
|
||||
)
|
||||
service gateway {
|
||||
@handler GenerateImage
|
||||
post /generate-image (GenerateImageReq) returns (GenerateImageData)
|
||||
}
|
||||
|
||||
@server (
|
||||
jwt: Auth
|
||||
group: scout
|
||||
prefix: /api/v1/scout
|
||||
middleware: AuthJWT
|
||||
)
|
||||
service gateway {
|
||||
@handler ListBrands
|
||||
get /brands returns (BrandListData)
|
||||
|
||||
@handler SaveBrand
|
||||
post /brands (BrandSaveReq) returns (BrandPublic)
|
||||
|
||||
@handler GetBrand
|
||||
get /brands/:id (BrandIdPath) returns (BrandPublic)
|
||||
|
||||
@handler RemoveBrand
|
||||
delete /brands/:id (BrandIdPath) returns (OkData)
|
||||
|
||||
@handler GetActiveBrand
|
||||
get /brands-active returns (BrandActiveData)
|
||||
|
||||
@handler SetActiveBrand
|
||||
post /brands-active (BrandSetActiveReq) returns (BrandActiveData)
|
||||
|
||||
@handler ListProducts
|
||||
get /products (ProductListReq) returns (ProductListData)
|
||||
|
||||
@handler ListAllProducts
|
||||
get /products/all returns (ProductListData)
|
||||
|
||||
@handler SaveProduct
|
||||
post /products (ProductSaveReq) returns (ProductPublic)
|
||||
|
||||
@handler GetProduct
|
||||
get /products/:id (ProductIdPath) returns (ProductPublic)
|
||||
|
||||
@handler RemoveProduct
|
||||
delete /products/:id (ProductIdPath) returns (OkData)
|
||||
|
||||
@handler ImportProduct
|
||||
post /products/import (ImportProductReq) returns (ImportProductData)
|
||||
|
||||
@handler PrepareBrief
|
||||
post /brief (ScoutBriefReq) returns (ScoutBriefPublic)
|
||||
|
||||
@handler RunScan
|
||||
post /scan (ScoutScanReq) returns (ScoutPostListData)
|
||||
|
||||
@handler ListScoutPosts
|
||||
get /posts (ScoutPostListReq) returns (ScoutPostListData)
|
||||
|
||||
@handler DraftOutreach
|
||||
post /posts/:id/draft (ScoutDraftPathReq) returns (ScoutPostPublic)
|
||||
|
||||
@handler SkipOutreach
|
||||
post /posts/:id/skip (ScoutPostIdPath) returns (ScoutPostPublic)
|
||||
|
||||
@handler MarkPublished
|
||||
post /posts/:id/mark-published (ScoutPostIdPath) returns (ScoutPostPublic)
|
||||
|
||||
@handler SendOutreach
|
||||
post /posts/:id/send (ScoutSendPathReq) returns (ScoutPostPublic)
|
||||
|
||||
@handler RemoveScoutPost
|
||||
delete /posts/:id (ScoutPostIdPath) returns (OkData)
|
||||
|
||||
@handler RemoveScoutTheme
|
||||
delete /themes/:themeKey (ScoutThemePath) returns (OkData)
|
||||
|
||||
@handler ListHomework
|
||||
get /homework returns (ScoutHomeworkListData)
|
||||
|
||||
@handler SaveHomework
|
||||
post /homework (ScoutHomeworkSaveReq) returns (ScoutHomeworkPublic)
|
||||
|
||||
@handler GetHomework
|
||||
get /homework/:themeKey (ScoutThemePath) returns (ScoutHomeworkPublic)
|
||||
|
||||
@handler RemoveHomework
|
||||
delete /homework/:themeKey (ScoutThemePath) returns (OkData)
|
||||
|
||||
@handler SetCrawlerSession
|
||||
post /crawler-session (ScoutCrawlerSessionReq) returns (OkData)
|
||||
|
||||
@handler ClearCrawlerSession
|
||||
delete /crawler-session returns (OkData)
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
syntax = "v1"
|
||||
|
||||
type (
|
||||
NotificationPublic {
|
||||
Id string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Body string `json:"body"`
|
||||
Kind string `json:"kind"` // job|system
|
||||
RefType string `json:"ref_type"`
|
||||
RefId string `json:"ref_id,optional"`
|
||||
ReadAt int64 `json:"read_at,optional"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
}
|
||||
|
||||
NotificationListData {
|
||||
List []NotificationPublic `json:"list"`
|
||||
}
|
||||
|
||||
UnreadCountData {
|
||||
Count int64 `json:"count"`
|
||||
}
|
||||
|
||||
NotificationIdPath {
|
||||
Id string `path:"id"`
|
||||
}
|
||||
)
|
||||
|
||||
@server (
|
||||
jwt: Auth
|
||||
group: notifications
|
||||
prefix: /api/v1/notifications
|
||||
middleware: AuthJWT
|
||||
)
|
||||
service gateway {
|
||||
@handler ListNotifications
|
||||
get / returns (NotificationListData)
|
||||
|
||||
@handler UnreadNotificationCount
|
||||
get /unread-count returns (UnreadCountData)
|
||||
|
||||
@handler MarkNotificationRead
|
||||
post /:id/read (NotificationIdPath) returns (OkData)
|
||||
|
||||
@handler MarkAllNotificationsRead
|
||||
post /read-all returns (OkData)
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
syntax = "v1"
|
||||
|
||||
type (
|
||||
AICompleteReq {
|
||||
Prompt string `json:"prompt"`
|
||||
Model string `json:"model,optional"`
|
||||
Meter string `json:"meter,optional"` // default ai_copy
|
||||
}
|
||||
|
||||
AICompleteData {
|
||||
Text string `json:"text"`
|
||||
KeyMode string `json:"key_mode"`
|
||||
Model string `json:"model"`
|
||||
}
|
||||
|
||||
SearchReq {
|
||||
Query string `json:"query"`
|
||||
Limit int `json:"limit,optional"`
|
||||
}
|
||||
|
||||
SearchHit {
|
||||
Title string `json:"title"`
|
||||
Url string `json:"url"`
|
||||
Snippet string `json:"snippet"`
|
||||
}
|
||||
|
||||
SearchData {
|
||||
List []SearchHit `json:"list"`
|
||||
KeyMode string `json:"key_mode"`
|
||||
}
|
||||
)
|
||||
|
||||
@server (
|
||||
jwt: Auth
|
||||
group: proxy
|
||||
prefix: /api/v1/proxy
|
||||
middleware: AuthJWT
|
||||
)
|
||||
service gateway {
|
||||
@handler AIComplete
|
||||
post /ai/complete (AICompleteReq) returns (AICompleteData)
|
||||
|
||||
@handler ExaSearch
|
||||
post /search (SearchReq) returns (SearchData)
|
||||
}
|
||||
|
|
@ -1,6 +1,12 @@
|
|||
syntax = "v1"
|
||||
|
||||
type (
|
||||
// GetAi:設定 + 模型清單一併回(避免前端分開打兩支)
|
||||
GetAiReq {
|
||||
// 可選:預覽另一個 provider 的模型清單(不改存檔)
|
||||
Provider string `form:"provider,optional"`
|
||||
}
|
||||
|
||||
AiSettingsData {
|
||||
Provider string `json:"provider"`
|
||||
Model string `json:"model"`
|
||||
|
|
@ -9,6 +15,15 @@ type (
|
|||
ApiKeyConfigured bool `json:"api_key_configured"`
|
||||
ResearchApiKeyConfigured bool `json:"research_api_key_configured"`
|
||||
PlatformKeyAvailable bool `json:"platform_key_available"`
|
||||
// Models — 目前 models_provider 的可用模型(真拉 + 5 分鐘快取)
|
||||
Models []string `json:"models"`
|
||||
ModelsProvider string `json:"models_provider"`
|
||||
// SelectedModel — 與 Model 相同;明確給前端「上次設定的模型」
|
||||
SelectedModel string `json:"selected_model"`
|
||||
// ModelsFromCache — 這次模型清單是否來自快取
|
||||
ModelsFromCache bool `json:"models_from_cache,optional"`
|
||||
// ModelsError — 真拉失敗時提示(仍回 fallback models)
|
||||
ModelsError string `json:"models_error,optional"`
|
||||
}
|
||||
|
||||
SaveAiReq {
|
||||
|
|
@ -45,6 +60,25 @@ type (
|
|||
ListModelsData {
|
||||
List []string `json:"list"`
|
||||
Provider string `json:"provider"`
|
||||
// SelectedModel — 若該 provider 為使用者目前存檔 provider,回傳已選 model
|
||||
SelectedModel string `json:"selected_model,optional"`
|
||||
FromCache bool `json:"from_cache,optional"`
|
||||
ModelsError string `json:"models_error,optional"`
|
||||
}
|
||||
|
||||
// Threads OAuth 平台狀態(App Secret 永不回傳)
|
||||
ThreadsSettingsData {
|
||||
Provider string `json:"provider"` // fake | meta
|
||||
Configured bool `json:"configured"`
|
||||
OauthReady bool `json:"oauth_ready"`
|
||||
ConnectPath string `json:"connect_path"` // 前端連帳入口
|
||||
// 給 Meta 後台「Valid OAuth Redirect URIs」貼上用
|
||||
CallbackUrl string `json:"callback_url"`
|
||||
// 前端公開 origin(應 https)
|
||||
PublicWebBase string `json:"public_web_base"`
|
||||
// App Id 遮罩,例 2733…9930;未設定空字串
|
||||
AppIdMasked string `json:"app_id_masked,optional"`
|
||||
Hint string `json:"hint"`
|
||||
}
|
||||
)
|
||||
|
||||
|
|
@ -55,7 +89,7 @@ type (
|
|||
)
|
||||
service gateway {
|
||||
@handler GetAi
|
||||
get /ai returns (AiSettingsData)
|
||||
get /ai (GetAiReq) returns (AiSettingsData)
|
||||
|
||||
@handler SaveAi
|
||||
put /ai (SaveAiReq) returns (AiSettingsData)
|
||||
|
|
@ -68,4 +102,7 @@ service gateway {
|
|||
|
||||
@handler ListModels
|
||||
get /models (ListModelsReq) returns (ListModelsData)
|
||||
|
||||
@handler GetThreads
|
||||
get /threads returns (ThreadsSettingsData)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,568 @@
|
|||
syntax = "v1"
|
||||
|
||||
// M4 Studio: personas / plays / outbox / compose / own-posts / mentions
|
||||
|
||||
type (
|
||||
PersonaDraftPublic {
|
||||
Identity string `json:"identity"`
|
||||
Tone string `json:"tone"`
|
||||
Audience string `json:"audience"`
|
||||
Hooks string `json:"hooks"`
|
||||
LanguageFingerprint string `json:"language_fingerprint"`
|
||||
Rhythm string `json:"rhythm"`
|
||||
Punctuation string `json:"punctuation"`
|
||||
ContentPatterns string `json:"content_patterns"`
|
||||
KnowledgeTranslation string `json:"knowledge_translation"`
|
||||
CtaStyle string `json:"cta_style"`
|
||||
Examples string `json:"examples"`
|
||||
Avoid string `json:"avoid"`
|
||||
}
|
||||
|
||||
StyleDimensionPublic {
|
||||
Summary string `json:"summary"`
|
||||
Evidence []string `json:"evidence,optional"`
|
||||
}
|
||||
|
||||
PersonaStylePublic {
|
||||
Draft PersonaDraftPublic `json:"draft"`
|
||||
DraftText string `json:"draft_text"`
|
||||
Source string `json:"source"`
|
||||
BenchmarkUsername string `json:"benchmark_username,optional"`
|
||||
SourceLabel string `json:"source_label,optional"`
|
||||
SampleCount int `json:"sample_count"`
|
||||
AnalyzedAt int64 `json:"analyzed_at,optional"`
|
||||
SamplePreviews []string `json:"sample_previews,optional"`
|
||||
// 8D:d1Tone…d8Risk → { summary, evidence }
|
||||
Dimensions map[string]StyleDimensionPublic `json:"dimensions,optional"`
|
||||
}
|
||||
|
||||
PersonaGuardPublic {
|
||||
Avoid []string `json:"avoid"`
|
||||
MaxChars int `json:"max_chars"`
|
||||
BanAiTone bool `json:"ban_ai_tone"`
|
||||
}
|
||||
|
||||
PersonaPublic {
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Brief string `json:"brief"`
|
||||
Status string `json:"status"`
|
||||
Style PersonaStylePublic `json:"style"`
|
||||
Guard PersonaGuardPublic `json:"guard"`
|
||||
Voice string `json:"voice,optional"`
|
||||
Notes string `json:"notes,optional"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
UpdatedAt int64 `json:"updated_at"`
|
||||
}
|
||||
|
||||
PersonaListData {
|
||||
List []PersonaPublic `json:"list"`
|
||||
}
|
||||
|
||||
PersonaSaveReq {
|
||||
Id string `json:"id,optional"`
|
||||
Name string `json:"name"`
|
||||
Brief string `json:"brief,optional"`
|
||||
Status string `json:"status,optional"`
|
||||
Style PersonaStylePublic `json:"style,optional"`
|
||||
Guard PersonaGuardPublic `json:"guard,optional"`
|
||||
Voice string `json:"voice,optional"`
|
||||
Notes string `json:"notes,optional"`
|
||||
}
|
||||
|
||||
PersonaIdPath {
|
||||
Id string `path:"id"`
|
||||
}
|
||||
|
||||
PersonaActiveData {
|
||||
Id string `json:"id"`
|
||||
}
|
||||
|
||||
PersonaSetActiveReq {
|
||||
Id string `json:"id"`
|
||||
}
|
||||
|
||||
PersonaAnalyzeTextReq {
|
||||
Id string `path:"id"`
|
||||
RawText string `json:"raw_text"`
|
||||
SourceLabel string `json:"source_label,optional"`
|
||||
}
|
||||
|
||||
PersonaAnalyzeAccountReq {
|
||||
Id string `path:"id"`
|
||||
Username string `json:"username"`
|
||||
}
|
||||
|
||||
// --- Plays ---
|
||||
ExternalTargetPublic {
|
||||
Url string `json:"url"`
|
||||
RawUrl string `json:"raw_url,optional"`
|
||||
Shortcode string `json:"shortcode,optional"`
|
||||
AuthorUsername string `json:"author_username,optional"`
|
||||
TextPreview string `json:"text_preview,optional"`
|
||||
MediaId string `json:"media_id,optional"`
|
||||
ResolvedAt int64 `json:"resolved_at,optional"`
|
||||
}
|
||||
|
||||
PlayStepPublic {
|
||||
Id string `json:"id"`
|
||||
SortOrder int `json:"sort_order"`
|
||||
Kind string `json:"kind"`
|
||||
AccountId string `json:"account_id"`
|
||||
Text string `json:"text"`
|
||||
DelayFromPreviousSec int `json:"delay_from_previous_sec"`
|
||||
PersonaId string `json:"persona_id,optional"`
|
||||
BrandId string `json:"brand_id,optional"`
|
||||
ImageUrls []string `json:"image_urls,optional"`
|
||||
}
|
||||
|
||||
PlayPublic {
|
||||
Id string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Topic string `json:"topic"`
|
||||
Status string `json:"status"`
|
||||
LeadAccountId string `json:"lead_account_id"`
|
||||
CastAccountIds []string `json:"cast_account_ids"`
|
||||
TargetOwnPostId string `json:"target_own_post_id,optional"`
|
||||
TargetExternal ExternalTargetPublic `json:"target_external,optional"`
|
||||
Steps []PlayStepPublic `json:"steps"`
|
||||
ScheduleStartAt int64 `json:"schedule_start_at"`
|
||||
IntervalMinutes int `json:"interval_minutes,optional"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
UpdatedAt int64 `json:"updated_at"`
|
||||
}
|
||||
|
||||
PlayListData {
|
||||
List []PlayPublic `json:"list"`
|
||||
}
|
||||
|
||||
PlaySaveReq {
|
||||
Id string `json:"id,optional"`
|
||||
Title string `json:"title"`
|
||||
Topic string `json:"topic,optional"`
|
||||
Status string `json:"status,optional"`
|
||||
LeadAccountId string `json:"lead_account_id"`
|
||||
CastAccountIds []string `json:"cast_account_ids,optional"`
|
||||
TargetOwnPostId string `json:"target_own_post_id,optional"`
|
||||
TargetExternal ExternalTargetPublic `json:"target_external,optional"`
|
||||
Steps []PlayStepPublic `json:"steps"`
|
||||
ScheduleStartAt int64 `json:"schedule_start_at,optional"`
|
||||
IntervalMinutes int `json:"interval_minutes,optional"`
|
||||
}
|
||||
|
||||
PlayIdPath {
|
||||
Id string `path:"id"`
|
||||
}
|
||||
|
||||
PlayByPostReq {
|
||||
OwnPostId string `form:"own_post_id"`
|
||||
}
|
||||
|
||||
PlayByExternalReq {
|
||||
Url string `form:"url"`
|
||||
}
|
||||
|
||||
PlayResolveReq {
|
||||
Url string `json:"url"`
|
||||
}
|
||||
|
||||
// AI 產劇本一步(真 LLM;互回/串場共用)
|
||||
PlayGenerateStepReq {
|
||||
PersonaId string `json:"persona_id,optional"`
|
||||
Context string `json:"context"` // 主貼/上一則/目標文
|
||||
Topic string `json:"topic,optional"`
|
||||
SpeakerLabel string `json:"speaker_label,optional"`
|
||||
IsLead bool `json:"is_lead,optional"`
|
||||
// mode: reply(預設)| root(串場主貼)
|
||||
Mode string `json:"mode,optional"`
|
||||
}
|
||||
|
||||
PlayGenerateStepData {
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
// 一次產完整劇本(背景 job)
|
||||
PlayGenerateScriptData {
|
||||
JobId string `json:"job_id"`
|
||||
Async bool `json:"async"`
|
||||
}
|
||||
|
||||
// --- Outbox ---
|
||||
OutboxStepPublic {
|
||||
Id string `json:"id"`
|
||||
StepId string `json:"step_id"`
|
||||
SortOrder int `json:"sort_order"`
|
||||
Kind string `json:"kind"`
|
||||
AccountId string `json:"account_id"`
|
||||
Text string `json:"text"`
|
||||
Status string `json:"status"`
|
||||
Error string `json:"error,optional"`
|
||||
ScheduledAt int64 `json:"scheduled_at,optional"`
|
||||
PublishedAt int64 `json:"published_at,optional"`
|
||||
}
|
||||
|
||||
OutboxPublic {
|
||||
Id string `json:"id"`
|
||||
PlayId string `json:"play_id"`
|
||||
Title string `json:"title"`
|
||||
Status string `json:"status"`
|
||||
Steps []OutboxStepPublic `json:"steps"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
UpdatedAt int64 `json:"updated_at"`
|
||||
}
|
||||
|
||||
OutboxListData {
|
||||
List []OutboxPublic `json:"list"`
|
||||
}
|
||||
|
||||
OutboxIdPath {
|
||||
Id string `path:"id"`
|
||||
}
|
||||
|
||||
OutboxRetryPath {
|
||||
Id string `path:"id"`
|
||||
StepId string `path:"stepId"`
|
||||
}
|
||||
|
||||
// --- Compose ---
|
||||
ComposeMimicReq {
|
||||
SourceText string `json:"source_text"`
|
||||
PersonaId string `json:"persona_id,optional"`
|
||||
// 可選:從「我的貼文」結構分析帶過來的備註(鉤子/結構/可複製點)
|
||||
StructureNotes string `json:"structure_notes,optional"`
|
||||
}
|
||||
|
||||
// 仿寫改背景 Job:立刻回 job_id;完成後從 job.payload.result_text 取文
|
||||
ComposeMimicData {
|
||||
// 相容:同步路徑才有;Job 路徑為空
|
||||
Text string `json:"text,optional"`
|
||||
JobId string `json:"job_id,optional"`
|
||||
Async bool `json:"async,optional"`
|
||||
}
|
||||
|
||||
// 人設試產:依指紋真 LLM 產主貼 + 回文(可帶新聞話題)
|
||||
ComposePersonaPreviewReq {
|
||||
PersonaId string `json:"persona_id"`
|
||||
// 手動話題;空則嘗試上網取新聞靈感
|
||||
Topic string `json:"topic,optional"`
|
||||
// 預設 true:無 topic 時抓即時新聞標題當靈感
|
||||
UseNews bool `json:"use_news,optional"`
|
||||
}
|
||||
|
||||
ComposePersonaPreviewData {
|
||||
Topic string `json:"topic"`
|
||||
TopicSource string `json:"topic_source"` // news | manual | fallback
|
||||
PostText string `json:"post_text"`
|
||||
ReplyText string `json:"reply_text"`
|
||||
Notes string `json:"notes,optional"`
|
||||
}
|
||||
|
||||
ComposeViralReq {
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
ViralAnalysisPublic {
|
||||
Hooks string `json:"hooks"`
|
||||
Structure string `json:"structure"`
|
||||
Emotion string `json:"emotion"`
|
||||
Summary string `json:"summary"`
|
||||
Cta string `json:"cta,optional"`
|
||||
Copyable string `json:"copyable,optional"`
|
||||
Risks string `json:"risks,optional"`
|
||||
}
|
||||
|
||||
ComposePublishReq {
|
||||
AccountId string `json:"account_id"`
|
||||
Text string `json:"text"`
|
||||
Title string `json:"title,optional"`
|
||||
ImageUrls []string `json:"image_urls,optional"`
|
||||
ScheduleStartAt int64 `json:"schedule_start_at,optional"`
|
||||
// Threads 話題標籤(topic_tag,1~50 字,可不加 #)
|
||||
TopicTag string `json:"topic_tag,optional"`
|
||||
}
|
||||
|
||||
// --- Own posts ---
|
||||
OwnPostReplyPublic {
|
||||
Id string `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Text string `json:"text"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
LikeCount int `json:"like_count,optional"`
|
||||
ReplyStatus string `json:"reply_status,optional"`
|
||||
RepliedBy string `json:"replied_by,optional"`
|
||||
RepliedAt int64 `json:"replied_at,optional"`
|
||||
ParentReplyId string `json:"parent_reply_id,optional"`
|
||||
IsMine bool `json:"is_mine,optional"`
|
||||
}
|
||||
|
||||
OwnPostPublic {
|
||||
Id string `json:"id"`
|
||||
AccountId string `json:"account_id"`
|
||||
MediaId string `json:"media_id,optional"`
|
||||
Text string `json:"text"`
|
||||
MediaType string `json:"media_type"`
|
||||
MediaUrl string `json:"media_url,optional"`
|
||||
ThumbnailUrl string `json:"thumbnail_url,optional"`
|
||||
Permalink string `json:"permalink,optional"`
|
||||
Shortcode string `json:"shortcode,optional"`
|
||||
TopicTag string `json:"topic_tag,optional"`
|
||||
LikeCount int `json:"like_count"`
|
||||
ReplyCount int `json:"reply_count"`
|
||||
RepostCount int `json:"repost_count"`
|
||||
QuoteCount int `json:"quote_count"`
|
||||
ViewCount int `json:"view_count"`
|
||||
ShareCount int `json:"share_count"`
|
||||
InsightsStatus string `json:"insights_status,optional"`
|
||||
FormulaSummary string `json:"formula_summary,optional"`
|
||||
Insight string `json:"insight,optional"`
|
||||
FormulaDetail string `json:"formula_detail,optional"`
|
||||
Replies []OwnPostReplyPublic `json:"replies"`
|
||||
PublishedAt int64 `json:"published_at"`
|
||||
}
|
||||
|
||||
OwnPostListData {
|
||||
List []OwnPostPublic `json:"list"`
|
||||
}
|
||||
|
||||
OwnPostListReq {
|
||||
AccountId string `form:"account_id,optional"`
|
||||
}
|
||||
|
||||
OwnPostSyncReq {
|
||||
AccountId string `json:"account_id"`
|
||||
}
|
||||
|
||||
OwnPostLastSyncedData {
|
||||
LastSyncedAt int64 `json:"last_synced_at"`
|
||||
}
|
||||
|
||||
OwnPostGenerateReplyReq {
|
||||
PostId string `json:"post_id"`
|
||||
ReplyId string `json:"reply_id,optional"`
|
||||
PersonaId string `json:"persona_id,optional"`
|
||||
}
|
||||
|
||||
OwnPostGenerateReplyData {
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
OwnPostSendReplyReq {
|
||||
PostId string `json:"post_id"`
|
||||
ReplyId string `json:"reply_id,optional"`
|
||||
Text string `json:"text"`
|
||||
AccountId string `json:"account_id,optional"`
|
||||
ImageUrls []string `json:"image_urls,optional"`
|
||||
}
|
||||
|
||||
OwnPostAnalyzeReq {
|
||||
PostId string `json:"post_id"`
|
||||
}
|
||||
|
||||
// 點開貼文後再載留言(避免 sync 一次打爆 conversation API)
|
||||
OwnPostLoadRepliesReq {
|
||||
PostId string `json:"post_id"`
|
||||
}
|
||||
|
||||
// --- Mentions ---
|
||||
MentionPublic {
|
||||
Id string `json:"id"`
|
||||
AccountId string `json:"account_id"`
|
||||
MediaId string `json:"media_id,optional"`
|
||||
FromUsername string `json:"from_username"`
|
||||
Text string `json:"text"`
|
||||
ContextSnippet string `json:"context_snippet"`
|
||||
Permalink string `json:"permalink,optional"`
|
||||
Status string `json:"status"`
|
||||
DraftText string `json:"draft_text,optional"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
}
|
||||
|
||||
MentionListData {
|
||||
List []MentionPublic `json:"list"`
|
||||
}
|
||||
|
||||
MentionListReq {
|
||||
AccountId string `form:"account_id,optional"`
|
||||
}
|
||||
|
||||
MentionSyncReq {
|
||||
AccountId string `json:"account_id"`
|
||||
}
|
||||
|
||||
MentionIdPath {
|
||||
Id string `path:"id"`
|
||||
}
|
||||
|
||||
MentionGenerateReq {
|
||||
Id string `path:"id"`
|
||||
PersonaId string `json:"persona_id,optional"`
|
||||
}
|
||||
|
||||
MentionMarkRepliedReq {
|
||||
Id string `path:"id"`
|
||||
Text string `json:"text,optional"`
|
||||
ImageUrls []string `json:"image_urls,optional"`
|
||||
}
|
||||
)
|
||||
|
||||
@server (
|
||||
jwt: Auth
|
||||
group: personas
|
||||
prefix: /api/v1/personas
|
||||
middleware: AuthJWT
|
||||
)
|
||||
service gateway {
|
||||
@handler ListPersonas
|
||||
get / returns (PersonaListData)
|
||||
|
||||
@handler GetActivePersona
|
||||
get /active returns (PersonaActiveData)
|
||||
|
||||
@handler SetActivePersona
|
||||
post /active (PersonaSetActiveReq) returns (PersonaActiveData)
|
||||
|
||||
@handler GetPersona
|
||||
get /:id (PersonaIdPath) returns (PersonaPublic)
|
||||
|
||||
@handler SavePersona
|
||||
post / (PersonaSaveReq) returns (PersonaPublic)
|
||||
|
||||
@handler RemovePersona
|
||||
delete /:id (PersonaIdPath) returns (OkData)
|
||||
|
||||
@handler AnalyzePersonaText
|
||||
post /:id/analyze-text (PersonaAnalyzeTextReq) returns (PersonaPublic)
|
||||
|
||||
@handler AnalyzePersonaAccount
|
||||
post /:id/analyze-account (PersonaAnalyzeAccountReq) returns (PersonaPublic)
|
||||
}
|
||||
|
||||
@server (
|
||||
jwt: Auth
|
||||
group: plays
|
||||
prefix: /api/v1/plays
|
||||
middleware: AuthJWT
|
||||
)
|
||||
service gateway {
|
||||
@handler ListPlays
|
||||
get / returns (PlayListData)
|
||||
|
||||
@handler ListPlaysByPost
|
||||
get /by-post (PlayByPostReq) returns (PlayListData)
|
||||
|
||||
@handler ListPlaysByExternal
|
||||
get /by-external (PlayByExternalReq) returns (PlayListData)
|
||||
|
||||
@handler ResolveExternalLink
|
||||
post /resolve-external (PlayResolveReq) returns (ExternalTargetPublic)
|
||||
|
||||
@handler GetPlay
|
||||
get /:id (PlayIdPath) returns (PlayPublic)
|
||||
|
||||
@handler SavePlay
|
||||
post / (PlaySaveReq) returns (PlayPublic)
|
||||
|
||||
@handler RemovePlay
|
||||
delete /:id (PlayIdPath) returns (OkData)
|
||||
|
||||
@handler SubmitPlay
|
||||
post /:id/submit (PlayIdPath) returns (OutboxPublic)
|
||||
|
||||
@handler GeneratePlayStep
|
||||
post /generate-step (PlayGenerateStepReq) returns (PlayGenerateStepData)
|
||||
|
||||
@handler GeneratePlayScript
|
||||
post /:id/generate-script (PlayIdPath) returns (PlayGenerateScriptData)
|
||||
}
|
||||
|
||||
@server (
|
||||
jwt: Auth
|
||||
group: outbox
|
||||
prefix: /api/v1/outbox
|
||||
middleware: AuthJWT
|
||||
)
|
||||
service gateway {
|
||||
@handler ListOutbox
|
||||
get / returns (OutboxListData)
|
||||
|
||||
@handler GetOutbox
|
||||
get /:id (OutboxIdPath) returns (OutboxPublic)
|
||||
|
||||
@handler RemoveOutbox
|
||||
delete /:id (OutboxIdPath) returns (OkData)
|
||||
|
||||
@handler RetryOutboxStep
|
||||
post /:id/steps/:stepId/retry (OutboxRetryPath) returns (OutboxPublic)
|
||||
}
|
||||
|
||||
@server (
|
||||
jwt: Auth
|
||||
group: compose
|
||||
prefix: /api/v1/compose
|
||||
middleware: AuthJWT
|
||||
)
|
||||
service gateway {
|
||||
@handler ComposeMimic
|
||||
post /mimic (ComposeMimicReq) returns (ComposeMimicData)
|
||||
|
||||
@handler ComposePersonaPreview
|
||||
post /persona-preview (ComposePersonaPreviewReq) returns (ComposePersonaPreviewData)
|
||||
|
||||
@handler ComposeAnalyzeViral
|
||||
post /analyze-viral (ComposeViralReq) returns (ViralAnalysisPublic)
|
||||
|
||||
@handler ComposePublishSingle
|
||||
post /publish-single (ComposePublishReq) returns (OutboxPublic)
|
||||
}
|
||||
|
||||
@server (
|
||||
jwt: Auth
|
||||
group: ownposts
|
||||
prefix: /api/v1/own-posts
|
||||
middleware: AuthJWT
|
||||
)
|
||||
service gateway {
|
||||
@handler ListOwnPosts
|
||||
get / (OwnPostListReq) returns (OwnPostListData)
|
||||
|
||||
@handler OwnPostsLastSynced
|
||||
get /last-synced-at returns (OwnPostLastSyncedData)
|
||||
|
||||
@handler SyncOwnPosts
|
||||
post /sync (OwnPostSyncReq) returns (OwnPostListData)
|
||||
|
||||
@handler OwnPostGenerateReply
|
||||
post /generate-reply (OwnPostGenerateReplyReq) returns (OwnPostGenerateReplyData)
|
||||
|
||||
@handler OwnPostSendReply
|
||||
post /send-reply (OwnPostSendReplyReq) returns (OwnPostPublic)
|
||||
|
||||
@handler OwnPostAnalyze
|
||||
post /analyze (OwnPostAnalyzeReq) returns (OwnPostPublic)
|
||||
|
||||
@handler OwnPostLoadReplies
|
||||
post /load-replies (OwnPostLoadRepliesReq) returns (OwnPostPublic)
|
||||
}
|
||||
|
||||
@server (
|
||||
jwt: Auth
|
||||
group: mentions
|
||||
prefix: /api/v1/mentions
|
||||
middleware: AuthJWT
|
||||
)
|
||||
service gateway {
|
||||
@handler ListMentions
|
||||
get / (MentionListReq) returns (MentionListData)
|
||||
|
||||
@handler SyncMentions
|
||||
post /sync (MentionSyncReq) returns (MentionListData)
|
||||
|
||||
@handler MentionGenerateReply
|
||||
post /:id/generate-reply (MentionGenerateReq) returns (MentionPublic)
|
||||
|
||||
@handler MentionMarkReplied
|
||||
post /:id/mark-replied (MentionMarkRepliedReq) returns (MentionPublic)
|
||||
|
||||
@handler MentionSkip
|
||||
post /:id/skip (MentionIdPath) returns (MentionPublic)
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
syntax = "v1"
|
||||
|
||||
type (
|
||||
ThreadsAccountPublic {
|
||||
Id string `json:"id"`
|
||||
Username string `json:"username"`
|
||||
DisplayName string `json:"display_name"`
|
||||
Connection string `json:"connection"` // connected|error|disconnected
|
||||
IsUsable bool `json:"is_usable"`
|
||||
AvatarColor string `json:"avatar_color,optional"`
|
||||
AvatarUrl string `json:"avatar_url,optional"`
|
||||
ErrorMessage string `json:"error_message,optional"`
|
||||
SessionExpiresAt int64 `json:"session_expires_at,optional"`
|
||||
SessionRefreshedAt int64 `json:"session_refreshed_at,optional"`
|
||||
// never expose access_token / refresh_token
|
||||
}
|
||||
|
||||
ThreadsAccountListData {
|
||||
List []ThreadsAccountPublic `json:"list"`
|
||||
}
|
||||
|
||||
ThreadsOAuthStartData {
|
||||
AuthorizeUrl string `json:"authorize_url"`
|
||||
State string `json:"state"`
|
||||
}
|
||||
|
||||
// Callback is query-string from Meta / fake provider (public).
|
||||
ThreadsOAuthCallbackReq {
|
||||
Code string `form:"code,optional"`
|
||||
State string `form:"state,optional"`
|
||||
Error string `form:"error,optional"`
|
||||
ErrorReason string `form:"error_reason,optional"`
|
||||
ErrorDescription string `form:"error_description,optional"`
|
||||
}
|
||||
|
||||
ThreadsOAuthCallbackData {
|
||||
Ok bool `json:"ok"`
|
||||
Message string `json:"message,optional"`
|
||||
// RedirectURL for custom handler (browser flow)
|
||||
RedirectUrl string `json:"redirect_url,optional"`
|
||||
}
|
||||
|
||||
ThreadsAccountIdPath {
|
||||
Id string `path:"id"`
|
||||
}
|
||||
|
||||
// 擴充(含舊版)匯入 Chrome storageState;寫入 scout crawler-session 供 dev 模式海巡
|
||||
ImportThreadsAccountSessionReq {
|
||||
// path id + body
|
||||
Id string `path:"id"`
|
||||
StorageState string `json:"storageState"`
|
||||
}
|
||||
|
||||
ImportThreadsAccountSessionData {
|
||||
Success bool `json:"success"`
|
||||
Valid bool `json:"valid"`
|
||||
Synced bool `json:"synced"`
|
||||
AccountId string `json:"account_id"`
|
||||
Username string `json:"username,optional"`
|
||||
Message string `json:"message"`
|
||||
UpdateAt int64 `json:"update_at,optional"`
|
||||
}
|
||||
)
|
||||
|
||||
// Public OAuth callback (no JWT)
|
||||
@server (
|
||||
group: threads
|
||||
prefix: /api/v1/threads-accounts
|
||||
)
|
||||
service gateway {
|
||||
@handler ThreadsOAuthCallback
|
||||
get /oauth/callback (ThreadsOAuthCallbackReq) returns (ThreadsOAuthCallbackData)
|
||||
}
|
||||
|
||||
@server (
|
||||
jwt: Auth
|
||||
group: threads
|
||||
prefix: /api/v1/threads-accounts
|
||||
middleware: AuthJWT
|
||||
)
|
||||
service gateway {
|
||||
@handler ThreadsOAuthStart
|
||||
get /oauth/start returns (ThreadsOAuthStartData)
|
||||
|
||||
@handler ListThreadsAccounts
|
||||
get / returns (ThreadsAccountListData)
|
||||
|
||||
@handler RefreshThreadsAccount
|
||||
post /:id/refresh (ThreadsAccountIdPath) returns (ThreadsAccountPublic)
|
||||
|
||||
// Chrome 擴充:匯入 Playwright storageState(舊路徑相容;實際存 crawler session)
|
||||
@handler ImportThreadsAccountSession
|
||||
post /:id/session/import (ImportThreadsAccountSessionReq) returns (ImportThreadsAccountSessionData)
|
||||
|
||||
@handler DisconnectThreadsAccount
|
||||
delete /:id (ThreadsAccountIdPath) returns (OkData)
|
||||
}
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
syntax = "v1"
|
||||
|
||||
type (
|
||||
UsageEventPublic {
|
||||
Id string `json:"id"`
|
||||
Uid int64 `json:"uid"`
|
||||
Meter string `json:"meter"`
|
||||
Credits int `json:"credits"`
|
||||
KeyMode string `json:"key_mode"`
|
||||
Label string `json:"label"`
|
||||
Source string `json:"source"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
}
|
||||
|
||||
UsageMeterCount {
|
||||
Count int `json:"count"`
|
||||
Credits int `json:"credits"`
|
||||
}
|
||||
|
||||
UsagePlatformBlock {
|
||||
CreditsUsed int `json:"credits_used"`
|
||||
CreditsRemaining int `json:"credits_remaining"`
|
||||
CreditsTotal int `json:"credits_total"`
|
||||
CallCount int `json:"call_count"`
|
||||
ByMeter map[string]UsageMeterCount `json:"by_meter,optional"`
|
||||
}
|
||||
|
||||
UsageByokBlock {
|
||||
CallCount int `json:"call_count"`
|
||||
ByMeter map[string]UsageMeterCount `json:"by_meter,optional"`
|
||||
}
|
||||
|
||||
UsageSummaryData {
|
||||
MonthKey string `json:"month_key"`
|
||||
Uid int64 `json:"uid"`
|
||||
PlanId string `json:"plan_id"`
|
||||
Unlimited bool `json:"unlimited"`
|
||||
Platform UsagePlatformBlock `json:"platform"`
|
||||
Byok UsageByokBlock `json:"byok"`
|
||||
// FE progress bar (platform only)
|
||||
TotalCredits int `json:"total_credits"`
|
||||
RemainingCredits int `json:"remaining_credits"`
|
||||
}
|
||||
|
||||
UsageSummaryReq {
|
||||
MonthKey string `form:"month_key,optional"`
|
||||
}
|
||||
|
||||
UsageEventsReq {
|
||||
MonthKey string `form:"month_key,optional"`
|
||||
KeyMode string `form:"key_mode,optional"` // platform|byok|all
|
||||
Limit int `form:"limit,optional"`
|
||||
}
|
||||
|
||||
UsageEventsData {
|
||||
List []UsageEventPublic `json:"list"`
|
||||
}
|
||||
|
||||
UsagePrefsData {
|
||||
PlanId string `json:"plan_id"`
|
||||
Unlimited bool `json:"unlimited"`
|
||||
}
|
||||
|
||||
UsageSetPrefsReq {
|
||||
Uid string `json:"uid"`
|
||||
PlanId string `json:"plan_id,optional"`
|
||||
Unlimited *bool `json:"unlimited,optional"`
|
||||
}
|
||||
|
||||
UsagePurchaseReq {
|
||||
PlanId string `json:"plan_id"`
|
||||
MockRef string `json:"mock_ref,optional"`
|
||||
}
|
||||
|
||||
UsagePurchasePublic {
|
||||
Id string `json:"id"`
|
||||
PlanId string `json:"plan_id"`
|
||||
MockRef string `json:"mock_ref,optional"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
}
|
||||
|
||||
UsagePurchasesData {
|
||||
List []UsagePurchasePublic `json:"list"`
|
||||
}
|
||||
|
||||
UsageTenantRow {
|
||||
Uid int64 `json:"uid"`
|
||||
PlanId string `json:"plan_id"`
|
||||
Unlimited bool `json:"unlimited"`
|
||||
PlatformCreditsUsed int `json:"platform_credits_used"`
|
||||
ByokCallCount int `json:"byok_call_count"`
|
||||
}
|
||||
|
||||
UsageTenantSummaryData {
|
||||
MonthKey string `json:"month_key"`
|
||||
PlatformCreditsUsed int `json:"platform_credits_used"`
|
||||
ByokCallCount int `json:"byok_call_count"`
|
||||
Members []UsageTenantRow `json:"members"`
|
||||
}
|
||||
|
||||
UsageTenantSummaryReq {
|
||||
MonthKey string `form:"month_key,optional"`
|
||||
}
|
||||
)
|
||||
|
||||
@server (
|
||||
jwt: Auth
|
||||
group: usage
|
||||
prefix: /api/v1/usage
|
||||
middleware: AuthJWT
|
||||
)
|
||||
service gateway {
|
||||
@handler GetUsageSummary
|
||||
get /summary (UsageSummaryReq) returns (UsageSummaryData)
|
||||
|
||||
@handler ListUsageEvents
|
||||
get /events (UsageEventsReq) returns (UsageEventsData)
|
||||
|
||||
@handler GetUsagePrefs
|
||||
get /prefs returns (UsagePrefsData)
|
||||
|
||||
@handler PurchasePlan
|
||||
post /purchase (UsagePurchaseReq) returns (UsagePurchasePublic)
|
||||
|
||||
@handler ListMyPurchases
|
||||
get /purchases returns (UsagePurchasesData)
|
||||
}
|
||||
|
||||
@server (
|
||||
jwt: Auth
|
||||
group: usage
|
||||
prefix: /api/v1/usage
|
||||
middleware: AuthJWT,AdminAuth
|
||||
)
|
||||
service gateway {
|
||||
@handler SetUsagePrefs
|
||||
post /prefs (UsageSetPrefsReq) returns (UsagePrefsData)
|
||||
|
||||
@handler GetTenantUsageSummary
|
||||
get /tenant-summary (UsageTenantSummaryReq) returns (UsageTenantSummaryData)
|
||||
}
|
||||
|
|
@ -27,7 +27,12 @@ type Config struct {
|
|||
RefreshExpire int64
|
||||
}
|
||||
Platform struct {
|
||||
// AIKey — legacy alias for XAIKey
|
||||
AIKey string `json:",optional"`
|
||||
// XAIKey — platform BYOK for xAI (api.x.ai)
|
||||
XAIKey string `json:",optional"`
|
||||
// OpenCodeKey — platform BYOK for OpenCode Go (opencode.ai/zen/go)
|
||||
OpenCodeKey string `json:",optional"`
|
||||
ExaKey string `json:",optional"`
|
||||
ThreadsAppId string `json:",optional"`
|
||||
ThreadsAppSecret string `json:",optional"`
|
||||
|
|
@ -62,6 +67,10 @@ type Config struct {
|
|||
// PublicWebBase — 前端 origin,用於重設密碼信內連結/logo(勿尾斜線)
|
||||
// 例:http://127.0.0.1:5173 或 https://threads-tool-dev.30cm.net
|
||||
PublicWebBase string `json:",optional,default=http://127.0.0.1:5173"`
|
||||
// PublicAPIBase — 對外 API origin(Threads OAuth redirect_uri 必須 https 公開網址)
|
||||
// 空則:若 PublicWebBase 為 https 則同 host;否則回落 http://127.0.0.1:Port
|
||||
// 例:https://threads-tool-dev.30cm.net
|
||||
PublicAPIBase string `json:",optional"`
|
||||
// Brand — 郵件 chrome(hermes);LogoURL 空則用 PublicWebBase + /brand-mark.jpg
|
||||
Brand struct {
|
||||
Name string `json:",optional,default=Harbor Desk"`
|
||||
|
|
@ -111,9 +120,25 @@ func (c *Config) ApplyEnv() {
|
|||
if v := os.Getenv("PLATFORM_AI_KEY"); v != "" {
|
||||
c.Platform.AIKey = v
|
||||
}
|
||||
if v := firstEnv("PLATFORM_XAI_KEY", "XAI_API_KEY"); v != "" {
|
||||
c.Platform.XAIKey = v
|
||||
}
|
||||
if v := firstEnv("PLATFORM_OPENCODE_KEY", "OPENCODE_API_KEY", "OPENCODE_GO_API_KEY"); v != "" {
|
||||
c.Platform.OpenCodeKey = v
|
||||
}
|
||||
// legacy AIKey → XAI when XAI empty
|
||||
if c.Platform.XAIKey == "" && c.Platform.AIKey != "" {
|
||||
c.Platform.XAIKey = c.Platform.AIKey
|
||||
}
|
||||
if v := os.Getenv("PLATFORM_EXA_KEY"); v != "" {
|
||||
c.Platform.ExaKey = v
|
||||
}
|
||||
if v := firstEnv("THREADS_APP_ID", "HAIXUN_THREADS_APP_ID"); v != "" {
|
||||
c.Platform.ThreadsAppId = v
|
||||
}
|
||||
if v := firstEnv("THREADS_APP_SECRET", "HAIXUN_THREADS_APP_SECRET"); v != "" {
|
||||
c.Platform.ThreadsAppSecret = v
|
||||
}
|
||||
if v := os.Getenv("WORKER_ID"); v != "" {
|
||||
c.Worker.ID = v
|
||||
}
|
||||
|
|
@ -155,6 +180,9 @@ func (c *Config) ApplyEnv() {
|
|||
if v := firstEnv("PUBLIC_WEB_BASE", "HAIXUN_PUBLIC_WEB_BASE"); v != "" {
|
||||
c.PublicWebBase = strings.TrimRight(v, "/")
|
||||
}
|
||||
if v := firstEnv("PUBLIC_API_BASE", "HAIXUN_PUBLIC_API_BASE"); v != "" {
|
||||
c.PublicAPIBase = strings.TrimRight(v, "/")
|
||||
}
|
||||
if v := os.Getenv("MAIL_BRAND_NAME"); v != "" {
|
||||
c.Brand.Name = v
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package compose
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/compose"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func ComposeAnalyzeViralHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.ComposeViralReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := compose.NewComposeAnalyzeViralLogic(r.Context(), svcCtx)
|
||||
data, err := l.ComposeAnalyzeViral(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package compose
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/compose"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func ComposeMimicHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.ComposeMimicReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := compose.NewComposeMimicLogic(r.Context(), svcCtx)
|
||||
data, err := l.ComposeMimic(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package compose
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/compose"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func ComposePersonaPreviewHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.ComposePersonaPreviewReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := compose.NewComposePersonaPreviewLogic(r.Context(), svcCtx)
|
||||
data, err := l.ComposePersonaPreview(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package compose
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/compose"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func ComposePublishSingleHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.ComposePublishReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := compose.NewComposePublishSingleLogic(r.Context(), svcCtx)
|
||||
data, err := l.ComposePublishSingle(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package extension
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"apps/backend/internal/logic/extension"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
)
|
||||
|
||||
func DownloadExtensionZipHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
l := extension.NewDownloadExtensionZipLogic(r.Context(), svcCtx)
|
||||
if _, err := l.DownloadExtensionZip(); err != nil {
|
||||
response.Write(r.Context(), w, nil, err)
|
||||
return
|
||||
}
|
||||
path := svcCtx.ExtensionZipPath
|
||||
if path == "" {
|
||||
path = extension.ResolveZipPath(svcCtx)
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/zip")
|
||||
w.Header().Set("Content-Disposition", `attachment; filename="haixun-threads-sync.zip"`)
|
||||
http.ServeFile(w, r, filepath.Clean(path))
|
||||
}
|
||||
}
|
||||
|
||||
// ensure zip exists for tests
|
||||
func zipExists(p string) bool {
|
||||
st, err := os.Stat(p)
|
||||
return err == nil && st.Size() > 0
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package inspire
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/inspire"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func ActivateInspireSessionHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.InspireSessionIdPath
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := inspire.NewActivateInspireSessionLogic(r.Context(), svcCtx)
|
||||
data, err := l.ActivateInspireSession(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
package inspire
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"apps/backend/internal/middleware"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
// ChatStreamHandler — SSE 串流靈感聊天/產文。
|
||||
// 事件(每行 data: JSON):
|
||||
//
|
||||
// {"type":"delta","text":"..."}
|
||||
// {"type":"done","session":{...},"message_id":"..."}
|
||||
// {"type":"error","message":"..."}
|
||||
func ChatStreamHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.InspireChatReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
return
|
||||
}
|
||||
uid, ok := middleware.UIDFrom(r.Context())
|
||||
if !ok || uid <= 0 {
|
||||
httpx.ErrorCtx(r.Context(), w, response.Biz(401, 401001, "missing authorization"))
|
||||
return
|
||||
}
|
||||
if svcCtx.Inspire == nil {
|
||||
httpx.ErrorCtx(r.Context(), w, response.Biz(503, 503001, "inspire not configured"))
|
||||
return
|
||||
}
|
||||
|
||||
flusher, ok := w.(http.Flusher)
|
||||
if !ok {
|
||||
httpx.ErrorCtx(r.Context(), w, response.Biz(500, 500000, "streaming unsupported"))
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "text/event-stream; charset=utf-8")
|
||||
w.Header().Set("Cache-Control", "no-cache, no-transform")
|
||||
w.Header().Set("Connection", "keep-alive")
|
||||
w.Header().Set("X-Accel-Buffering", "no")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
flusher.Flush()
|
||||
|
||||
writeEvent := func(v any) bool {
|
||||
b, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if _, err := w.Write([]byte("data: ")); err != nil {
|
||||
return false
|
||||
}
|
||||
if _, err := w.Write(b); err != nil {
|
||||
return false
|
||||
}
|
||||
if _, err := w.Write([]byte("\n\n")); err != nil {
|
||||
return false
|
||||
}
|
||||
flusher.Flush()
|
||||
return true
|
||||
}
|
||||
|
||||
mode := strings.TrimSpace(req.Mode)
|
||||
if mode == "" {
|
||||
mode = "chat"
|
||||
}
|
||||
out, err := svcCtx.Inspire.ChatStream(r.Context(), uid, req.Message, req.PinnedIds, mode, req.PersonaId, req.SessionId, req.Material, func(chunk string) error {
|
||||
if chunk == "" {
|
||||
return nil
|
||||
}
|
||||
if !writeEvent(map[string]any{"type": "delta", "text": chunk}) {
|
||||
return http.ErrAbortHandler // client gone
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
_ = writeEvent(map[string]any{"type": "error", "message": err.Error()})
|
||||
return
|
||||
}
|
||||
sess := out.Session
|
||||
pub := types.SessionFromDomain(sess)
|
||||
msgID := ""
|
||||
if len(sess.Messages) > 0 {
|
||||
msgID = sess.Messages[len(sess.Messages)-1].ID
|
||||
}
|
||||
// 回傳實際送 AI 的 prompt 指紋/全文,供前端與預覽對照
|
||||
_ = writeEvent(map[string]any{
|
||||
"type": "done",
|
||||
"session": pub,
|
||||
"message_id": msgID,
|
||||
"prompt": out.Prompt,
|
||||
"prompt_fingerprint": out.Fingerprint,
|
||||
"prompt_char_count": out.CharCount,
|
||||
"prompt_rune_count": out.RuneCount,
|
||||
"prompt_sections": out.Sections,
|
||||
})
|
||||
logx.WithContext(r.Context()).Infof("inspire chat-stream ok uid=%d mode=%s fp=%s chars=%d", uid, mode, out.Fingerprint, out.CharCount)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package inspire
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/inspire"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
)
|
||||
|
||||
func ClearInspireSessionHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
l := inspire.NewClearInspireSessionLogic(r.Context(), svcCtx)
|
||||
data, err := l.ClearInspireSession()
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package inspire
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/inspire"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func CreateInspireSessionHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.InspireSessionCreateReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := inspire.NewCreateInspireSessionLogic(r.Context(), svcCtx)
|
||||
data, err := l.CreateInspireSession(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package inspire
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/inspire"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func DeleteInspireSessionHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.InspireSessionIdPath
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := inspire.NewDeleteInspireSessionLogic(r.Context(), svcCtx)
|
||||
data, err := l.DeleteInspireSession(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package inspire
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/inspire"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func GetInspireSessionByIdHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.InspireSessionIdPath
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := inspire.NewGetInspireSessionByIdLogic(r.Context(), svcCtx)
|
||||
data, err := l.GetInspireSessionById(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package inspire
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/inspire"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
)
|
||||
|
||||
func GetInspireSessionHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
l := inspire.NewGetInspireSessionLogic(r.Context(), svcCtx)
|
||||
data, err := l.GetInspireSession()
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package inspire
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/inspire"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func InspireChatHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.InspireChatReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := inspire.NewInspireChatLogic(r.Context(), svcCtx)
|
||||
data, err := l.InspireChat(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package inspire
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/inspire"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func InspirePromptPreviewHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.InspirePromptPreviewReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := inspire.NewInspirePromptPreviewLogic(r.Context(), svcCtx)
|
||||
data, err := l.InspirePromptPreview(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package inspire
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/inspire"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
)
|
||||
|
||||
func ListInspireElementsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
l := inspire.NewListInspireElementsLogic(r.Context(), svcCtx)
|
||||
data, err := l.ListInspireElements()
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package inspire
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/inspire"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
)
|
||||
|
||||
func ListInspireSessionsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
l := inspire.NewListInspireSessionsLogic(r.Context(), svcCtx)
|
||||
data, err := l.ListInspireSessions()
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package inspire
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/inspire"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
)
|
||||
|
||||
func ListTrendsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
l := inspire.NewListTrendsLogic(r.Context(), svcCtx)
|
||||
data, err := l.ListTrends()
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package inspire
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/inspire"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
)
|
||||
|
||||
func RefreshTrendsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
l := inspire.NewRefreshTrendsLogic(r.Context(), svcCtx)
|
||||
data, err := l.RefreshTrends()
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package inspire
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/inspire"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func RemoveInspireElementHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.InspireElementIdPath
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := inspire.NewRemoveInspireElementLogic(r.Context(), svcCtx)
|
||||
data, err := l.RemoveInspireElement(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package inspire
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/inspire"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func SaveInspireElementHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.InspireElementSaveReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := inspire.NewSaveInspireElementLogic(r.Context(), svcCtx)
|
||||
data, err := l.SaveInspireElement(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
inspireHandler "apps/backend/internal/handler/inspire"
|
||||
"apps/backend/internal/svc"
|
||||
|
||||
"github.com/zeromicro/go-zero/rest"
|
||||
)
|
||||
|
||||
// RegisterInspireStream 註冊靈感 SSE 路由(手寫,避開 goctl JSON envelope)。
|
||||
func RegisterInspireStream(server *rest.Server, serverCtx *svc.ServiceContext) {
|
||||
server.AddRoutes(
|
||||
rest.WithMiddlewares(
|
||||
[]rest.Middleware{serverCtx.AuthJWT},
|
||||
[]rest.Route{
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/chat-stream",
|
||||
Handler: inspireHandler.ChatStreamHandler(serverCtx),
|
||||
},
|
||||
}...,
|
||||
),
|
||||
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
|
||||
rest.WithPrefix("/api/v1/inspire"),
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package jobs
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/jobs"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func DeleteJobHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.JobIdPath
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := jobs.NewDeleteJobLogic(r.Context(), svcCtx)
|
||||
data, err := l.DeleteJob(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package jobs
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/jobs"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func GetJobHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.JobIdPath
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := jobs.NewGetJobLogic(r.Context(), svcCtx)
|
||||
data, err := l.GetJob(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package jobs
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/jobs"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
)
|
||||
|
||||
func ListJobsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
l := jobs.NewListJobsLogic(r.Context(), svcCtx)
|
||||
data, err := l.ListJobs()
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package jobs
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/jobs"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
)
|
||||
|
||||
func StartDemoJobHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
l := jobs.NewStartDemoJobLogic(r.Context(), svcCtx)
|
||||
data, err := l.StartDemoJob()
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package media
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/media"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func GenerateImageHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.GenerateImageReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := media.NewGenerateImageLogic(r.Context(), svcCtx)
|
||||
data, err := l.GenerateImage(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package mentions
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/mentions"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func ListMentionsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.MentionListReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := mentions.NewListMentionsLogic(r.Context(), svcCtx)
|
||||
data, err := l.ListMentions(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package mentions
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/mentions"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func MentionGenerateReplyHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.MentionGenerateReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := mentions.NewMentionGenerateReplyLogic(r.Context(), svcCtx)
|
||||
data, err := l.MentionGenerateReply(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package mentions
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/mentions"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func MentionMarkRepliedHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.MentionMarkRepliedReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := mentions.NewMentionMarkRepliedLogic(r.Context(), svcCtx)
|
||||
data, err := l.MentionMarkReplied(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package mentions
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/mentions"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func MentionSkipHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.MentionIdPath
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := mentions.NewMentionSkipLogic(r.Context(), svcCtx)
|
||||
data, err := l.MentionSkip(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package mentions
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/mentions"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func SyncMentionsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.MentionSyncReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := mentions.NewSyncMentionsLogic(r.Context(), svcCtx)
|
||||
data, err := l.SyncMentions(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package notifications
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/notifications"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
)
|
||||
|
||||
func ListNotificationsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
l := notifications.NewListNotificationsLogic(r.Context(), svcCtx)
|
||||
data, err := l.ListNotifications()
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package notifications
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/notifications"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
)
|
||||
|
||||
func MarkAllNotificationsReadHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
l := notifications.NewMarkAllNotificationsReadLogic(r.Context(), svcCtx)
|
||||
data, err := l.MarkAllNotificationsRead()
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package notifications
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/notifications"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func MarkNotificationReadHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.NotificationIdPath
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := notifications.NewMarkNotificationReadLogic(r.Context(), svcCtx)
|
||||
data, err := l.MarkNotificationRead(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package notifications
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/notifications"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
)
|
||||
|
||||
func UnreadNotificationCountHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
l := notifications.NewUnreadNotificationCountLogic(r.Context(), svcCtx)
|
||||
data, err := l.UnreadNotificationCount()
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package outbox
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/outbox"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func GetOutboxHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.OutboxIdPath
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := outbox.NewGetOutboxLogic(r.Context(), svcCtx)
|
||||
data, err := l.GetOutbox(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package outbox
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/outbox"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
)
|
||||
|
||||
func ListOutboxHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
l := outbox.NewListOutboxLogic(r.Context(), svcCtx)
|
||||
data, err := l.ListOutbox()
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package outbox
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/outbox"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func RemoveOutboxHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.OutboxIdPath
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := outbox.NewRemoveOutboxLogic(r.Context(), svcCtx)
|
||||
data, err := l.RemoveOutbox(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package outbox
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/outbox"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func RetryOutboxStepHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.OutboxRetryPath
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := outbox.NewRetryOutboxStepLogic(r.Context(), svcCtx)
|
||||
data, err := l.RetryOutboxStep(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package ownposts
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/ownposts"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func ListOwnPostsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.OwnPostListReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := ownposts.NewListOwnPostsLogic(r.Context(), svcCtx)
|
||||
data, err := l.ListOwnPosts(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package ownposts
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/ownposts"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func OwnPostAnalyzeHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.OwnPostAnalyzeReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := ownposts.NewOwnPostAnalyzeLogic(r.Context(), svcCtx)
|
||||
data, err := l.OwnPostAnalyze(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package ownposts
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/ownposts"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func OwnPostGenerateReplyHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.OwnPostGenerateReplyReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := ownposts.NewOwnPostGenerateReplyLogic(r.Context(), svcCtx)
|
||||
data, err := l.OwnPostGenerateReply(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package ownposts
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/ownposts"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func OwnPostLoadRepliesHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.OwnPostLoadRepliesReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := ownposts.NewOwnPostLoadRepliesLogic(r.Context(), svcCtx)
|
||||
data, err := l.OwnPostLoadReplies(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package ownposts
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/ownposts"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func OwnPostSendReplyHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.OwnPostSendReplyReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := ownposts.NewOwnPostSendReplyLogic(r.Context(), svcCtx)
|
||||
data, err := l.OwnPostSendReply(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package ownposts
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/ownposts"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
)
|
||||
|
||||
func OwnPostsLastSyncedHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
l := ownposts.NewOwnPostsLastSyncedLogic(r.Context(), svcCtx)
|
||||
data, err := l.OwnPostsLastSynced()
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package ownposts
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/ownposts"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func SyncOwnPostsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.OwnPostSyncReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := ownposts.NewSyncOwnPostsLogic(r.Context(), svcCtx)
|
||||
data, err := l.SyncOwnPosts(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package personas
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/personas"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func AnalyzePersonaAccountHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.PersonaAnalyzeAccountReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := personas.NewAnalyzePersonaAccountLogic(r.Context(), svcCtx)
|
||||
data, err := l.AnalyzePersonaAccount(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package personas
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/personas"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func AnalyzePersonaTextHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.PersonaAnalyzeTextReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := personas.NewAnalyzePersonaTextLogic(r.Context(), svcCtx)
|
||||
data, err := l.AnalyzePersonaText(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package personas
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/personas"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
)
|
||||
|
||||
func GetActivePersonaHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
l := personas.NewGetActivePersonaLogic(r.Context(), svcCtx)
|
||||
data, err := l.GetActivePersona()
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package personas
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/personas"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func GetPersonaHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.PersonaIdPath
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := personas.NewGetPersonaLogic(r.Context(), svcCtx)
|
||||
data, err := l.GetPersona(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package personas
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/personas"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
)
|
||||
|
||||
func ListPersonasHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
l := personas.NewListPersonasLogic(r.Context(), svcCtx)
|
||||
data, err := l.ListPersonas()
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package personas
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/personas"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func RemovePersonaHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.PersonaIdPath
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := personas.NewRemovePersonaLogic(r.Context(), svcCtx)
|
||||
data, err := l.RemovePersona(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package personas
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/personas"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func SavePersonaHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.PersonaSaveReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := personas.NewSavePersonaLogic(r.Context(), svcCtx)
|
||||
data, err := l.SavePersona(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package personas
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/personas"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func SetActivePersonaHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.PersonaSetActiveReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := personas.NewSetActivePersonaLogic(r.Context(), svcCtx)
|
||||
data, err := l.SetActivePersona(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package plays
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/plays"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func GeneratePlayScriptHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.PlayIdPath
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := plays.NewGeneratePlayScriptLogic(r.Context(), svcCtx)
|
||||
data, err := l.GeneratePlayScript(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package plays
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/plays"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func GeneratePlayStepHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.PlayGenerateStepReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := plays.NewGeneratePlayStepLogic(r.Context(), svcCtx)
|
||||
data, err := l.GeneratePlayStep(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package plays
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/plays"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func GetPlayHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.PlayIdPath
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := plays.NewGetPlayLogic(r.Context(), svcCtx)
|
||||
data, err := l.GetPlay(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package plays
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/plays"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func ListPlaysByExternalHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.PlayByExternalReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := plays.NewListPlaysByExternalLogic(r.Context(), svcCtx)
|
||||
data, err := l.ListPlaysByExternal(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package plays
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/plays"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func ListPlaysByPostHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.PlayByPostReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := plays.NewListPlaysByPostLogic(r.Context(), svcCtx)
|
||||
data, err := l.ListPlaysByPost(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package plays
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/plays"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
)
|
||||
|
||||
func ListPlaysHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
l := plays.NewListPlaysLogic(r.Context(), svcCtx)
|
||||
data, err := l.ListPlays()
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package plays
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/plays"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func RemovePlayHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.PlayIdPath
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := plays.NewRemovePlayLogic(r.Context(), svcCtx)
|
||||
data, err := l.RemovePlay(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package plays
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/plays"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func ResolveExternalLinkHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.PlayResolveReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := plays.NewResolveExternalLinkLogic(r.Context(), svcCtx)
|
||||
data, err := l.ResolveExternalLink(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package plays
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/plays"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func SavePlayHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.PlaySaveReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := plays.NewSavePlayLogic(r.Context(), svcCtx)
|
||||
data, err := l.SavePlay(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package plays
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/plays"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func SubmitPlayHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.PlayIdPath
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := plays.NewSubmitPlayLogic(r.Context(), svcCtx)
|
||||
data, err := l.SubmitPlay(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/proxy"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func AICompleteHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.AICompleteReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := proxy.NewAICompleteLogic(r.Context(), svcCtx)
|
||||
data, err := l.AIComplete(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/proxy"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func ExaSearchHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.SearchReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := proxy.NewExaSearchLogic(r.Context(), svcCtx)
|
||||
data, err := l.ExaSearch(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package research
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/research"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func ResearchSearchHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.ResearchSearchReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := research.NewResearchSearchLogic(r.Context(), svcCtx)
|
||||
data, err := l.ResearchSearch(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -8,9 +8,24 @@ import (
|
|||
|
||||
admin "apps/backend/internal/handler/admin"
|
||||
auth "apps/backend/internal/handler/auth"
|
||||
compose "apps/backend/internal/handler/compose"
|
||||
extension "apps/backend/internal/handler/extension"
|
||||
inspire "apps/backend/internal/handler/inspire"
|
||||
jobs "apps/backend/internal/handler/jobs"
|
||||
media "apps/backend/internal/handler/media"
|
||||
mentions "apps/backend/internal/handler/mentions"
|
||||
notifications "apps/backend/internal/handler/notifications"
|
||||
outbox "apps/backend/internal/handler/outbox"
|
||||
ownposts "apps/backend/internal/handler/ownposts"
|
||||
personas "apps/backend/internal/handler/personas"
|
||||
ping "apps/backend/internal/handler/ping"
|
||||
plays "apps/backend/internal/handler/plays"
|
||||
proxy "apps/backend/internal/handler/proxy"
|
||||
research "apps/backend/internal/handler/research"
|
||||
scout "apps/backend/internal/handler/scout"
|
||||
settings "apps/backend/internal/handler/settings"
|
||||
threads "apps/backend/internal/handler/threads"
|
||||
usage "apps/backend/internal/handler/usage"
|
||||
"apps/backend/internal/svc"
|
||||
|
||||
"github.com/zeromicro/go-zero/rest"
|
||||
|
|
@ -171,6 +186,171 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
|
|||
rest.WithPrefix("/api/v1/auth"),
|
||||
)
|
||||
|
||||
server.AddRoutes(
|
||||
rest.WithMiddlewares(
|
||||
[]rest.Middleware{serverCtx.AuthJWT},
|
||||
[]rest.Route{
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/analyze-viral",
|
||||
Handler: compose.ComposeAnalyzeViralHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/mimic",
|
||||
Handler: compose.ComposeMimicHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/persona-preview",
|
||||
Handler: compose.ComposePersonaPreviewHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/publish-single",
|
||||
Handler: compose.ComposePublishSingleHandler(serverCtx),
|
||||
},
|
||||
}...,
|
||||
),
|
||||
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
|
||||
rest.WithPrefix("/api/v1/compose"),
|
||||
)
|
||||
|
||||
server.AddRoutes(
|
||||
rest.WithMiddlewares(
|
||||
[]rest.Middleware{serverCtx.AuthJWT},
|
||||
[]rest.Route{
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/download",
|
||||
Handler: extension.DownloadExtensionZipHandler(serverCtx),
|
||||
},
|
||||
}...,
|
||||
),
|
||||
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
|
||||
rest.WithPrefix("/api/v1/extension"),
|
||||
)
|
||||
|
||||
server.AddRoutes(
|
||||
rest.WithMiddlewares(
|
||||
[]rest.Middleware{serverCtx.AuthJWT},
|
||||
[]rest.Route{
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/chat",
|
||||
Handler: inspire.InspireChatHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/elements",
|
||||
Handler: inspire.ListInspireElementsHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/elements",
|
||||
Handler: inspire.SaveInspireElementHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodDelete,
|
||||
Path: "/elements/:id",
|
||||
Handler: inspire.RemoveInspireElementHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/prompt-preview",
|
||||
Handler: inspire.InspirePromptPreviewHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/session",
|
||||
Handler: inspire.GetInspireSessionHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/session/clear",
|
||||
Handler: inspire.ClearInspireSessionHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/sessions",
|
||||
Handler: inspire.ListInspireSessionsHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/sessions",
|
||||
Handler: inspire.CreateInspireSessionHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/sessions/:id",
|
||||
Handler: inspire.GetInspireSessionByIdHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodDelete,
|
||||
Path: "/sessions/:id",
|
||||
Handler: inspire.DeleteInspireSessionHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/sessions/:id/activate",
|
||||
Handler: inspire.ActivateInspireSessionHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/trends",
|
||||
Handler: inspire.ListTrendsHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/trends/refresh",
|
||||
Handler: inspire.RefreshTrendsHandler(serverCtx),
|
||||
},
|
||||
}...,
|
||||
),
|
||||
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
|
||||
rest.WithPrefix("/api/v1/inspire"),
|
||||
)
|
||||
|
||||
server.AddRoutes(
|
||||
rest.WithMiddlewares(
|
||||
[]rest.Middleware{serverCtx.AuthJWT},
|
||||
[]rest.Route{
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/",
|
||||
Handler: jobs.ListJobsHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/:id",
|
||||
Handler: jobs.GetJobHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodDelete,
|
||||
Path: "/:id",
|
||||
Handler: jobs.DeleteJobHandler(serverCtx),
|
||||
},
|
||||
}...,
|
||||
),
|
||||
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
|
||||
rest.WithPrefix("/api/v1/jobs"),
|
||||
)
|
||||
|
||||
server.AddRoutes(
|
||||
rest.WithMiddlewares(
|
||||
[]rest.Middleware{serverCtx.AuthJWT, serverCtx.AdminAuth},
|
||||
[]rest.Route{
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/demo",
|
||||
Handler: jobs.StartDemoJobHandler(serverCtx),
|
||||
},
|
||||
}...,
|
||||
),
|
||||
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
|
||||
rest.WithPrefix("/api/v1/jobs"),
|
||||
)
|
||||
|
||||
server.AddRoutes(
|
||||
rest.WithMiddlewares(
|
||||
[]rest.Middleware{serverCtx.AuthJWT},
|
||||
|
|
@ -185,6 +365,211 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
|
|||
rest.WithPrefix("/api/v1/media"),
|
||||
)
|
||||
|
||||
server.AddRoutes(
|
||||
rest.WithMiddlewares(
|
||||
[]rest.Middleware{serverCtx.AuthJWT},
|
||||
[]rest.Route{
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/generate-image",
|
||||
Handler: media.GenerateImageHandler(serverCtx),
|
||||
},
|
||||
}...,
|
||||
),
|
||||
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
|
||||
rest.WithPrefix("/api/v1/media"),
|
||||
)
|
||||
|
||||
server.AddRoutes(
|
||||
rest.WithMiddlewares(
|
||||
[]rest.Middleware{serverCtx.AuthJWT},
|
||||
[]rest.Route{
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/",
|
||||
Handler: mentions.ListMentionsHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/:id/generate-reply",
|
||||
Handler: mentions.MentionGenerateReplyHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/:id/mark-replied",
|
||||
Handler: mentions.MentionMarkRepliedHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/:id/skip",
|
||||
Handler: mentions.MentionSkipHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/sync",
|
||||
Handler: mentions.SyncMentionsHandler(serverCtx),
|
||||
},
|
||||
}...,
|
||||
),
|
||||
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
|
||||
rest.WithPrefix("/api/v1/mentions"),
|
||||
)
|
||||
|
||||
server.AddRoutes(
|
||||
rest.WithMiddlewares(
|
||||
[]rest.Middleware{serverCtx.AuthJWT},
|
||||
[]rest.Route{
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/",
|
||||
Handler: notifications.ListNotificationsHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/:id/read",
|
||||
Handler: notifications.MarkNotificationReadHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/read-all",
|
||||
Handler: notifications.MarkAllNotificationsReadHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/unread-count",
|
||||
Handler: notifications.UnreadNotificationCountHandler(serverCtx),
|
||||
},
|
||||
}...,
|
||||
),
|
||||
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
|
||||
rest.WithPrefix("/api/v1/notifications"),
|
||||
)
|
||||
|
||||
server.AddRoutes(
|
||||
rest.WithMiddlewares(
|
||||
[]rest.Middleware{serverCtx.AuthJWT},
|
||||
[]rest.Route{
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/",
|
||||
Handler: outbox.ListOutboxHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/:id",
|
||||
Handler: outbox.GetOutboxHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodDelete,
|
||||
Path: "/:id",
|
||||
Handler: outbox.RemoveOutboxHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/:id/steps/:stepId/retry",
|
||||
Handler: outbox.RetryOutboxStepHandler(serverCtx),
|
||||
},
|
||||
}...,
|
||||
),
|
||||
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
|
||||
rest.WithPrefix("/api/v1/outbox"),
|
||||
)
|
||||
|
||||
server.AddRoutes(
|
||||
rest.WithMiddlewares(
|
||||
[]rest.Middleware{serverCtx.AuthJWT},
|
||||
[]rest.Route{
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/",
|
||||
Handler: ownposts.ListOwnPostsHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/analyze",
|
||||
Handler: ownposts.OwnPostAnalyzeHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/generate-reply",
|
||||
Handler: ownposts.OwnPostGenerateReplyHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/last-synced-at",
|
||||
Handler: ownposts.OwnPostsLastSyncedHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/load-replies",
|
||||
Handler: ownposts.OwnPostLoadRepliesHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/send-reply",
|
||||
Handler: ownposts.OwnPostSendReplyHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/sync",
|
||||
Handler: ownposts.SyncOwnPostsHandler(serverCtx),
|
||||
},
|
||||
}...,
|
||||
),
|
||||
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
|
||||
rest.WithPrefix("/api/v1/own-posts"),
|
||||
)
|
||||
|
||||
server.AddRoutes(
|
||||
rest.WithMiddlewares(
|
||||
[]rest.Middleware{serverCtx.AuthJWT},
|
||||
[]rest.Route{
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/",
|
||||
Handler: personas.ListPersonasHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/",
|
||||
Handler: personas.SavePersonaHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/:id",
|
||||
Handler: personas.GetPersonaHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodDelete,
|
||||
Path: "/:id",
|
||||
Handler: personas.RemovePersonaHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/:id/analyze-account",
|
||||
Handler: personas.AnalyzePersonaAccountHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/:id/analyze-text",
|
||||
Handler: personas.AnalyzePersonaTextHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/active",
|
||||
Handler: personas.GetActivePersonaHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/active",
|
||||
Handler: personas.SetActivePersonaHandler(serverCtx),
|
||||
},
|
||||
}...,
|
||||
),
|
||||
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
|
||||
rest.WithPrefix("/api/v1/personas"),
|
||||
)
|
||||
|
||||
server.AddRoutes(
|
||||
[]rest.Route{
|
||||
{
|
||||
|
|
@ -201,6 +586,246 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
|
|||
rest.WithPrefix("/api/v1"),
|
||||
)
|
||||
|
||||
server.AddRoutes(
|
||||
rest.WithMiddlewares(
|
||||
[]rest.Middleware{serverCtx.AuthJWT},
|
||||
[]rest.Route{
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/",
|
||||
Handler: plays.ListPlaysHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/",
|
||||
Handler: plays.SavePlayHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/:id",
|
||||
Handler: plays.GetPlayHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodDelete,
|
||||
Path: "/:id",
|
||||
Handler: plays.RemovePlayHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/:id/generate-script",
|
||||
Handler: plays.GeneratePlayScriptHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/:id/submit",
|
||||
Handler: plays.SubmitPlayHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/by-external",
|
||||
Handler: plays.ListPlaysByExternalHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/by-post",
|
||||
Handler: plays.ListPlaysByPostHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/generate-step",
|
||||
Handler: plays.GeneratePlayStepHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/resolve-external",
|
||||
Handler: plays.ResolveExternalLinkHandler(serverCtx),
|
||||
},
|
||||
}...,
|
||||
),
|
||||
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
|
||||
rest.WithPrefix("/api/v1/plays"),
|
||||
)
|
||||
|
||||
server.AddRoutes(
|
||||
rest.WithMiddlewares(
|
||||
[]rest.Middleware{serverCtx.AuthJWT},
|
||||
[]rest.Route{
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/ai/complete",
|
||||
Handler: proxy.AICompleteHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/search",
|
||||
Handler: proxy.ExaSearchHandler(serverCtx),
|
||||
},
|
||||
}...,
|
||||
),
|
||||
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
|
||||
rest.WithPrefix("/api/v1/proxy"),
|
||||
)
|
||||
|
||||
server.AddRoutes(
|
||||
rest.WithMiddlewares(
|
||||
[]rest.Middleware{serverCtx.AuthJWT},
|
||||
[]rest.Route{
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/search",
|
||||
Handler: research.ResearchSearchHandler(serverCtx),
|
||||
},
|
||||
}...,
|
||||
),
|
||||
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
|
||||
rest.WithPrefix("/api/v1/research"),
|
||||
)
|
||||
|
||||
server.AddRoutes(
|
||||
rest.WithMiddlewares(
|
||||
[]rest.Middleware{serverCtx.AuthJWT},
|
||||
[]rest.Route{
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/brands",
|
||||
Handler: scout.ListBrandsHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/brands",
|
||||
Handler: scout.SaveBrandHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/brands-active",
|
||||
Handler: scout.GetActiveBrandHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/brands-active",
|
||||
Handler: scout.SetActiveBrandHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/brands/:id",
|
||||
Handler: scout.GetBrandHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodDelete,
|
||||
Path: "/brands/:id",
|
||||
Handler: scout.RemoveBrandHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/brief",
|
||||
Handler: scout.PrepareBriefHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/crawler-session",
|
||||
Handler: scout.SetCrawlerSessionHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodDelete,
|
||||
Path: "/crawler-session",
|
||||
Handler: scout.ClearCrawlerSessionHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/homework",
|
||||
Handler: scout.ListHomeworkHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/homework",
|
||||
Handler: scout.SaveHomeworkHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/homework/:themeKey",
|
||||
Handler: scout.GetHomeworkHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodDelete,
|
||||
Path: "/homework/:themeKey",
|
||||
Handler: scout.RemoveHomeworkHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/posts",
|
||||
Handler: scout.ListScoutPostsHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodDelete,
|
||||
Path: "/posts/:id",
|
||||
Handler: scout.RemoveScoutPostHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/posts/:id/draft",
|
||||
Handler: scout.DraftOutreachHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/posts/:id/mark-published",
|
||||
Handler: scout.MarkPublishedHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/posts/:id/send",
|
||||
Handler: scout.SendOutreachHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/posts/:id/skip",
|
||||
Handler: scout.SkipOutreachHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/products",
|
||||
Handler: scout.ListProductsHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/products",
|
||||
Handler: scout.SaveProductHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/products/:id",
|
||||
Handler: scout.GetProductHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodDelete,
|
||||
Path: "/products/:id",
|
||||
Handler: scout.RemoveProductHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/products/all",
|
||||
Handler: scout.ListAllProductsHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/products/import",
|
||||
Handler: scout.ImportProductHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/scan",
|
||||
Handler: scout.RunScanHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodDelete,
|
||||
Path: "/themes/:themeKey",
|
||||
Handler: scout.RemoveScoutThemeHandler(serverCtx),
|
||||
},
|
||||
}...,
|
||||
),
|
||||
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
|
||||
rest.WithPrefix("/api/v1/scout"),
|
||||
)
|
||||
|
||||
server.AddRoutes(
|
||||
rest.WithMiddlewares(
|
||||
[]rest.Middleware{serverCtx.AuthJWT},
|
||||
|
|
@ -230,8 +855,114 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
|
|||
Path: "/placement",
|
||||
Handler: settings.SavePlacementHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/threads",
|
||||
Handler: settings.GetThreadsHandler(serverCtx),
|
||||
},
|
||||
}...,
|
||||
),
|
||||
rest.WithPrefix("/api/v1/settings"),
|
||||
)
|
||||
|
||||
server.AddRoutes(
|
||||
[]rest.Route{
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/oauth/callback",
|
||||
Handler: threads.ThreadsOAuthCallbackHandler(serverCtx),
|
||||
},
|
||||
},
|
||||
rest.WithPrefix("/api/v1/threads-accounts"),
|
||||
)
|
||||
|
||||
server.AddRoutes(
|
||||
rest.WithMiddlewares(
|
||||
[]rest.Middleware{serverCtx.AuthJWT},
|
||||
[]rest.Route{
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/",
|
||||
Handler: threads.ListThreadsAccountsHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodDelete,
|
||||
Path: "/:id",
|
||||
Handler: threads.DisconnectThreadsAccountHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/:id/refresh",
|
||||
Handler: threads.RefreshThreadsAccountHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/:id/session/import",
|
||||
Handler: threads.ImportThreadsAccountSessionHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/oauth/start",
|
||||
Handler: threads.ThreadsOAuthStartHandler(serverCtx),
|
||||
},
|
||||
}...,
|
||||
),
|
||||
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
|
||||
rest.WithPrefix("/api/v1/threads-accounts"),
|
||||
)
|
||||
|
||||
server.AddRoutes(
|
||||
rest.WithMiddlewares(
|
||||
[]rest.Middleware{serverCtx.AuthJWT},
|
||||
[]rest.Route{
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/events",
|
||||
Handler: usage.ListUsageEventsHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/prefs",
|
||||
Handler: usage.GetUsagePrefsHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/purchase",
|
||||
Handler: usage.PurchasePlanHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/purchases",
|
||||
Handler: usage.ListMyPurchasesHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/summary",
|
||||
Handler: usage.GetUsageSummaryHandler(serverCtx),
|
||||
},
|
||||
}...,
|
||||
),
|
||||
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
|
||||
rest.WithPrefix("/api/v1/usage"),
|
||||
)
|
||||
|
||||
server.AddRoutes(
|
||||
rest.WithMiddlewares(
|
||||
[]rest.Middleware{serverCtx.AuthJWT, serverCtx.AdminAuth},
|
||||
[]rest.Route{
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/prefs",
|
||||
Handler: usage.SetUsagePrefsHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/tenant-summary",
|
||||
Handler: usage.GetTenantUsageSummaryHandler(serverCtx),
|
||||
},
|
||||
}...,
|
||||
),
|
||||
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
|
||||
rest.WithPrefix("/api/v1/usage"),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package scout
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/scout"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
)
|
||||
|
||||
func ClearCrawlerSessionHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
l := scout.NewClearCrawlerSessionLogic(r.Context(), svcCtx)
|
||||
data, err := l.ClearCrawlerSession()
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package scout
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/scout"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func DraftOutreachHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.ScoutDraftPathReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := scout.NewDraftOutreachLogic(r.Context(), svcCtx)
|
||||
data, err := l.DraftOutreach(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package scout
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/scout"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
)
|
||||
|
||||
func GetActiveBrandHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
l := scout.NewGetActiveBrandLogic(r.Context(), svcCtx)
|
||||
data, err := l.GetActiveBrand()
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package scout
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/scout"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func GetBrandHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.BrandIdPath
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := scout.NewGetBrandLogic(r.Context(), svcCtx)
|
||||
data, err := l.GetBrand(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package scout
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/scout"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func GetHomeworkHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.ScoutThemePath
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := scout.NewGetHomeworkLogic(r.Context(), svcCtx)
|
||||
data, err := l.GetHomework(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package scout
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/scout"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func GetProductHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.ProductIdPath
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := scout.NewGetProductLogic(r.Context(), svcCtx)
|
||||
data, err := l.GetProduct(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package scout
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/scout"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func ImportProductHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.ImportProductReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := scout.NewImportProductLogic(r.Context(), svcCtx)
|
||||
data, err := l.ImportProduct(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package scout
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/scout"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
)
|
||||
|
||||
func ListAllProductsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
l := scout.NewListAllProductsLogic(r.Context(), svcCtx)
|
||||
data, err := l.ListAllProducts()
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package scout
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/scout"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
)
|
||||
|
||||
func ListBrandsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
l := scout.NewListBrandsLogic(r.Context(), svcCtx)
|
||||
data, err := l.ListBrands()
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package scout
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/scout"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
)
|
||||
|
||||
func ListHomeworkHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
l := scout.NewListHomeworkLogic(r.Context(), svcCtx)
|
||||
data, err := l.ListHomework()
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package scout
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/scout"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func ListProductsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.ProductListReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := scout.NewListProductsLogic(r.Context(), svcCtx)
|
||||
data, err := l.ListProducts(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package scout
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/scout"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func ListScoutPostsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.ScoutPostListReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := scout.NewListScoutPostsLogic(r.Context(), svcCtx)
|
||||
data, err := l.ListScoutPosts(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package scout
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/scout"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func MarkPublishedHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.ScoutPostIdPath
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := scout.NewMarkPublishedLogic(r.Context(), svcCtx)
|
||||
data, err := l.MarkPublished(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package scout
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/scout"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func PrepareBriefHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.ScoutBriefReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := scout.NewPrepareBriefLogic(r.Context(), svcCtx)
|
||||
data, err := l.PrepareBrief(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package scout
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/scout"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func RemoveBrandHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.BrandIdPath
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := scout.NewRemoveBrandLogic(r.Context(), svcCtx)
|
||||
data, err := l.RemoveBrand(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package scout
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/scout"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func RemoveHomeworkHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.ScoutThemePath
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := scout.NewRemoveHomeworkLogic(r.Context(), svcCtx)
|
||||
data, err := l.RemoveHomework(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl <no value>
|
||||
|
||||
package scout
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"apps/backend/internal/logic/scout"
|
||||
"apps/backend/internal/response"
|
||||
"apps/backend/internal/svc"
|
||||
"apps/backend/internal/types"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func RemoveProductHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.ProductIdPath
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
response.Write(r.Context(), w, nil, response.WrapRequestError(err))
|
||||
return
|
||||
}
|
||||
|
||||
l := scout.NewRemoveProductLogic(r.Context(), svcCtx)
|
||||
data, err := l.RemoveProduct(&req)
|
||||
response.Write(r.Context(), w, data, err)
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue