package ai import ( "context" "strings" "unicode" ) type langCtxKey struct{} // WithResponseLanguage attaches UI/locale language to ctx for system prompt injection. func WithResponseLanguage(ctx context.Context, lang string) context.Context { if ctx == nil { ctx = context.Background() } return context.WithValue(ctx, langCtxKey{}, NormalizeResponseLanguage(lang)) } // ResponseLanguageFrom returns zh-TW | en (default zh-TW). func ResponseLanguageFrom(ctx context.Context) string { if ctx == nil { return "zh-TW" } if v, ok := ctx.Value(langCtxKey{}).(string); ok && v != "" { return NormalizeResponseLanguage(v) } return "zh-TW" } // NormalizeResponseLanguage maps preferred_language / Accept-Language → zh-TW | en. func NormalizeResponseLanguage(raw string) string { s := strings.ToLower(strings.TrimSpace(raw)) if s == "" { return "zh-TW" } if i := strings.IndexAny(s, ",;"); i >= 0 { s = strings.TrimSpace(s[:i]) } s = strings.ReplaceAll(s, "_", "-") if s == "en" || strings.HasPrefix(s, "en-") { return "en" } // zh / zh-TW / zh-Hant / zh-CN → 產品主語系繁中 return "zh-TW" } // SystemPromptForLanguage is always injected as the first system message before user content. // 只約束語言,不要綁「產品助手」人設——否則仿寫/產文會像客服而不是本人在發 Threads。 func SystemPromptForLanguage(lang string) string { switch NormalizeResponseLanguage(lang) { case "en": return strings.TrimSpace(` Language rule (mandatory): - Write in natural English unless the user explicitly asks for another language. - For JSON/structured output, keep human-readable string values in English. - Do not add meta commentary (e.g. "As an AI…") unless asked. `) default: return strings.TrimSpace(` 語言規則(強制): - 使用自然的「繁體中文(台灣用語)」,除非使用者明確要求其他語言。 - 若要求 JSON/結構化輸出,給人看的字串也要用繁中。 - 不要加「作為 AI…」「以下是分析…」這類 meta 前綴;直接完成任務。 - 產文/仿寫時像真人滑手機在打字,不要像客服或文案機器人。 `) } } // PickLanguage prefers member preferred_language, then Accept-Language header. func PickLanguage(preferredLanguage, acceptLanguage string) string { if strings.TrimSpace(preferredLanguage) != "" { return NormalizeResponseLanguage(preferredLanguage) } return NormalizeResponseLanguage(acceptLanguage) } // InferScriptLanguage 從文本統計漢字 vs 拉丁字母,推 zh-TW | en;信號不足回 ""。 // 用於人設指紋/範例:英文人物應回英文,不該被 UI 語系或「繁中」硬規則蓋掉。 func InferScriptLanguage(texts ...string) string { var han, latin int for _, t := range texts { for _, r := range t { switch { case unicode.Is(unicode.Han, r): han++ case (r >= 'A' && r <= 'Z') || (r >= 'a' && r <= 'z'): latin++ } } } total := han + latin if total < 16 { return "" } // 拉丁明顯佔優 → 英文 if latin >= han*2 && latin >= 16 { return "en" } // 漢字夠多 → 繁中 if han >= 12 && han >= latin { return "zh-TW" } return "" }