Kaynağa Gözat

优化报错翻译

liyanbo 2 hafta önce
ebeveyn
işleme
89c3920107

+ 215 - 0
src/components/ai/dict/doubao/arkError.js

@@ -0,0 +1,215 @@
+export const ARK_ERROR_CODE_MAP = {
+  InvalidParameter: '参数无效',
+  'InvalidEndpoint.ClosedEndpoint': '端点已关闭或暂不可用',
+  InvalidParameterValue: '参数值无效',
+  MissingParameter: '缺少必填参数',
+  InvalidAuthentication: '认证失败',
+  InsufficientBalance: '余额不足',
+  AccountOverdueError: '账户欠费',
+  ModelNotFound: '模型不存在',
+  ModelNotOpen: '模型未开通',
+  ModelNotSupported: '当前模型不支持此操作',
+  RateLimitExceeded: '请求频率超限,请稍后重试',
+  RequestEntityTooLarge: '请求内容过大',
+  ServiceUnavailable: '服务暂时不可用,请稍后重试',
+  InternalError: '服务内部错误',
+  ContentModerationFailed: '内容审核未通过',
+  ImageDownloadFailed: '参考图下载失败,请检查图片链接',
+  InvalidImageUrl: '参考图地址无效',
+  ImageProcessingFailed: '图片处理失败',
+  VideoGenerationFailed: '视频生成失败',
+  TaskNotFound: '任务不存在',
+  TaskExpired: '任务已过期',
+  Timeout: '请求超时,请稍后重试',
+  InvalidResolution: '分辨率不支持',
+  ResolutionNotSupported: '当前模型不支持该分辨率',
+  ParamNotSupported: '当前模型不支持该参数',
+  UnsupportedImageFormat: '不支持的图片格式',
+  ImageTooLarge: '图片过大',
+  ImageTooSmall: '图片过小',
+  InvalidPrompt: '提示词不符合规范',
+  PromptTooLong: '提示词过长',
+}
+
+const CODE_USER_MSG_MAP = {
+  AccountOverdueError: '账户已欠费,请联系管理员充值后再试',
+  ModelNotOpen: 'AI 模型服务未开通,请联系管理员',
+  ModelNotFound: 'AI 模型不可用,请联系管理员',
+  ModelNotSupported: '当前暂不支持该操作,请联系管理员',
+  'InvalidEndpoint.ClosedEndpoint': '服务暂不可用,请稍后重试',
+  ServiceUnavailable: '服务暂不可用,请稍后重试',
+  InternalError: '服务异常,请稍后重试',
+  InvalidAuthentication: '认证失败,请联系管理员',
+  RateLimitExceeded: '操作过于频繁,请稍后再试',
+  TaskExpired: '任务已过期,请重新生成',
+  TaskNotFound: '任务不存在,请重新生成',
+  Timeout: '请求超时,请稍后重试',
+  ContentModerationFailed: '内容不符合规范,请修改后重试',
+  InsufficientBalance: '积分不足,请联系管理员充值',
+  RequestEntityTooLarge: '请求内容过大,请缩减后重试',
+}
+
+const ARK_PARAM_KEYWORD_MAP = {
+  resolution: '分辨率',
+  prompt: '提示词',
+  model: '模型',
+  duration: '视频时长',
+  width: '宽度',
+  height: '高度',
+  image: '图片',
+  content: '内容',
+  contents: '内容',
+  image_url: '图片链接',
+  url: '地址',
+  seed: '随机种子',
+  temperature: '随机性',
+  top_p: 'Top-P采样',
+  max_tokens: '最大Token数',
+  text: '文本',
+}
+
+const ARK_MSG_KEYWORD_MAP = [
+  ['specified in the request is not valid: the parameter image pixel count specified in the request must be greater than or equal to', '不符合要求: 图片像素数必须大于等于'],
+  ['specified in the request is not valid: the parameter', '不符合要求:'],
+  ['specified in the request is not valid', '不符合要求'],
+  ['specified in the request is not supported', '不支持当前请求'],
+  ['the specified resolution is not supported', '该分辨率不受支持'],
+  ['is not supported for model', '不支持'],
+  ['Error while downloading image', '图片下载失败'],
+  ['expected the width to be at least', '要求宽度至少为'],
+  ['expected the height to be at least', '要求高度至少为'],
+  ['expected the width to be at most', '要求宽度最大为'],
+  ['expected the height to be at most', '要求高度最大为'],
+  ['image pixel count specified in the request must be greater than or equal to', '图片像素数必须大于等于'],
+  ['image pixel count', '图片像素数'],
+  ['but received a', '但实际获得'],
+  ['pixels', '像素'],
+  ['instead of', '而非'],
+  ['instead.', '。'],
+  [' instead', ''],
+  ['image ', '图片 '],
+  ['expected at most one image content with unspecified role but got', '最多只能有一张图片内容,但实际有'],
+  ['expected at most one image content', '最多只能有一张图片内容'],
+  ['with unspecified role but got', '但实际有'],
+  ['url field cannot be empty', '图片链接不能为空'],
+  ['image content', '图片内容'],
+  ['for model', ''],
+  ['in i2v', ''],
+  ['in t2i', ''],
+  ['The parameter', '参数'],
+  ['the parameter', ''],
+  ['error:', '错误:'],
+  ['invalid parameter', '参数无效'],
+  ['missing required parameter', '缺少必填参数'],
+  ['not found', '未找到'],
+  ['request timeout', '请求超时'],
+].sort((a, b) => b[0].length - a[0].length)
+
+const SENSITIVE_PATTERNS = [
+  /\bdoubao-[\w.-]+\b/gi,
+  /\bseedance[\w.-]*\b/gi,
+  /\bseedream[\w.-]*\b/gi,
+  /\bep-\w+/gi,
+  /\bark[\w\s-]*console\b/gi,
+  /\bArk\s*Console\b/g,
+  /\bendpoint\b/gi,
+  /\bi2v\b/gi,
+  /\bt2i\b/gi,
+  /\baccount\s+\d+\b/gi,
+  /\b账户\s*\d+\b/g,
+  /\b\d{10,}\b/g,
+  /Request id:?\s*[a-zA-Z0-9\-]+/gi,
+  /requestId='[^']*'/gi,
+]
+
+const TYPE_LABEL_MAP = {
+  BadRequest: '请求错误',
+  'Bad Request': '请求错误',
+  Unauthorized: '未授权',
+  Forbidden: '禁止访问',
+  NotFound: '资源不存在',
+  'Not Found': '资源不存在',
+  ServerError: '服务器错误',
+}
+
+const translateParam = (param) => {
+  const parts = param.split('.')
+  return parts.map((seg) => {
+    const m = seg.match(/^(\w+)(\[\d+\])?$/)
+    if (!m) return ARK_PARAM_KEYWORD_MAP[seg] || seg
+    const word = m[1]
+    const index = m[2] || ''
+    return (ARK_PARAM_KEYWORD_MAP[word] || word) + index
+  }).join('.')
+}
+
+const escapeRegExp = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
+
+const replaceAll = (str, from, to) => {
+  const re = new RegExp(escapeRegExp(from), 'gi')
+  return str.replace(re, to)
+}
+
+const sanitizeSensitiveWords = (str) => {
+  let s = str
+  s = s.replace(/`[^`]*`/g, (m) => {
+    for (const p of SENSITIVE_PATTERNS) {
+      if (p.test(m)) return '参数'
+    }
+    return m
+  })
+  for (const p of SENSITIVE_PATTERNS) {
+    s = s.replace(p, '')
+  }
+  s = s.replace(/\s+/g, ' ').trim()
+  s = s.replace(/\s+([,.:;!?])/g, '$1')
+  s = s.replace(/^[,.:;!?\s]+/, '')
+  s = s.replace(/[,.:;!?\s]+$/, '')
+  s = s.replace(/^[,:;]\s*/, '')
+  s = s.replace(/\s{2,}/g, ' ')
+  return s.trim()
+}
+
+export const parseArkErrorMessage = (errorMessage) => {
+  if (!errorMessage) return '未知错误'
+
+  const codeMatch = errorMessage.match(/code='([^']+)'/)
+  const typeMatch = errorMessage.match(/type='([^']+)'/)
+  const paramMatch = errorMessage.match(/param='([^']*)'/)
+  const statusMatch = errorMessage.match(/statusCode=(\d+)/)
+  const msgMatch = errorMessage.match(/message='([^']+)'/)
+
+  const code = codeMatch ? codeMatch[1] : ''
+  const param = paramMatch ? paramMatch[1] : ''
+  const status = statusMatch ? statusMatch[1] : ''
+
+  if (code && CODE_USER_MSG_MAP[code]) {
+    return CODE_USER_MSG_MAP[code]
+  }
+
+  let detail = msgMatch ? msgMatch[1] : errorMessage
+
+  if (param) {
+    const translatedParam = translateParam(param)
+    const backtickRe = new RegExp('`' + escapeRegExp(param) + '`', 'g')
+    detail = detail.replace(backtickRe, '`' + translatedParam + '`')
+  }
+
+  for (const [en, zh] of ARK_MSG_KEYWORD_MAP) {
+    detail = replaceAll(detail, en, zh)
+  }
+
+  detail = sanitizeSensitiveWords(detail)
+
+  if (code && ARK_ERROR_CODE_MAP[code]) {
+    const label = ARK_ERROR_CODE_MAP[code]
+    return status ? `[${label}(${status})] ${detail}` : `[${label}] ${detail}`
+  }
+
+  if (typeMatch && typeMatch[1]) {
+    const typeLabel = TYPE_LABEL_MAP[typeMatch[1]] || typeMatch[1]
+    return status ? `[${typeLabel}(${status})] ${detail}` : `[${typeLabel}] ${detail}`
+  }
+
+  return detail
+}

+ 1 - 8
src/components/ai/image/ImageToImage.vue

@@ -145,6 +145,7 @@ import {getModelIdByType, ModelPlatformEnum, ModelTypeEnum} from '@/api/teachers
 import {
   Back, DArrowRight, Download, Refresh, RefreshLeft, RefreshRight, Right, ZoomIn, ZoomOut,
 } from '@element-plus/icons-vue'
+import { parseArkErrorMessage } from '@/components/ai/dict/doubao/arkError.js'
 
 // 定义props
 const props = defineProps({
@@ -333,14 +334,6 @@ const MAX_POLL_FAIL = 5
 /** 生成唯一ID */
 const genMsgId = () => Date.now().toString(36) + Math.random().toString(36).slice(2, 6)
 
-/** 解析 ArkHttpException 错误信息 */
-const parseArkErrorMessage = (errorMessage) => {
-  if (!errorMessage) return '未知错误'
-  const match = errorMessage.match(/message='([^']*)'/)
-  if (match) return match[1]
-  return errorMessage
-}
-
 /** 轮询生成中的任务 */
 const refreshWatchImages = async () => {
   const imageIds = Object.keys(inProgressImageMap.value).map(Number)

+ 1 - 8
src/components/ai/image/TextToImage.vue

@@ -151,6 +151,7 @@ import {getModelIdByType, ModelPlatformEnum, ModelTypeEnum} from '@/api/teachers
 import {
   Back, DArrowRight, Download, Refresh, RefreshLeft, RefreshRight, Right, ZoomIn, ZoomOut,
 } from '@element-plus/icons-vue'
+import { parseArkErrorMessage } from '@/components/ai/dict/doubao/arkError.js'
 
 // 定义props
 const props = defineProps({
@@ -325,14 +326,6 @@ const MAX_POLL_FAIL = 5
 /** 生成唯一ID */
 const genMsgId = () => Date.now().toString(36) + Math.random().toString(36).slice(2, 6)
 
-/** 解析 ArkHttpException 错误信息 */
-const parseArkErrorMessage = (errorMessage) => {
-  if (!errorMessage) return '未知错误'
-  const match = errorMessage.match(/message='([^']*)'/)
-  if (match) return match[1]
-  return errorMessage
-}
-
 /** 轮询生成中的任务 */
 const refreshWatchImages = async () => {
   const imageIds = Object.keys(inProgressImageMap.value).map(Number)

+ 4 - 3
src/components/ai/text/TextToText.vue

@@ -382,7 +382,6 @@ const doSendMessage = async (content) => {
 
   // 通过emit事件通知父组件保存进度
   emits('saveProgress', "aiCount", 1)
-  console.log(props.isCourse);
   if (props.isCourse){
     emits('saveProgress', "course", 100)
   }
@@ -454,6 +453,8 @@ const doSendMessageStream = async (userMessage) => {
       conversationInAbortController.value,
       enableContext.value,
       async (res) => {
+
+        console.log("========res:", res.data);
         const { code, data, msg } = JSON.parse(res.data);
         if (code !== 0) {
           console.error(`对话异常! ${msg}`);
@@ -995,7 +996,7 @@ defineExpose({
   border-radius: rpx(5);
   cursor: pointer;
   box-shadow: 0 0px 2px rgba(0, 0, 0, 0.3);
-  
+
   // 取消点击后的边框
   &:focus,
   &:focus-visible {
@@ -1003,4 +1004,4 @@ defineExpose({
     box-shadow: 0 0px 2px rgba(0, 0, 0, 0.3);
   }
 }
-</style>
+</style>

+ 1 - 8
src/components/ai/video/ImageToVideo.vue

@@ -124,6 +124,7 @@ import {getModelIdByType, ModelPlatformEnum, ModelTypeEnum} from '@/api/teachers
 import {
   Back, DArrowRight, Refresh, RefreshLeft, RefreshRight, Right, ZoomIn, ZoomOut,
 } from '@element-plus/icons-vue'
+import { parseArkErrorMessage } from '@/components/ai/dict/doubao/arkError.js'
 
 // 定义props
 const props = defineProps({
@@ -311,14 +312,6 @@ const MAX_POLL_FAIL = 5 // 轮询接口连续失败上限
 /** 生成唯一ID,给每条消息做 key */
 const genMsgId = () => Date.now().toString(36) + Math.random().toString(36).slice(2, 6)
 
-/** 解析 ArkHttpException 错误信息,提取关键 message */
-const parseArkErrorMessage = (errorMessage) => {
-  if (!errorMessage) return '未知错误'
-  const match = errorMessage.match(/message='([^']*)'/)
-  if (match) return match[1]
-  return errorMessage
-}
-
 /** 轮询生成中的任务 */
 const refreshWatchImages = async () => {
   const imageIds = Object.keys(inProgressImageMap.value).map(Number)