> = {
error_unavailable: 'Service temporarily unavailable',
error_unknown: 'Unknown request error',
error_send: 'Failed to send, please try again',
+ error_upload_failed: 'Image upload failed, please try again',
error_stream_unsupported: 'Browser does not support streaming',
},
};
diff --git a/client/src/index.ts b/client/src/index.ts
index 2116a4d..7cb9732 100644
--- a/client/src/index.ts
+++ b/client/src/index.ts
@@ -28,6 +28,7 @@ export type {
SDKConfig,
ResolvedConfig,
ChatMessage,
+ ImageAttachment,
RagSource,
CategoryNode,
ChatbotSDKInstance,
diff --git a/client/src/types.ts b/client/src/types.ts
index 43cc94c..6fc6d1f 100644
--- a/client/src/types.ts
+++ b/client/src/types.ts
@@ -83,6 +83,10 @@ export interface SDKConfig {
/** 是否输出调试日志,默认 true */
debug?: boolean;
+ // === 图片上传配置 ===
+ /** 是否允许上传图片参与对话,默认 true */
+ allowImageUpload?: boolean;
+
// === 通知配置 ===
/** 弹窗关闭时收到新消息是否播放提示音,默认 false */
sound?: boolean;
@@ -168,6 +172,20 @@ export interface ResolvedConfig {
onMessage?: (msg: ChatMessage) => void;
/** 当前对话 ID(自动管理,从 /conversation/list 获取或自动生成) */
chatId: string;
+ /** 是否允许上传图片参与对话 */
+ allowImageUpload: boolean;
+}
+
+/** 图片附件 */
+export interface ImageAttachment {
+ /** 文件名 */
+ name: string;
+ /** 可访问的 URL */
+ url: string;
+ /** MIME 类型 */
+ mimeType?: string;
+ /** 文件大小(字节) */
+ size?: number;
}
/** 聊天消息 */
@@ -180,6 +198,8 @@ export interface ChatMessage {
content: string;
/** 时间戳(毫秒) */
timestamp: number;
+ /** 可选:用户消息携带的图片 */
+ images?: ImageAttachment[];
/** 可选:RAG 引用来源 */
sources?: RagSource[];
/** 可选:用户反馈 'up' | 'down',预留后端对接位 */
diff --git a/src/main/java/com/wok/supportbot/controller/AttachmentController.java b/src/main/java/com/wok/supportbot/controller/AttachmentController.java
index 2b09ce1..fa8a21c 100644
--- a/src/main/java/com/wok/supportbot/controller/AttachmentController.java
+++ b/src/main/java/com/wok/supportbot/controller/AttachmentController.java
@@ -3,7 +3,6 @@ package com.wok.supportbot.controller;
import com.wok.supportbot.config.StorageProperties;
import com.wok.supportbot.service.SftpStorageService;
import org.springframework.http.ResponseEntity;
-import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@@ -35,11 +34,14 @@ public class AttachmentController {
/**
* 上传图片/附件
*
+ * 鉴权由 {@code SdkAuthFilter} 承担(拦截 /attachment/upload,验证 SDK JWT 或管理后台 JWT),
+ * 与 /ai/** 接口一致,方法层不再叠加 @PreAuthorize(否则 SDK Token 会被 JwtAuthFilter 用管理后台
+ * 密钥重复验证失败,导致 isAuthenticated() 判定为未认证)。
+ *
* @param file 上传的文件
* @return 上传结果:data 内含 url / name / type / mimeType / size
*/
@PostMapping("/upload")
- @PreAuthorize("isAuthenticated()")
public ResponseEntity