Compare commits

...

2 Commits

Author SHA1 Message Date
ItzCrazyKns
cb1d85e458 feat(readme): add volumes 2025-10-21 16:57:57 +05:30
ItzCrazyKns
ce78b4ff62 feat(app): show "add model" button 2025-10-21 16:32:40 +05:30
5 changed files with 109 additions and 99 deletions

View File

@@ -79,19 +79,19 @@ There are mainly 2 ways of installing Perplexica - With Docker, Without Docker.
Perplexica can be easily run using Docker. Simply run the following command: Perplexica can be easily run using Docker. Simply run the following command:
```bash ```bash
docker run -p 3000:3000 --name perplexica itzcrazykns1337/perplexica:latest docker run -d -p 3000:3000 -v perplexica-data:/home/perplexica/data -v perplexica-uploads:/home/perplexica/uploads --name perplexica itzcrazykns1337/perplexica:latest
``` ```
This will pull and start the Perplexica container with the bundled SearxNG search engine. Once running, open your browser and navigate to http://localhost:3000. You can then configure your settings (API keys, models, etc.) directly in the setup screen. This will pull and start the Perplexica container with the bundled SearxNG search engine. Once running, open your browser and navigate to http://localhost:3000. You can then configure your settings (API keys, models, etc.) directly in the setup screen.
**Note**: The image includes both Perplexica and SearxNG, so no additional setup is required. **Note**: The image includes both Perplexica and SearxNG, so no additional setup is required. The `-v` flags create persistent volumes for your data and uploaded files.
#### Using Perplexica with Your Own SearxNG Instance #### Using Perplexica with Your Own SearxNG Instance
If you already have SearxNG running, you can use the slim version of Perplexica: If you already have SearxNG running, you can use the slim version of Perplexica:
```bash ```bash
docker run -p 3000:3000 -e SEARXNG_API_URL=http://your-searxng-url:8080 --name perplexica itzcrazykns1337/perplexica:slim-latest docker run -d -p 3000:3000 -e SEARXNG_API_URL=http://your-searxng-url:8080 -v perplexica-data:/home/perplexica/data -v perplexica-uploads:/home/perplexica/uploads --name perplexica itzcrazykns1337/perplexica:slim-latest
``` ```
**Important**: Make sure your SearxNG instance has: **Important**: Make sure your SearxNG instance has:
@@ -118,7 +118,7 @@ If you prefer to build from source or need more control:
```bash ```bash
docker build -t perplexica . docker build -t perplexica .
docker run -p 3000:3000 --name perplexica perplexica docker run -d -p 3000:3000 -v perplexica-data:/home/perplexica/data -v perplexica-uploads:/home/perplexica/uploads --name perplexica perplexica
``` ```
5. Access Perplexica at http://localhost:3000 and configure your settings in the setup screen. 5. Access Perplexica at http://localhost:3000 and configure your settings in the setup screen.

15
docker-compose.yaml Normal file
View File

@@ -0,0 +1,15 @@
services:
perplexica:
image: itzcrazykns1337/perplexica:latest
ports:
- "3000:3000"
volumes:
- data:/home/perplexica/data
- uploads:/home/perplexica/uploads
restart: unless-stopped
volumes:
data:
name: 'perplexica-data'
uploads:
name: 'perplexica-uploads'

View File

@@ -10,7 +10,7 @@ Simply pull the latest image and restart your container:
docker pull itzcrazykns1337/perplexica:latest docker pull itzcrazykns1337/perplexica:latest
docker stop perplexica docker stop perplexica
docker rm perplexica docker rm perplexica
docker run -p 3000:3000 --name perplexica itzcrazykns1337/perplexica:latest docker run -d -p 3000:3000 -v perplexica-data:/home/perplexica/data -v perplexica-uploads:/home/perplexica/uploads --name perplexica itzcrazykns1337/perplexica:latest
``` ```
For slim version: For slim version:
@@ -19,7 +19,7 @@ For slim version:
docker pull itzcrazykns1337/perplexica:slim-latest docker pull itzcrazykns1337/perplexica:slim-latest
docker stop perplexica docker stop perplexica
docker rm perplexica docker rm perplexica
docker run -p 3000:3000 -e SEARXNG_API_URL=http://your-searxng-url:8080 --name perplexica itzcrazykns1337/perplexica:slim-latest docker run -d -p 3000:3000 -e SEARXNG_API_URL=http://your-searxng-url:8080 -v perplexica-data:/home/perplexica/data -v perplexica-uploads:/home/perplexica/uploads --name perplexica itzcrazykns1337/perplexica:slim-latest
``` ```
Once updated, go to http://localhost:3000 and verify the latest changes. Your settings are preserved automatically. Once updated, go to http://localhost:3000 and verify the latest changes. Your settings are preserved automatically.

View File

@@ -112,100 +112,96 @@ const ModelProvider = ({
> >
<div className="border-t border-light-200 dark:border-dark-200" /> <div className="border-t border-light-200 dark:border-dark-200" />
<div className="flex flex-col gap-y-4 px-5 py-4"> <div className="flex flex-col gap-y-4 px-5 py-4">
{modelProvider.chatModels.length > 0 && ( <div className="flex flex-col gap-y-2">
<div className="flex flex-col gap-y-2"> <div className="flex flex-row w-full justify-between items-center">
<div className="flex flex-row w-full justify-between items-center"> <p className="text-[11px] lg:text-xs text-black/70 dark:text-white/70">
<p className="text-[11px] lg:text-xs text-black/70 dark:text-white/70"> Chat models
Chat models </p>
</p> <AddModel
<AddModel providerId={modelProvider.id}
providerId={modelProvider.id} setProviders={setProviders}
setProviders={setProviders} type="chat"
type="chat" />
/>
</div>
<div className="flex flex-col gap-2">
{modelProvider.chatModels.some((m) => m.key === 'error') ? (
<div className="flex flex-row items-center gap-2 text-xs lg:text-sm text-red-500 dark:text-red-400 rounded-lg bg-red-50 dark:bg-red-950/20 px-3 py-2 border border-red-200 dark:border-red-900/30">
<AlertCircle size={16} className="shrink-0" />
<span className="break-words">
{
modelProvider.chatModels.find(
(m) => m.key === 'error',
)?.name
}
</span>
</div>
) : (
<div className="flex flex-row flex-wrap gap-2">
{modelProvider.chatModels.map((model, index) => (
<div
key={`${modelProvider.id}-chat-${model.key}-${index}`}
className="flex flex-row items-center space-x-1 text-xs lg:text-sm text-black/70 dark:text-white/70 rounded-lg bg-light-secondary dark:bg-dark-secondary px-3 py-1.5"
>
<span>{model.name}</span>
<button
onClick={() => {
handleModelDelete('chat', model.key);
}}
>
<X size={12} />
</button>
</div>
))}
</div>
)}
</div>
</div> </div>
)} <div className="flex flex-col gap-2">
{modelProvider.embeddingModels.length > 0 && ( {modelProvider.chatModels.some((m) => m.key === 'error') ? (
<div className="flex flex-col gap-y-2"> <div className="flex flex-row items-center gap-2 text-xs lg:text-sm text-red-500 dark:text-red-400 rounded-lg bg-red-50 dark:bg-red-950/20 px-3 py-2 border border-red-200 dark:border-red-900/30">
<div className="flex flex-row w-full justify-between items-center"> <AlertCircle size={16} className="shrink-0" />
<p className="text-[11px] lg:text-xs text-black/70 dark:text-white/70"> <span className="break-words">
Embedding models {
</p> modelProvider.chatModels.find(
<AddModel (m) => m.key === 'error',
providerId={modelProvider.id} )?.name
setProviders={setProviders} }
type="embedding" </span>
/> </div>
</div> ) : (
<div className="flex flex-col gap-2"> <div className="flex flex-row flex-wrap gap-2">
{modelProvider.embeddingModels.some( {modelProvider.chatModels.map((model, index) => (
(m) => m.key === 'error', <div
) ? ( key={`${modelProvider.id}-chat-${model.key}-${index}`}
<div className="flex flex-row items-center gap-2 text-xs lg:text-sm text-red-500 dark:text-red-400 rounded-lg bg-red-50 dark:bg-red-950/20 px-3 py-2 border border-red-200 dark:border-red-900/30"> className="flex flex-row items-center space-x-1 text-xs lg:text-sm text-black/70 dark:text-white/70 rounded-lg bg-light-secondary dark:bg-dark-secondary px-3 py-1.5"
<AlertCircle size={16} className="shrink-0" /> >
<span className="break-words"> <span>{model.name}</span>
{ <button
modelProvider.embeddingModels.find( onClick={() => {
(m) => m.key === 'error', handleModelDelete('chat', model.key);
)?.name }}
}
</span>
</div>
) : (
<div className="flex flex-row flex-wrap gap-2">
{modelProvider.embeddingModels.map((model, index) => (
<div
key={`${modelProvider.id}-embedding-${model.key}-${index}`}
className="flex flex-row items-center space-x-1 text-xs lg:text-sm text-black/70 dark:text-white/70 rounded-lg bg-light-secondary dark:bg-dark-secondary px-3 py-1.5"
> >
<span>{model.name}</span> <X size={12} />
<button </button>
onClick={() => { </div>
handleModelDelete('embedding', model.key); ))}
}} </div>
> )}
<X size={12} />
</button>
</div>
))}
</div>
)}
</div>
</div> </div>
)} </div>
<div className="flex flex-col gap-y-2">
<div className="flex flex-row w-full justify-between items-center">
<p className="text-[11px] lg:text-xs text-black/70 dark:text-white/70">
Embedding models
</p>
<AddModel
providerId={modelProvider.id}
setProviders={setProviders}
type="embedding"
/>
</div>
<div className="flex flex-col gap-2">
{modelProvider.embeddingModels.some(
(m) => m.key === 'error',
) ? (
<div className="flex flex-row items-center gap-2 text-xs lg:text-sm text-red-500 dark:text-red-400 rounded-lg bg-red-50 dark:bg-red-950/20 px-3 py-2 border border-red-200 dark:border-red-900/30">
<AlertCircle size={16} className="shrink-0" />
<span className="break-words">
{
modelProvider.embeddingModels.find(
(m) => m.key === 'error',
)?.name
}
</span>
</div>
) : (
<div className="flex flex-row flex-wrap gap-2">
{modelProvider.embeddingModels.map((model, index) => (
<div
key={`${modelProvider.id}-embedding-${model.key}-${index}`}
className="flex flex-row items-center space-x-1 text-xs lg:text-sm text-black/70 dark:text-white/70 rounded-lg bg-light-secondary dark:bg-dark-secondary px-3 py-1.5"
>
<span>{model.name}</span>
<button
onClick={() => {
handleModelDelete('embedding', model.key);
}}
>
<X size={12} />
</button>
</div>
))}
</div>
)}
</div>
</div>
</div> </div>
</motion.div> </motion.div>
)} )}

View File

@@ -63,8 +63,7 @@ const SetupConfig = ({
} }
}; };
const hasProviders = const hasProviders = providers.length > 0;
providers.filter((p) => p.chatModels.length > 0).length > 0;
return ( return (
<div className="w-[95vw] md:w-[80vw] lg:w-[65vw] mx-auto px-2 sm:px-4 md:px-6 flex flex-col space-y-6"> <div className="w-[95vw] md:w-[80vw] lg:w-[65vw] mx-auto px-2 sm:px-4 md:px-6 flex flex-col space-y-6">