生成错误信息记录
This commit is contained in:
parent
ade0e0250c
commit
490b6eca29
@ -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 {
|
||||
private static instance: ImagesTaskCache;
|
||||
private taskCache: Map<string, number|string>;
|
||||
private taskCache: Map<string, TaskResult>;
|
||||
private tosProcessedTasks: Set<string>; // 记录已处理TOS上传的任务
|
||||
private cleanupInterval: NodeJS.Timeout | null = null;
|
||||
|
||||
private constructor() {
|
||||
this.taskCache = new Map<string, number|string>();
|
||||
this.tosProcessedTasks = new Set<string>();
|
||||
cacheLog("ImagesTaskCache initialized");
|
||||
|
||||
// 启动定时清理任务(每30分钟)
|
||||
this.taskCache = new Map();
|
||||
this.tosProcessedTasks = new Set();
|
||||
this.startPeriodicCleanup();
|
||||
cacheLog("ImagesTaskCache initialized");
|
||||
}
|
||||
|
||||
public static getInstance(): ImagesTaskCache {
|
||||
@ -71,7 +77,10 @@ export class ImagesTaskCache {
|
||||
|
||||
public startTask(taskId: string): void {
|
||||
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}`);
|
||||
}
|
||||
|
||||
@ -101,7 +110,7 @@ export class ImagesTaskCache {
|
||||
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)) {
|
||||
cacheLog(`Attempted to finish non-existent task: ${taskId}`);
|
||||
return;
|
||||
@ -139,12 +148,17 @@ export class ImagesTaskCache {
|
||||
case -3: statusMessage = 'timed out'; break;
|
||||
}
|
||||
|
||||
// 存储最终URL(TOS地址或原始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})`);
|
||||
}
|
||||
|
||||
public getTaskStatus(taskId: string): number | string | undefined {
|
||||
public getTaskStatus(taskId: string): TaskResult | undefined {
|
||||
return this.taskCache.get(taskId);
|
||||
}
|
||||
|
||||
@ -168,14 +182,20 @@ export class ImagesTaskCache {
|
||||
* @param taskId 任务ID
|
||||
* @returns 任务结果,如果不存在返回undefined
|
||||
*/
|
||||
public getTaskResultAndClear(taskId: string): number | string | undefined {
|
||||
public getTaskResultAndClear(taskId: string): TaskResult | undefined {
|
||||
const result = this.taskCache.get(taskId);
|
||||
if (result && typeof result === 'string') {
|
||||
// 只有当任务完成时(返回字符串URL)才清除缓存
|
||||
this.taskCache.delete(taskId);
|
||||
this.tosProcessedTasks.delete(taskId);
|
||||
cacheLog(`Task ${taskId} result retrieved and cache cleared`);
|
||||
if (!result) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// 如果任务已完成(状态为字符串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;
|
||||
}
|
||||
|
||||
@ -184,23 +204,24 @@ export class ImagesTaskCache {
|
||||
* 防止在低配置服务器上内存泄漏
|
||||
*/
|
||||
public clearExpiredTasks(): void {
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const expiredTime = 3600; // 1尊时
|
||||
let clearCount = 0;
|
||||
const now = Date.now();
|
||||
const expiredTasks: string[] = [];
|
||||
|
||||
for (const [taskId, status] of this.taskCache.entries()) {
|
||||
if (typeof status === 'number' && status > 0) {
|
||||
// 这是一个时间戳,检查是否过期
|
||||
if (now - status > expiredTime) {
|
||||
this.taskCache.delete(taskId);
|
||||
this.tosProcessedTasks.delete(taskId);
|
||||
clearCount++;
|
||||
}
|
||||
for (const [taskId, result] of this.taskCache.entries()) {
|
||||
// 检查任务是否超过24小时
|
||||
if (now - result.timestamp > 24 * 60 * 60 * 1000) {
|
||||
expiredTasks.push(taskId);
|
||||
}
|
||||
}
|
||||
|
||||
if (clearCount > 0) {
|
||||
cacheLog(`Cleared ${clearCount} expired tasks`);
|
||||
for (const taskId of expiredTasks) {
|
||||
this.taskCache.delete(taskId);
|
||||
this.tosProcessedTasks.delete(taskId);
|
||||
cacheLog(`Expired task cleared: ${taskId}`);
|
||||
}
|
||||
|
||||
if (expiredTasks.length > 0) {
|
||||
cacheLog(`Cleared ${expiredTasks.length} expired tasks`);
|
||||
}
|
||||
}
|
||||
|
||||
@ -211,10 +232,10 @@ export class ImagesTaskCache {
|
||||
let completedTasks = 0;
|
||||
let pendingTasks = 0;
|
||||
|
||||
for (const [, status] of this.taskCache.entries()) {
|
||||
if (typeof status === 'string') {
|
||||
for (const result of this.taskCache.values()) {
|
||||
if (typeof result.status === 'number' && result.status < 0) {
|
||||
completedTasks++;
|
||||
} else if (typeof status === 'number' && status > 0) {
|
||||
} else {
|
||||
pendingTasks++;
|
||||
}
|
||||
}
|
||||
@ -228,11 +249,13 @@ export class ImagesTaskCache {
|
||||
|
||||
public getPendingTasks(): 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);
|
||||
}
|
||||
}
|
||||
|
||||
return pendingTasks;
|
||||
}
|
||||
|
||||
|
||||
@ -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 {
|
||||
private static instance: VideoTaskCache;
|
||||
private taskCache: Map<string, number|string>;
|
||||
private taskCache: Map<string, TaskResult>;
|
||||
private tosProcessedTasks: Set<string>; // 记录已处理TOS上传的任务
|
||||
private cleanupInterval: NodeJS.Timeout | null = null;
|
||||
|
||||
private constructor() {
|
||||
this.taskCache = new Map<string, number|string>();
|
||||
this.tosProcessedTasks = new Set<string>();
|
||||
cacheLog("VideoTaskCache initialized");
|
||||
|
||||
// 启动定时清理任务(每30分钟)
|
||||
this.taskCache = new Map();
|
||||
this.tosProcessedTasks = new Set();
|
||||
this.startPeriodicCleanup();
|
||||
cacheLog("VideoTaskCache initialized");
|
||||
}
|
||||
|
||||
public static getInstance(): VideoTaskCache {
|
||||
@ -71,7 +77,10 @@ export class VideoTaskCache {
|
||||
|
||||
public startTask(taskId: string): void {
|
||||
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}`);
|
||||
}
|
||||
|
||||
@ -101,7 +110,7 @@ export class VideoTaskCache {
|
||||
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)) {
|
||||
cacheLog(`Attempted to finish non-existent task: ${taskId}`);
|
||||
return;
|
||||
@ -139,12 +148,17 @@ export class VideoTaskCache {
|
||||
case -3: statusMessage = 'timed out'; break;
|
||||
}
|
||||
|
||||
// 存储最终URL(TOS地址或原始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})`);
|
||||
}
|
||||
|
||||
public getTaskStatus(taskId: string): number | string | undefined {
|
||||
public getTaskStatus(taskId: string): TaskResult | undefined {
|
||||
return this.taskCache.get(taskId);
|
||||
}
|
||||
|
||||
@ -168,14 +182,20 @@ export class VideoTaskCache {
|
||||
* @param taskId 任务ID
|
||||
* @returns 任务结果,如果不存在返回undefined
|
||||
*/
|
||||
public getTaskResultAndClear(taskId: string): number | string | undefined {
|
||||
public getTaskResultAndClear(taskId: string): TaskResult | undefined {
|
||||
const result = this.taskCache.get(taskId);
|
||||
if (result && typeof result === 'string') {
|
||||
// 只有当任务完成时(返回字符串URL)才清除缓存
|
||||
this.taskCache.delete(taskId);
|
||||
this.tosProcessedTasks.delete(taskId);
|
||||
cacheLog(`Task ${taskId} result retrieved and cache cleared`);
|
||||
if (!result) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// 如果任务已完成(状态为字符串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;
|
||||
}
|
||||
|
||||
@ -184,23 +204,24 @@ export class VideoTaskCache {
|
||||
* 防止在低配置服务器上内存泄漏
|
||||
*/
|
||||
public clearExpiredTasks(): void {
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const expiredTime = 3600; // 1小时
|
||||
let clearCount = 0;
|
||||
const now = Date.now();
|
||||
const expiredTasks: string[] = [];
|
||||
|
||||
for (const [taskId, status] of this.taskCache.entries()) {
|
||||
if (typeof status === 'number' && status > 0) {
|
||||
// 这是一个时间戳,检查是否过期
|
||||
if (now - status > expiredTime) {
|
||||
this.taskCache.delete(taskId);
|
||||
this.tosProcessedTasks.delete(taskId);
|
||||
clearCount++;
|
||||
}
|
||||
for (const [taskId, result] of this.taskCache.entries()) {
|
||||
// 检查任务是否超过24小时
|
||||
if (now - result.timestamp > 24 * 60 * 60 * 1000) {
|
||||
expiredTasks.push(taskId);
|
||||
}
|
||||
}
|
||||
|
||||
if (clearCount > 0) {
|
||||
cacheLog(`Cleared ${clearCount} expired tasks`);
|
||||
for (const taskId of expiredTasks) {
|
||||
this.taskCache.delete(taskId);
|
||||
this.tosProcessedTasks.delete(taskId);
|
||||
cacheLog(`Expired task cleared: ${taskId}`);
|
||||
}
|
||||
|
||||
if (expiredTasks.length > 0) {
|
||||
cacheLog(`Cleared ${expiredTasks.length} expired tasks`);
|
||||
}
|
||||
}
|
||||
|
||||
@ -211,10 +232,10 @@ export class VideoTaskCache {
|
||||
let completedTasks = 0;
|
||||
let pendingTasks = 0;
|
||||
|
||||
for (const [, status] of this.taskCache.entries()) {
|
||||
if (typeof status === 'string') {
|
||||
for (const result of this.taskCache.values()) {
|
||||
if (typeof result.status === 'number' && result.status < 0) {
|
||||
completedTasks++;
|
||||
} else if (typeof status === 'number' && status > 0) {
|
||||
} else {
|
||||
pendingTasks++;
|
||||
}
|
||||
}
|
||||
@ -228,11 +249,13 @@ export class VideoTaskCache {
|
||||
|
||||
public getPendingTasks(): 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);
|
||||
}
|
||||
}
|
||||
|
||||
return pendingTasks;
|
||||
}
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ export default {
|
||||
API_FILE_URL_INVALID: [-2003, '远程文件URL非法'],
|
||||
API_FILE_EXECEEDS_SIZE: [-2004, '远程文件超出大小'],
|
||||
API_CHAT_STREAM_PUSHING: [-2005, '已有对话流正在输出'],
|
||||
API_CONTENT_FILTERED: [-2006, '内容由于合规问题已被阻止生成'],
|
||||
API_CONTENT_FILTERED: [-2006, 'sensitive 存在敏感信息'],
|
||||
API_IMAGE_GENERATION_FAILED: [-2007, '图像生成失败'],
|
||||
API_VIDEO_GENERATION_FAILED: [-2008, '视频生成失败'],
|
||||
API_IMAGE_GENERATION_INSUFFICIENT_POINTS: [-2009, '即梦积分不足'],
|
||||
|
||||
@ -137,7 +137,7 @@ export async function generateImages(
|
||||
const historyId = aigc_data.history_record_id;
|
||||
if (!historyId)
|
||||
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) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 5000));
|
||||
const result = await request("post", "/mweb/v1/get_history_by_ids", refreshToken, {
|
||||
@ -245,13 +245,15 @@ export async function generateImages(
|
||||
throw new APIException(EX.API_IMAGE_GENERATION_FAILED, "记录不存在");
|
||||
status = result[historyId].status;
|
||||
failCode = result[historyId].fail_code;
|
||||
fail_msg = result[historyId].fail_msg;
|
||||
item_list = result[historyId].item_list;
|
||||
}
|
||||
if (status === 30) {
|
||||
if (failCode === '2038')
|
||||
if (failCode == '2038' || failCode == '2041') {
|
||||
throw new APIException(EX.API_CONTENT_FILTERED);
|
||||
else
|
||||
} else {
|
||||
throw new APIException(EX.API_IMAGE_GENERATION_FAILED);
|
||||
}
|
||||
}
|
||||
const imageUrls = item_list.map((item) => {
|
||||
if(!item?.image?.large_images?.[0]?.image_url)
|
||||
@ -262,16 +264,18 @@ export async function generateImages(
|
||||
if (validImageUrls.length > 0) {
|
||||
await imagesTaskCache.finishTask(task_id, -1, validImageUrls.join(",")); // Success
|
||||
} 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.
|
||||
// This could happen if item_list is empty or items don't have video_url.
|
||||
await imagesTaskCache.finishTask(task_id, -2); // Failure
|
||||
throw new APIException(EX.API_IMAGE_GENERATION_FAILED, "图片生成未返回有效链接");
|
||||
await imagesTaskCache.finishTask(task_id, -2, "", errorMessage); // Failure
|
||||
throw new APIException(EX.API_IMAGE_GENERATION_FAILED, errorMessage);
|
||||
}
|
||||
return validImageUrls;
|
||||
}catch (error) {
|
||||
logger.error(`图片生成任务 ${task_id} 异常: ${error.message}`);
|
||||
await imagesTaskCache.finishTask(task_id, -2); // Failure due to exception
|
||||
const errorMessage = error.message || "图片生成过程中发生未知错误";
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@ -224,13 +224,15 @@ export async function generateVideo(
|
||||
}
|
||||
status = result[historyId].status;
|
||||
failCode = result[historyId].fail_code;
|
||||
const fail_msg = result[historyId].fail_msg;
|
||||
item_list = result[historyId].item_list;
|
||||
}
|
||||
if (status === 30) {
|
||||
if (failCode === '2038')
|
||||
if (failCode === '2038' || failCode == '2041') {
|
||||
throw new APIException(EX.API_CONTENT_FILTERED);
|
||||
else
|
||||
} else {
|
||||
throw new APIException(EX.API_VIDEO_GENERATION_FAILED);
|
||||
}
|
||||
}
|
||||
// Assuming success if status is not 30 (failed) and not 20 (pending)
|
||||
// and item_list is populated.
|
||||
@ -246,14 +248,18 @@ export async function generateVideo(
|
||||
if (validVideoUrls.length > 0) {
|
||||
await videoTaskCache.finishTask(task_id, -1, validVideoUrls.join(",")); // Success
|
||||
} else {
|
||||
const errorMessage = "视频生成未返回有效链接";
|
||||
logger.error(`视频生成任务 ${task_id} 异常: ${errorMessage}`);
|
||||
// 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.
|
||||
await videoTaskCache.finishTask(task_id, -2); // Failure
|
||||
throw new APIException(EX.API_VIDEO_GENERATION_FAILED, "视频生成未返回有效链接");
|
||||
await videoTaskCache.finishTask(task_id, -2, "", errorMessage); // Failure
|
||||
throw new APIException(EX.API_VIDEO_GENERATION_FAILED, errorMessage);
|
||||
}
|
||||
return validVideoUrls;
|
||||
} 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
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,20 +28,30 @@ export default {
|
||||
const imagesTaskCache = ImagesTaskCache.getInstance();
|
||||
|
||||
// 使用新的方法获取任务结果并清理缓存
|
||||
let res = imagesTaskCache.getTaskResultAndClear(task_id);
|
||||
let result = imagesTaskCache.getTaskResultAndClear(task_id);
|
||||
|
||||
if (typeof res === 'string') {
|
||||
// 任务已完成,返回TOS地址(已经在finishTask中处理过)
|
||||
if (result && typeof result.status === 'number' && result.status < 0) {
|
||||
// 任务已完成
|
||||
return {
|
||||
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 {
|
||||
// 任务进行中或失败,不清理缓存
|
||||
res = imagesTaskCache.getTaskStatus(task_id);
|
||||
result = imagesTaskCache.getTaskStatus(task_id);
|
||||
return {
|
||||
created: util.unixTimestamp(),
|
||||
data: { task_id, url: "", status: res || 0 },
|
||||
data: {
|
||||
task_id,
|
||||
url: "",
|
||||
status: result?.status || 0,
|
||||
error_message: result?.errorMessage || null
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,20 +28,30 @@ export default {
|
||||
const videoTaskCache = VideoTaskCache.getInstance();
|
||||
|
||||
// 使用新的方法获取任务结果并清理缓存
|
||||
let res = videoTaskCache.getTaskResultAndClear(task_id);
|
||||
let result = videoTaskCache.getTaskResultAndClear(task_id);
|
||||
|
||||
if (typeof res === 'string') {
|
||||
// 任务已完成,返回TOS地址(已经在finishTask中处理过)
|
||||
if (result && typeof result.status === 'number' && result.status < 0) {
|
||||
// 任务已完成
|
||||
return {
|
||||
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 {
|
||||
// 任务进行中或失败,不清理缓存
|
||||
res = videoTaskCache.getTaskStatus(task_id);
|
||||
result = videoTaskCache.getTaskStatus(task_id);
|
||||
return {
|
||||
created: util.unixTimestamp(),
|
||||
data: { task_id, url: "", status: res || 0 },
|
||||
data: {
|
||||
task_id,
|
||||
url: "",
|
||||
status: result?.status || 0,
|
||||
error_message: result?.errorMessage || null
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user