Add drag-and-drop functionality for chat attachments and update message sending logic
This commit is contained in:
76
src/App.jsx
76
src/App.jsx
@@ -1457,9 +1457,52 @@ async function regenerateFromIndex(index, overrideUserText = null) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleChatDragEnter = (event) => {
|
||||||
|
if (activeSidebarMode !== 'chats' || !hasFilePayload(event)) return
|
||||||
|
event.preventDefault()
|
||||||
|
imageDragDepthRef.current += 1
|
||||||
|
if (selectedModelSupportsVision && eventHasImageFiles(event)) {
|
||||||
|
setIsChatDragActive(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleChatDragOver = (event) => {
|
||||||
|
if (activeSidebarMode !== 'chats' || !hasFilePayload(event)) return
|
||||||
|
event.preventDefault()
|
||||||
|
event.dataTransfer.dropEffect = selectedModelSupportsVision ? 'copy' : 'none'
|
||||||
|
if (selectedModelSupportsVision && eventHasImageFiles(event) && !isChatDragActive) {
|
||||||
|
setIsChatDragActive(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleChatDragLeave = (event) => {
|
||||||
|
if (activeSidebarMode !== 'chats' || !hasFilePayload(event)) return
|
||||||
|
imageDragDepthRef.current = Math.max(0, imageDragDepthRef.current - 1)
|
||||||
|
if (imageDragDepthRef.current === 0) {
|
||||||
|
setIsChatDragActive(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleChatDrop = async (event) => {
|
||||||
|
if (activeSidebarMode !== 'chats' || !hasFilePayload(event)) return
|
||||||
|
event.preventDefault()
|
||||||
|
imageDragDepthRef.current = 0
|
||||||
|
setIsChatDragActive(false)
|
||||||
|
if (!selectedModelSupportsVision) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
await appendComposerImageFiles(event.dataTransfer?.files)
|
||||||
|
textareaRef.current?.focus()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async function sendMessage() {
|
async function sendMessage() {
|
||||||
if (isSending || !input.trim() || !model) return
|
const trimmedInput = input.trim()
|
||||||
|
if (isSending || (!trimmedInput && composerAttachments.length === 0) || !model) return
|
||||||
|
if (composerAttachments.length > 0 && !selectedModelSupportsVision) {
|
||||||
|
window.alert('The selected model does not support image inputs.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
let targetSessionId = activeSessionId
|
let targetSessionId = activeSessionId
|
||||||
let isNewChat = false
|
let isNewChat = false
|
||||||
@@ -1473,7 +1516,13 @@ async function sendMessage() {
|
|||||||
isNewChat = currentSession && currentSession.name === "New Chat" && currentSession.messages.length === 0
|
isNewChat = currentSession && currentSession.name === "New Chat" && currentSession.messages.length === 0
|
||||||
}
|
}
|
||||||
|
|
||||||
const userMsg = { role: 'user', content: input.trim(), id: `msg-${Date.now()}-${Math.random()}` }
|
const outgoingAttachments = composerAttachments.map(({ id, ...attachment }) => ({ ...attachment }))
|
||||||
|
const userMsg = {
|
||||||
|
role: 'user',
|
||||||
|
content: trimmedInput,
|
||||||
|
attachments: outgoingAttachments,
|
||||||
|
id: `msg-${Date.now()}-${Math.random()}`
|
||||||
|
}
|
||||||
justSentMessage.current = true
|
justSentMessage.current = true
|
||||||
lastSentSessionRef.current = targetSessionId
|
lastSentSessionRef.current = targetSessionId
|
||||||
setUserScrolledUp(targetSessionId, false)
|
setUserScrolledUp(targetSessionId, false)
|
||||||
@@ -1491,25 +1540,26 @@ async function sendMessage() {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
setInput('')
|
setInput('')
|
||||||
|
setComposerAttachments([])
|
||||||
})
|
})
|
||||||
requestAnimationFrame(() => scrollToBottom('auto', targetSessionId))
|
requestAnimationFrame(() => scrollToBottom('auto', targetSessionId))
|
||||||
|
|
||||||
const requestController = beginCancelableRequest(targetSessionId)
|
const requestController = beginCancelableRequest(targetSessionId)
|
||||||
try {
|
try {
|
||||||
let historyForSearch = []
|
let historyForSearch = []
|
||||||
try {
|
if (userMsg.content) try {
|
||||||
const existing = (chatSessions.find(s => s.session_id === targetSessionId)?.messages) || []
|
const existing = (chatSessions.find(s => s.session_id === targetSessionId)?.messages) || []
|
||||||
const lastFew = existing.slice(-8).map(m => ({ role: m.role, content: m.content || '' }))
|
const lastFew = existing.slice(-8).map(m => ({ role: m.role, content: m.content || '' }))
|
||||||
historyForSearch = [...lastFew, { role: 'user', content: userMsg.content }]
|
historyForSearch = [...lastFew, { role: 'user', content: userMsg.content }]
|
||||||
} catch {}
|
} catch {}
|
||||||
|
|
||||||
let enrichedPrompt = userMsg.content
|
let enrichedPrompt = userMsg.content || null
|
||||||
let citationSources = []
|
let citationSources = []
|
||||||
const contextBlocks = []
|
const contextBlocks = []
|
||||||
|
|
||||||
const selectedLibrary = getChatLibraryForSession(targetSessionId)
|
const selectedLibrary = getChatLibraryForSession(targetSessionId)
|
||||||
|
|
||||||
if (selectedLibrary?.states?.is_indexed) {
|
if (userMsg.content && selectedLibrary?.states?.is_indexed) {
|
||||||
try {
|
try {
|
||||||
const localContext = await fetchLocalLibraryContext(selectedLibrary.slug, userMsg.content, requestController.signal)
|
const localContext = await fetchLocalLibraryContext(selectedLibrary.slug, userMsg.content, requestController.signal)
|
||||||
if (localContext.contextBlock) {
|
if (localContext.contextBlock) {
|
||||||
@@ -1524,7 +1574,7 @@ async function sendMessage() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (webSearchEnabled) {
|
if (userMsg.content && webSearchEnabled) {
|
||||||
try {
|
try {
|
||||||
const resp = await fetch(`${backendApiUrl}/websearch`, {
|
const resp = await fetch(`${backendApiUrl}/websearch`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -1553,7 +1603,7 @@ async function sendMessage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
citationSources = [...new Set(citationSources)]
|
citationSources = [...new Set(citationSources)]
|
||||||
if (contextBlocks.length > 0) {
|
if (userMsg.content && contextBlocks.length > 0) {
|
||||||
enrichedPrompt = `${userMsg.content}\n\n${contextBlocks.join('\n\n')}`
|
enrichedPrompt = `${userMsg.content}\n\n${contextBlocks.join('\n\n')}`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1578,9 +1628,10 @@ async function sendMessage() {
|
|||||||
session_id: targetSessionId,
|
session_id: targetSessionId,
|
||||||
model,
|
model,
|
||||||
message: userMsg.content,
|
message: userMsg.content,
|
||||||
enriched_message: contextBlocks.length > 0 ? enrichedPrompt : null,
|
enriched_message: userMsg.content && contextBlocks.length > 0 ? enrichedPrompt : null,
|
||||||
stream: true,
|
stream: true,
|
||||||
sources: citationSources || []
|
sources: citationSources || [],
|
||||||
|
attachments: outgoingAttachments,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
if (!res.ok) throw new Error(`HTTP ${res.status}`)
|
if (!res.ok) throw new Error(`HTTP ${res.status}`)
|
||||||
@@ -1641,9 +1692,10 @@ async function sendMessage() {
|
|||||||
session_id: targetSessionId,
|
session_id: targetSessionId,
|
||||||
model,
|
model,
|
||||||
message: userMsg.content,
|
message: userMsg.content,
|
||||||
enriched_message: contextBlocks.length > 0 ? enrichedPrompt : null,
|
enriched_message: userMsg.content && contextBlocks.length > 0 ? enrichedPrompt : null,
|
||||||
stream: false,
|
stream: false,
|
||||||
sources: citationSources || []
|
sources: citationSources || [],
|
||||||
|
attachments: outgoingAttachments,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
if (!res.ok) throw new Error(`HTTP ${res.status}`)
|
if (!res.ok) throw new Error(`HTTP ${res.status}`)
|
||||||
@@ -1688,7 +1740,7 @@ async function sendMessage() {
|
|||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
session_id: targetSessionId,
|
session_id: targetSessionId,
|
||||||
message: userMsg.content,
|
message: userMsg.content || (outgoingAttachments.length > 0 ? 'Image attachment' : userMsg.content),
|
||||||
model
|
model
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user