pjpjq commited on
Commit
6b6ca97
·
verified ·
1 Parent(s): a09ac11

Deploy Perplexica to Hugging Face with nginx basic auth

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
.assets/demo.gif ADDED

Git LFS Details

  • SHA256: 9320f88e52d7d50630b037a76dd2909abcd07350479ce65c91ac437a9ad9761a
  • Pointer size: 133 Bytes
  • Size of remote file: 32.7 MB
.assets/manifest.json ADDED
File without changes
.assets/perplexica-screenshot.png ADDED

Git LFS Details

  • SHA256: ff3961b739eb2c4d8aa7809421f776d1dc580ce9c2cda4f5f96ff59accd6f704
  • Pointer size: 132 Bytes
  • Size of remote file: 2.19 MB
.assets/sponsers/exa.png ADDED
.assets/sponsers/warp.png ADDED

Git LFS Details

  • SHA256: 300de1e6df0d89aadf498f4406ae8802805c2ccf35f79a2c4f528d65f7e1eb61
  • Pointer size: 131 Bytes
  • Size of remote file: 443 kB
.dockerignore ADDED
@@ -0,0 +1 @@
 
 
1
+ **/node_modules
.eslintrc.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ {
2
+ "extends": "next/core-web-vitals"
3
+ }
.gitattributes CHANGED
@@ -33,3 +33,10 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ .assets/demo.gif filter=lfs diff=lfs merge=lfs -text
37
+ .assets/perplexica-screenshot.png filter=lfs diff=lfs merge=lfs -text
38
+ .assets/sponsers/warp.png filter=lfs diff=lfs merge=lfs -text
39
+ public/screenshots/p1.png filter=lfs diff=lfs merge=lfs -text
40
+ public/screenshots/p1_small.png filter=lfs diff=lfs merge=lfs -text
41
+ public/screenshots/p2.png filter=lfs diff=lfs merge=lfs -text
42
+ public/screenshots/p2_small.png filter=lfs diff=lfs merge=lfs -text
.github/ISSUE_TEMPLATE/bug_report.md ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ name: Bug report
3
+ about: Create an issue to help us fix bugs
4
+ title: ''
5
+ labels: bug
6
+ assignees: ''
7
+ ---
8
+
9
+ **Describe the bug**
10
+ A clear and concise description of what the bug is.
11
+
12
+ **To Reproduce**
13
+ Steps to reproduce the behavior:
14
+
15
+ 1. Go to '...'
16
+ 2. Click on '....'
17
+ 3. Scroll down to '....'
18
+ 4. See error
19
+
20
+ **Expected behavior**
21
+ A clear and concise description of what you expected to happen.
22
+
23
+ **Screenshots**
24
+ If applicable, add screenshots to help explain your problem.
25
+
26
+ **Additional context**
27
+ Add any other context about the problem here.
.github/ISSUE_TEMPLATE/custom.md ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ ---
2
+ name: Custom issue template
3
+ about: Describe this issue template's purpose here.
4
+ title: ''
5
+ labels: ''
6
+ assignees: ''
7
+ ---
.github/ISSUE_TEMPLATE/feature_request.md ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ name: Feature request
3
+ about: Suggest an idea for this project
4
+ title: ''
5
+ labels: enhancement
6
+ assignees: ''
7
+ ---
8
+
9
+ **Is your feature request related to a problem? Please describe.**
10
+ A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
11
+
12
+ **Describe the solution you'd like**
13
+ A clear and concise description of what you want to happen.
14
+
15
+ **Describe alternatives you've considered**
16
+ A clear and concise description of any alternative solutions or features you've considered.
17
+
18
+ **Additional context**
19
+ Add any other context or screenshots about the feature request here.
.github/workflows/docker-build.yaml ADDED
@@ -0,0 +1,217 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Build & Push Docker Images
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - master
7
+ - canary
8
+ release:
9
+ types: [published]
10
+
11
+ jobs:
12
+ build-amd64:
13
+ runs-on: ubuntu-latest
14
+ strategy:
15
+ matrix:
16
+ variant:
17
+ - name: full
18
+ dockerfile: Dockerfile
19
+ - name: slim
20
+ dockerfile: Dockerfile.slim
21
+ steps:
22
+ - name: Checkout code
23
+ uses: actions/checkout@v3
24
+
25
+ - name: Set up Docker Buildx
26
+ uses: docker/setup-buildx-action@v2
27
+ with:
28
+ install: true
29
+
30
+ - name: Log in to DockerHub
31
+ uses: docker/login-action@v2
32
+ with:
33
+ username: ${{ secrets.DOCKER_USERNAME }}
34
+ password: ${{ secrets.DOCKER_PASSWORD }}
35
+
36
+ - name: Extract version from release tag
37
+ if: github.event_name == 'release'
38
+ id: version
39
+ run: echo "RELEASE_VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
40
+
41
+ - name: Build and push AMD64 Docker image (master)
42
+ if: github.ref == 'refs/heads/master' && github.event_name == 'push'
43
+ run: |
44
+ DOCKERFILE=${{ matrix.variant.dockerfile }}
45
+ VARIANT=${{ matrix.variant.name }}
46
+ docker buildx build --platform linux/amd64 \
47
+ --cache-from=type=registry,ref=itzcrazykns1337/perplexica:${VARIANT}-amd64 \
48
+ --cache-to=type=inline \
49
+ --provenance false \
50
+ -f $DOCKERFILE \
51
+ -t itzcrazykns1337/perplexica:${VARIANT}-amd64 \
52
+ --push .
53
+
54
+ - name: Build and push AMD64 Canary Docker image
55
+ if: github.ref == 'refs/heads/canary' && github.event_name == 'push'
56
+ run: |
57
+ DOCKERFILE=${{ matrix.variant.dockerfile }}
58
+ VARIANT=${{ matrix.variant.name }}
59
+ docker buildx build --platform linux/amd64 \
60
+ --cache-from=type=registry,ref=itzcrazykns1337/perplexica:${VARIANT}-canary-amd64 \
61
+ --cache-to=type=inline \
62
+ --provenance false \
63
+ -f $DOCKERFILE \
64
+ -t itzcrazykns1337/perplexica:${VARIANT}-canary-amd64 \
65
+ --push .
66
+
67
+ - name: Build and push AMD64 release Docker image
68
+ if: github.event_name == 'release'
69
+ run: |
70
+ DOCKERFILE=${{ matrix.variant.dockerfile }}
71
+ VARIANT=${{ matrix.variant.name }}
72
+ docker buildx build --platform linux/amd64 \
73
+ --cache-from=type=registry,ref=itzcrazykns1337/perplexica:${VARIANT}-${{ env.RELEASE_VERSION }}-amd64 \
74
+ --cache-to=type=inline \
75
+ --provenance false \
76
+ -f $DOCKERFILE \
77
+ -t itzcrazykns1337/perplexica:${VARIANT}-${{ env.RELEASE_VERSION }}-amd64 \
78
+ --push .
79
+
80
+ build-arm64:
81
+ runs-on: ubuntu-24.04-arm
82
+ strategy:
83
+ matrix:
84
+ variant:
85
+ - name: full
86
+ dockerfile: Dockerfile
87
+ - name: slim
88
+ dockerfile: Dockerfile.slim
89
+ steps:
90
+ - name: Checkout code
91
+ uses: actions/checkout@v3
92
+
93
+ - name: Set up Docker Buildx
94
+ uses: docker/setup-buildx-action@v2
95
+ with:
96
+ install: true
97
+
98
+ - name: Log in to DockerHub
99
+ uses: docker/login-action@v2
100
+ with:
101
+ username: ${{ secrets.DOCKER_USERNAME }}
102
+ password: ${{ secrets.DOCKER_PASSWORD }}
103
+
104
+ - name: Extract version from release tag
105
+ if: github.event_name == 'release'
106
+ id: version
107
+ run: echo "RELEASE_VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
108
+
109
+ - name: Build and push ARM64 Docker image (master)
110
+ if: github.ref == 'refs/heads/master' && github.event_name == 'push'
111
+ run: |
112
+ DOCKERFILE=${{ matrix.variant.dockerfile }}
113
+ VARIANT=${{ matrix.variant.name }}
114
+ docker buildx build --platform linux/arm64 \
115
+ --cache-from=type=registry,ref=itzcrazykns1337/perplexica:${VARIANT}-arm64 \
116
+ --cache-to=type=inline \
117
+ --provenance false \
118
+ -f $DOCKERFILE \
119
+ -t itzcrazykns1337/perplexica:${VARIANT}-arm64 \
120
+ --push .
121
+
122
+ - name: Build and push ARM64 Canary Docker image
123
+ if: github.ref == 'refs/heads/canary' && github.event_name == 'push'
124
+ run: |
125
+ DOCKERFILE=${{ matrix.variant.dockerfile }}
126
+ VARIANT=${{ matrix.variant.name }}
127
+ docker buildx build --platform linux/arm64 \
128
+ --cache-from=type=registry,ref=itzcrazykns1337/perplexica:${VARIANT}-canary-arm64 \
129
+ --cache-to=type=inline \
130
+ --provenance false \
131
+ -f $DOCKERFILE \
132
+ -t itzcrazykns1337/perplexica:${VARIANT}-canary-arm64 \
133
+ --push .
134
+
135
+ - name: Build and push ARM64 release Docker image
136
+ if: github.event_name == 'release'
137
+ run: |
138
+ DOCKERFILE=${{ matrix.variant.dockerfile }}
139
+ VARIANT=${{ matrix.variant.name }}
140
+ docker buildx build --platform linux/arm64 \
141
+ --cache-from=type=registry,ref=itzcrazykns1337/perplexica:${VARIANT}-${{ env.RELEASE_VERSION }}-arm64 \
142
+ --cache-to=type=inline \
143
+ --provenance false \
144
+ -f $DOCKERFILE \
145
+ -t itzcrazykns1337/perplexica:${VARIANT}-${{ env.RELEASE_VERSION }}-arm64 \
146
+ --push .
147
+
148
+ manifest:
149
+ needs: [build-amd64, build-arm64]
150
+ runs-on: ubuntu-latest
151
+ strategy:
152
+ matrix:
153
+ variant: [full, slim]
154
+ steps:
155
+ - name: Log in to DockerHub
156
+ uses: docker/login-action@v2
157
+ with:
158
+ username: ${{ secrets.DOCKER_USERNAME }}
159
+ password: ${{ secrets.DOCKER_PASSWORD }}
160
+
161
+ - name: Extract version from release tag
162
+ if: github.event_name == 'release'
163
+ id: version
164
+ run: echo "RELEASE_VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
165
+
166
+ - name: Create and push manifest for main
167
+ if: github.ref == 'refs/heads/master' && github.event_name == 'push'
168
+ run: |
169
+ VARIANT=${{ matrix.variant }}
170
+ docker manifest create itzcrazykns1337/perplexica:${VARIANT}-latest \
171
+ --amend itzcrazykns1337/perplexica:${VARIANT}-amd64 \
172
+ --amend itzcrazykns1337/perplexica:${VARIANT}-arm64
173
+ docker manifest push itzcrazykns1337/perplexica:${VARIANT}-latest
174
+
175
+ if [ "$VARIANT" = "full" ]; then
176
+ docker manifest create itzcrazykns1337/perplexica:latest \
177
+ --amend itzcrazykns1337/perplexica:${VARIANT}-amd64 \
178
+ --amend itzcrazykns1337/perplexica:${VARIANT}-arm64
179
+ docker manifest push itzcrazykns1337/perplexica:latest
180
+
181
+ docker manifest create itzcrazykns1337/perplexica:main \
182
+ --amend itzcrazykns1337/perplexica:${VARIANT}-amd64 \
183
+ --amend itzcrazykns1337/perplexica:${VARIANT}-arm64
184
+ docker manifest push itzcrazykns1337/perplexica:main
185
+ fi
186
+
187
+ - name: Create and push manifest for canary
188
+ if: github.ref == 'refs/heads/canary' && github.event_name == 'push'
189
+ run: |
190
+ VARIANT=${{ matrix.variant }}
191
+ docker manifest create itzcrazykns1337/perplexica:${VARIANT}-canary \
192
+ --amend itzcrazykns1337/perplexica:${VARIANT}-canary-amd64 \
193
+ --amend itzcrazykns1337/perplexica:${VARIANT}-canary-arm64
194
+ docker manifest push itzcrazykns1337/perplexica:${VARIANT}-canary
195
+
196
+ if [ "$VARIANT" = "full" ]; then
197
+ docker manifest create itzcrazykns1337/perplexica:canary \
198
+ --amend itzcrazykns1337/perplexica:${VARIANT}-canary-amd64 \
199
+ --amend itzcrazykns1337/perplexica:${VARIANT}-canary-arm64
200
+ docker manifest push itzcrazykns1337/perplexica:canary
201
+ fi
202
+
203
+ - name: Create and push manifest for releases
204
+ if: github.event_name == 'release'
205
+ run: |
206
+ VARIANT=${{ matrix.variant }}
207
+ docker manifest create itzcrazykns1337/perplexica:${VARIANT}-${{ env.RELEASE_VERSION }} \
208
+ --amend itzcrazykns1337/perplexica:${VARIANT}-${{ env.RELEASE_VERSION }}-amd64 \
209
+ --amend itzcrazykns1337/perplexica:${VARIANT}-${{ env.RELEASE_VERSION }}-arm64
210
+ docker manifest push itzcrazykns1337/perplexica:${VARIANT}-${{ env.RELEASE_VERSION }}
211
+
212
+ if [ "$VARIANT" = "full" ]; then
213
+ docker manifest create itzcrazykns1337/perplexica:${{ env.RELEASE_VERSION }} \
214
+ --amend itzcrazykns1337/perplexica:${VARIANT}-${{ env.RELEASE_VERSION }}-amd64 \
215
+ --amend itzcrazykns1337/perplexica:${VARIANT}-${{ env.RELEASE_VERSION }}-arm64
216
+ docker manifest push itzcrazykns1337/perplexica:${{ env.RELEASE_VERSION }}
217
+ fi
.gitignore ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Node.js
2
+ node_modules/
3
+ npm-debug.log
4
+ yarn-error.log
5
+
6
+ # Build output
7
+ .next/
8
+ out/
9
+ dist/
10
+
11
+ # IDE/Editor specific
12
+ .vscode/
13
+ .idea/
14
+ *.iml
15
+
16
+ # Environment variables
17
+ .env
18
+ .env.local
19
+ .env.development.local
20
+ .env.test.local
21
+ .env.production.local
22
+
23
+ # Config files
24
+ config.toml
25
+
26
+ # Log files
27
+ logs/
28
+ *.log
29
+
30
+ # Testing
31
+ /coverage/
32
+
33
+ # Miscellaneous
34
+ .DS_Store
35
+ Thumbs.db
36
+
37
+ # Db
38
+ db.sqlite
39
+ /searxng
40
+
41
+ certificates
.prettierignore ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Ignore all files in the node_modules directory
2
+ node_modules
3
+
4
+ # Ignore all files in the .next directory (Next.js build output)
5
+ .next
6
+
7
+ # Ignore all files in the .out directory (TypeScript build output)
8
+ .out
9
+
10
+ # Ignore all files in the .cache directory (Prettier cache)
11
+ .cache
12
+
13
+ # Ignore all files in the .vscode directory (Visual Studio Code settings)
14
+ .vscode
15
+
16
+ # Ignore all files in the .idea directory (IntelliJ IDEA settings)
17
+ .idea
18
+
19
+ # Ignore all files in the dist directory (build output)
20
+ dist
21
+
22
+ # Ignore all files in the build directory (build output)
23
+ build
24
+
25
+ # Ignore all files in the coverage directory (test coverage reports)
26
+ coverage
27
+
28
+ # Ignore all files with the .log extension
29
+ *.log
30
+
31
+ # Ignore all files with the .tmp extension
32
+ *.tmp
33
+
34
+ # Ignore all files with the .swp extension
35
+ *.swp
36
+
37
+ # Ignore all files with the .DS_Store extension (macOS specific)
38
+ .DS_Store
39
+
40
+ # Ignore all files in uploads directory
41
+ uploads
.prettierrc.js ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /** @type {import("prettier").Config} */
2
+
3
+ const config = {
4
+ printWidth: 80,
5
+ trailingComma: 'all',
6
+ endOfLine: 'auto',
7
+ singleQuote: true,
8
+ tabWidth: 2,
9
+ };
10
+
11
+ module.exports = config;
CONTRIBUTING.md ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # How to Contribute to Perplexica
2
+
3
+ Thanks for your interest in contributing to Perplexica! Your help makes this project better. This guide explains how to contribute effectively.
4
+
5
+ Perplexica is a modern AI chat application with advanced search capabilities.
6
+
7
+ ## Project Structure
8
+
9
+ Perplexica's codebase is organized as follows:
10
+
11
+ - **UI Components and Pages**:
12
+ - **Components (`src/components`)**: Reusable UI components.
13
+ - **Pages and Routes (`src/app`)**: Next.js app directory structure with page components.
14
+ - Main app routes include: home (`/`), chat (`/c`), discover (`/discover`), and library (`/library`).
15
+ - **API Routes (`src/app/api`)**: Server endpoints implemented with Next.js route handlers.
16
+ - **Backend Logic (`src/lib`)**: Contains all the backend functionality including search, database, and API logic.
17
+ - The search system lives in `src/lib/agents/search`.
18
+ - The search pipeline is split into classification, research, widgets, and writing.
19
+ - Database functionality is in `src/lib/db`.
20
+ - Chat model and embedding model providers are in `src/lib/models/providers`, and models are loaded via `src/lib/models/registry.ts`.
21
+ - Prompt templates are in `src/lib/prompts`.
22
+ - SearXNG integration is in `src/lib/searxng.ts`.
23
+ - Upload search lives in `src/lib/uploads`.
24
+
25
+ ### Where to make changes
26
+
27
+ If you are not sure where to start, use this section as a map.
28
+
29
+ - **Search behavior and reasoning**
30
+
31
+ - `src/lib/agents/search` contains the core chat and search pipeline.
32
+ - `classifier.ts` decides whether research is needed and what should run.
33
+ - `researcher/` gathers information in the background.
34
+
35
+ - **Add or change a search capability**
36
+
37
+ - Research tools (web, academic, discussions, uploads, scraping) live in `src/lib/agents/search/researcher/actions`.
38
+ - Tools are registered in `src/lib/agents/search/researcher/actions/index.ts`.
39
+
40
+ - **Add or change widgets**
41
+
42
+ - Widgets live in `src/lib/agents/search/widgets`.
43
+ - Widgets run in parallel with research and show structured results in the UI.
44
+
45
+ - **Model integrations**
46
+
47
+ - Providers live in `src/lib/models/providers`.
48
+ - Add new providers there and wire them into the model registry so they show up in the app.
49
+
50
+ - **Architecture docs**
51
+ - High level overview: `docs/architecture/README.md`
52
+ - High level flow: `docs/architecture/WORKING.md`
53
+
54
+ ## API Documentation
55
+
56
+ Perplexica includes API documentation for programmatic access.
57
+
58
+ - **Search API**: For detailed documentation, see `docs/API/SEARCH.md`.
59
+
60
+ ## Setting Up Your Environment
61
+
62
+ Before diving into coding, setting up your local environment is key. Here's what you need to do:
63
+
64
+ 1. Run `npm install` to install all dependencies.
65
+ 2. Use `npm run dev` to start the application in development mode.
66
+ 3. Open http://localhost:3000 and complete the setup in the UI (API keys, models, search backend URL, etc.).
67
+
68
+ Database migrations are applied automatically on startup.
69
+
70
+ For full installation options (Docker and non Docker), see the installation guide in the repository README.
71
+
72
+ **Please note**: Docker configurations are present for setting up production environments, whereas `npm run dev` is used for development purposes.
73
+
74
+ ## Coding and Contribution Practices
75
+
76
+ Before committing changes:
77
+
78
+ 1. Ensure that your code functions correctly by thorough testing.
79
+ 2. Always run `npm run format:write` to format your code according to the project's coding standards. This helps maintain consistency and code quality.
80
+ 3. We currently do not have a code of conduct, but it is in the works. In the meantime, please be mindful of how you engage with the project and its community.
81
+
82
+ Following these steps will help maintain the integrity of Perplexica's codebase and facilitate a smoother integration of your valuable contributions. Thank you for your support and commitment to improving Perplexica.
Dockerfile ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM node:24.5.0-slim AS builder
2
+
3
+ RUN apt-get update && apt-get install -y python3 python3-pip sqlite3 && rm -rf /var/lib/apt/lists/*
4
+
5
+ WORKDIR /home/perplexica
6
+
7
+ COPY package.json yarn.lock ./
8
+ RUN yarn install --frozen-lockfile --network-timeout 600000
9
+
10
+ COPY tsconfig.json next.config.mjs next-env.d.ts postcss.config.js drizzle.config.ts tailwind.config.ts ./
11
+ COPY src ./src
12
+ COPY public ./public
13
+ COPY drizzle ./drizzle
14
+
15
+ RUN mkdir -p /home/perplexica/data
16
+ RUN yarn build
17
+
18
+ FROM node:24.5.0-slim
19
+
20
+ RUN apt-get update && apt-get install -y \
21
+ python3-dev python3-babel python3-venv python-is-python3 \
22
+ uwsgi uwsgi-plugin-python3 \
23
+ git build-essential libxslt-dev zlib1g-dev libffi-dev libssl-dev \
24
+ curl sudo nginx openssl \
25
+ && rm -rf /var/lib/apt/lists/*
26
+
27
+ WORKDIR /home/perplexica
28
+
29
+ COPY --from=builder /home/perplexica/public ./public
30
+ COPY --from=builder /home/perplexica/.next/static ./public/_next/static
31
+ COPY --from=builder /home/perplexica/.next/standalone ./
32
+ COPY --from=builder /home/perplexica/data ./data
33
+ COPY drizzle ./drizzle
34
+
35
+ RUN mkdir /home/perplexica/uploads
36
+
37
+ RUN useradd --shell /bin/bash --system \
38
+ --home-dir "/usr/local/searxng" \
39
+ --comment 'Privacy-respecting metasearch engine' \
40
+ searxng
41
+
42
+ RUN mkdir "/usr/local/searxng"
43
+ RUN mkdir -p /etc/searxng
44
+ RUN chown -R "searxng:searxng" "/usr/local/searxng"
45
+
46
+ COPY searxng/settings.yml /etc/searxng/settings.yml
47
+ COPY searxng/limiter.toml /etc/searxng/limiter.toml
48
+ COPY searxng/uwsgi.ini /etc/searxng/uwsgi.ini
49
+ RUN chown -R searxng:searxng /etc/searxng
50
+
51
+ USER searxng
52
+
53
+ RUN git clone "https://github.com/searxng/searxng" \
54
+ "/usr/local/searxng/searxng-src"
55
+
56
+ RUN python3 -m venv "/usr/local/searxng/searx-pyenv"
57
+ RUN "/usr/local/searxng/searx-pyenv/bin/pip" install --upgrade pip setuptools wheel pyyaml msgspec
58
+ RUN cd "/usr/local/searxng/searxng-src" && \
59
+ "/usr/local/searxng/searx-pyenv/bin/pip" install --use-pep517 --no-build-isolation -e .
60
+
61
+ USER root
62
+
63
+ WORKDIR /home/perplexica
64
+ COPY entrypoint.sh ./entrypoint.sh
65
+ COPY entrypoint-hf.sh ./entrypoint-hf.sh
66
+ COPY hf.nginx.conf ./hf.nginx.conf
67
+ RUN chmod +x ./entrypoint.sh
68
+ RUN chmod +x ./entrypoint-hf.sh
69
+ RUN sed -i 's/\r$//' ./entrypoint.sh || true
70
+ RUN sed -i 's/\r$//' ./entrypoint-hf.sh || true
71
+
72
+ RUN echo "searxng ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
73
+
74
+ EXPOSE 7860 8080
75
+
76
+ ENV SEARXNG_API_URL=http://localhost:8080
77
+
78
+ CMD ["/home/perplexica/entrypoint-hf.sh"]
Dockerfile.slim ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM node:24.5.0-slim AS builder
2
+
3
+ RUN apt-get update && apt-get install -y python3 python3-pip sqlite3 && rm -rf /var/lib/apt/lists/*
4
+
5
+ WORKDIR /home/perplexica
6
+
7
+ COPY package.json yarn.lock ./
8
+ RUN yarn install --frozen-lockfile --network-timeout 600000
9
+
10
+ COPY tsconfig.json next.config.mjs next-env.d.ts postcss.config.js drizzle.config.ts tailwind.config.ts ./
11
+ COPY src ./src
12
+ COPY public ./public
13
+ COPY drizzle ./drizzle
14
+
15
+ RUN mkdir -p /home/perplexica/data
16
+ RUN yarn build
17
+
18
+ FROM node:24.5.0-slim
19
+
20
+ RUN apt-get update && apt-get install -y python3 python3-pip sqlite3 && rm -rf /var/lib/apt/lists/*
21
+
22
+ WORKDIR /home/perplexica
23
+
24
+ COPY --from=builder /home/perplexica/public ./public
25
+ COPY --from=builder /home/perplexica/.next/static ./public/_next/static
26
+
27
+ COPY --from=builder /home/perplexica/.next/standalone ./
28
+ COPY --from=builder /home/perplexica/data ./data
29
+ COPY drizzle ./drizzle
30
+
31
+ RUN mkdir /home/perplexica/uploads
32
+
33
+ EXPOSE 3000
34
+
35
+ CMD ["node", "server.js"]
LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ItzCrazyKns
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
README.md CHANGED
@@ -1,10 +1,276 @@
1
  ---
2
- title: Perplexica Auth
3
- emoji: 🔥
4
- colorFrom: purple
5
- colorTo: blue
6
  sdk: docker
 
7
  pinned: false
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: Perplexica
3
+ emoji: "🔍"
4
+ colorFrom: blue
5
+ colorTo: indigo
6
  sdk: docker
7
+ app_port: 7860
8
  pinned: false
9
  ---
10
 
11
+ # Perplexica 🔍
12
+
13
+ [![GitHub Repo stars](https://img.shields.io/github/stars/ItzCrazyKns/Perplexica?style=social)](https://github.com/ItzCrazyKns/Perplexica/stargazers)
14
+ [![GitHub forks](https://img.shields.io/github/forks/ItzCrazyKns/Perplexica?style=social)](https://github.com/ItzCrazyKns/Perplexica/network/members)
15
+ [![GitHub watchers](https://img.shields.io/github/watchers/ItzCrazyKns/Perplexica?style=social)](https://github.com/ItzCrazyKns/Perplexica/watchers)
16
+ [![Docker Pulls](https://img.shields.io/docker/pulls/itzcrazykns1337/perplexica?color=blue)](https://hub.docker.com/r/itzcrazykns1337/perplexica)
17
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/ItzCrazyKns/Perplexica/blob/master/LICENSE)
18
+ [![GitHub last commit](https://img.shields.io/github/last-commit/ItzCrazyKns/Perplexica?color=green)](https://github.com/ItzCrazyKns/Perplexica/commits/master)
19
+ [![Discord](https://dcbadge.limes.pink/api/server/26aArMy8tT?style=flat)](https://discord.gg/26aArMy8tT)
20
+
21
+ Perplexica is a **privacy-focused AI answering engine** that runs entirely on your own hardware. It combines knowledge from the vast internet with support for **local LLMs** (Ollama) and cloud providers (OpenAI, Claude, Groq), delivering accurate answers with **cited sources** while keeping your searches completely private.
22
+
23
+ ![preview](.assets/perplexica-screenshot.png)
24
+
25
+ Want to know more about its architecture and how it works? You can read it [here](https://github.com/ItzCrazyKns/Perplexica/tree/master/docs/architecture/README.md).
26
+
27
+ ## ✨ Features
28
+
29
+ 🤖 **Support for all major AI providers** - Use local LLMs through Ollama or connect to OpenAI, Anthropic Claude, Google Gemini, Groq, and more. Mix and match models based on your needs.
30
+
31
+ ⚡ **Smart search modes** - Choose Speed Mode when you need quick answers, Balanced Mode for everyday searches, or Quality Mode for deep research.
32
+
33
+ 🧭 **Pick your sources** - Search the web, discussions, or academic papers. More sources and integrations are in progress.
34
+
35
+ 🧩 **Widgets** - Helpful UI cards that show up when relevant, like weather, calculations, stock prices, and other quick lookups.
36
+
37
+ 🔍 **Web search powered by SearxNG** - Access multiple search engines while keeping your identity private. Support for Tavily and Exa coming soon for even better results.
38
+
39
+ 📷 **Image and video search** - Find visual content alongside text results. Search isn't limited to just articles anymore.
40
+
41
+ 📄 **File uploads** - Upload documents and ask questions about them. PDFs, text files, images - Perplexica understands them all.
42
+
43
+ 🌐 **Search specific domains** - Limit your search to specific websites when you know where to look. Perfect for technical documentation or research papers.
44
+
45
+ 💡 **Smart suggestions** - Get intelligent search suggestions as you type, helping you formulate better queries.
46
+
47
+ 📚 **Discover** - Browse interesting articles and trending content throughout the day. Stay informed without even searching.
48
+
49
+ 🕒 **Search history** - Every search is saved locally so you can revisit your discoveries anytime. Your research is never lost.
50
+
51
+ ✨ **More coming soon** - We're actively developing new features based on community feedback. Join our Discord to help shape Perplexica's future!
52
+
53
+ ## Sponsors
54
+
55
+ Perplexica's development is powered by the generous support of our sponsors. Their contributions help keep this project free, open-source, and accessible to everyone.
56
+
57
+ <div align="center">
58
+
59
+
60
+ <a href="https://www.warp.dev/perplexica">
61
+ <img alt="Warp Terminal" src=".assets/sponsers/warp.png" width="100%">
62
+ </a>
63
+
64
+ ### **✨ [Try Warp - The AI-Powered Terminal →](https://www.warp.dev/perplexica)**
65
+
66
+ Warp is revolutionizing development workflows with AI-powered features, modern UX, and blazing-fast performance. Used by developers at top companies worldwide.
67
+
68
+ </div>
69
+
70
+ ---
71
+
72
+ We'd also like to thank the following partners for their generous support:
73
+
74
+ <table>
75
+ <tr>
76
+ <td width="100" align="center">
77
+ <a href="https://dashboard.exa.ai" target="_blank">
78
+ <img src=".assets/sponsers/exa.png" alt="Exa" width="80" height="80" style="border-radius: .75rem;" />
79
+ </a>
80
+ </td>
81
+ <td>
82
+ <a href="https://dashboard.exa.ai">Exa</a> • The Perfect Web Search API for LLMs - web search, crawling, deep research, and answer APIs
83
+ </td>
84
+ </tr>
85
+ </table>
86
+
87
+ ## Installation
88
+
89
+ There are mainly 2 ways of installing Perplexica - With Docker, Without Docker. Using Docker is highly recommended.
90
+
91
+ ### Getting Started with Docker (Recommended)
92
+
93
+ Perplexica can be easily run using Docker. Simply run the following command:
94
+
95
+ ```bash
96
+ docker run -d -p 3000:3000 -v perplexica-data:/home/perplexica/data --name perplexica itzcrazykns1337/perplexica:latest
97
+ ```
98
+
99
+ 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.
100
+
101
+ **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.
102
+
103
+ #### Using Perplexica with Your Own SearxNG Instance
104
+
105
+ If you already have SearxNG running, you can use the slim version of Perplexica:
106
+
107
+ ```bash
108
+ docker run -d -p 3000:3000 -e SEARXNG_API_URL=http://your-searxng-url:8080 -v perplexica-data:/home/perplexica/data --name perplexica itzcrazykns1337/perplexica:slim-latest
109
+ ```
110
+
111
+ **Important**: Make sure your SearxNG instance has:
112
+
113
+ - JSON format enabled in the settings
114
+ - Wolfram Alpha search engine enabled
115
+
116
+ Replace `http://your-searxng-url:8080` with your actual SearxNG URL. Then configure your AI provider settings in the setup screen at http://localhost:3000.
117
+
118
+ #### Advanced Setup (Building from Source)
119
+
120
+ If you prefer to build from source or need more control:
121
+
122
+ 1. Ensure Docker is installed and running on your system.
123
+ 2. Clone the Perplexica repository:
124
+
125
+ ```bash
126
+ git clone https://github.com/ItzCrazyKns/Perplexica.git
127
+ ```
128
+
129
+ 3. After cloning, navigate to the directory containing the project files.
130
+
131
+ 4. Build and run using Docker:
132
+
133
+ ```bash
134
+ docker build -t perplexica .
135
+ docker run -d -p 3000:3000 -v perplexica-data:/home/perplexica/data --name perplexica perplexica
136
+ ```
137
+
138
+ 5. Access Perplexica at http://localhost:3000 and configure your settings in the setup screen.
139
+
140
+ **Note**: After the containers are built, you can start Perplexica directly from Docker without having to open a terminal.
141
+
142
+ ### Non-Docker Installation
143
+
144
+ 1. Install SearXNG and allow `JSON` format in the SearXNG settings. Make sure Wolfram Alpha search engine is also enabled.
145
+ 2. Clone the repository:
146
+
147
+ ```bash
148
+ git clone https://github.com/ItzCrazyKns/Perplexica.git
149
+ cd Perplexica
150
+ ```
151
+
152
+ 3. Install dependencies:
153
+
154
+ ```bash
155
+ npm i
156
+ ```
157
+
158
+ 4. Build the application:
159
+
160
+ ```bash
161
+ npm run build
162
+ ```
163
+
164
+ 5. Start the application:
165
+
166
+ ```bash
167
+ npm run start
168
+ ```
169
+
170
+ 6. Open your browser and navigate to http://localhost:3000 to complete the setup and configure your settings (API keys, models, SearxNG URL, etc.) in the setup screen.
171
+
172
+ **Note**: Using Docker is recommended as it simplifies the setup process, especially for managing environment variables and dependencies.
173
+
174
+ See the [installation documentation](https://github.com/ItzCrazyKns/Perplexica/tree/master/docs/installation) for more information like updating, etc.
175
+
176
+ ### Troubleshooting
177
+
178
+ #### Local OpenAI-API-Compliant Servers
179
+
180
+ If Perplexica tells you that you haven't configured any chat model providers, ensure that:
181
+
182
+ 1. Your server is running on `0.0.0.0` (not `127.0.0.1`) and on the same port you put in the API URL.
183
+ 2. You have specified the correct model name loaded by your local LLM server.
184
+ 3. You have specified the correct API key, or if one is not defined, you have put _something_ in the API key field and not left it empty.
185
+
186
+ #### Ollama Connection Errors
187
+
188
+ If you're encountering an Ollama connection error, it is likely due to the backend being unable to connect to Ollama's API. To fix this issue you can:
189
+
190
+ 1. **Check your Ollama API URL:** Ensure that the API URL is correctly set in the settings menu.
191
+ 2. **Update API URL Based on OS:**
192
+
193
+ - **Windows:** Use `http://host.docker.internal:11434`
194
+ - **Mac:** Use `http://host.docker.internal:11434`
195
+ - **Linux:** Use `http://<private_ip_of_host>:11434`
196
+
197
+ Adjust the port number if you're using a different one.
198
+
199
+ 3. **Linux Users - Expose Ollama to Network:**
200
+
201
+ - Inside `/etc/systemd/system/ollama.service`, you need to add `Environment="OLLAMA_HOST=0.0.0.0:11434"`. (Change the port number if you are using a different one.) Then reload the systemd manager configuration with `systemctl daemon-reload`, and restart Ollama by `systemctl restart ollama`. For more information see [Ollama docs](https://github.com/ollama/ollama/blob/main/docs/faq.md#setting-environment-variables-on-linux)
202
+
203
+ - Ensure that the port (default is 11434) is not blocked by your firewall.
204
+
205
+ #### Lemonade Connection Errors
206
+
207
+ If you're encountering a Lemonade connection error, it is likely due to the backend being unable to connect to Lemonade's API. To fix this issue you can:
208
+
209
+ 1. **Check your Lemonade API URL:** Ensure that the API URL is correctly set in the settings menu.
210
+ 2. **Update API URL Based on OS:**
211
+
212
+ - **Windows:** Use `http://host.docker.internal:8000`
213
+ - **Mac:** Use `http://host.docker.internal:8000`
214
+ - **Linux:** Use `http://<private_ip_of_host>:8000`
215
+
216
+ Adjust the port number if you're using a different one.
217
+
218
+ 3. **Ensure Lemonade Server is Running:**
219
+
220
+ - Make sure your Lemonade server is running and accessible on the configured port (default is 8000).
221
+ - Verify that Lemonade is configured to accept connections from all interfaces (`0.0.0.0`), not just localhost (`127.0.0.1`).
222
+ - Ensure that the port (default is 8000) is not blocked by your firewall.
223
+
224
+ ## Using as a Search Engine
225
+
226
+ If you wish to use Perplexica as an alternative to traditional search engines like Google or Bing, or if you want to add a shortcut for quick access from your browser's search bar, follow these steps:
227
+
228
+ 1. Open your browser's settings.
229
+ 2. Navigate to the 'Search Engines' section.
230
+ 3. Add a new site search with the following URL: `http://localhost:3000/?q=%s`. Replace `localhost` with your IP address or domain name, and `3000` with the port number if Perplexica is not hosted locally.
231
+ 4. Click the add button. Now, you can use Perplexica directly from your browser's search bar.
232
+
233
+ ## Using Perplexica's API
234
+
235
+ Perplexica also provides an API for developers looking to integrate its powerful search engine into their own applications. You can run searches, use multiple models and get answers to your queries.
236
+
237
+ For more details, check out the full documentation [here](https://github.com/ItzCrazyKns/Perplexica/tree/master/docs/API/SEARCH.md).
238
+
239
+ ## Expose Perplexica to network
240
+
241
+ Perplexica runs on Next.js and handles all API requests. It works right away on the same network and stays accessible even with port forwarding.
242
+
243
+ ## One-Click Deployment
244
+
245
+ [![Deploy to Sealos](https://raw.githubusercontent.com/labring-actions/templates/main/Deploy-on-Sealos.svg)](https://usw.sealos.io/?openapp=system-template%3FtemplateName%3Dperplexica)
246
+ [![Deploy to RepoCloud](https://d16t0pc4846x52.cloudfront.net/deploylobe.svg)](https://repocloud.io/details/?app_id=267)
247
+ [![Run on ClawCloud](https://raw.githubusercontent.com/ClawCloud/Run-Template/refs/heads/main/Run-on-ClawCloud.svg)](https://template.run.claw.cloud/?referralCode=U11MRQ8U9RM4&openapp=system-fastdeploy%3FtemplateName%3Dperplexica)
248
+ [![Deploy on Hostinger](https://assets.hostinger.com/vps/deploy.svg)](https://www.hostinger.com/vps/docker-hosting?compose_url=https://raw.githubusercontent.com/ItzCrazyKns/Perplexica/refs/heads/master/docker-compose.yaml)
249
+
250
+ ## Upcoming Features
251
+
252
+ - [ ] Adding more widgets, integrations, search sources
253
+ - [ ] Adding ability to create custom agents (name T.B.D.)
254
+ - [ ] Adding authentication
255
+
256
+ ## Support Us
257
+
258
+ If you find Perplexica useful, consider giving us a star on GitHub. This helps more people discover Perplexica and supports the development of new features. Your support is greatly appreciated.
259
+
260
+ ### Donations
261
+
262
+ We also accept donations to help sustain our project. If you would like to contribute, you can use the following options to donate. Thank you for your support!
263
+
264
+ | Ethereum |
265
+ | ----------------------------------------------------- |
266
+ | Address: `0xB025a84b2F269570Eb8D4b05DEdaA41D8525B6DD` |
267
+
268
+ ## Contribution
269
+
270
+ Perplexica is built on the idea that AI and large language models should be easy for everyone to use. If you find bugs or have ideas, please share them in via GitHub Issues. For more information on contributing to Perplexica you can read the [CONTRIBUTING.md](CONTRIBUTING.md) file to learn more about Perplexica and how you can contribute to it.
271
+
272
+ ## Help and Support
273
+
274
+ If you have any questions or feedback, please feel free to reach out to us. You can create an issue on GitHub or join our Discord server. There, you can connect with other users, share your experiences and reviews, and receive more personalized help. [Click here](https://discord.gg/EFwsmQDgAu) to join the Discord server. To discuss matters outside of regular support, feel free to contact me on Discord at `itzcrazykns`.
275
+
276
+ Thank you for exploring Perplexica, the AI-powered search engine designed to enhance your search experience. We are constantly working to improve Perplexica and expand its capabilities. We value your feedback and contributions which help us make Perplexica even better. Don't forget to check back for updates and new features!
data/.gitignore ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ *
2
+ !.gitignore
docker-compose.yaml ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ services:
2
+ perplexica:
3
+ image: itzcrazykns1337/perplexica:latest
4
+ build:
5
+ context: .
6
+ ports:
7
+ - '3000:3000'
8
+ volumes:
9
+ - data:/home/perplexica/data
10
+ restart: unless-stopped
11
+
12
+ volumes:
13
+ data:
14
+ name: 'perplexica-data'
docs/API/SEARCH.md ADDED
@@ -0,0 +1,190 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Perplexica Search API Documentation
2
+
3
+ ## Overview
4
+
5
+ Perplexica’s Search API makes it easy to use our AI-powered search engine. You can run different types of searches, pick the models you want to use, and get the most recent info. Follow the following headings to learn more about Perplexica's search API.
6
+
7
+ ## Endpoints
8
+
9
+ ### Get Available Providers and Models
10
+
11
+ Before making search requests, you'll need to get the available providers and their models.
12
+
13
+ #### **GET** `/api/providers`
14
+
15
+ **Full URL**: `http://localhost:3000/api/providers`
16
+
17
+ Returns a list of all active providers with their available chat and embedding models.
18
+
19
+ **Response Example:**
20
+
21
+ ```json
22
+ {
23
+ "providers": [
24
+ {
25
+ "id": "550e8400-e29b-41d4-a716-446655440000",
26
+ "name": "OpenAI",
27
+ "chatModels": [
28
+ {
29
+ "name": "GPT 4 Omni Mini",
30
+ "key": "gpt-4o-mini"
31
+ },
32
+ {
33
+ "name": "GPT 4 Omni",
34
+ "key": "gpt-4o"
35
+ }
36
+ ],
37
+ "embeddingModels": [
38
+ {
39
+ "name": "Text Embedding 3 Large",
40
+ "key": "text-embedding-3-large"
41
+ }
42
+ ]
43
+ }
44
+ ]
45
+ }
46
+ ```
47
+
48
+ Use the `id` field as the `providerId` and the `key` field from the models arrays when making search requests.
49
+
50
+ ### Search Query
51
+
52
+ #### **POST** `/api/search`
53
+
54
+ **Full URL**: `http://localhost:3000/api/search`
55
+
56
+ **Note**: Replace `localhost:3000` with your Perplexica instance URL if running on a different host or port
57
+
58
+ ### Request
59
+
60
+ The API accepts a JSON object in the request body, where you define the enabled search `sources`, chat models, embedding models, and your query.
61
+
62
+ #### Request Body Structure
63
+
64
+ ```json
65
+ {
66
+ "chatModel": {
67
+ "providerId": "550e8400-e29b-41d4-a716-446655440000",
68
+ "key": "gpt-4o-mini"
69
+ },
70
+ "embeddingModel": {
71
+ "providerId": "550e8400-e29b-41d4-a716-446655440000",
72
+ "key": "text-embedding-3-large"
73
+ },
74
+ "optimizationMode": "speed",
75
+ "sources": ["web"],
76
+ "query": "What is Perplexica",
77
+ "history": [
78
+ ["human", "Hi, how are you?"],
79
+ ["assistant", "I am doing well, how can I help you today?"]
80
+ ],
81
+ "systemInstructions": "Focus on providing technical details about Perplexica's architecture.",
82
+ "stream": false
83
+ }
84
+ ```
85
+
86
+ **Note**: The `providerId` must be a valid UUID obtained from the `/api/providers` endpoint. The example above uses a sample UUID for demonstration.
87
+
88
+ ### Request Parameters
89
+
90
+ - **`chatModel`** (object, required): Defines the chat model to be used for the query. To get available providers and models, send a GET request to `http://localhost:3000/api/providers`.
91
+
92
+ - `providerId` (string): The UUID of the provider. You can get this from the `/api/providers` endpoint response.
93
+ - `key` (string): The model key/identifier (e.g., `gpt-4o-mini`, `llama3.1:latest`). Use the `key` value from the provider's `chatModels` array, not the display name.
94
+
95
+ - **`embeddingModel`** (object, required): Defines the embedding model for similarity-based searching. To get available providers and models, send a GET request to `http://localhost:3000/api/providers`.
96
+
97
+ - `providerId` (string): The UUID of the embedding provider. You can get this from the `/api/providers` endpoint response.
98
+ - `key` (string): The embedding model key (e.g., `text-embedding-3-large`, `nomic-embed-text`). Use the `key` value from the provider's `embeddingModels` array, not the display name.
99
+
100
+ - **`sources`** (array, required): Which search sources to enable. Available values:
101
+
102
+ - `web`, `academic`, `discussions`.
103
+
104
+ - **`optimizationMode`** (string, optional): Specifies the optimization mode to control the balance between performance and quality. Available modes:
105
+
106
+ - `speed`: Prioritize speed and return the fastest answer.
107
+ - `balanced`: Provide a balanced answer with good speed and reasonable quality.
108
+ - `quality`: Prioritize answer quality (may be slower).
109
+
110
+ - **`query`** (string, required): The search query or question.
111
+
112
+ - **`systemInstructions`** (string, optional): Custom instructions provided by the user to guide the AI's response. These instructions are treated as user preferences and have lower priority than the system's core instructions. For example, you can specify a particular writing style, format, or focus area.
113
+
114
+ - **`history`** (array, optional): An array of message pairs representing the conversation history. Each pair consists of a role (either 'human' or 'assistant') and the message content. This allows the system to use the context of the conversation to refine results. Example:
115
+
116
+ ```json
117
+ [
118
+ ["human", "What is Perplexica?"],
119
+ ["assistant", "Perplexica is an AI-powered search engine..."]
120
+ ]
121
+ ```
122
+
123
+ - **`stream`** (boolean, optional): When set to `true`, enables streaming responses. Default is `false`.
124
+
125
+ ### Response
126
+
127
+ The response from the API includes both the final message and the sources used to generate that message.
128
+
129
+ #### Standard Response (stream: false)
130
+
131
+ ```json
132
+ {
133
+ "message": "Perplexica is an innovative, open-source AI-powered search engine designed to enhance the way users search for information online. Here are some key features and characteristics of Perplexica:\n\n- **AI-Powered Technology**: It utilizes advanced machine learning algorithms to not only retrieve information but also to understand the context and intent behind user queries, providing more relevant results [1][5].\n\n- **Open-Source**: Being open-source, Perplexica offers flexibility and transparency, allowing users to explore its functionalities without the constraints of proprietary software [3][10].",
134
+ "sources": [
135
+ {
136
+ "content": "Perplexica is an innovative, open-source AI-powered search engine designed to enhance the way users search for information online.",
137
+ "metadata": {
138
+ "title": "What is Perplexica, and how does it function as an AI-powered search ...",
139
+ "url": "https://askai.glarity.app/search/What-is-Perplexica--and-how-does-it-function-as-an-AI-powered-search-engine"
140
+ }
141
+ },
142
+ {
143
+ "content": "Perplexica is an open-source AI-powered search tool that dives deep into the internet to find precise answers.",
144
+ "metadata": {
145
+ "title": "Sahar Mor's Post",
146
+ "url": "https://www.linkedin.com/posts/sahar-mor_a-new-open-source-project-called-perplexica-activity-7204489745668694016-ncja"
147
+ }
148
+ }
149
+ ....
150
+ ]
151
+ }
152
+ ```
153
+
154
+ #### Streaming Response (stream: true)
155
+
156
+ When streaming is enabled, the API returns a stream of newline-delimited JSON objects using Server-Sent Events (SSE). Each line contains a complete, valid JSON object. The response has `Content-Type: text/event-stream`.
157
+
158
+ Example of streamed response objects:
159
+
160
+ ```
161
+ {"type":"init","data":"Stream connected"}
162
+ {"type":"sources","data":[{"content":"...","metadata":{"title":"...","url":"..."}},...]}
163
+ {"type":"response","data":"Perplexica is an "}
164
+ {"type":"response","data":"innovative, open-source "}
165
+ {"type":"response","data":"AI-powered search engine..."}
166
+ {"type":"done"}
167
+ ```
168
+
169
+ Clients should process each line as a separate JSON object. The different message types include:
170
+
171
+ - **`init`**: Initial connection message
172
+ - **`sources`**: All sources used for the response
173
+ - **`response`**: Chunks of the generated answer text
174
+ - **`done`**: Indicates the stream is complete
175
+
176
+ ### Fields in the Response
177
+
178
+ - **`message`** (string): The search result, generated based on the query and enabled `sources`.
179
+ - **`sources`** (array): A list of sources that were used to generate the search result. Each source includes:
180
+ - `content`: A snippet of the relevant content from the source.
181
+ - `metadata`: Metadata about the source, including:
182
+ - `title`: The title of the webpage.
183
+ - `url`: The URL of the webpage.
184
+
185
+ ### Error Handling
186
+
187
+ If an error occurs during the search process, the API will return an appropriate error message with an HTTP status code.
188
+
189
+ - **400**: If the request is malformed or missing required fields (e.g., no `sources` or `query`).
190
+ - **500**: If an internal server error occurs during the search.
docs/architecture/README.md ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Perplexica Architecture
2
+
3
+ Perplexica is a Next.js application that combines an AI chat experience with search.
4
+
5
+ For a high level flow, see [WORKING.md](WORKING.md). For deeper implementation details, see [CONTRIBUTING.md](../../CONTRIBUTING.md).
6
+
7
+ ## Key components
8
+
9
+ 1. **User Interface**
10
+
11
+ - A web based UI that lets users chat, search, and view citations.
12
+
13
+ 2. **API Routes**
14
+
15
+ - `POST /api/chat` powers the chat UI.
16
+ - `POST /api/search` provides a programmatic search endpoint.
17
+ - `GET /api/providers` lists available providers and model keys.
18
+
19
+ 3. **Agents and Orchestration**
20
+
21
+ - The system classifies the question first.
22
+ - It can run research and widgets in parallel.
23
+ - It generates the final answer and includes citations.
24
+
25
+ 4. **Search Backend**
26
+
27
+ - A meta search backend is used to fetch relevant web results when research is enabled.
28
+
29
+ 5. **LLMs (Large Language Models)**
30
+
31
+ - Used for classification, writing answers, and producing citations.
32
+
33
+ 6. **Embedding Models**
34
+
35
+ - Used for semantic search over user uploaded files.
36
+
37
+ 7. **Storage**
38
+ - Chats and messages are stored so conversations can be reloaded.
docs/architecture/WORKING.md ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # How Perplexica Works
2
+
3
+ This is a high level overview of how Perplexica answers a question.
4
+
5
+ If you want a component level overview, see [README.md](README.md).
6
+
7
+ If you want implementation details, see [CONTRIBUTING.md](../../CONTRIBUTING.md).
8
+
9
+ ## What happens when you ask a question
10
+
11
+ When you send a message in the UI, the app calls `POST /api/chat`.
12
+
13
+ At a high level, we do three things:
14
+
15
+ 1. Classify the question and decide what to do next.
16
+ 2. Run research and widgets in parallel.
17
+ 3. Write the final answer and include citations.
18
+
19
+ ## Classification
20
+
21
+ Before searching or answering, we run a classification step.
22
+
23
+ This step decides things like:
24
+
25
+ - Whether we should do research for this question
26
+ - Whether we should show any widgets
27
+ - How to rewrite the question into a clearer standalone form
28
+
29
+ ## Widgets
30
+
31
+ Widgets are small, structured helpers that can run alongside research.
32
+
33
+ Examples include weather, stocks, and simple calculations.
34
+
35
+ If a widget is relevant, we show it in the UI while the answer is still being generated.
36
+
37
+ Widgets are helpful context for the answer, but they are not part of what the model should cite.
38
+
39
+ ## Research
40
+
41
+ If research is needed, we gather information in the background while widgets can run.
42
+
43
+ Depending on configuration, research may include web lookup and searching user uploaded files.
44
+
45
+ ## Answer generation
46
+
47
+ Once we have enough context, the chat model generates the final response.
48
+
49
+ You can control the tradeoff between speed and quality using `optimizationMode`:
50
+
51
+ - `speed`
52
+ - `balanced`
53
+ - `quality`
54
+
55
+ ## How citations work
56
+
57
+ We prompt the model to cite the references it used. The UI then renders those citations alongside the supporting links.
58
+
59
+ ## Search API
60
+
61
+ If you are integrating Perplexica into another product, you can call `POST /api/search`.
62
+
63
+ It returns:
64
+
65
+ - `message`: the generated answer
66
+ - `sources`: supporting references used for the answer
67
+
68
+ You can also enable streaming by setting `stream: true`.
69
+
70
+ ## Image and video search
71
+
72
+ Image and video search use separate endpoints (`POST /api/images` and `POST /api/videos`). We generate a focused query using the chat model, then fetch matching results from a search backend.
docs/installation/UPDATING.md ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Update Perplexica to the latest version
2
+
3
+ To update Perplexica to the latest version, follow these steps:
4
+
5
+ ## For Docker users (Using pre-built images)
6
+
7
+ Simply pull the latest image and restart your container:
8
+
9
+ ```bash
10
+ docker pull itzcrazykns1337/perplexica:latest
11
+ docker stop perplexica
12
+ docker rm perplexica
13
+ docker run -d -p 3000:3000 -v perplexica-data:/home/perplexica/data --name perplexica itzcrazykns1337/perplexica:latest
14
+ ```
15
+
16
+ For slim version:
17
+
18
+ ```bash
19
+ docker pull itzcrazykns1337/perplexica:slim-latest
20
+ docker stop perplexica
21
+ docker rm perplexica
22
+ docker run -d -p 3000:3000 -e SEARXNG_API_URL=http://your-searxng-url:8080 -v perplexica-data:/home/perplexica/data --name perplexica itzcrazykns1337/perplexica:slim-latest
23
+ ```
24
+
25
+ Once updated, go to http://localhost:3000 and verify the latest changes. Your settings are preserved automatically.
26
+
27
+ ## For Docker users (Building from source)
28
+
29
+ 1. Navigate to your Perplexica directory and pull the latest changes:
30
+
31
+ ```bash
32
+ cd Perplexica
33
+ git pull origin master
34
+ ```
35
+
36
+ 2. Rebuild the Docker image:
37
+
38
+ ```bash
39
+ docker build -t perplexica .
40
+ ```
41
+
42
+ 3. Stop and remove the old container, then start the new one:
43
+
44
+ ```bash
45
+ docker stop perplexica
46
+ docker rm perplexica
47
+ docker run -p 3000:3000 -p 8080:8080 --name perplexica perplexica
48
+ ```
49
+
50
+ 4. Once the command completes, go to http://localhost:3000 and verify the latest changes.
51
+
52
+ ## For non-Docker users
53
+
54
+ 1. Navigate to your Perplexica directory and pull the latest changes:
55
+
56
+ ```bash
57
+ cd Perplexica
58
+ git pull origin master
59
+ ```
60
+
61
+ 2. Install any new dependencies:
62
+
63
+ ```bash
64
+ npm i
65
+ ```
66
+
67
+ 3. Rebuild the application:
68
+
69
+ ```bash
70
+ npm run build
71
+ ```
72
+
73
+ 4. Restart the application:
74
+
75
+ ```bash
76
+ npm run start
77
+ ```
78
+
79
+ 5. Go to http://localhost:3000 and verify the latest changes. Your settings are preserved automatically.
80
+
81
+ ---
drizzle.config.ts ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { defineConfig } from 'drizzle-kit';
2
+ import path from 'path';
3
+
4
+ export default defineConfig({
5
+ dialect: 'sqlite',
6
+ schema: './src/lib/db/schema.ts',
7
+ out: './drizzle',
8
+ dbCredentials: {
9
+ url: path.join(process.cwd(), 'data', 'db.sqlite'),
10
+ },
11
+ });
drizzle/0000_fuzzy_randall.sql ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ CREATE TABLE IF NOT EXISTS `chats` (
2
+ `id` text PRIMARY KEY NOT NULL,
3
+ `title` text NOT NULL,
4
+ `createdAt` text NOT NULL,
5
+ `focusMode` text NOT NULL,
6
+ `files` text DEFAULT '[]'
7
+ );
8
+ --> statement-breakpoint
9
+ CREATE TABLE IF NOT EXISTS `messages` (
10
+ `id` integer PRIMARY KEY NOT NULL,
11
+ `content` text NOT NULL,
12
+ `chatId` text NOT NULL,
13
+ `messageId` text NOT NULL,
14
+ `type` text,
15
+ `metadata` text
16
+ );
drizzle/0001_wise_rockslide.sql ADDED
@@ -0,0 +1 @@
 
 
1
+ /* Do nothing */
drizzle/0002_daffy_wrecker.sql ADDED
@@ -0,0 +1 @@
 
 
1
+ /* do nothing */
drizzle/meta/0000_snapshot.json ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "version": "6",
3
+ "dialect": "sqlite",
4
+ "id": "ef3a044b-0f34-40b5-babb-2bb3a909ba27",
5
+ "prevId": "00000000-0000-0000-0000-000000000000",
6
+ "tables": {
7
+ "chats": {
8
+ "name": "chats",
9
+ "columns": {
10
+ "id": {
11
+ "name": "id",
12
+ "type": "text",
13
+ "primaryKey": true,
14
+ "notNull": true,
15
+ "autoincrement": false
16
+ },
17
+ "title": {
18
+ "name": "title",
19
+ "type": "text",
20
+ "primaryKey": false,
21
+ "notNull": true,
22
+ "autoincrement": false
23
+ },
24
+ "createdAt": {
25
+ "name": "createdAt",
26
+ "type": "text",
27
+ "primaryKey": false,
28
+ "notNull": true,
29
+ "autoincrement": false
30
+ },
31
+ "focusMode": {
32
+ "name": "focusMode",
33
+ "type": "text",
34
+ "primaryKey": false,
35
+ "notNull": true,
36
+ "autoincrement": false
37
+ },
38
+ "files": {
39
+ "name": "files",
40
+ "type": "text",
41
+ "primaryKey": false,
42
+ "notNull": false,
43
+ "autoincrement": false,
44
+ "default": "'[]'"
45
+ }
46
+ },
47
+ "indexes": {},
48
+ "foreignKeys": {},
49
+ "compositePrimaryKeys": {},
50
+ "uniqueConstraints": {},
51
+ "checkConstraints": {}
52
+ },
53
+ "messages": {
54
+ "name": "messages",
55
+ "columns": {
56
+ "id": {
57
+ "name": "id",
58
+ "type": "integer",
59
+ "primaryKey": true,
60
+ "notNull": true,
61
+ "autoincrement": false
62
+ },
63
+ "content": {
64
+ "name": "content",
65
+ "type": "text",
66
+ "primaryKey": false,
67
+ "notNull": true,
68
+ "autoincrement": false
69
+ },
70
+ "chatId": {
71
+ "name": "chatId",
72
+ "type": "text",
73
+ "primaryKey": false,
74
+ "notNull": true,
75
+ "autoincrement": false
76
+ },
77
+ "messageId": {
78
+ "name": "messageId",
79
+ "type": "text",
80
+ "primaryKey": false,
81
+ "notNull": true,
82
+ "autoincrement": false
83
+ },
84
+ "type": {
85
+ "name": "type",
86
+ "type": "text",
87
+ "primaryKey": false,
88
+ "notNull": false,
89
+ "autoincrement": false
90
+ },
91
+ "metadata": {
92
+ "name": "metadata",
93
+ "type": "text",
94
+ "primaryKey": false,
95
+ "notNull": false,
96
+ "autoincrement": false
97
+ }
98
+ },
99
+ "indexes": {},
100
+ "foreignKeys": {},
101
+ "compositePrimaryKeys": {},
102
+ "uniqueConstraints": {},
103
+ "checkConstraints": {}
104
+ }
105
+ },
106
+ "views": {},
107
+ "enums": {},
108
+ "_meta": {
109
+ "schemas": {},
110
+ "tables": {},
111
+ "columns": {}
112
+ },
113
+ "internal": {
114
+ "indexes": {}
115
+ }
116
+ }
drizzle/meta/0001_snapshot.json ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "version": "6",
3
+ "dialect": "sqlite",
4
+ "id": "6dedf55f-0e44-478f-82cf-14a21ac686f8",
5
+ "prevId": "ef3a044b-0f34-40b5-babb-2bb3a909ba27",
6
+ "tables": {
7
+ "chats": {
8
+ "name": "chats",
9
+ "columns": {
10
+ "id": {
11
+ "name": "id",
12
+ "type": "text",
13
+ "primaryKey": true,
14
+ "notNull": true,
15
+ "autoincrement": false
16
+ },
17
+ "title": {
18
+ "name": "title",
19
+ "type": "text",
20
+ "primaryKey": false,
21
+ "notNull": true,
22
+ "autoincrement": false
23
+ },
24
+ "createdAt": {
25
+ "name": "createdAt",
26
+ "type": "text",
27
+ "primaryKey": false,
28
+ "notNull": true,
29
+ "autoincrement": false
30
+ },
31
+ "focusMode": {
32
+ "name": "focusMode",
33
+ "type": "text",
34
+ "primaryKey": false,
35
+ "notNull": true,
36
+ "autoincrement": false
37
+ },
38
+ "files": {
39
+ "name": "files",
40
+ "type": "text",
41
+ "primaryKey": false,
42
+ "notNull": false,
43
+ "autoincrement": false,
44
+ "default": "'[]'"
45
+ }
46
+ },
47
+ "indexes": {},
48
+ "foreignKeys": {},
49
+ "compositePrimaryKeys": {},
50
+ "uniqueConstraints": {},
51
+ "checkConstraints": {}
52
+ },
53
+ "messages": {
54
+ "name": "messages",
55
+ "columns": {
56
+ "id": {
57
+ "name": "id",
58
+ "type": "integer",
59
+ "primaryKey": true,
60
+ "notNull": true,
61
+ "autoincrement": false
62
+ },
63
+ "type": {
64
+ "name": "type",
65
+ "type": "text",
66
+ "primaryKey": false,
67
+ "notNull": true,
68
+ "autoincrement": false
69
+ },
70
+ "chatId": {
71
+ "name": "chatId",
72
+ "type": "text",
73
+ "primaryKey": false,
74
+ "notNull": true,
75
+ "autoincrement": false
76
+ },
77
+ "createdAt": {
78
+ "name": "createdAt",
79
+ "type": "text",
80
+ "primaryKey": false,
81
+ "notNull": true,
82
+ "autoincrement": false,
83
+ "default": "CURRENT_TIMESTAMP"
84
+ },
85
+ "messageId": {
86
+ "name": "messageId",
87
+ "type": "text",
88
+ "primaryKey": false,
89
+ "notNull": true,
90
+ "autoincrement": false
91
+ },
92
+ "content": {
93
+ "name": "content",
94
+ "type": "text",
95
+ "primaryKey": false,
96
+ "notNull": false,
97
+ "autoincrement": false
98
+ },
99
+ "sources": {
100
+ "name": "sources",
101
+ "type": "text",
102
+ "primaryKey": false,
103
+ "notNull": false,
104
+ "autoincrement": false,
105
+ "default": "'[]'"
106
+ }
107
+ },
108
+ "indexes": {},
109
+ "foreignKeys": {},
110
+ "compositePrimaryKeys": {},
111
+ "uniqueConstraints": {},
112
+ "checkConstraints": {}
113
+ }
114
+ },
115
+ "views": {},
116
+ "enums": {},
117
+ "_meta": {
118
+ "schemas": {},
119
+ "tables": {},
120
+ "columns": {}
121
+ },
122
+ "internal": {
123
+ "indexes": {}
124
+ }
125
+ }
drizzle/meta/0002_snapshot.json ADDED
@@ -0,0 +1,132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "version": "6",
3
+ "dialect": "sqlite",
4
+ "id": "1c5eb804-d6b4-48ec-9a8f-75fb729c8e52",
5
+ "prevId": "6dedf55f-0e44-478f-82cf-14a21ac686f8",
6
+ "tables": {
7
+ "chats": {
8
+ "name": "chats",
9
+ "columns": {
10
+ "id": {
11
+ "name": "id",
12
+ "type": "text",
13
+ "primaryKey": true,
14
+ "notNull": true,
15
+ "autoincrement": false
16
+ },
17
+ "title": {
18
+ "name": "title",
19
+ "type": "text",
20
+ "primaryKey": false,
21
+ "notNull": true,
22
+ "autoincrement": false
23
+ },
24
+ "createdAt": {
25
+ "name": "createdAt",
26
+ "type": "text",
27
+ "primaryKey": false,
28
+ "notNull": true,
29
+ "autoincrement": false
30
+ },
31
+ "sources": {
32
+ "name": "sources",
33
+ "type": "text",
34
+ "primaryKey": false,
35
+ "notNull": true,
36
+ "autoincrement": false
37
+ },
38
+ "files": {
39
+ "name": "files",
40
+ "type": "text",
41
+ "primaryKey": false,
42
+ "notNull": false,
43
+ "autoincrement": false,
44
+ "default": "'[]'"
45
+ }
46
+ },
47
+ "indexes": {},
48
+ "foreignKeys": {},
49
+ "compositePrimaryKeys": {},
50
+ "uniqueConstraints": {},
51
+ "checkConstraints": {}
52
+ },
53
+ "messages": {
54
+ "name": "messages",
55
+ "columns": {
56
+ "id": {
57
+ "name": "id",
58
+ "type": "integer",
59
+ "primaryKey": true,
60
+ "notNull": true,
61
+ "autoincrement": false
62
+ },
63
+ "messageId": {
64
+ "name": "messageId",
65
+ "type": "text",
66
+ "primaryKey": false,
67
+ "notNull": true,
68
+ "autoincrement": false
69
+ },
70
+ "chatId": {
71
+ "name": "chatId",
72
+ "type": "text",
73
+ "primaryKey": false,
74
+ "notNull": true,
75
+ "autoincrement": false
76
+ },
77
+ "backendId": {
78
+ "name": "backendId",
79
+ "type": "text",
80
+ "primaryKey": false,
81
+ "notNull": true,
82
+ "autoincrement": false
83
+ },
84
+ "query": {
85
+ "name": "query",
86
+ "type": "text",
87
+ "primaryKey": false,
88
+ "notNull": true,
89
+ "autoincrement": false
90
+ },
91
+ "createdAt": {
92
+ "name": "createdAt",
93
+ "type": "text",
94
+ "primaryKey": false,
95
+ "notNull": true,
96
+ "autoincrement": false
97
+ },
98
+ "responseBlocks": {
99
+ "name": "responseBlocks",
100
+ "type": "text",
101
+ "primaryKey": false,
102
+ "notNull": false,
103
+ "autoincrement": false,
104
+ "default": "'[]'"
105
+ },
106
+ "status": {
107
+ "name": "status",
108
+ "type": "text",
109
+ "primaryKey": false,
110
+ "notNull": false,
111
+ "autoincrement": false,
112
+ "default": "'answering'"
113
+ }
114
+ },
115
+ "indexes": {},
116
+ "foreignKeys": {},
117
+ "compositePrimaryKeys": {},
118
+ "uniqueConstraints": {},
119
+ "checkConstraints": {}
120
+ }
121
+ },
122
+ "views": {},
123
+ "enums": {},
124
+ "_meta": {
125
+ "schemas": {},
126
+ "tables": {},
127
+ "columns": {}
128
+ },
129
+ "internal": {
130
+ "indexes": {}
131
+ }
132
+ }
drizzle/meta/_journal.json ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "version": "7",
3
+ "dialect": "sqlite",
4
+ "entries": [
5
+ {
6
+ "idx": 0,
7
+ "version": "6",
8
+ "when": 1748405503809,
9
+ "tag": "0000_fuzzy_randall",
10
+ "breakpoints": true
11
+ },
12
+ {
13
+ "idx": 1,
14
+ "version": "6",
15
+ "when": 1758863991284,
16
+ "tag": "0001_wise_rockslide",
17
+ "breakpoints": true
18
+ },
19
+ {
20
+ "idx": 2,
21
+ "version": "6",
22
+ "when": 1763732708332,
23
+ "tag": "0002_daffy_wrecker",
24
+ "breakpoints": true
25
+ }
26
+ ]
27
+ }
entrypoint-hf.sh ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ PORT="${PORT:-7860}"
5
+ SPACE_PASSWORD="${PASSWORD:-${password:-}}"
6
+
7
+ if [ -z "${SPACE_PASSWORD}" ]; then
8
+ echo "ERROR: PASSWORD secret is required for this public Space."
9
+ exit 1
10
+ fi
11
+
12
+ password_hash="$(openssl passwd -apr1 "${SPACE_PASSWORD}")"
13
+ printf "admin:%s\n" "${password_hash}" >/tmp/.htpasswd
14
+ cat >/tmp/nginx.auth.conf <<EOF
15
+ auth_basic "Perplexica";
16
+ auth_basic_user_file /tmp/.htpasswd;
17
+ EOF
18
+
19
+ sed "s/__PORT__/${PORT}/g" /home/perplexica/hf.nginx.conf >/tmp/nginx.conf
20
+
21
+ echo "Starting SearXNG..."
22
+ sudo -H -u searxng bash -c "cd /usr/local/searxng/searxng-src && export SEARXNG_SETTINGS_PATH='/etc/searxng/settings.yml' && export FLASK_APP=searx/webapp.py && /usr/local/searxng/searx-pyenv/bin/python -m flask run --host=0.0.0.0 --port=8080" &
23
+ SEARXNG_PID=$!
24
+
25
+ echo "Waiting for SearXNG..."
26
+ COUNTER=0
27
+ MAX_TRIES=30
28
+ until curl -s http://127.0.0.1:8080 >/dev/null 2>&1; do
29
+ COUNTER=$((COUNTER + 1))
30
+ if [ "${COUNTER}" -ge "${MAX_TRIES}" ]; then
31
+ echo "WARNING: SearXNG health check timeout, continuing startup."
32
+ break
33
+ fi
34
+ sleep 1
35
+ done
36
+
37
+ echo "Starting Perplexica..."
38
+ cd /home/perplexica
39
+ HOSTNAME=0.0.0.0 PORT=3000 node server.js &
40
+ NODE_PID=$!
41
+
42
+ echo "Starting Nginx..."
43
+ nginx -g "daemon off;" -c /tmp/nginx.conf &
44
+ NGINX_PID=$!
45
+
46
+ cleanup() {
47
+ kill "${NGINX_PID}" "${NODE_PID}" "${SEARXNG_PID}" 2>/dev/null || true
48
+ }
49
+
50
+ trap cleanup SIGINT SIGTERM
51
+
52
+ set +e
53
+ wait -n "${NGINX_PID}" "${NODE_PID}" "${SEARXNG_PID}"
54
+ status=$?
55
+ set -e
56
+
57
+ cleanup
58
+ wait || true
59
+ exit "${status}"
entrypoint.sh ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/sh
2
+ set -e
3
+
4
+ echo "Starting SearXNG..."
5
+
6
+ sudo -H -u searxng bash -c "cd /usr/local/searxng/searxng-src && export SEARXNG_SETTINGS_PATH='/etc/searxng/settings.yml' && export FLASK_APP=searx/webapp.py && /usr/local/searxng/searx-pyenv/bin/python -m flask run --host=0.0.0.0 --port=8080" &
7
+ SEARXNG_PID=$!
8
+
9
+ echo "Waiting for SearXNG to be ready..."
10
+ sleep 5
11
+
12
+ COUNTER=0
13
+ MAX_TRIES=30
14
+ until curl -s http://localhost:8080 > /dev/null 2>&1; do
15
+ COUNTER=$((COUNTER+1))
16
+ if [ $COUNTER -ge $MAX_TRIES ]; then
17
+ echo "Warning: SearXNG health check timeout, but continuing..."
18
+ break
19
+ fi
20
+ sleep 1
21
+ done
22
+
23
+ if curl -s http://localhost:8080 > /dev/null 2>&1; then
24
+ echo "SearXNG started successfully (PID: $SEARXNG_PID)"
25
+ else
26
+ echo "SearXNG may not be fully ready, but continuing (PID: $SEARXNG_PID)"
27
+ fi
28
+
29
+ cd /home/perplexica
30
+ echo "Starting Perplexica..."
31
+
32
+ exec node server.js
hf.nginx.conf ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ events {
2
+ worker_connections 1024;
3
+ }
4
+
5
+ pid /tmp/nginx.pid;
6
+
7
+ http {
8
+ access_log /dev/stdout;
9
+ error_log /dev/stderr;
10
+
11
+ server {
12
+ listen __PORT__;
13
+ listen [::]:__PORT__;
14
+ server_name _;
15
+ include /tmp/nginx.auth.conf;
16
+
17
+ location / {
18
+ proxy_pass http://127.0.0.1:3000;
19
+ proxy_http_version 1.1;
20
+ proxy_set_header Host $host;
21
+ proxy_set_header X-Real-IP $remote_addr;
22
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
23
+ proxy_set_header X-Forwarded-Proto $scheme;
24
+ proxy_set_header Upgrade $http_upgrade;
25
+ proxy_set_header Connection "upgrade";
26
+ proxy_read_timeout 600s;
27
+ proxy_send_timeout 600s;
28
+ }
29
+ }
30
+ }
next-env.d.ts ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ /// <reference types="next" />
2
+ /// <reference types="next/image-types/global" />
3
+ import './.next/dev/types/routes.d.ts';
4
+
5
+ // NOTE: This file should not be edited
6
+ // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
next.config.mjs ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pkg from './package.json' with { type: 'json' };
2
+
3
+ /** @type {import('next').NextConfig} */
4
+ const nextConfig = {
5
+ output: 'standalone',
6
+ images: {
7
+ remotePatterns: [
8
+ {
9
+ hostname: 's2.googleusercontent.com',
10
+ },
11
+ ],
12
+ },
13
+ serverExternalPackages: ['pdf-parse'],
14
+ outputFileTracingIncludes: {
15
+ '/api/**': [
16
+ './node_modules/@napi-rs/canvas/**',
17
+ './node_modules/@napi-rs/canvas-linux-x64-gnu/**',
18
+ './node_modules/@napi-rs/canvas-linux-x64-musl/**',
19
+ ],
20
+ },
21
+ env: {
22
+ NEXT_PUBLIC_VERSION: pkg.version,
23
+ },
24
+ };
25
+
26
+ export default nextConfig;
package.json ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "perplexica",
3
+ "version": "1.12.1",
4
+ "license": "MIT",
5
+ "author": "ItzCrazyKns",
6
+ "scripts": {
7
+ "dev": "next dev --webpack",
8
+ "build": "next build --webpack",
9
+ "start": "next start",
10
+ "lint": "next lint",
11
+ "format:write": "prettier . --write"
12
+ },
13
+ "dependencies": {
14
+ "@google/genai": "^1.34.0",
15
+ "@headlessui/react": "^2.2.0",
16
+ "@headlessui/tailwindcss": "^0.2.2",
17
+ "@huggingface/transformers": "^3.8.1",
18
+ "@icons-pack/react-simple-icons": "^12.3.0",
19
+ "@phosphor-icons/react": "^2.1.10",
20
+ "@radix-ui/react-tooltip": "^1.2.8",
21
+ "@tailwindcss/typography": "^0.5.12",
22
+ "@toolsycc/json-repair": "^0.1.22",
23
+ "axios": "^1.8.3",
24
+ "better-sqlite3": "^11.9.1",
25
+ "clsx": "^2.1.0",
26
+ "drizzle-orm": "^0.40.1",
27
+ "js-tiktoken": "^1.0.21",
28
+ "jspdf": "^3.0.4",
29
+ "lightweight-charts": "^5.0.9",
30
+ "lucide-react": "^0.556.0",
31
+ "mammoth": "^1.9.1",
32
+ "markdown-to-jsx": "^7.7.2",
33
+ "mathjs": "^15.1.0",
34
+ "motion": "^12.23.26",
35
+ "next": "^16.0.7",
36
+ "next-themes": "^0.3.0",
37
+ "officeparser": "^5.2.2",
38
+ "ollama": "^0.6.3",
39
+ "openai": "^6.9.0",
40
+ "partial-json": "^0.1.7",
41
+ "pdf-parse": "^2.4.5",
42
+ "react": "^18",
43
+ "react-dom": "^18",
44
+ "react-syntax-highlighter": "^16.1.0",
45
+ "react-text-to-speech": "^0.14.5",
46
+ "react-textarea-autosize": "^8.5.3",
47
+ "rfc6902": "^5.1.2",
48
+ "sonner": "^1.4.41",
49
+ "tailwind-merge": "^2.2.2",
50
+ "turndown": "^7.2.2",
51
+ "yahoo-finance2": "^3.10.2",
52
+ "yet-another-react-lightbox": "^3.17.2",
53
+ "zod": "^4.1.12"
54
+ },
55
+ "devDependencies": {
56
+ "@types/better-sqlite3": "^7.6.12",
57
+ "@types/jspdf": "^2.0.0",
58
+ "@types/node": "^24.8.1",
59
+ "@types/pdf-parse": "^1.1.4",
60
+ "@types/react": "^18",
61
+ "@types/react-dom": "^18",
62
+ "@types/react-syntax-highlighter": "^15.5.13",
63
+ "@types/turndown": "^5.0.6",
64
+ "autoprefixer": "^10.0.1",
65
+ "drizzle-kit": "^0.30.5",
66
+ "eslint": "^8",
67
+ "eslint-config-next": "14.1.4",
68
+ "postcss": "^8",
69
+ "prettier": "^3.2.5",
70
+ "tailwindcss": "^3.3.0",
71
+ "typescript": "^5.9.3"
72
+ },
73
+ "optionalDependencies": {
74
+ "@napi-rs/canvas": "^0.1.87"
75
+ }
76
+ }
postcss.config.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ module.exports = {
2
+ plugins: {
3
+ tailwindcss: {},
4
+ autoprefixer: {},
5
+ },
6
+ };
public/fonts/pp-ed-ul.otf ADDED
Binary file (57.8 kB). View file
 
public/icon-100.png ADDED
public/icon-50.png ADDED
public/icon.png ADDED
public/next.svg ADDED
public/screenshots/p1.png ADDED

Git LFS Details

  • SHA256: e9996e56f3ffdf4f3d0634884668d96c5ce1d3a93506682af749ea3e90cd6b40
  • Pointer size: 131 Bytes
  • Size of remote file: 187 kB
public/screenshots/p1_small.png ADDED

Git LFS Details

  • SHA256: 51db1cff86244c374966ac565073a6b90430491edbf610deb7ef202230680e7b
  • Pointer size: 131 Bytes
  • Size of remote file: 133 kB
public/screenshots/p2.png ADDED

Git LFS Details

  • SHA256: 80c9eca9049eace63b0e22b4ddeb02613921abd8351e01f52696b60d0c6412f5
  • Pointer size: 131 Bytes
  • Size of remote file: 642 kB
public/screenshots/p2_small.png ADDED

Git LFS Details

  • SHA256: b57ef05bbe0f6889eb6c938f302e7b9f85da344a4bea949c6076237f87769b4c
  • Pointer size: 131 Bytes
  • Size of remote file: 206 kB