thread-master/backend/internal/library/placement/context.go

173 lines
4.8 KiB
Go
Raw Normal View History

2026-06-26 08:37:04 +00:00
package placement
import (
"fmt"
"strings"
"haixun-backend/internal/library/websearch"
)
// 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
WebSearchProvider string
BraveAPIKey string
ExaAPIKey string
BraveCountry string
BraveSearchLang string
ExaUserLocation string
ApiConnected bool
BrowserConnected bool
ThreadsAPIAccessToken string
ScrapeReplies bool
RepliesPerPost int
}
type ResearchSettings struct {
WebSearchProvider string
BraveAPIKey string
ExaAPIKey string
BraveCountry string
BraveSearchLang string
ExaUserLocation string
ExpandStrategy string
}
func BuildMemberContext(
tenantID, ownerUID, activeAccountID string,
prefs ConnectionPrefsInput,
apiConnected, browserConnected bool,
research ResearchSettings,
scrapeReplies bool,
repliesPerPost int,
) MemberContext {
mode := ParseSearchSourceMode(prefs.SearchSourceMode)
if prefs.DevMode && strings.TrimSpace(prefs.SearchSourceMode) == "" {
mode = SearchSourceCrawler
}
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"
}
userLocation := strings.TrimSpace(research.ExaUserLocation)
if userLocation == "" {
userLocation = "TW"
}
if repliesPerPost <= 0 {
repliesPerPost = 10
}
return MemberContext{
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,
}
}
func (c MemberContext) PayloadFields() map[string]any {
return map[string]any{
"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)
}
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))
}