fix: handle A-Copilot agent responses and image filename encoding

This commit is contained in:
2026-10-19 14:47:21 +09:00
parent 8c051c4bf4
commit 6c70c53b33
9 changed files with 197 additions and 14 deletions
+10 -2
View File
@@ -10,6 +10,14 @@ export type AgentImageScope = { studentId: string; courseId: string; week: numbe
export type AgentImageReference = { token: string; name: string; mimeType: 'image/png'; size: number; url: string };
type ImageClaim = AgentImageScope & { type: 'agent-image'; id: string; name: string; key: string; size: number; sha256: string };
function normalizeImageFileName(fileName: string): string {
if (/^[\u0000-\u00ff]*$/.test(fileName)) {
try { fileName = new TextDecoder('utf-8', { fatal: true }).decode(Buffer.from(fileName, 'latin1')); }
catch { /* Preserve genuine Latin-1 names that are not misdecoded UTF-8. */ }
}
return fileName.replace(/[\\/\u0000-\u001f]/g, '_').slice(0, 255) || 'image.png';
}
export function supportsAgentImages(provider: string, model: string): boolean {
return provider === 'QWEN' && ['qwen3.7-plus', 'qwen3.7-flash', 'qwen3.8-max', 'qwen3.8-flash', 'qwen-vl-plus', 'qwen-vl-max']
.some(id => model === id || model.startsWith(`${id}-`));
@@ -35,7 +43,7 @@ export class AgentImagesService {
}
const id = randomUUID();
const key = this.storage.createLmsAgentImageKey({ courseId: scope.courseId, userId: scope.studentId, imageId: id });
const name = file.originalname.replace(/[\\/\u0000-\u001f]/g, '_').slice(0, 255) || 'image.png';
const name = normalizeImageFileName(file.originalname);
const claim: ImageClaim = { ...scope, type: 'agent-image', id, name, key, size: body.length, sha256: createHash('sha256').update(body).digest('hex') };
const token = this.credentials.encrypt(JSON.stringify(claim));
const url = await this.storage.uploadPublicFile({ key, body, contentType: 'image/png' }).catch(() => { throw new BadGatewayException('첨부 이미지 업로드에 실패했습니다. 잠시 후 다시 전송해주세요.'); });
@@ -61,7 +69,7 @@ export class AgentImagesService {
seen.add(claim.id);
const url = this.storage.publicUrl(claim.key);
if (!url) throw new BadRequestException('첨부 이미지 주소를 찾을 수 없습니다.');
return { token: item.token, name: claim.name, mimeType: 'image/png', size: claim.size, url };
return { token: item.token, name: normalizeImageFileName(claim.name), mimeType: 'image/png', size: claim.size, url };
});
}