haixunMaster/haixun-backend/internal/library/placement/context.go

173 lines
4.8 KiB
Go
Raw Normal View History

2026-06-24 10:02:42 +00:00
package placement
2026-06-25 08:20:03 +00:00
import (
"fmt"
"strings"
"haixun-backend/internal/library/websearch"
)
2026-06-24 10:02:42 +00:00
// ConnectionPrefsInput mirrors persisted account connection prefs without importing threads_account.
type ConnectionPrefsInput struct {
DevMode bool
SearchSourceMode string
}
// MemberContext is resolved per login member (email account) + active Threads operating account.
type MemberContext struct {
TenantID string
OwnerUID string
ActiveAccountID string
DevMode bool
SearchSourceMode SearchSourceMode
AllowsThreadsAPI bool
AllowsBrave bool
AllowsCrawler bool
2026-06-25 08:20:03 +00:00
WebSearchProvider string
2026-06-24 10:02:42 +00:00
BraveAPIKey string
2026-06-25 08:20:03 +00:00
ExaAPIKey string
2026-06-24 10:02:42 +00:00
BraveCountry string
BraveSearchLang string
2026-06-25 08:20:03 +00:00
ExaUserLocation string
2026-06-24 10:02:42 +00:00
ApiConnected bool
BrowserConnected bool
ThreadsAPIAccessToken string
ScrapeReplies bool
RepliesPerPost int
}
type ResearchSettings struct {
2026-06-25 08:20:03 +00:00
WebSearchProvider string
BraveAPIKey string
ExaAPIKey string
BraveCountry string
BraveSearchLang string
ExaUserLocation string
ExpandStrategy string
2026-06-24 10:02:42 +00:00
}
func BuildMemberContext(
tenantID, ownerUID, activeAccountID string,
prefs ConnectionPrefsInput,
apiConnected, browserConnected bool,
research ResearchSettings,
scrapeReplies bool,
repliesPerPost int,
) MemberContext {
mode := ParseSearchSourceMode(prefs.SearchSourceMode)
2026-06-25 08:20:03 +00:00
if prefs.DevMode && strings.TrimSpace(prefs.SearchSourceMode) == "" {
mode = SearchSourceCrawler
}
2026-06-24 10:02:42 +00:00
allowsCrawler := ModeAllowsCrawler(mode)
allowsThreads := ModeAllowsThreadsAPI(mode)
allowsBrave := ModeAllowsBrave(mode)
country := strings.TrimSpace(research.BraveCountry)
if country == "" {
country = "tw"
}
lang := strings.TrimSpace(research.BraveSearchLang)
if lang == "" {
lang = "zh-hant"
}
2026-06-25 08:20:03 +00:00
userLocation := strings.TrimSpace(research.ExaUserLocation)
if userLocation == "" {
userLocation = "TW"
}
2026-06-24 10:02:42 +00:00
if repliesPerPost <= 0 {
repliesPerPost = 10
}
return MemberContext{
2026-06-25 08:20:03 +00:00
TenantID: tenantID,
OwnerUID: ownerUID,
ActiveAccountID: activeAccountID,
DevMode: prefs.DevMode,
SearchSourceMode: mode,
AllowsThreadsAPI: allowsThreads,
AllowsBrave: allowsBrave,
AllowsCrawler: allowsCrawler,
WebSearchProvider: string(websearch.ParseProvider(research.WebSearchProvider)),
BraveAPIKey: strings.TrimSpace(research.BraveAPIKey),
ExaAPIKey: strings.TrimSpace(research.ExaAPIKey),
BraveCountry: country,
BraveSearchLang: lang,
ExaUserLocation: userLocation,
ApiConnected: apiConnected,
BrowserConnected: browserConnected,
ScrapeReplies: scrapeReplies,
RepliesPerPost: repliesPerPost,
2026-06-24 10:02:42 +00:00
}
}
func (c MemberContext) PayloadFields() map[string]any {
return map[string]any{
2026-06-25 08:20:03 +00:00
"tenant_id": c.TenantID,
"owner_uid": c.OwnerUID,
"threads_account_id": c.ActiveAccountID,
"dev_mode": c.DevMode,
"search_source_mode": string(c.SearchSourceMode),
"allows_threads_api": c.AllowsThreadsAPI,
"allows_brave": c.AllowsBrave,
"allows_crawler": c.AllowsCrawler,
"web_search_provider": c.WebSearchProvider,
"brave_country": c.BraveCountry,
"brave_search_lang": c.BraveSearchLang,
"exa_user_location": c.ExaUserLocation,
"api_connected": c.ApiConnected,
"browser_connected": c.BrowserConnected,
"scrape_replies": c.ScrapeReplies,
"replies_per_post": c.RepliesPerPost,
}
}
func (c MemberContext) WebSearchProviderEnum() websearch.Provider {
return websearch.ParseProvider(c.WebSearchProvider)
}
func (c MemberContext) WebSearchAPIKey() string {
if c.WebSearchProviderEnum() == websearch.ProviderExa {
return strings.TrimSpace(c.ExaAPIKey)
2026-06-24 10:02:42 +00:00
}
2026-06-25 08:20:03 +00:00
return strings.TrimSpace(c.BraveAPIKey)
}
func (c MemberContext) WebSearchConfig() websearch.Config {
return websearch.ConfigFromMember(
c.BraveAPIKey,
c.ExaAPIKey,
c.WebSearchProvider,
c.BraveCountry,
c.BraveSearchLang,
c.ExaUserLocation,
)
}
func (c MemberContext) WebSearchProviderLabel() string {
return websearch.ProviderLabel(c.WebSearchProviderEnum())
}
func (c MemberContext) WebSearchDiscoverChannel() DiscoverChannel {
if c.WebSearchProviderEnum() == websearch.ProviderExa {
return DiscoverExa
}
return DiscoverBrave
}
func MissingWebSearchKey(research ResearchSettings) bool {
return strings.TrimSpace(websearch.ActiveAPIKey(websearch.ConfigFromMember(
research.BraveAPIKey,
research.ExaAPIKey,
research.WebSearchProvider,
research.BraveCountry,
research.BraveSearchLang,
research.ExaUserLocation,
))) == ""
}
func WebSearchKeyRequiredMessage(research ResearchSettings) string {
provider := websearch.ParseProvider(research.WebSearchProvider)
return fmt.Sprintf("請在設定頁設定 %s Search API key跟隨此登入帳號", websearch.ProviderLabel(provider))
2026-06-24 10:02:42 +00:00
}