This commit is contained in:
Willie Zutz
2025-02-15 23:09:37 +00:00
committed by GitHub
10 changed files with 137 additions and 2 deletions

View File

@@ -5,6 +5,7 @@ import { getAvailableChatModelProviders } from '../lib/providers';
import { HumanMessage, AIMessage } from '@langchain/core/messages'; import { HumanMessage, AIMessage } from '@langchain/core/messages';
import logger from '../utils/logger'; import logger from '../utils/logger';
import { ChatOpenAI } from '@langchain/openai'; import { ChatOpenAI } from '@langchain/openai';
import { ChatOllama } from '@langchain/community/chat_models/ollama';
import { import {
getCustomOpenaiApiKey, getCustomOpenaiApiKey,
getCustomOpenaiApiUrl, getCustomOpenaiApiUrl,
@@ -16,6 +17,7 @@ const router = express.Router();
interface ChatModel { interface ChatModel {
provider: string; provider: string;
model: string; model: string;
ollamaContextWindow?: number;
} }
interface ImageSearchBody { interface ImageSearchBody {
@@ -61,6 +63,10 @@ router.post('/', async (req, res) => {
) { ) {
llm = chatModelProviders[chatModelProvider][chatModel] llm = chatModelProviders[chatModelProvider][chatModel]
.model as unknown as BaseChatModel | undefined; .model as unknown as BaseChatModel | undefined;
if (llm instanceof ChatOllama) {
llm.numCtx = body.chatModel?.ollamaContextWindow || 2048;
}
} }
if (!llm) { if (!llm) {

View File

@@ -15,12 +15,14 @@ import {
getCustomOpenaiApiUrl, getCustomOpenaiApiUrl,
getCustomOpenaiModelName, getCustomOpenaiModelName,
} from '../config'; } from '../config';
import { ChatOllama } from '@langchain/community/chat_models/ollama';
const router = express.Router(); const router = express.Router();
interface chatModel { interface chatModel {
provider: string; provider: string;
model: string; model: string;
ollamaContextWindow?: number;
customOpenAIKey?: string; customOpenAIKey?: string;
customOpenAIBaseURL?: string; customOpenAIBaseURL?: string;
} }
@@ -78,6 +80,7 @@ router.post('/', async (req, res) => {
const embeddingModel = const embeddingModel =
body.embeddingModel?.model || body.embeddingModel?.model ||
Object.keys(embeddingModelProviders[embeddingModelProvider])[0]; Object.keys(embeddingModelProviders[embeddingModelProvider])[0];
const ollamaContextWindow = body.chatModel?.ollamaContextWindow || 2048;
let llm: BaseChatModel | undefined; let llm: BaseChatModel | undefined;
let embeddings: Embeddings | undefined; let embeddings: Embeddings | undefined;
@@ -99,6 +102,9 @@ router.post('/', async (req, res) => {
) { ) {
llm = chatModelProviders[chatModelProvider][chatModel] llm = chatModelProviders[chatModelProvider][chatModel]
.model as unknown as BaseChatModel | undefined; .model as unknown as BaseChatModel | undefined;
if (llm instanceof ChatOllama) {
llm.numCtx = ollamaContextWindow;
}
} }
if ( if (

View File

@@ -10,12 +10,14 @@ import {
getCustomOpenaiApiUrl, getCustomOpenaiApiUrl,
getCustomOpenaiModelName, getCustomOpenaiModelName,
} from '../config'; } from '../config';
import { ChatOllama } from '@langchain/community/chat_models/ollama';
const router = express.Router(); const router = express.Router();
interface ChatModel { interface ChatModel {
provider: string; provider: string;
model: string; model: string;
ollamaContextWindow?: number;
} }
interface SuggestionsBody { interface SuggestionsBody {
@@ -60,6 +62,9 @@ router.post('/', async (req, res) => {
) { ) {
llm = chatModelProviders[chatModelProvider][chatModel] llm = chatModelProviders[chatModelProvider][chatModel]
.model as unknown as BaseChatModel | undefined; .model as unknown as BaseChatModel | undefined;
if (llm instanceof ChatOllama) {
llm.numCtx = body.chatModel?.ollamaContextWindow || 2048;
}
} }
if (!llm) { if (!llm) {

View File

@@ -10,12 +10,14 @@ import {
getCustomOpenaiApiUrl, getCustomOpenaiApiUrl,
getCustomOpenaiModelName, getCustomOpenaiModelName,
} from '../config'; } from '../config';
import { ChatOllama } from '@langchain/community/chat_models/ollama';
const router = express.Router(); const router = express.Router();
interface ChatModel { interface ChatModel {
provider: string; provider: string;
model: string; model: string;
ollamaContextWindow?: number;
} }
interface VideoSearchBody { interface VideoSearchBody {
@@ -61,6 +63,10 @@ router.post('/', async (req, res) => {
) { ) {
llm = chatModelProviders[chatModelProvider][chatModel] llm = chatModelProviders[chatModelProvider][chatModel]
.model as unknown as BaseChatModel | undefined; .model as unknown as BaseChatModel | undefined;
if (llm instanceof ChatOllama) {
llm.numCtx = body.chatModel?.ollamaContextWindow || 2048;
}
} }
if (!llm) { if (!llm) {

View File

@@ -14,6 +14,7 @@ import {
getCustomOpenaiApiUrl, getCustomOpenaiApiUrl,
getCustomOpenaiModelName, getCustomOpenaiModelName,
} from '../config'; } from '../config';
import { ChatOllama } from '@langchain/community/chat_models/ollama';
export const handleConnection = async ( export const handleConnection = async (
ws: WebSocket, ws: WebSocket,
@@ -42,6 +43,8 @@ export const handleConnection = async (
searchParams.get('embeddingModel') || searchParams.get('embeddingModel') ||
Object.keys(embeddingModelProviders[embeddingModelProvider])[0]; Object.keys(embeddingModelProviders[embeddingModelProvider])[0];
const ollamaContextWindow = searchParams.get('ollamaContextWindow');
let llm: BaseChatModel | undefined; let llm: BaseChatModel | undefined;
let embeddings: Embeddings | undefined; let embeddings: Embeddings | undefined;
@@ -52,6 +55,9 @@ export const handleConnection = async (
) { ) {
llm = chatModelProviders[chatModelProvider][chatModel] llm = chatModelProviders[chatModelProvider][chatModel]
.model as unknown as BaseChatModel | undefined; .model as unknown as BaseChatModel | undefined;
if (llm instanceof ChatOllama) {
llm.numCtx = ollamaContextWindow ? parseInt(ollamaContextWindow) : 2048;
}
} else if (chatModelProvider == 'custom_openai') { } else if (chatModelProvider == 'custom_openai') {
const customOpenaiApiKey = getCustomOpenaiApiKey(); const customOpenaiApiKey = getCustomOpenaiApiKey();
const customOpenaiApiUrl = getCustomOpenaiApiUrl(); const customOpenaiApiUrl = getCustomOpenaiApiUrl();

View File

@@ -23,6 +23,7 @@ interface SettingsType {
customOpenaiApiKey: string; customOpenaiApiKey: string;
customOpenaiApiUrl: string; customOpenaiApiUrl: string;
customOpenaiModelName: string; customOpenaiModelName: string;
ollamaContextWindow: number;
} }
interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> { interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
@@ -112,6 +113,11 @@ const Page = () => {
const [automaticImageSearch, setAutomaticImageSearch] = useState(false); const [automaticImageSearch, setAutomaticImageSearch] = useState(false);
const [automaticVideoSearch, setAutomaticVideoSearch] = useState(false); const [automaticVideoSearch, setAutomaticVideoSearch] = useState(false);
const [savingStates, setSavingStates] = useState<Record<string, boolean>>({}); const [savingStates, setSavingStates] = useState<Record<string, boolean>>({});
const [contextWindowSize, setContextWindowSize] = useState(2048);
const [isCustomContextWindow, setIsCustomContextWindow] = useState(false);
const predefinedContextSizes = [
1024, 2048, 3072, 4096, 8192, 16384, 32768, 65536, 131072,
];
useEffect(() => { useEffect(() => {
const fetchConfig = async () => { const fetchConfig = async () => {
@@ -123,6 +129,7 @@ const Page = () => {
}); });
const data = (await res.json()) as SettingsType; const data = (await res.json()) as SettingsType;
setConfig(data); setConfig(data);
const chatModelProvidersKeys = Object.keys(data.chatModelProviders || {}); const chatModelProvidersKeys = Object.keys(data.chatModelProviders || {});
@@ -171,6 +178,13 @@ const Page = () => {
setAutomaticVideoSearch( setAutomaticVideoSearch(
localStorage.getItem('autoVideoSearch') === 'true', localStorage.getItem('autoVideoSearch') === 'true',
); );
const storedContextWindow = parseInt(
localStorage.getItem('ollamaContextWindow') ?? '2048',
);
setContextWindowSize(storedContextWindow);
setIsCustomContextWindow(
!predefinedContextSizes.includes(storedContextWindow),
);
setIsLoading(false); setIsLoading(false);
}; };
@@ -331,6 +345,8 @@ const Page = () => {
localStorage.setItem('embeddingModelProvider', value); localStorage.setItem('embeddingModelProvider', value);
} else if (key === 'embeddingModel') { } else if (key === 'embeddingModel') {
localStorage.setItem('embeddingModel', value); localStorage.setItem('embeddingModel', value);
} else if (key === 'ollamaContextWindow') {
localStorage.setItem('ollamaContextWindow', value.toString());
} }
} catch (err) { } catch (err) {
console.error('Failed to save:', err); console.error('Failed to save:', err);
@@ -548,6 +564,78 @@ const Page = () => {
]; ];
})()} })()}
/> />
{selectedChatModelProvider === 'ollama' && (
<div className="flex flex-col space-y-1">
<p className="text-black/70 dark:text-white/70 text-sm">
Chat Context Window Size
</p>
<Select
value={
isCustomContextWindow
? 'custom'
: contextWindowSize.toString()
}
onChange={(e) => {
const value = e.target.value;
if (value === 'custom') {
setIsCustomContextWindow(true);
} else {
setIsCustomContextWindow(false);
const numValue = parseInt(value);
setContextWindowSize(numValue);
setConfig((prev) => ({
...prev!,
ollamaContextWindow: numValue,
}));
saveConfig('ollamaContextWindow', numValue);
}
}}
options={[
...predefinedContextSizes.map((size) => ({
value: size.toString(),
label: `${size.toLocaleString()} tokens`,
})),
{ value: 'custom', label: 'Custom...' },
]}
/>
{isCustomContextWindow && (
<div className="mt-2">
<Input
type="number"
min={512}
value={contextWindowSize}
placeholder="Custom context window size (minimum 512)"
isSaving={savingStates['ollamaContextWindow']}
onChange={(e) => {
// Allow any value to be typed
const value =
parseInt(e.target.value) ||
contextWindowSize;
setContextWindowSize(value);
}}
onSave={(value) => {
// Validate only when saving
const numValue = Math.max(
512,
parseInt(value) || 2048,
);
setContextWindowSize(numValue);
setConfig((prev) => ({
...prev!,
ollamaContextWindow: numValue,
}));
saveConfig('ollamaContextWindow', numValue);
}}
/>
</div>
)}
<p className="text-xs text-black/60 dark:text-white/60 mt-0.5">
{isCustomContextWindow
? 'Adjust the context window size for Ollama models (minimum 512 tokens)'
: 'Adjust the context window size for Ollama models'}
</p>
</div>
)}
</div> </div>
)} )}
</div> </div>

View File

@@ -197,6 +197,11 @@ const useSocket = (
'openAIBaseURL', 'openAIBaseURL',
localStorage.getItem('openAIBaseURL')!, localStorage.getItem('openAIBaseURL')!,
); );
} else {
searchParams.append(
'ollamaContextWindow',
localStorage.getItem('ollamaContextWindow') || '2048',
);
} }
searchParams.append('embeddingModel', embeddingModel!); searchParams.append('embeddingModel', embeddingModel!);

View File

@@ -33,9 +33,10 @@ const SearchImages = ({
const chatModelProvider = localStorage.getItem('chatModelProvider'); const chatModelProvider = localStorage.getItem('chatModelProvider');
const chatModel = localStorage.getItem('chatModel'); const chatModel = localStorage.getItem('chatModel');
const customOpenAIBaseURL = localStorage.getItem('openAIBaseURL'); const customOpenAIBaseURL = localStorage.getItem('openAIBaseURL');
const customOpenAIKey = localStorage.getItem('openAIApiKey'); const customOpenAIKey = localStorage.getItem('openAIApiKey');
const ollamaContextWindow =
localStorage.getItem('ollamaContextWindow') || '2048';
const res = await fetch( const res = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/images`, `${process.env.NEXT_PUBLIC_API_URL}/images`,
@@ -54,6 +55,9 @@ const SearchImages = ({
customOpenAIBaseURL: customOpenAIBaseURL, customOpenAIBaseURL: customOpenAIBaseURL,
customOpenAIKey: customOpenAIKey, customOpenAIKey: customOpenAIKey,
}), }),
...(chatModelProvider === 'ollama' && {
ollamaContextWindow: parseInt(ollamaContextWindow),
}),
}, },
}), }),
}, },

View File

@@ -48,9 +48,10 @@ const Searchvideos = ({
const chatModelProvider = localStorage.getItem('chatModelProvider'); const chatModelProvider = localStorage.getItem('chatModelProvider');
const chatModel = localStorage.getItem('chatModel'); const chatModel = localStorage.getItem('chatModel');
const customOpenAIBaseURL = localStorage.getItem('openAIBaseURL'); const customOpenAIBaseURL = localStorage.getItem('openAIBaseURL');
const customOpenAIKey = localStorage.getItem('openAIApiKey'); const customOpenAIKey = localStorage.getItem('openAIApiKey');
const ollamaContextWindow =
localStorage.getItem('ollamaContextWindow') || '2048';
const res = await fetch( const res = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/videos`, `${process.env.NEXT_PUBLIC_API_URL}/videos`,
@@ -69,6 +70,9 @@ const Searchvideos = ({
customOpenAIBaseURL: customOpenAIBaseURL, customOpenAIBaseURL: customOpenAIBaseURL,
customOpenAIKey: customOpenAIKey, customOpenAIKey: customOpenAIKey,
}), }),
...(chatModelProvider === 'ollama' && {
ollamaContextWindow: parseInt(ollamaContextWindow),
}),
}, },
}), }),
}, },

View File

@@ -6,6 +6,8 @@ export const getSuggestions = async (chatHisory: Message[]) => {
const customOpenAIKey = localStorage.getItem('openAIApiKey'); const customOpenAIKey = localStorage.getItem('openAIApiKey');
const customOpenAIBaseURL = localStorage.getItem('openAIBaseURL'); const customOpenAIBaseURL = localStorage.getItem('openAIBaseURL');
const ollamaContextWindow =
localStorage.getItem('ollamaContextWindow') || '2048';
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/suggestions`, { const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/suggestions`, {
method: 'POST', method: 'POST',
@@ -21,6 +23,9 @@ export const getSuggestions = async (chatHisory: Message[]) => {
customOpenAIKey, customOpenAIKey,
customOpenAIBaseURL, customOpenAIBaseURL,
}), }),
...(chatModelProvider === 'ollama' && {
ollamaContextWindow: parseInt(ollamaContextWindow),
}),
}, },
}), }),
}); });