• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
统哥
博客园    首页    新随笔    联系   管理    订阅  订阅

微信小程序-评价内容安全解决方案

1、需求提出

业务:“订单完成后需要增加一个用户评价的功能”。

产品:“好的,我们在前端新做一个页面可以评价。有好评、一般、差评,再加一个文本框输入评价内容。”

开发:“可以做。”

业务&产品:“多久能完成?我们希望尽快上线,如果可以的话,想自动生成一些评价的数据,在详细页显示 ♪(^∇^*)。这样对增加业务量有很大帮助。”

开发:“有啥问题呢,产品给方案给设计就能做啊。时间还得看设计方案WBS之后才好确认。”

业务:“一个星期够了吧,这个着急上线。就一个简单的评价功能。”

产品:“业务需求确认了,我去找UI设计下。过2天给你原型。”

Two days later...

产品@开发:“具体需求(附带一个链接)。”

打开链接一看,确实很简单:

1、一个前端的评价页面:上面是评价等级,五个小星星。下面一个评价内容文本框。提交还弹窗“评价成功! 产品详情查看评价内容”。

2、一个管理后台页面(没有UI设计,比较粗糙):类似列表显示评价内容,上面搜索条件,列表字段:订单号、用户、评价等级、内容、时间。尼玛还有一个导出功能,这是从其他页面截图的吧,这评价还导出??

开发心里OS:“这虽然有点粗鄙,但也要先做吧,毕竟后面做出来之后他们就会基于这个完善(修改)了😁。先设计表结构、再出接口、最后管理后台页面,这样就能前后端并行节省时间,提高效率。”

前端@产品:“这只有选中的⭐样式图片,不选中的是啥样?能半颗星选吗?评价多少个字啊,测试会测一个字的🙄。” (前端还是挺负责的搞事情 😖)

开发设计:

1、评价关联订单,订单中可能多个产品,评价也要对应产品吧,但是这需求没体现啊,咋搞,唉。还得设计兼容。

2、评价字段只有评价等级、评价内容。如果以后增加服务评价、物流评价呢,现在要不要考虑扩展。难搞,一周上线来得及不,还得讨论。

3、用户评价,看起来是评价,但是是用户自主输入,万一有啥不健康内容😏,或评价负面情绪,这对业务或平台都是伤害啊。

4、用户追评、添加图片、视频。。。存储问题。。。

这时突然响起:李玖哲的《想太多》 :“是我想太多你总这样说,但你却没有真的心疼我。是我想太多我也这样说,这是唯一能安慰我的理由”。

打住,打住。别往下想了。需求已经来了,时间已经定了,总要先开发,拿点东西出来吧。

OK,OK。难不倒聪明的程序员。MVP最小可行产品先出来,后面在迭代更新。

One week later。。。

基本功能的评价(评价等级、内容)功能已上线。

一波推广和宣传后,陆续产生了很多评价。各种各样的,好评、吐槽都有。随意评价也有。这些评价都显示在了前端,突然业务紧急在群里@开发,有一个恶意评价需要处理。

呵呵😄,早就料到会有这种情况。不慌,开发时已经预留了逻辑删除,在后台开放此功能即可。

新的问题产生:不能让人工一个个审核吧。

答案是肯定的,给钱就行。

寻找解决方案,思路:

1、在输入时控制,检测内容安全信息。

2、在后台可过滤显示内容,限制显示或隐藏评论。

3、加入AI识别评论情绪,对好评不限制,对消极的评价做标识,不显示到用户前端。

微信小程序有“文本内容安全检测”接口,检查一段文本是否含有违法违规内容。

应用场景举例:

  1. 用户个人资料违规文字检测;
  2. 媒体新闻类用户发表文章,评论内容检测;
  3. 游戏类用户编辑上传的素材(如答题类小游戏用户上传的问题及答案)检测等。 频率限制:单个 appId 调用上限为 4000 次/分钟,2,000,000 次/天。

直接在用户输入完成后通过 HTTPS 调用,如果存在违规内容提示用户健康评论。

 1         public static MsgSecCheck_resp MsgSecCheck(MsgSecCheck_req model)
 2         #region
 3         {
 4             string ACCESS_TOKEN = GetAccessToken();
 5             string url = $"https://api.weixin.qq.com/wxa/msg_sec_check?access_token={ACCESS_TOKEN}";
 6             try
 7             {
 8                 var json = HttpClientUti.DoPost(url, JsonHelper.ObjectToJson(model));
 9                 var remodel = JsonHelper.JsonToObject<MsgSecCheck_resp>(json);
10                 return remodel;
11             }
12             catch (Exception ex)
13             {
14                 return new MsgSecCheck_resp { errcode = -1, errmsg = "msgSecCheck接口异常," + ex.Message };
15             }
16         }
17         #endregion
View Code
 1 #region models
 2 public class MsgSecCheck_req
 3 #region
 4 {
 5     /// <summary>
 6     /// 用户的openid(用户需在近两小时访问过小程序)
 7     /// </summary>
 8     public string openid { get; set; }
 9 
10     /// <summary>
11     /// 场景枚举值(1 资料;2 评论;3 论坛;4 社交日志)
12     /// </summary>
13     public int scene { get; set; }
14 
15     /// <summary>
16     /// 接口版本号,2.0版本为固定值2
17     /// </summary>
18     public int version { get; set; } = 2;
19     public string content { get; set; }
20 }
21 #endregion
22 public class MsgSecCheck_resp
23 #region
24 {
25     public int errcode { get; set; }
26     public string errmsg { get; set; }
27     public Result_Entity result { get; set; }
28     public List<Detail_Entity> detail { get; set; }
29     public string trace_id { get; set; }
30 
31     public class Result_Entity
32     {
33         /// <summary>
34         /// 建议,有risky、pass、review三种值
35         /// </summary>
36         public string suggest { get; set; }
37         /// <summary>
38         /// 命中标签枚举值,100 正常;10001 广告;20001 时政;20002 色情;20003 辱骂;20006 违法犯罪;20008 欺诈;20012 低俗;20013 版权;21000 其他
39         /// </summary>
40         public int label { get; set; }
41     }
42 
43     public class Detail_Entity
44     {
45         public string strategy { get; set; }
46         public int errcode { get; set; }
47         public string suggest { get; set; }
48 
49         /// <summary>
50         /// 命中标签枚举值,100 正常;10001 广告;20001 时政;20002 色情;20003 辱骂;20006 违法犯罪;20008 欺诈;20012 低俗;20013 版权;21000 其他
51         /// </summary>
52         public int label { get; set; }
53 
54         /// <summary>
55         /// 0-100,代表置信度,越高代表越有可能属于当前返回的标签(label)
56         /// </summary>
57         public int prob { get; set; }
58         public int level { get; set; }
59         public string keyword { get; set; }
60     }
61 
62 }
63 #endregion
64 
65 
66 #endregion
View Code

 测试:

正常返回:pass

{
    "errcode": 0,
    "errmsg": "ok",
    "result": 
    {
        "suggest": "pass",
        "label": 100
    },
    "detail": 
    [
        {
            "strategy": "keyword",
            "errcode": 0,
            "suggest": null,
            "label": 0,
            "prob": 0,
            "level": 0,
            "keyword": null
        },
        {
            "strategy": "content_model",
            "errcode": 0,
            "suggest": "pass",
            "label": 100,
            "prob": 90,
            "level": 0,
            "keyword": null
        }
    ],
    "trace_id": "6836b8c9-378131c4-28e85c19"
}
View Code

有风险的:risky

{
    "errcode": 0,
    "errmsg": "ok",
    "result": {
        "suggest": "risky",
        "label": 20003
    },
    "detail": [
        {
            "strategy": "keyword",
            "errcode": 0,
            "suggest": null,
            "label": 0,
            "prob": 0,
            "level": 0,
            "keyword": null
        },
        {
            "strategy": "content_model",
            "errcode": 0,
            "suggest": "risky",
            "label": 20003,
            "prob": 90,
            "level": 0,
            "keyword": null
        }
    ],
    "trace_id": "6836b976-5808541a-78b3c137"
}
View Code

过了第一关,下面我们还需要对评论情绪做个分析。不能让负面的评价随便显示😄,我们需要正能量。

实现情绪识别分类需要一个LLM大模型,不过考虑到资源的情况,我们能有免费的绝不花一毛钱,找不到免费的,或其他成本太高,我们就不考虑了。

使用ML.NET训练一个模型。ML.NET 是面向 .NET 开发人员的开源跨平台机器学习框架,支持将自定义机器学习模型集成到 .NET 应用程序中。

1、使用“模型生成器工具”,Visual Studio 扩展的图形化工具,用于生成、训练和部署自定义机器学习模型。

 方案:数据分类。》环境:本地(CPU)

 数据:文件或SQL Server都是可以的。Label标签就是要预测的列(使用1代表好评,0代表差评)。

 训练:

 评估:

使用:

//Load sample data
var sampleData = new SentimentModel2.ModelInput()
{
    Col0 = @"服务差",
};

//Load model and predict output
var result = SentimentModel2.Predict(sampleData);
View Code

 

2、API 方式

安装ML包

准备数据:格式要求评价内容  label标识(1好评,0差评)

运动鞋网面的黄渍居然洗干净了,鞋底的纹路里的泥垢也清得很彻底,太专业了! 1

洗衣店把我的衣服洗破了一个洞,只愿意退洗衣费,完全不赔偿衣服价值。 0

示例代码:训练模型并保存导出

 static void ApiCreateAndTrainModel()
 {
     MLContext mLContext = new MLContext();

     //加载数据
     IDataView dataView = mLContext.Data.LoadFromTextFile<SentimentData>(_dataPath, hasHeader: false);

     //训练数据
     //var pipeline = mLContext.Transforms.Text.FeaturizeText("Features", "SentimentText");

     var pipeline = mLContext.Transforms.Text.FeaturizeText
        (
        outputColumnName: "Features",
        inputColumnName: nameof(SentimentData.SentimentText)
        )
    .Append(mLContext.BinaryClassification.Trainers.SdcaLogisticRegression(labelColumnName: "Label", featureColumnName: "Features"));
     //训练
     var model = pipeline.Fit(dataView);

     //评估
     IDataView predictions = model.Transform(dataView);
     CalibratedBinaryClassificationMetrics metrics = mLContext.BinaryClassification.Evaluate(predictions, "Label");

     Console.WriteLine($"Accuracy: {metrics.Accuracy:P2}");
     Console.WriteLine($"Auc: {metrics.AreaUnderRocCurve:P2}");
     Console.WriteLine($"F1Score: {metrics.F1Score:P2}");

     //预测
     PredictionEngine<SentimentData, SentimentPrediction> predictionFunction = mLContext.Model.CreatePredictionEngine<SentimentData, SentimentPrediction>(model);
     SentimentData sampleStatement = new SentimentData
     {
         SentimentText = "店家说用了超声波清洗,难怪这么干净!"
     };
     var resultPrediction = predictionFunction.Predict(sampleStatement);

     Console.WriteLine(JsonConvert.SerializeObject(resultPrediction));

     Console.WriteLine($@"Sentiment: {resultPrediction.SentimentText} | 
                 Prediction: {(Convert.ToBoolean(resultPrediction.Prediction) ? "好评" : "差评")} | Probability: {resultPrediction.Probability} ");

     //保存
     mLContext.Model.Save(model, dataView.Schema, "model.zip");
 }
View Code

测试使用模型:

static readonly string _modelFile = Path.Combine(Environment.CurrentDirectory, "", @"model.zip");
var mlContext = new MLContext();
var model = mlContext.Model.Load(_modelFile, out var schema);
var _predictionEngine = mlContext.Model.CreatePredictionEngine<SentimentData, SentimentPrediction>(model);

var result = _predictionEngine.Predict(new SentimentData { SentimentText = "洗的非常干净" });
Console.WriteLine(JsonConvert.SerializeObject(result));
View Code

结果:

Accuracy: 98.92%
Auc: 99.87%
F1Score: 98.99%

{"SentimentText":"洗的非常干净","Sentiment":false,"Prediction":true,"Probability":0.9957315,"Score":5.4522142}

开发:“总算折腾结束了,微信端的API,在结合模型的情感分析,基本能过滤掉大部分了。不过模型的准确性有很多影响因素:数据质量、算法选择、不同超参数。模型也是一个迭代的过程。”

内心OS:“初期模型质量不达标,可以结合业务反选嘛,评论默认不显示,准确识别通过后显示” 😙

总结:

产品&业务:这个方案挺好,微信的API是免费的,管理后台操作功能齐全,AI识别情绪筛选,技术开发自己搞定,不用投入钱,快速上线,出了问题甩锅方便。

😪😪😪 结束。

 

posted @ 2025-06-03 08:44  统哥  阅读(89)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3