mirror of
https://github.com/ItzCrazyKns/Perplexica.git
synced 2025-06-22 01:38:47 +00:00
Compare commits
6 Commits
v1.10.0-rc
...
44753ae3b2
Author | SHA1 | Date | |
---|---|---|---|
44753ae3b2 | |||
115e6b2a71 | |||
a5c79c92ed | |||
db3cea446e | |||
80ac0c92ba | |||
5ed8fb47aa |
@ -10,23 +10,25 @@ To update Perplexica to the latest version, follow these steps:
|
|||||||
git clone https://github.com/ItzCrazyKns/Perplexica.git
|
git clone https://github.com/ItzCrazyKns/Perplexica.git
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Navigate to the Project Directory.
|
2. Navigate to the project directory.
|
||||||
|
|
||||||
3. Pull latest images from registry.
|
3. Check for changes in the configuration files. If the `sample.config.toml` file contains new fields, delete your existing `config.toml` file, rename `sample.config.toml` to `config.toml`, and update the configuration accordingly.
|
||||||
|
|
||||||
|
4. Pull the latest images from the registry.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker compose pull
|
docker compose pull
|
||||||
```
|
```
|
||||||
|
|
||||||
4. Update and Recreate containers.
|
5. Update and recreate the containers.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker compose up -d
|
docker compose up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
5. Once the command completes running go to http://localhost:3000 and verify the latest changes.
|
6. Once the command completes, go to http://localhost:3000 and verify the latest changes.
|
||||||
|
|
||||||
## For non Docker users
|
## For non-Docker users
|
||||||
|
|
||||||
1. Clone the latest version of Perplexica from GitHub:
|
1. Clone the latest version of Perplexica from GitHub:
|
||||||
|
|
||||||
@ -34,7 +36,14 @@ To update Perplexica to the latest version, follow these steps:
|
|||||||
git clone https://github.com/ItzCrazyKns/Perplexica.git
|
git clone https://github.com/ItzCrazyKns/Perplexica.git
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Navigate to the Project Directory
|
2. Navigate to the project directory.
|
||||||
3. Execute `npm i` in both the `ui` folder and the root directory.
|
|
||||||
4. Once packages are updated, execute `npm run build` in both the `ui` folder and the root directory.
|
3. Check for changes in the configuration files. If the `sample.config.toml` file contains new fields, delete your existing `config.toml` file, rename `sample.config.toml` to `config.toml`, and update the configuration accordingly.
|
||||||
5. Finally, start both the frontend and the backend by running `npm run start` in both the `ui` folder and the root directory.
|
|
||||||
|
4. Execute `npm i` in both the `ui` folder and the root directory.
|
||||||
|
|
||||||
|
5. Once the packages are updated, execute `npm run build` in both the `ui` folder and the root directory.
|
||||||
|
|
||||||
|
6. Finally, start both the frontend and the backend by running `npm run start` in both the `ui` folder and the root directory.
|
||||||
|
|
||||||
|
---
|
||||||
|
@ -85,10 +85,12 @@ router.post('/', async (req, res) => {
|
|||||||
if (body.chatModel?.provider === 'custom_openai') {
|
if (body.chatModel?.provider === 'custom_openai') {
|
||||||
llm = new ChatOpenAI({
|
llm = new ChatOpenAI({
|
||||||
modelName: body.chatModel?.model || getCustomOpenaiModelName(),
|
modelName: body.chatModel?.model || getCustomOpenaiModelName(),
|
||||||
openAIApiKey: body.chatModel?.customOpenAIKey || getCustomOpenaiApiKey(),
|
openAIApiKey:
|
||||||
|
body.chatModel?.customOpenAIKey || getCustomOpenaiApiKey(),
|
||||||
temperature: 0.7,
|
temperature: 0.7,
|
||||||
configuration: {
|
configuration: {
|
||||||
baseURL: body.chatModel?.customOpenAIBaseURL || getCustomOpenaiApiUrl(),
|
baseURL:
|
||||||
|
body.chatModel?.customOpenAIBaseURL || getCustomOpenaiApiUrl(),
|
||||||
},
|
},
|
||||||
}) as unknown as BaseChatModel;
|
}) as unknown as BaseChatModel;
|
||||||
} else if (
|
} else if (
|
||||||
|
@ -223,11 +223,11 @@ const Page = () => {
|
|||||||
setChatModels(data.chatModelProviders || {});
|
setChatModels(data.chatModelProviders || {});
|
||||||
setEmbeddingModels(data.embeddingModelProviders || {});
|
setEmbeddingModels(data.embeddingModelProviders || {});
|
||||||
|
|
||||||
const currentProvider = selectedChatModelProvider;
|
const currentChatProvider = selectedChatModelProvider;
|
||||||
const newProviders = Object.keys(data.chatModelProviders || {});
|
const newChatProviders = Object.keys(data.chatModelProviders || {});
|
||||||
|
|
||||||
if (!currentProvider && newProviders.length > 0) {
|
if (!currentChatProvider && newChatProviders.length > 0) {
|
||||||
const firstProvider = newProviders[0];
|
const firstProvider = newChatProviders[0];
|
||||||
const firstModel = data.chatModelProviders[firstProvider]?.[0]?.name;
|
const firstModel = data.chatModelProviders[firstProvider]?.[0]?.name;
|
||||||
|
|
||||||
if (firstModel) {
|
if (firstModel) {
|
||||||
@ -237,11 +237,11 @@ const Page = () => {
|
|||||||
localStorage.setItem('chatModel', firstModel);
|
localStorage.setItem('chatModel', firstModel);
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
currentProvider &&
|
currentChatProvider &&
|
||||||
(!data.chatModelProviders ||
|
(!data.chatModelProviders ||
|
||||||
!data.chatModelProviders[currentProvider] ||
|
!data.chatModelProviders[currentChatProvider] ||
|
||||||
!Array.isArray(data.chatModelProviders[currentProvider]) ||
|
!Array.isArray(data.chatModelProviders[currentChatProvider]) ||
|
||||||
data.chatModelProviders[currentProvider].length === 0)
|
data.chatModelProviders[currentChatProvider].length === 0)
|
||||||
) {
|
) {
|
||||||
const firstValidProvider = Object.entries(
|
const firstValidProvider = Object.entries(
|
||||||
data.chatModelProviders || {},
|
data.chatModelProviders || {},
|
||||||
@ -267,6 +267,55 @@ const Page = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const currentEmbeddingProvider = selectedEmbeddingModelProvider;
|
||||||
|
const newEmbeddingProviders = Object.keys(
|
||||||
|
data.embeddingModelProviders || {},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!currentEmbeddingProvider && newEmbeddingProviders.length > 0) {
|
||||||
|
const firstProvider = newEmbeddingProviders[0];
|
||||||
|
const firstModel =
|
||||||
|
data.embeddingModelProviders[firstProvider]?.[0]?.name;
|
||||||
|
|
||||||
|
if (firstModel) {
|
||||||
|
setSelectedEmbeddingModelProvider(firstProvider);
|
||||||
|
setSelectedEmbeddingModel(firstModel);
|
||||||
|
localStorage.setItem('embeddingModelProvider', firstProvider);
|
||||||
|
localStorage.setItem('embeddingModel', firstModel);
|
||||||
|
}
|
||||||
|
} else if (
|
||||||
|
currentEmbeddingProvider &&
|
||||||
|
(!data.embeddingModelProviders ||
|
||||||
|
!data.embeddingModelProviders[currentEmbeddingProvider] ||
|
||||||
|
!Array.isArray(
|
||||||
|
data.embeddingModelProviders[currentEmbeddingProvider],
|
||||||
|
) ||
|
||||||
|
data.embeddingModelProviders[currentEmbeddingProvider].length === 0)
|
||||||
|
) {
|
||||||
|
const firstValidProvider = Object.entries(
|
||||||
|
data.embeddingModelProviders || {},
|
||||||
|
).find(
|
||||||
|
([_, models]) => Array.isArray(models) && models.length > 0,
|
||||||
|
)?.[0];
|
||||||
|
|
||||||
|
if (firstValidProvider) {
|
||||||
|
setSelectedEmbeddingModelProvider(firstValidProvider);
|
||||||
|
setSelectedEmbeddingModel(
|
||||||
|
data.embeddingModelProviders[firstValidProvider][0].name,
|
||||||
|
);
|
||||||
|
localStorage.setItem('embeddingModelProvider', firstValidProvider);
|
||||||
|
localStorage.setItem(
|
||||||
|
'embeddingModel',
|
||||||
|
data.embeddingModelProviders[firstValidProvider][0].name,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
setSelectedEmbeddingModelProvider(null);
|
||||||
|
setSelectedEmbeddingModel(null);
|
||||||
|
localStorage.removeItem('embeddingModelProvider');
|
||||||
|
localStorage.removeItem('embeddingModel');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setConfig(data);
|
setConfig(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,6 +327,10 @@ const Page = () => {
|
|||||||
localStorage.setItem('chatModelProvider', value);
|
localStorage.setItem('chatModelProvider', value);
|
||||||
} else if (key === 'chatModel') {
|
} else if (key === 'chatModel') {
|
||||||
localStorage.setItem('chatModel', value);
|
localStorage.setItem('chatModel', value);
|
||||||
|
} else if (key === 'embeddingModelProvider') {
|
||||||
|
localStorage.setItem('embeddingModelProvider', value);
|
||||||
|
} else if (key === 'embeddingModel') {
|
||||||
|
localStorage.setItem('embeddingModel', value);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Failed to save:', err);
|
console.error('Failed to save:', err);
|
||||||
@ -436,7 +489,6 @@ const Page = () => {
|
|||||||
const value = e.target.value;
|
const value = e.target.value;
|
||||||
setSelectedChatModelProvider(value);
|
setSelectedChatModelProvider(value);
|
||||||
saveConfig('chatModelProvider', value);
|
saveConfig('chatModelProvider', value);
|
||||||
// Auto-select first model of new provider
|
|
||||||
const firstModel =
|
const firstModel =
|
||||||
config.chatModelProviders[value]?.[0]?.name;
|
config.chatModelProviders[value]?.[0]?.name;
|
||||||
if (firstModel) {
|
if (firstModel) {
|
||||||
@ -554,6 +606,81 @@ const Page = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{config.embeddingModelProviders && (
|
||||||
|
<div className="flex flex-col space-y-4 mt-4 pt-4 border-t border-light-200 dark:border-dark-200">
|
||||||
|
<div className="flex flex-col space-y-1">
|
||||||
|
<p className="text-black/70 dark:text-white/70 text-sm">
|
||||||
|
Embedding Model Provider
|
||||||
|
</p>
|
||||||
|
<Select
|
||||||
|
value={selectedEmbeddingModelProvider ?? undefined}
|
||||||
|
onChange={(e) => {
|
||||||
|
const value = e.target.value;
|
||||||
|
setSelectedEmbeddingModelProvider(value);
|
||||||
|
saveConfig('embeddingModelProvider', value);
|
||||||
|
const firstModel =
|
||||||
|
config.embeddingModelProviders[value]?.[0]?.name;
|
||||||
|
if (firstModel) {
|
||||||
|
setSelectedEmbeddingModel(firstModel);
|
||||||
|
saveConfig('embeddingModel', firstModel);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
options={Object.keys(config.embeddingModelProviders).map(
|
||||||
|
(provider) => ({
|
||||||
|
value: provider,
|
||||||
|
label:
|
||||||
|
provider.charAt(0).toUpperCase() +
|
||||||
|
provider.slice(1),
|
||||||
|
}),
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{selectedEmbeddingModelProvider && (
|
||||||
|
<div className="flex flex-col space-y-1">
|
||||||
|
<p className="text-black/70 dark:text-white/70 text-sm">
|
||||||
|
Embedding Model
|
||||||
|
</p>
|
||||||
|
<Select
|
||||||
|
value={selectedEmbeddingModel ?? undefined}
|
||||||
|
onChange={(e) => {
|
||||||
|
const value = e.target.value;
|
||||||
|
setSelectedEmbeddingModel(value);
|
||||||
|
saveConfig('embeddingModel', value);
|
||||||
|
}}
|
||||||
|
options={(() => {
|
||||||
|
const embeddingModelProvider =
|
||||||
|
config.embeddingModelProviders[
|
||||||
|
selectedEmbeddingModelProvider
|
||||||
|
];
|
||||||
|
return embeddingModelProvider
|
||||||
|
? embeddingModelProvider.length > 0
|
||||||
|
? embeddingModelProvider.map((model) => ({
|
||||||
|
value: model.name,
|
||||||
|
label: model.displayName,
|
||||||
|
}))
|
||||||
|
: [
|
||||||
|
{
|
||||||
|
value: '',
|
||||||
|
label: 'No models available',
|
||||||
|
disabled: true,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: [
|
||||||
|
{
|
||||||
|
value: '',
|
||||||
|
label:
|
||||||
|
'Invalid provider, please check backend logs',
|
||||||
|
disabled: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
})()}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</SettingsSection>
|
</SettingsSection>
|
||||||
|
|
||||||
<SettingsSection title="API Keys">
|
<SettingsSection title="API Keys">
|
||||||
|
@ -397,6 +397,8 @@ const ChatWindow = ({ id }: { id?: string }) => {
|
|||||||
|
|
||||||
const [isMessagesLoaded, setIsMessagesLoaded] = useState(false);
|
const [isMessagesLoaded, setIsMessagesLoaded] = useState(false);
|
||||||
|
|
||||||
|
const [pendingRewrite, setPendingRewrite] = useState<{ content: string; messageId: string } | null>(null);
|
||||||
|
|
||||||
const [notFound, setNotFound] = useState(false);
|
const [notFound, setNotFound] = useState(false);
|
||||||
|
|
||||||
const [isSettingsOpen, setIsSettingsOpen] = useState(false);
|
const [isSettingsOpen, setIsSettingsOpen] = useState(false);
|
||||||
@ -436,6 +438,12 @@ const ChatWindow = ({ id }: { id?: string }) => {
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const chatHistoryRef = useRef<[string, string][]>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
chatHistoryRef.current = chatHistory;
|
||||||
|
}, [chatHistory]);
|
||||||
|
|
||||||
const messagesRef = useRef<Message[]>([]);
|
const messagesRef = useRef<Message[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -478,7 +486,7 @@ const ChatWindow = ({ id }: { id?: string }) => {
|
|||||||
files: fileIds,
|
files: fileIds,
|
||||||
focusMode: focusMode,
|
focusMode: focusMode,
|
||||||
optimizationMode: optimizationMode,
|
optimizationMode: optimizationMode,
|
||||||
history: [...chatHistory, ['human', message]],
|
history: [...chatHistoryRef.current],
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -604,15 +612,22 @@ const ChatWindow = ({ id }: { id?: string }) => {
|
|||||||
const message = messages[index - 1];
|
const message = messages[index - 1];
|
||||||
|
|
||||||
setMessages((prev) => {
|
setMessages((prev) => {
|
||||||
return [...prev.slice(0, messages.length > 2 ? index - 1 : 0)];
|
return [...prev.slice(0, messages.length >= 2 ? index - 1 : 0)];
|
||||||
});
|
});
|
||||||
setChatHistory((prev) => {
|
setChatHistory((prev) => {
|
||||||
return [...prev.slice(0, messages.length > 2 ? index - 1 : 0)];
|
return [...prev.slice(0, messages.length >= 2 ? index - 1 : 0)];
|
||||||
});
|
});
|
||||||
|
|
||||||
sendMessage(message.content, message.messageId);
|
setPendingRewrite({content: message.content, messageId: message.messageId});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (pendingRewrite) {
|
||||||
|
sendMessage(pendingRewrite.content, pendingRewrite.messageId);
|
||||||
|
setPendingRewrite(null);
|
||||||
|
}
|
||||||
|
}, [pendingRewrite]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isReady && initialMessage && ws?.readyState === 1) {
|
if (isReady && initialMessage && ws?.readyState === 1) {
|
||||||
sendMessage(initialMessage);
|
sendMessage(initialMessage);
|
||||||
|
Reference in New Issue
Block a user