|
@@ -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
|
|
|
|
|
+}
|