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

105 lines
3.1 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 ""
}