aliyun sensor server

This commit is contained in:
tamakyi
2026-09-10 18:04:19 +08:00
parent e3e59e7c69
commit 8e2325eda5
38 changed files with 3147 additions and 344 deletions
@@ -0,0 +1,71 @@
// Copyright 2022 E99p1ant. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
// Package moderation 提供跨场景统一的内容审核守卫。
//
// 存在意义:提问、投票、私聊三条链路都要对用户输入做内容审核,过去各自调用
// censor.Text 并自行解释结果,判定口径一旦调整就要改多处,极易遗漏。
// 本包收敛为唯一入口:调审核 → 按箱主「审核严格度」裁决 → 返回是否放行。
package moderation
import (
"context"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/tamakyi/TamaBox/internal/conf"
"github.com/tamakyi/TamaBox/internal/i18n"
"github.com/tamakyi/TamaBox/internal/security/censor"
)
// StrictnessFor 解析账号最终生效的严格度档位:
// - 账号显式设置了档位(lax / standard / strict)→ 用该档位;
// - 账号未设置(空值,存量账号的默认形态)→ 跟随站点默认
// [security] default_moderation_strictness;
// - 站点默认同样为空或非法 → 回退 censor.DefaultStrictness(严格)。
//
// 回退方向刻意取「严格」:配置缺失或非法时宁可从严,也不要因为识别失败
// 把全站静默切到最松档(那等于在配置出错时悄悄放大漏放面)。
func StrictnessFor(raw string) censor.Strictness {
if raw != "" {
return censor.ParseStrictness(raw)
}
return censor.ParseStrictness(conf.Security.DefaultModerationStrictness)
}
// Check 执行一次内容审核,并按箱主严格度裁决是否放行。
//
// 这是提问 / 投票 / 私聊三类场景**唯一**应当使用的审核入口。
//
// 返回:
// - resp:审核明细,调用方用于落 content_censor_metadata 等审计字段;裁决失败时可能为 nil。
// - err != nil:应当拒绝本次提交,错误信息已按 lang 本地化,可直接展示给用户。
//
// 审核服务不可用(超时/报错)时仍为 fail-closed 拒绝提交:这是引入本能力之前就存在的
// 行为,不在本次改造范围内(相关可用性问题另见 outputs/llm-moderation-feasibility 评审)。
func Check(ctx context.Context, strictness censor.Strictness, lang, text string) (*censor.TextCensorResponse, error) {
resp, err := censor.Text(ctx, text)
if err != nil {
logrus.WithContext(ctx).WithError(err).
WithField("strictness", string(strictness)).
Error("Failed to censor text")
return nil, errors.New(i18n.T(lang, "censor.unavailable"))
}
if resp == nil {
return nil, errors.New(i18n.T(lang, "censor.unavailable"))
}
decision, detail := censor.Decide(string(strictness), resp)
if decision.Blocked() {
logrus.WithContext(ctx).
WithField("strictness", string(strictness)).
WithField("source", resp.SourceName).
WithField("forbidden_type", resp.ForbiddenType).
Info("Text blocked by moderation strictness policy")
return resp, errors.New(resp.ErrorMessageFor(detail))
}
return resp, nil
}