thread-master/apps/backend/internal/module/ai/language.go

105 lines
3.1 KiB
Go
Raw Permalink Normal View History

2026-07-13 01:15:30 +00:00
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 ""
}