生成错误信息记录

This commit is contained in:
jonathang4 2025-10-10 19:09:57 +08:00
parent ade0e0250c
commit 490b6eca29
7 changed files with 180 additions and 104 deletions

View File

@ -24,19 +24,25 @@ function cacheLog(value: string, color?: string) {
} }
} }
// 定义任务结果接口
interface TaskResult {
status: -1 | -2 | -3 | number;
url?: string;
errorMessage?: string;
timestamp: number;
}
export class ImagesTaskCache { export class ImagesTaskCache {
private static instance: ImagesTaskCache; private static instance: ImagesTaskCache;
private taskCache: Map<string, number|string>; private taskCache: Map<string, TaskResult>;
private tosProcessedTasks: Set<string>; // 记录已处理TOS上传的任务 private tosProcessedTasks: Set<string>; // 记录已处理TOS上传的任务
private cleanupInterval: NodeJS.Timeout | null = null; private cleanupInterval: NodeJS.Timeout | null = null;
private constructor() { private constructor() {
this.taskCache = new Map<string, number|string>(); this.taskCache = new Map();
this.tosProcessedTasks = new Set<string>(); this.tosProcessedTasks = new Set();
cacheLog("ImagesTaskCache initialized");
// 启动定时清理任务每30分钟
this.startPeriodicCleanup(); this.startPeriodicCleanup();
cacheLog("ImagesTaskCache initialized");
} }
public static getInstance(): ImagesTaskCache { public static getInstance(): ImagesTaskCache {
@ -71,7 +77,10 @@ export class ImagesTaskCache {
public startTask(taskId: string): void { public startTask(taskId: string): void {
const startTime = Math.floor(Date.now() / 1000); // Current time in seconds const startTime = Math.floor(Date.now() / 1000); // Current time in seconds
this.taskCache.set(taskId, startTime); this.taskCache.set(taskId, {
status: startTime,
timestamp: Date.now()
});
cacheLog(`Task started: ${taskId} at ${startTime}`); cacheLog(`Task started: ${taskId} at ${startTime}`);
} }
@ -101,7 +110,7 @@ export class ImagesTaskCache {
return tosUrls; return tosUrls;
} }
public async finishTask(taskId: string, status: -1 | -2 | -3, url: string = ''): Promise<void> { public async finishTask(taskId: string, status: -1 | -2 | -3, url: string = '', errorMessage?: string): Promise<void> {
if (!this.taskCache.has(taskId)) { if (!this.taskCache.has(taskId)) {
cacheLog(`Attempted to finish non-existent task: ${taskId}`); cacheLog(`Attempted to finish non-existent task: ${taskId}`);
return; return;
@ -139,12 +148,17 @@ export class ImagesTaskCache {
case -3: statusMessage = 'timed out'; break; case -3: statusMessage = 'timed out'; break;
} }
// 存储最终URLTOS地址或原始URL // 存储任务结果,包括错误信息
this.taskCache.set(taskId, finalUrl || status); this.taskCache.set(taskId, {
status,
url: finalUrl,
errorMessage: status !== -1 ? errorMessage : undefined,
timestamp: Date.now()
});
cacheLog(`Task ${taskId} finished ${statusMessage} (status: ${status})`); cacheLog(`Task ${taskId} finished ${statusMessage} (status: ${status})`);
} }
public getTaskStatus(taskId: string): number | string | undefined { public getTaskStatus(taskId: string): TaskResult | undefined {
return this.taskCache.get(taskId); return this.taskCache.get(taskId);
} }
@ -168,14 +182,20 @@ export class ImagesTaskCache {
* @param taskId ID * @param taskId ID
* @returns undefined * @returns undefined
*/ */
public getTaskResultAndClear(taskId: string): number | string | undefined { public getTaskResultAndClear(taskId: string): TaskResult | undefined {
const result = this.taskCache.get(taskId); const result = this.taskCache.get(taskId);
if (result && typeof result === 'string') { if (!result) {
// 只有当任务完成时返回字符串URL才清除缓存 return undefined;
this.taskCache.delete(taskId);
this.tosProcessedTasks.delete(taskId);
cacheLog(`Task ${taskId} result retrieved and cache cleared`);
} }
// 如果任务已完成状态为字符串URL或负数状态码则清理缓存
if (typeof result.status === 'number' && result.status < 0) {
this.taskCache.delete(taskId);
cacheLog(`Task ${taskId} result retrieved and cache cleared`);
return result;
}
// 任务仍在进行中,不清理缓存
return result; return result;
} }
@ -184,23 +204,24 @@ export class ImagesTaskCache {
* *
*/ */
public clearExpiredTasks(): void { public clearExpiredTasks(): void {
const now = Math.floor(Date.now() / 1000); const now = Date.now();
const expiredTime = 3600; // 1尊时 const expiredTasks: string[] = [];
let clearCount = 0;
for (const [taskId, status] of this.taskCache.entries()) { for (const [taskId, result] of this.taskCache.entries()) {
if (typeof status === 'number' && status > 0) { // 检查任务是否超过24小时
// 这是一个时间戳,检查是否过期 if (now - result.timestamp > 24 * 60 * 60 * 1000) {
if (now - status > expiredTime) { expiredTasks.push(taskId);
}
}
for (const taskId of expiredTasks) {
this.taskCache.delete(taskId); this.taskCache.delete(taskId);
this.tosProcessedTasks.delete(taskId); this.tosProcessedTasks.delete(taskId);
clearCount++; cacheLog(`Expired task cleared: ${taskId}`);
}
}
} }
if (clearCount > 0) { if (expiredTasks.length > 0) {
cacheLog(`Cleared ${clearCount} expired tasks`); cacheLog(`Cleared ${expiredTasks.length} expired tasks`);
} }
} }
@ -211,10 +232,10 @@ export class ImagesTaskCache {
let completedTasks = 0; let completedTasks = 0;
let pendingTasks = 0; let pendingTasks = 0;
for (const [, status] of this.taskCache.entries()) { for (const result of this.taskCache.values()) {
if (typeof status === 'string') { if (typeof result.status === 'number' && result.status < 0) {
completedTasks++; completedTasks++;
} else if (typeof status === 'number' && status > 0) { } else {
pendingTasks++; pendingTasks++;
} }
} }
@ -228,11 +249,13 @@ export class ImagesTaskCache {
public getPendingTasks(): string[] { public getPendingTasks(): string[] {
const pendingTasks: string[] = []; const pendingTasks: string[] = [];
for (const [taskId, status] of this.taskCache.entries()) {
if (typeof status == 'number' && status > 0) { for (const [taskId, result] of this.taskCache.entries()) {
if (typeof result.status === 'number' && result.status >= 0) {
pendingTasks.push(taskId); pendingTasks.push(taskId);
} }
} }
return pendingTasks; return pendingTasks;
} }

View File

@ -24,19 +24,25 @@ function cacheLog(value: string, color?: string) {
} }
} }
// 定义任务结果接口
interface TaskResult {
status: -1 | -2 | -3 | number;
url?: string;
errorMessage?: string;
timestamp: number;
}
export class VideoTaskCache { export class VideoTaskCache {
private static instance: VideoTaskCache; private static instance: VideoTaskCache;
private taskCache: Map<string, number|string>; private taskCache: Map<string, TaskResult>;
private tosProcessedTasks: Set<string>; // 记录已处理TOS上传的任务 private tosProcessedTasks: Set<string>; // 记录已处理TOS上传的任务
private cleanupInterval: NodeJS.Timeout | null = null; private cleanupInterval: NodeJS.Timeout | null = null;
private constructor() { private constructor() {
this.taskCache = new Map<string, number|string>(); this.taskCache = new Map();
this.tosProcessedTasks = new Set<string>(); this.tosProcessedTasks = new Set();
cacheLog("VideoTaskCache initialized");
// 启动定时清理任务每30分钟
this.startPeriodicCleanup(); this.startPeriodicCleanup();
cacheLog("VideoTaskCache initialized");
} }
public static getInstance(): VideoTaskCache { public static getInstance(): VideoTaskCache {
@ -71,7 +77,10 @@ export class VideoTaskCache {
public startTask(taskId: string): void { public startTask(taskId: string): void {
const startTime = Math.floor(Date.now() / 1000); // Current time in seconds const startTime = Math.floor(Date.now() / 1000); // Current time in seconds
this.taskCache.set(taskId, startTime); this.taskCache.set(taskId, {
status: startTime,
timestamp: Date.now()
});
cacheLog(`Task started: ${taskId} at ${startTime}`); cacheLog(`Task started: ${taskId} at ${startTime}`);
} }
@ -101,7 +110,7 @@ export class VideoTaskCache {
return tosUrls; return tosUrls;
} }
public async finishTask(taskId: string, status: -1 | -2 | -3, url: string = ''): Promise<void> { public async finishTask(taskId: string, status: -1 | -2 | -3, url: string = '', errorMessage?: string): Promise<void> {
if (!this.taskCache.has(taskId)) { if (!this.taskCache.has(taskId)) {
cacheLog(`Attempted to finish non-existent task: ${taskId}`); cacheLog(`Attempted to finish non-existent task: ${taskId}`);
return; return;
@ -139,12 +148,17 @@ export class VideoTaskCache {
case -3: statusMessage = 'timed out'; break; case -3: statusMessage = 'timed out'; break;
} }
// 存储最终URLTOS地址或原始URL // 存储任务结果,包括错误信息
this.taskCache.set(taskId, finalUrl || status); this.taskCache.set(taskId, {
status,
url: finalUrl,
errorMessage: status !== -1 ? errorMessage : undefined,
timestamp: Date.now()
});
cacheLog(`Task ${taskId} finished ${statusMessage} (status: ${status})`); cacheLog(`Task ${taskId} finished ${statusMessage} (status: ${status})`);
} }
public getTaskStatus(taskId: string): number | string | undefined { public getTaskStatus(taskId: string): TaskResult | undefined {
return this.taskCache.get(taskId); return this.taskCache.get(taskId);
} }
@ -168,14 +182,20 @@ export class VideoTaskCache {
* @param taskId ID * @param taskId ID
* @returns undefined * @returns undefined
*/ */
public getTaskResultAndClear(taskId: string): number | string | undefined { public getTaskResultAndClear(taskId: string): TaskResult | undefined {
const result = this.taskCache.get(taskId); const result = this.taskCache.get(taskId);
if (result && typeof result === 'string') { if (!result) {
// 只有当任务完成时返回字符串URL才清除缓存 return undefined;
this.taskCache.delete(taskId);
this.tosProcessedTasks.delete(taskId);
cacheLog(`Task ${taskId} result retrieved and cache cleared`);
} }
// 如果任务已完成状态为字符串URL或负数状态码则清理缓存
if (typeof result.status === 'number' && result.status < 0) {
this.taskCache.delete(taskId);
cacheLog(`Task ${taskId} result retrieved and cache cleared`);
return result;
}
// 任务仍在进行中,不清理缓存
return result; return result;
} }
@ -184,23 +204,24 @@ export class VideoTaskCache {
* *
*/ */
public clearExpiredTasks(): void { public clearExpiredTasks(): void {
const now = Math.floor(Date.now() / 1000); const now = Date.now();
const expiredTime = 3600; // 1小时 const expiredTasks: string[] = [];
let clearCount = 0;
for (const [taskId, status] of this.taskCache.entries()) { for (const [taskId, result] of this.taskCache.entries()) {
if (typeof status === 'number' && status > 0) { // 检查任务是否超过24小时
// 这是一个时间戳,检查是否过期 if (now - result.timestamp > 24 * 60 * 60 * 1000) {
if (now - status > expiredTime) { expiredTasks.push(taskId);
}
}
for (const taskId of expiredTasks) {
this.taskCache.delete(taskId); this.taskCache.delete(taskId);
this.tosProcessedTasks.delete(taskId); this.tosProcessedTasks.delete(taskId);
clearCount++; cacheLog(`Expired task cleared: ${taskId}`);
}
}
} }
if (clearCount > 0) { if (expiredTasks.length > 0) {
cacheLog(`Cleared ${clearCount} expired tasks`); cacheLog(`Cleared ${expiredTasks.length} expired tasks`);
} }
} }
@ -211,10 +232,10 @@ export class VideoTaskCache {
let completedTasks = 0; let completedTasks = 0;
let pendingTasks = 0; let pendingTasks = 0;
for (const [, status] of this.taskCache.entries()) { for (const result of this.taskCache.values()) {
if (typeof status === 'string') { if (typeof result.status === 'number' && result.status < 0) {
completedTasks++; completedTasks++;
} else if (typeof status === 'number' && status > 0) { } else {
pendingTasks++; pendingTasks++;
} }
} }
@ -228,11 +249,13 @@ export class VideoTaskCache {
public getPendingTasks(): string[] { public getPendingTasks(): string[] {
const pendingTasks: string[] = []; const pendingTasks: string[] = [];
for (const [taskId, status] of this.taskCache.entries()) {
if (typeof status == 'number' && status > 0) { for (const [taskId, result] of this.taskCache.entries()) {
if (typeof result.status === 'number' && result.status >= 0) {
pendingTasks.push(taskId); pendingTasks.push(taskId);
} }
} }
return pendingTasks; return pendingTasks;
} }

View File

@ -6,7 +6,7 @@ export default {
API_FILE_URL_INVALID: [-2003, '远程文件URL非法'], API_FILE_URL_INVALID: [-2003, '远程文件URL非法'],
API_FILE_EXECEEDS_SIZE: [-2004, '远程文件超出大小'], API_FILE_EXECEEDS_SIZE: [-2004, '远程文件超出大小'],
API_CHAT_STREAM_PUSHING: [-2005, '已有对话流正在输出'], API_CHAT_STREAM_PUSHING: [-2005, '已有对话流正在输出'],
API_CONTENT_FILTERED: [-2006, '内容由于合规问题已被阻止生成'], API_CONTENT_FILTERED: [-2006, 'sensitive 存在敏感信息'],
API_IMAGE_GENERATION_FAILED: [-2007, '图像生成失败'], API_IMAGE_GENERATION_FAILED: [-2007, '图像生成失败'],
API_VIDEO_GENERATION_FAILED: [-2008, '视频生成失败'], API_VIDEO_GENERATION_FAILED: [-2008, '视频生成失败'],
API_IMAGE_GENERATION_INSUFFICIENT_POINTS: [-2009, '即梦积分不足'], API_IMAGE_GENERATION_INSUFFICIENT_POINTS: [-2009, '即梦积分不足'],

View File

@ -137,7 +137,7 @@ export async function generateImages(
const historyId = aigc_data.history_record_id; const historyId = aigc_data.history_record_id;
if (!historyId) if (!historyId)
throw new APIException(EX.API_IMAGE_GENERATION_FAILED, "记录ID不存在"); throw new APIException(EX.API_IMAGE_GENERATION_FAILED, "记录ID不存在");
let status = 20, failCode, item_list = []; let status = 20, failCode = '', fail_msg = '', item_list = [];
while (status === 20) { while (status === 20) {
await new Promise((resolve) => setTimeout(resolve, 5000)); await new Promise((resolve) => setTimeout(resolve, 5000));
const result = await request("post", "/mweb/v1/get_history_by_ids", refreshToken, { const result = await request("post", "/mweb/v1/get_history_by_ids", refreshToken, {
@ -245,14 +245,16 @@ export async function generateImages(
throw new APIException(EX.API_IMAGE_GENERATION_FAILED, "记录不存在"); throw new APIException(EX.API_IMAGE_GENERATION_FAILED, "记录不存在");
status = result[historyId].status; status = result[historyId].status;
failCode = result[historyId].fail_code; failCode = result[historyId].fail_code;
fail_msg = result[historyId].fail_msg;
item_list = result[historyId].item_list; item_list = result[historyId].item_list;
} }
if (status === 30) { if (status === 30) {
if (failCode === '2038') if (failCode == '2038' || failCode == '2041') {
throw new APIException(EX.API_CONTENT_FILTERED); throw new APIException(EX.API_CONTENT_FILTERED);
else } else {
throw new APIException(EX.API_IMAGE_GENERATION_FAILED); throw new APIException(EX.API_IMAGE_GENERATION_FAILED);
} }
}
const imageUrls = item_list.map((item) => { const imageUrls = item_list.map((item) => {
if(!item?.image?.large_images?.[0]?.image_url) if(!item?.image?.large_images?.[0]?.image_url)
return item?.common_attr?.cover_url || null; return item?.common_attr?.cover_url || null;
@ -262,16 +264,18 @@ export async function generateImages(
if (validImageUrls.length > 0) { if (validImageUrls.length > 0) {
await imagesTaskCache.finishTask(task_id, -1, validImageUrls.join(",")); // Success await imagesTaskCache.finishTask(task_id, -1, validImageUrls.join(",")); // Success
} else { } else {
logger.error(`图片生成任务 ${task_id} 异常: 图片生成未返回有效链接`); const errorMessage = "图片生成未返回有效链接";
logger.error(`图片生成任务 ${task_id} 异常: ${errorMessage}`);
// If no valid URLs but no explicit error thrown earlier, consider it a failure. // If no valid URLs but no explicit error thrown earlier, consider it a failure.
// This could happen if item_list is empty or items don't have video_url. // This could happen if item_list is empty or items don't have video_url.
await imagesTaskCache.finishTask(task_id, -2); // Failure await imagesTaskCache.finishTask(task_id, -2, "", errorMessage); // Failure
throw new APIException(EX.API_IMAGE_GENERATION_FAILED, "图片生成未返回有效链接"); throw new APIException(EX.API_IMAGE_GENERATION_FAILED, errorMessage);
} }
return validImageUrls; return validImageUrls;
}catch (error) { }catch (error) {
logger.error(`图片生成任务 ${task_id} 异常: ${error.message}`); const errorMessage = error.message || "图片生成过程中发生未知错误";
await imagesTaskCache.finishTask(task_id, -2); // Failure due to exception logger.error(`图片生成任务 ${task_id} 异常: ${errorMessage}`);
await imagesTaskCache.finishTask(task_id, -2, "", errorMessage); // Failure due to exception
throw error; // Re-throw the error to be handled by the caller throw error; // Re-throw the error to be handled by the caller
} }
} }

View File

@ -224,14 +224,16 @@ export async function generateVideo(
} }
status = result[historyId].status; status = result[historyId].status;
failCode = result[historyId].fail_code; failCode = result[historyId].fail_code;
const fail_msg = result[historyId].fail_msg;
item_list = result[historyId].item_list; item_list = result[historyId].item_list;
} }
if (status === 30) { if (status === 30) {
if (failCode === '2038') if (failCode === '2038' || failCode == '2041') {
throw new APIException(EX.API_CONTENT_FILTERED); throw new APIException(EX.API_CONTENT_FILTERED);
else } else {
throw new APIException(EX.API_VIDEO_GENERATION_FAILED); throw new APIException(EX.API_VIDEO_GENERATION_FAILED);
} }
}
// Assuming success if status is not 30 (failed) and not 20 (pending) // Assuming success if status is not 30 (failed) and not 20 (pending)
// and item_list is populated. // and item_list is populated.
// A more robust check might be needed depending on actual API behavior for success. // A more robust check might be needed depending on actual API behavior for success.
@ -246,14 +248,18 @@ export async function generateVideo(
if (validVideoUrls.length > 0) { if (validVideoUrls.length > 0) {
await videoTaskCache.finishTask(task_id, -1, validVideoUrls.join(",")); // Success await videoTaskCache.finishTask(task_id, -1, validVideoUrls.join(",")); // Success
} else { } else {
const errorMessage = "视频生成未返回有效链接";
logger.error(`视频生成任务 ${task_id} 异常: ${errorMessage}`);
// If no valid URLs but no explicit error thrown earlier, consider it a failure. // If no valid URLs but no explicit error thrown earlier, consider it a failure.
// This could happen if item_list is empty or items don't have video_url. // This could happen if item_list is empty or items don't have video_url.
await videoTaskCache.finishTask(task_id, -2); // Failure await videoTaskCache.finishTask(task_id, -2, "", errorMessage); // Failure
throw new APIException(EX.API_VIDEO_GENERATION_FAILED, "视频生成未返回有效链接"); throw new APIException(EX.API_VIDEO_GENERATION_FAILED, errorMessage);
} }
return validVideoUrls; return validVideoUrls;
} catch (error) { } catch (error) {
await videoTaskCache.finishTask(task_id, -2); // Failure due to exception const errorMessage = error.message || "视频生成过程中发生未知错误";
logger.error(`视频生成任务 ${task_id} 异常: ${errorMessage}`);
await videoTaskCache.finishTask(task_id, -2, "", errorMessage); // Failure due to exception
throw error; // Re-throw the error to be handled by the caller throw error; // Re-throw the error to be handled by the caller
} }
} }

View File

@ -28,20 +28,30 @@ export default {
const imagesTaskCache = ImagesTaskCache.getInstance(); const imagesTaskCache = ImagesTaskCache.getInstance();
// 使用新的方法获取任务结果并清理缓存 // 使用新的方法获取任务结果并清理缓存
let res = imagesTaskCache.getTaskResultAndClear(task_id); let result = imagesTaskCache.getTaskResultAndClear(task_id);
if (typeof res === 'string') { if (result && typeof result.status === 'number' && result.status < 0) {
// 任务已完成返回TOS地址已经在finishTask中处理过 // 任务已完成
return { return {
created: util.unixTimestamp(), created: util.unixTimestamp(),
data: { task_id, url: res, status: -1 }, data: {
task_id,
url: result.url || "",
status: result.status,
error_message: result.errorMessage || null
},
}; };
} else { } else {
// 任务进行中或失败,不清理缓存 // 任务进行中或失败,不清理缓存
res = imagesTaskCache.getTaskStatus(task_id); result = imagesTaskCache.getTaskStatus(task_id);
return { return {
created: util.unixTimestamp(), created: util.unixTimestamp(),
data: { task_id, url: "", status: res || 0 }, data: {
task_id,
url: "",
status: result?.status || 0,
error_message: result?.errorMessage || null
},
}; };
} }
} }

View File

@ -28,20 +28,30 @@ export default {
const videoTaskCache = VideoTaskCache.getInstance(); const videoTaskCache = VideoTaskCache.getInstance();
// 使用新的方法获取任务结果并清理缓存 // 使用新的方法获取任务结果并清理缓存
let res = videoTaskCache.getTaskResultAndClear(task_id); let result = videoTaskCache.getTaskResultAndClear(task_id);
if (typeof res === 'string') { if (result && typeof result.status === 'number' && result.status < 0) {
// 任务已完成返回TOS地址已经在finishTask中处理过 // 任务已完成
return { return {
created: util.unixTimestamp(), created: util.unixTimestamp(),
data: { task_id, url: res, status: -1 }, data: {
task_id,
url: result.url || "",
status: result.status,
error_message: result.errorMessage || null
},
}; };
} else { } else {
// 任务进行中或失败,不清理缓存 // 任务进行中或失败,不清理缓存
res = videoTaskCache.getTaskStatus(task_id); result = videoTaskCache.getTaskStatus(task_id);
return { return {
created: util.unixTimestamp(), created: util.unixTimestamp(),
data: { task_id, url: "", status: res || 0 }, data: {
task_id,
url: "",
status: result?.status || 0,
error_message: result?.errorMessage || null
},
}; };
} }
} }