Compare commits

..

3 Commits

Author SHA1 Message Date
ItzCrazyKns
3098622cb0 Merge branch 'pr/1082' 2026-03-27 17:53:59 +05:30
ItzCrazyKns
3646495bdf feat(ollama): update reasoning model list 2026-03-27 17:16:57 +05:30
Nick
0e33641927 fix: handle upload errors and reset spinner state 2026-03-26 19:20:24 +00:00
3 changed files with 97 additions and 37 deletions

View File

@@ -18,6 +18,7 @@ import { Fragment, useRef, useState } from 'react';
import { useChat } from '@/lib/hooks/useChat'; import { useChat } from '@/lib/hooks/useChat';
import { AnimatePresence } from 'motion/react'; import { AnimatePresence } from 'motion/react';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import { toast } from 'sonner';
const Attach = () => { const Attach = () => {
const { files, setFiles, setFileIds, fileIds } = useChat(); const { files, setFiles, setFileIds, fileIds } = useChat();
@@ -26,31 +27,59 @@ const Attach = () => {
const fileInputRef = useRef<any>(); const fileInputRef = useRef<any>();
const handleChange = async (e: React.ChangeEvent<HTMLInputElement>) => { const handleChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
setLoading(true); const selectedFiles = e.target.files;
const data = new FormData();
for (let i = 0; i < e.target.files!.length; i++) { if (!selectedFiles?.length) {
data.append('files', e.target.files![i]); return;
} }
const embeddingModelProvider = localStorage.getItem( setLoading(true);
'embeddingModelProviderId',
);
const embeddingModel = localStorage.getItem('embeddingModelKey');
data.append('embedding_model_provider_id', embeddingModelProvider!); try {
data.append('embedding_model_key', embeddingModel!); const data = new FormData();
const res = await fetch(`/api/uploads`, { for (let i = 0; i < selectedFiles.length; i++) {
method: 'POST', data.append('files', selectedFiles[i]);
body: data, }
});
const resData = await res.json(); const embeddingModelProvider = localStorage.getItem(
'embeddingModelProviderId',
);
const embeddingModel = localStorage.getItem('embeddingModelKey');
setFiles([...files, ...resData.files]); if (!embeddingModelProvider || !embeddingModel) {
setFileIds([...fileIds, ...resData.files.map((file: any) => file.fileId)]); throw new Error('Please select an embedding model before uploading.');
setLoading(false); }
data.append('embedding_model_provider_id', embeddingModelProvider);
data.append('embedding_model_key', embeddingModel);
const res = await fetch(`/api/uploads`, {
method: 'POST',
body: data,
});
const resData = await res.json().catch(() => ({}));
if (!res.ok) {
throw new Error(resData.message || 'Failed to upload file(s).');
}
if (!Array.isArray(resData.files)) {
throw new Error('Invalid upload response from server.');
}
setFiles([...files, ...resData.files]);
setFileIds([
...fileIds,
...resData.files.map((file: any) => file.fileId),
]);
} catch (err: any) {
toast(err?.message || 'Failed to upload file(s).');
} finally {
setLoading(false);
e.target.value = '';
}
}; };
return loading ? ( return loading ? (

View File

@@ -9,6 +9,7 @@ import { Fragment, useRef, useState } from 'react';
import { useChat } from '@/lib/hooks/useChat'; import { useChat } from '@/lib/hooks/useChat';
import { AnimatePresence } from 'motion/react'; import { AnimatePresence } from 'motion/react';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import { toast } from 'sonner';
const AttachSmall = () => { const AttachSmall = () => {
const { files, setFiles, setFileIds, fileIds } = useChat(); const { files, setFiles, setFileIds, fileIds } = useChat();
@@ -17,31 +18,59 @@ const AttachSmall = () => {
const fileInputRef = useRef<any>(); const fileInputRef = useRef<any>();
const handleChange = async (e: React.ChangeEvent<HTMLInputElement>) => { const handleChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
setLoading(true); const selectedFiles = e.target.files;
const data = new FormData();
for (let i = 0; i < e.target.files!.length; i++) { if (!selectedFiles?.length) {
data.append('files', e.target.files![i]); return;
} }
const embeddingModelProvider = localStorage.getItem( setLoading(true);
'embeddingModelProviderId',
);
const embeddingModel = localStorage.getItem('embeddingModelKey');
data.append('embedding_model_provider_id', embeddingModelProvider!); try {
data.append('embedding_model_key', embeddingModel!); const data = new FormData();
const res = await fetch(`/api/uploads`, { for (let i = 0; i < selectedFiles.length; i++) {
method: 'POST', data.append('files', selectedFiles[i]);
body: data, }
});
const resData = await res.json(); const embeddingModelProvider = localStorage.getItem(
'embeddingModelProviderId',
);
const embeddingModel = localStorage.getItem('embeddingModelKey');
setFiles([...files, ...resData.files]); if (!embeddingModelProvider || !embeddingModel) {
setFileIds([...fileIds, ...resData.files.map((file: any) => file.fileId)]); throw new Error('Please select an embedding model before uploading.');
setLoading(false); }
data.append('embedding_model_provider_id', embeddingModelProvider);
data.append('embedding_model_key', embeddingModel);
const res = await fetch(`/api/uploads`, {
method: 'POST',
body: data,
});
const resData = await res.json().catch(() => ({}));
if (!res.ok) {
throw new Error(resData.message || 'Failed to upload file(s).');
}
if (!Array.isArray(resData.files)) {
throw new Error('Invalid upload response from server.');
}
setFiles([...files, ...resData.files]);
setFileIds([
...fileIds,
...resData.files.map((file: any) => file.fileId),
]);
} catch (err: any) {
toast(err?.message || 'Failed to upload file(s).');
} finally {
setLoading(false);
e.target.value = '';
}
}; };
return loading ? ( return loading ? (

View File

@@ -25,7 +25,9 @@ const reasoningModels = [
'qwen3', 'qwen3',
'deepseek-v3.1', 'deepseek-v3.1',
'magistral', 'magistral',
'nemotron-3-nano', 'nemotron-3',
'nemotron-cascade-2',
'glm-4.7-flash',
]; ];
class OllamaLLM extends BaseLLM<OllamaConfig> { class OllamaLLM extends BaseLLM<OllamaConfig> {