feat: DeepSeek 选择时禁止上传图片附件
DeepSeek 不支持多模态,前端层面阻止用户选择图片文件: - ChatInput 根据 provider 动态控制 accept 属性(DeepSeek不包含image/*) - addFiles 中过滤图片文件(DeepSeek自动跳过) - Paperclip 按钮 Tooltip 区分提示 - provider 切换后即时生效(通过 useAgentStore 响应式读取)
This commit is contained in:
@@ -46,6 +46,10 @@ export function ChatInput(): React.JSX.Element {
|
|||||||
const isStreaming = useAgentStore((s) => s.isStreaming);
|
const isStreaming = useAgentStore((s) => s.isStreaming);
|
||||||
const tokenUsage = useAgentStore((s) => s.tokenUsage);
|
const tokenUsage = useAgentStore((s) => s.tokenUsage);
|
||||||
const currentSessionId = useSessionStore((s) => s.currentSessionId);
|
const currentSessionId = useSessionStore((s) => s.currentSessionId);
|
||||||
|
const provider = useAgentStore((s) => s.provider);
|
||||||
|
|
||||||
|
/** DeepSeek 不支持多模态图片 */
|
||||||
|
const supportsImages = provider !== 'deepseek';
|
||||||
|
|
||||||
// 草稿自动保存
|
// 草稿自动保存
|
||||||
useEffect(() => { if (currentSessionId) { const d = sessionStorage.getItem(`draft-${currentSessionId}`); setInput(d ?? ''); } }, [currentSessionId]);
|
useEffect(() => { if (currentSessionId) { const d = sessionStorage.getItem(`draft-${currentSessionId}`); setInput(d ?? ''); } }, [currentSessionId]);
|
||||||
@@ -85,9 +89,21 @@ export function ChatInput(): React.JSX.Element {
|
|||||||
|
|
||||||
const addFiles = useCallback(async (files: FileList | File[]) => {
|
const addFiles = useCallback(async (files: FileList | File[]) => {
|
||||||
const fileArray = Array.from(files).slice(0, 5); // 最多 5 个附件
|
const fileArray = Array.from(files).slice(0, 5); // 最多 5 个附件
|
||||||
const newAttachments = await Promise.all(fileArray.map(processFile));
|
|
||||||
|
// DeepSeek 不支持多模态,过滤图片
|
||||||
|
const filtered = supportsImages
|
||||||
|
? fileArray
|
||||||
|
: fileArray.filter((f) => !IMAGE_TYPES.includes(f.type));
|
||||||
|
|
||||||
|
if (filtered.length < fileArray.length && !supportsImages) {
|
||||||
|
// TODO: 用 Toast 提示用户 "DeepSeek 不支持图片,已自动跳过 N 个图片文件"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filtered.length === 0) return;
|
||||||
|
|
||||||
|
const newAttachments = await Promise.all(filtered.map(processFile));
|
||||||
setAttachments((prev) => [...prev, ...newAttachments]);
|
setAttachments((prev) => [...prev, ...newAttachments]);
|
||||||
}, [processFile]);
|
}, [processFile, supportsImages]);
|
||||||
|
|
||||||
const removeAttachment = useCallback((id: string) => {
|
const removeAttachment = useCallback((id: string) => {
|
||||||
setAttachments((prev) => prev.filter((a) => a.id !== id));
|
setAttachments((prev) => prev.filter((a) => a.id !== id));
|
||||||
@@ -224,7 +240,7 @@ export function ChatInput(): React.JSX.Element {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<input ref={fileInputRef} type="file" multiple accept="image/*,.txt,.md,.json,.csv,.ts,.tsx,.js,.jsx,.py,.rb,.go,.rs,.java,.c,.cpp,.h,.css,.html,.xml,.yaml,.yml,.toml,.ini,.sh,.sql,.log,.pdf" style={{ display: 'none' }} onChange={handleFileChange} />
|
<input ref={fileInputRef} type="file" multiple accept={supportsImages ? 'image/*,.txt,.md,.json,.csv,.ts,.tsx,.js,.jsx,.py,.rb,.go,.rs,.java,.c,.cpp,.h,.css,.html,.xml,.yaml,.yml,.toml,.ini,.sh,.sql,.log,.pdf' : '.txt,.md,.json,.csv,.ts,.tsx,.js,.jsx,.py,.rb,.go,.rs,.java,.c,.cpp,.h,.css,.html,.xml,.yaml,.yml,.toml,.ini,.sh,.sql,.log,.pdf'} style={{ display: 'none' }} onChange={handleFileChange} />
|
||||||
|
|
||||||
<textarea
|
<textarea
|
||||||
ref={textareaRef} data-chat-input value={input} onChange={handleChange} onKeyDown={handleKeyDown}
|
ref={textareaRef} data-chat-input value={input} onChange={handleChange} onKeyDown={handleKeyDown}
|
||||||
@@ -236,7 +252,7 @@ export function ChatInput(): React.JSX.Element {
|
|||||||
|
|
||||||
<Stack direction="row" justifyContent="space-between" alignItems="center" sx={{ mt: 1, minHeight: 32 }}>
|
<Stack direction="row" justifyContent="space-between" alignItems="center" sx={{ mt: 1, minHeight: 32 }}>
|
||||||
{/* 左侧:附件按钮 */}
|
{/* 左侧:附件按钮 */}
|
||||||
<Tooltip title="附加文件(图片/文本/代码)">
|
<Tooltip title={supportsImages ? '附加文件(图片/文本/代码)' : '附加文件(文本/代码)— DeepSeek 不支持图片'}>
|
||||||
<IconButton size="small" sx={{ color: 'text.secondary' }} onClick={handleFileSelect}>
|
<IconButton size="small" sx={{ color: 'text.secondary' }} onClick={handleFileSelect}>
|
||||||
<Paperclip size={14} />
|
<Paperclip size={14} />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
|||||||
Reference in New Issue
Block a user