hhillmanpick
3174 号用户
Lv.3
加入时间:2026-01-09

问题已经解决,欢迎各位过来拿金币

兄弟们燃尽了,自己写了个本地的违禁词,现在可以了,受不了,后面拦不住我再加其他违禁词进去,微信这个接口有 bug,我看有很多人都说拦不住,我已经提交了工单,看看微信后续什么结果吧,总的来说就是多媒体违禁拦截的接口没问题,文本违禁拦截的接口有问题,不一定全部可以拦截,需要自己写本地的违禁词拦截 😒

idr 吗,那你也会出现我这种情况吗

@libra2 2 是评论的类型,所以传的是 2,3 是帖子类型

打印了,传的就是这个

文本检测 {'content': '我想草拟', 'openid': 'ozxtT15kwJZrIeer7GsJQ9nMphqA', 'scene': 2, 'version': 2} {'errcode': 0, 'errmsg': 'ok', 'detail': [{'strategy': 'keyword', 'errcode': 0}, {'strategy': 'content_model', 'errcode': 0, 'suggest': 'pass', 'label': 100, 'prob': 90}], 'trace_id': '6968a9a1-40bcc957-15249ba8', 'result': {'suggest': 'pass', 'label': 100}}

image
我发现是小程序无法拦截,但是调试工具确实是确认违规了,我后端代码那也传的是正确的 content,有点奇怪了

@libra2 是啊,我感觉他这个接口是不是就有问题,恶心死我了

@libra2 一直说让我接微信的文本检测接口,我已经接了,而且也同步判断了,我上传图片也是这个写法,上传黄图就会自动拦截,但是文本就不行,说些涉黄的言论还是可以通过

那没有,我就是想知道这是什么问题,这个涉黄评论微信小程序审核那卡了我半个月了,恶心死我了

现在我发布的评论涉黄,但是微信的文本监管接口没有拦截我发布的涉黄评论,直接让通过了

import logging
from dataclasses import dataclass
from typing import Any, Optional, Iterable, List

import requests
from django.conf import settings
from django.core.cache import cache
from rest_framework.exceptions import ValidationError

logger = logging.getLogger(name)

def _normalize_wx_resp(raw: Optional[dict]) -> dict:
raw = raw or {}
return {
"errcode": raw.get("errcode", 0),
"errmsg": raw.get("errmsg", ""),
"trace_id": raw.get("trace_id", ""),
"result": raw.get("result") or {},
"detail": raw.get("detail") or [],
}

def check_text_and_report(
*,
user,
text: str,
scene: int,
strict: bool = True,
require_openid: bool = True,
) -> dict:
appid = getattr(settings, "WECHAT_APPID", "") or getattr(settings, "WX_MINI_APPID", "")
secret = getattr(settings, "WECHAT_SECRET", "") or getattr(settings, "WX_MINI_SECRET", "")
if not appid or not secret:
raise ValidationError("未配置 WECHAT_APPID/WECHAT_SECRET,无法进行内容审核")

复制
client = WeChatMiniProgramSecCheck(appid=appid, secret=secret)
openid = get_user_openid(user)

if require_openid and not openid:
    raise ValidationError({"message": "未获取到 openid,无法完成内容审核", "sec_check": {"suggest": "no_openid"}})

parts_reports: List[dict] = []

for part in _split_text(text, max_len=2000):
    res = client.msg_sec_check(content=part, openid=openid, scene=int(scene), version=2)
    report = _normalize_wx_resp(res.raw)
    report.update({"suggest": res.suggest, "label": res.label})
    parts_reports.append(report)

    logger.info("wx sec_check: uid=%s scene=%s suggest=%s label=%s trace=%s",
                getattr(user, "id", None), scene, res.suggest, res.label, report.get("trace_id"))

    if res.ok:
        continue

    # review/risky:明确不通过
    if res.suggest in ("review", "risky"):
        raise ValidationError({"message": "内容可能包含敏感信息,请修改后再提交", "sec_check": report})

    # 其它异常:strict=True 直接拒绝(并把微信返回带出去)
    if strict:
        raise ValidationError({"message": "内容审核服务异常,请稍后重试", "sec_check": report})

    # strict=False:按你原来策略(这里默认还是拒绝更安全)
    raise ValidationError({"message": "内容审核失败,请稍后重试", "sec_check": report})

# 多段合并返回:给前端 parts,必要时也能取最后一次
return {
    "scene": int(scene),
    "openid": (openid or "")[:8] + "..." if openid else "",
    "parts": parts_reports,
    "result": parts_reports[-1].get("result") if parts_reports else {},
    "detail": sum((p.get("detail", []) for p in parts_reports), []),
}

@dataclass
class WxSecCheckResult:
ok: bool
suggest: str = ""
label: Optional[int] = None
raw: Optional[dict] = None

class WeChatMiniProgramSecCheck:
TOKEN_URL = " https://api.weixin.qq.com/cgi-bin/token "
MSG_SEC_CHECK_URL = " https://api.weixin.qq.com/wxa/msg_sec_check "

复制
TOKEN_INVALID_CODES = {40001, 40014, 42001}

def __init__(self, appid: str, secret: str):
    self.appid = appid
    self.secret = secret

def _cache_key(self) -> str:
    return f"wx:mp:access_token:{self.appid}"

def _get_access_token(self) -> str:
    ck = self._cache_key()
    cached = cache.get(ck)
    if cached:
        return cached

    resp = requests.get(
        self.TOKEN_URL,
        params={
            "grant_type": "client_credential",
            "appid": self.appid,
            "secret": self.secret,
        },
        timeout=6,
    )
    data = resp.json()
    if "access_token" not in data:
        raise RuntimeError(f"get_access_token failed: {data}")

    token = data["access_token"]
    expires_in = int(data.get("expires_in", 7200))
    cache.set(ck, token, timeout=max(expires_in - 300, 60))
    return token

def _invalidate_access_token(self) -> None:
    cache.delete(self._cache_key())

def msg_sec_check(self, *, content: str, openid: Optional[str] = None, scene: int = 2,
                  version: int = 2) -> WxSecCheckResult:
    content = (content or "").strip()
    if not content:
        return WxSecCheckResult(ok=False, suggest="empty")

    if not getattr(settings, "WECHAT_SEC_CHECK_ENABLED", True):
        return WxSecCheckResult(ok=True, suggest="pass (disabled)")

    if not openid:
        return WxSecCheckResult(ok=False, suggest="no_openid", raw={"errmsg": "missing openid"})

    def _do_call(token: str) -> dict:
        payload: dict[str, Any] = {
            "content": content,
            "openid": openid,
            "scene": int(scene),
            "version": int(version),
        }
        r = requests.post(self.MSG_SEC_CHECK_URL, params={"access_token": token}, json=payload, timeout=6)
        return r.json()

    token = self._get_access_token()
    data = _do_call(token)

    if int(data.get("errcode") or 0) in self.TOKEN_INVALID_CODES:
        self._invalidate_access_token()
        token = self._get_access_token()
        data = _do_call(token)

    errcode = int(data.get("errcode") or 0)
    if errcode != 0:
        logger.warning("wx msg_sec_check error: %s", data)
        return WxSecCheckResult(ok=False, suggest="api_error", raw=data)

    if "result" not in data:
        logger.warning("wx msg_sec_check bad response (no result): %s", data)
        return WxSecCheckResult(ok=False, suggest="bad_response", raw=data)

    result = data.get("result") or {}
    suggest = result.get("suggest") or "pass"
    label = result.get("label")
    return WxSecCheckResult(ok=(suggest == "pass"), suggest=suggest, label=label, raw=data)

def get_user_openid(user) -> Optional[str]:
for key in ("openid", "wx_openid", "wechat_openid"):
v = getattr(user, key, None)
if v:
return v

复制
info = getattr(user, "info", None)
if info:
    for key in ("openid", "wx_openid", "wechat_openid"):
        v = getattr(info, key, None)
        if v:
            return v
return None

def _split_text(text: str, max_len: int = 2000) -> Iterable[str]:
"""
微信 msg_sec_check 文本长度通常不超过 2000 字符:contentReference[oaicite:2]{index=2}
超长就分段逐段检测。
"""
s = (text or "").strip()
if not s:
return []

复制
buf = []
cur = ""
for ch in s:
    if len(cur) >= max_len:
        buf.append(cur)
        cur = ""
    cur += ch
if cur:
    buf.append(cur)
return buf

def check_text_or_raise(*, user, text: str, scene: int, strict: bool = False, require_openid: bool = False) -> None:
appid = getattr(settings, "WECHAT_APPID", "") or getattr(settings, "WX_MINI_APPID", "")
secret = getattr(settings, "WECHAT_SECRET", "") or getattr(settings, "WX_MINI_SECRET", "")
if not appid or not secret:
raise ValidationError("未配置 WECHAT_APPID/WECHAT_SECRET,无法进行内容审核")

复制
client = WeChatMiniProgramSecCheck(appid=appid, secret=secret)
openid = get_user_openid(user)

if require_openid and not openid:
    raise ValidationError("未获取到 openid,无法完成内容审核,请退出重进小程序或重新登录后再试")

for part in _split_text(text, max_len=2000):
    res = client.msg_sec_check(
        content=part,
        openid=openid,
        scene=int(scene),
        version=2,
    )

    if res.ok:
        continue

    logger.warning("wx sec_check block: suggest=%s label=%s raw=%s", res.suggest, res.label, res.raw)

    if res.suggest in ("review", "risky"):
        raise ValidationError("内容可能包含敏感信息,请修改后再提交")
    if res.suggest == "empty":
        raise ValidationError("内容不能为空")

    # api_error:严格模式一律拒绝;非严格按 fail-open 配置决定
    if res.suggest == "api_error":
        if strict:
            raise ValidationError("内容审核服务异常,请稍后重试")
        if getattr(settings, "WECHAT_SEC_CHECK_FAIL_OPEN", False):
            continue
        raise ValidationError("内容审核失败,请稍后重试")

    raise ValidationError("内容审核失败,请稍后重试")

image
各位大佬看看这是为什么,我说这些涉黄的,微信的文本检测接口还是可以通过,我服了

图片我不知道怎么发出来,有大佬教我一下怎么发图片吗