mirror of
https://github.com/ItzCrazyKns/Perplexica.git
synced 2025-06-20 08:48:35 +00:00
Compare commits
8 Commits
v1.10.0-rc
...
ccc26d8fef
Author | SHA1 | Date | |
---|---|---|---|
ccc26d8fef | |||
4d24d73161 | |||
4c73caadf6 | |||
5f0b87f4a9 | |||
115e6b2a71 | |||
a5c79c92ed | |||
db3cea446e | |||
adf8f087f2 |
@ -44,7 +44,7 @@ Want to know more about its architecture and how it works? You can read it [here
|
||||
- **Normal Mode:** Processes your query and performs a web search.
|
||||
- **Focus Modes:** Special modes to better answer specific types of questions. Perplexica currently has 6 focus modes:
|
||||
- **All Mode:** Searches the entire web to find the best results.
|
||||
- **Writing Assistant Mode:** Helpful for writing tasks that does not require searching the web.
|
||||
- **Writing Assistant Mode:** Helpful for writing tasks that do not require searching the web.
|
||||
- **Academic Search Mode:** Finds articles and papers, ideal for academic research.
|
||||
- **YouTube Search Mode:** Finds YouTube videos based on the search query.
|
||||
- **Wolfram Alpha Search Mode:** Answers queries that need calculations or data analysis using Wolfram Alpha.
|
||||
|
@ -7,34 +7,43 @@ To update Perplexica to the latest version, follow these steps:
|
||||
1. Clone the latest version of Perplexica from GitHub:
|
||||
|
||||
```bash
|
||||
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
|
||||
docker compose pull
|
||||
```
|
||||
|
||||
4. Update and Recreate containers.
|
||||
5. Update and recreate the containers.
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/ItzCrazyKns/Perplexica.git
|
||||
git clone https://github.com/ItzCrazyKns/Perplexica.git
|
||||
```
|
||||
|
||||
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.
|
||||
5. Finally, start both the frontend and the backend by running `npm run start` in both the `ui` folder and the root directory.
|
||||
2. Navigate to the project 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.
|
||||
|
||||
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.
|
||||
|
||||
---
|
||||
|
@ -1,5 +1,6 @@
|
||||
export const webSearchRetrieverPrompt = `
|
||||
You are an AI question rephraser. You will be given a conversation and a follow-up question, you will have to rephrase the follow up question so it is a standalone question and can be used by another LLM to search the web for information to answer it.
|
||||
If you receive a question in a language other than English and it is related to the region, culture, or customs associated with that language, process the question in the original language. Otherwise, translate it into English and proceed with the following instructions.
|
||||
If it is a smple writing task or a greeting (unless the greeting contains a question after it) like Hi, Hello, How are you, etc. than a question then you need to return \`not_needed\` as the response (This is because the LLM won't need to search the web for finding information on this topic).
|
||||
If the user asks some question from some URL or wants you to summarize a PDF or a webpage (via URL) you need to return the links inside the \`links\` XML block and the question inside the \`question\` XML block. If the user wants to you to summarize the webpage or the PDF you need to return \`summarize\` inside the \`question\` XML block in place of a question and the link to summarize in the \`links\` XML block.
|
||||
You must always return the rephrased question inside the \`question\` XML block, if there are no links in the follow-up question then don't insert a \`links\` XML block in your response.
|
||||
|
@ -85,10 +85,12 @@ router.post('/', async (req, res) => {
|
||||
if (body.chatModel?.provider === 'custom_openai') {
|
||||
llm = new ChatOpenAI({
|
||||
modelName: body.chatModel?.model || getCustomOpenaiModelName(),
|
||||
openAIApiKey: body.chatModel?.customOpenAIKey || getCustomOpenaiApiKey(),
|
||||
openAIApiKey:
|
||||
body.chatModel?.customOpenAIKey || getCustomOpenaiApiKey(),
|
||||
temperature: 0.7,
|
||||
configuration: {
|
||||
baseURL: body.chatModel?.customOpenAIBaseURL || getCustomOpenaiApiUrl(),
|
||||
baseURL:
|
||||
body.chatModel?.customOpenAIBaseURL || getCustomOpenaiApiUrl(),
|
||||
},
|
||||
}) as unknown as BaseChatModel;
|
||||
} else if (
|
||||
|
@ -223,11 +223,11 @@ const Page = () => {
|
||||
setChatModels(data.chatModelProviders || {});
|
||||
setEmbeddingModels(data.embeddingModelProviders || {});
|
||||
|
||||
const currentProvider = selectedChatModelProvider;
|
||||
const newProviders = Object.keys(data.chatModelProviders || {});
|
||||
const currentChatProvider = selectedChatModelProvider;
|
||||
const newChatProviders = Object.keys(data.chatModelProviders || {});
|
||||
|
||||
if (!currentProvider && newProviders.length > 0) {
|
||||
const firstProvider = newProviders[0];
|
||||
if (!currentChatProvider && newChatProviders.length > 0) {
|
||||
const firstProvider = newChatProviders[0];
|
||||
const firstModel = data.chatModelProviders[firstProvider]?.[0]?.name;
|
||||
|
||||
if (firstModel) {
|
||||
@ -237,11 +237,11 @@ const Page = () => {
|
||||
localStorage.setItem('chatModel', firstModel);
|
||||
}
|
||||
} else if (
|
||||
currentProvider &&
|
||||
currentChatProvider &&
|
||||
(!data.chatModelProviders ||
|
||||
!data.chatModelProviders[currentProvider] ||
|
||||
!Array.isArray(data.chatModelProviders[currentProvider]) ||
|
||||
data.chatModelProviders[currentProvider].length === 0)
|
||||
!data.chatModelProviders[currentChatProvider] ||
|
||||
!Array.isArray(data.chatModelProviders[currentChatProvider]) ||
|
||||
data.chatModelProviders[currentChatProvider].length === 0)
|
||||
) {
|
||||
const firstValidProvider = Object.entries(
|
||||
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);
|
||||
}
|
||||
|
||||
@ -278,6 +327,10 @@ const Page = () => {
|
||||
localStorage.setItem('chatModelProvider', value);
|
||||
} else if (key === 'chatModel') {
|
||||
localStorage.setItem('chatModel', value);
|
||||
} else if (key === 'embeddingModelProvider') {
|
||||
localStorage.setItem('embeddingModelProvider', value);
|
||||
} else if (key === 'embeddingModel') {
|
||||
localStorage.setItem('embeddingModel', value);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Failed to save:', err);
|
||||
@ -436,7 +489,6 @@ const Page = () => {
|
||||
const value = e.target.value;
|
||||
setSelectedChatModelProvider(value);
|
||||
saveConfig('chatModelProvider', value);
|
||||
// Auto-select first model of new provider
|
||||
const firstModel =
|
||||
config.chatModelProviders[value]?.[0]?.name;
|
||||
if (firstModel) {
|
||||
@ -511,12 +563,16 @@ const Page = () => {
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="Model name"
|
||||
defaultValue={config.customOpenaiModelName}
|
||||
onChange={(e) =>
|
||||
setConfig({
|
||||
...config,
|
||||
value={config.customOpenaiModelName}
|
||||
isSaving={savingStates['customOpenaiModelName']}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setConfig((prev) => ({
|
||||
...prev!,
|
||||
customOpenaiModelName: e.target.value,
|
||||
})
|
||||
}));
|
||||
}}
|
||||
onSave={(value) =>
|
||||
saveConfig('customOpenaiModelName', value)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
@ -527,12 +583,16 @@ const Page = () => {
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="Custom OpenAI API Key"
|
||||
defaultValue={config.customOpenaiApiKey}
|
||||
onChange={(e) =>
|
||||
setConfig({
|
||||
...config,
|
||||
value={config.customOpenaiApiKey}
|
||||
isSaving={savingStates['customOpenaiApiKey']}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setConfig((prev) => ({
|
||||
...prev!,
|
||||
customOpenaiApiKey: e.target.value,
|
||||
})
|
||||
}));
|
||||
}}
|
||||
onSave={(value) =>
|
||||
saveConfig('customOpenaiApiKey', value)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
@ -543,17 +603,96 @@ const Page = () => {
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="Custom OpenAI Base URL"
|
||||
defaultValue={config.customOpenaiApiUrl}
|
||||
onChange={(e) =>
|
||||
setConfig({
|
||||
...config,
|
||||
value={config.customOpenaiApiUrl}
|
||||
isSaving={savingStates['customOpenaiApiUrl']}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setConfig((prev) => ({
|
||||
...prev!,
|
||||
customOpenaiApiUrl: e.target.value,
|
||||
})
|
||||
}));
|
||||
}}
|
||||
onSave={(value) =>
|
||||
saveConfig('customOpenaiApiUrl', value)
|
||||
}
|
||||
/>
|
||||
</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 title="API Keys">
|
||||
|
Reference in New Issue
Block a user