contentSecurityCheck.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. /**
  2. * 内容安全检测工具类
  3. * 用于检测用户发布的文字、图片是否包含色情、低俗、违规等内容
  4. * 使用微信小程序内容安全API
  5. */
  6. const BASE_URL = 'https://api.zhongruanke.cn/api'
  7. // 敏感词列表(本地基础过滤)
  8. const SENSITIVE_WORDS = [
  9. // 色情相关
  10. '色情', '裸体', '性爱', '约炮', '一夜情', '援交', '卖淫', '嫖娼',
  11. // 低俗相关
  12. '傻逼', '操你', '草泥马', '妈的', '他妈的', '狗日的', '王八蛋',
  13. // 违规相关
  14. '赌博', '毒品', '枪支', '炸弹', '恐怖', '暴力',
  15. // 诈骗相关
  16. '刷单', '兼职日结', '高额返利', '免费领取'
  17. ]
  18. /**
  19. * 本地敏感词检测
  20. */
  21. function localTextCheck(content) {
  22. if (!content) return { safe: true, message: '' }
  23. const lowerContent = content.toLowerCase()
  24. for (const word of SENSITIVE_WORDS) {
  25. if (lowerContent.includes(word.toLowerCase())) {
  26. return {
  27. safe: false,
  28. message: '内容包含敏感词,请修改后重试'
  29. }
  30. }
  31. }
  32. return { safe: true, message: '' }
  33. }
  34. /**
  35. * 检测文字内容是否安全
  36. */
  37. async function checkText(content) {
  38. if (!content || !content.trim()) {
  39. return { safe: true, message: '' }
  40. }
  41. // 1. 本地敏感词过滤(快速检测)
  42. const localResult = localTextCheck(content)
  43. if (!localResult.safe) {
  44. return localResult
  45. }
  46. // 2. 调用后端接口进行内容安全检测
  47. try {
  48. const [error, res] = await uni.request({
  49. url: BASE_URL + '/content-security/check-text',
  50. method: 'POST',
  51. data: { content: content },
  52. timeout: 10000
  53. })
  54. if (error) {
  55. console.error('文字安全检测请求失败:', error)
  56. return localResult
  57. }
  58. if (res.statusCode === 200 && res.data) {
  59. if (res.data.code === 200) {
  60. const data = res.data.data
  61. if (data && data.safe === false) {
  62. return {
  63. safe: false,
  64. message: data.message || '内容包含违规信息,请修改后重试'
  65. }
  66. }
  67. } else if (res.data.code === 87014) {
  68. return {
  69. safe: false,
  70. message: '内容包含违规信息,请修改后重试'
  71. }
  72. }
  73. }
  74. return { safe: true, message: '' }
  75. } catch (e) {
  76. console.error('文字安全检测异常:', e)
  77. return localResult
  78. }
  79. }
  80. /**
  81. * 检测图片是否安全
  82. */
  83. async function checkImage(imageUrl) {
  84. if (!imageUrl) {
  85. return { safe: true, message: '' }
  86. }
  87. // 如果是本地临时文件,跳过检测
  88. if (imageUrl.startsWith('wxfile://') || imageUrl.startsWith('http://tmp/')) {
  89. return { safe: true, message: '' }
  90. }
  91. try {
  92. const [error, res] = await uni.request({
  93. url: BASE_URL + '/content-security/check-image',
  94. method: 'POST',
  95. data: { imageUrl: imageUrl },
  96. timeout: 15000
  97. })
  98. if (error) {
  99. console.error('图片安全检测请求失败:', error)
  100. return { safe: true, message: '' }
  101. }
  102. if (res.statusCode === 200 && res.data) {
  103. if (res.data.code === 200) {
  104. const data = res.data.data
  105. if (data && data.safe === false) {
  106. return {
  107. safe: false,
  108. message: data.message || '图片包含违规内容,请更换后重试'
  109. }
  110. }
  111. } else if (res.data.code === 87014) {
  112. return {
  113. safe: false,
  114. message: '图片包含违规内容,请更换后重试'
  115. }
  116. }
  117. }
  118. return { safe: true, message: '' }
  119. } catch (e) {
  120. console.error('图片安全检测异常:', e)
  121. return { safe: true, message: '' }
  122. }
  123. }
  124. /**
  125. * 批量检测图片是否安全
  126. */
  127. async function checkImages(imageUrls) {
  128. if (!imageUrls || imageUrls.length === 0) {
  129. return { safe: true, message: '', failedIndex: -1 }
  130. }
  131. // 过滤掉本地临时文件
  132. const networkUrls = imageUrls.filter(url =>
  133. url && !url.startsWith('wxfile://') && !url.startsWith('http://tmp/')
  134. )
  135. if (networkUrls.length === 0) {
  136. return { safe: true, message: '', failedIndex: -1 }
  137. }
  138. // 逐个检测图片
  139. for (let i = 0; i < networkUrls.length; i++) {
  140. const result = await checkImage(networkUrls[i])
  141. if (!result.safe) {
  142. return {
  143. safe: false,
  144. message: `第${i + 1}张图片包含违规内容,请更换后重试`,
  145. failedIndex: i
  146. }
  147. }
  148. }
  149. return { safe: true, message: '', failedIndex: -1 }
  150. }
  151. /**
  152. * 综合检测文字和图片
  153. */
  154. async function checkContent(content, imageUrls) {
  155. // 1. 检测文字
  156. const textResult = await checkText(content)
  157. if (!textResult.safe) {
  158. return textResult
  159. }
  160. // 2. 检测图片
  161. if (imageUrls && imageUrls.length > 0) {
  162. const imageResult = await checkImages(imageUrls)
  163. if (!imageResult.safe) {
  164. return imageResult
  165. }
  166. }
  167. return { safe: true, message: '' }
  168. }
  169. // 导出模块
  170. export default {
  171. checkText,
  172. checkImage,
  173. checkImages,
  174. checkContent,
  175. localTextCheck
  176. }