mirror of
https://github.com/ItzCrazyKns/Perplexica.git
synced 2026-03-21 03:54:26 +00:00
Compare commits
2 Commits
master
...
feat/impro
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2e2c584169 | ||
|
|
a755867e87 |
BIN
.assets/perplexica-screenshot.png
Normal file
BIN
.assets/perplexica-screenshot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.1 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.6 MiB |
80
.github/workflows/docker-build.yaml
vendored
80
.github/workflows/docker-build.yaml
vendored
@@ -44,11 +44,11 @@ jobs:
|
|||||||
DOCKERFILE=${{ matrix.variant.dockerfile }}
|
DOCKERFILE=${{ matrix.variant.dockerfile }}
|
||||||
VARIANT=${{ matrix.variant.name }}
|
VARIANT=${{ matrix.variant.name }}
|
||||||
docker buildx build --platform linux/amd64 \
|
docker buildx build --platform linux/amd64 \
|
||||||
--cache-from=type=registry,ref=itzcrazykns1337/vane:${VARIANT}-amd64 \
|
--cache-from=type=registry,ref=itzcrazykns1337/perplexica:${VARIANT}-amd64 \
|
||||||
--cache-to=type=inline \
|
--cache-to=type=inline \
|
||||||
--provenance false \
|
--provenance false \
|
||||||
-f $DOCKERFILE \
|
-f $DOCKERFILE \
|
||||||
-t itzcrazykns1337/vane:${VARIANT}-amd64 \
|
-t itzcrazykns1337/perplexica:${VARIANT}-amd64 \
|
||||||
--push .
|
--push .
|
||||||
|
|
||||||
- name: Build and push AMD64 Canary Docker image
|
- name: Build and push AMD64 Canary Docker image
|
||||||
@@ -57,11 +57,11 @@ jobs:
|
|||||||
DOCKERFILE=${{ matrix.variant.dockerfile }}
|
DOCKERFILE=${{ matrix.variant.dockerfile }}
|
||||||
VARIANT=${{ matrix.variant.name }}
|
VARIANT=${{ matrix.variant.name }}
|
||||||
docker buildx build --platform linux/amd64 \
|
docker buildx build --platform linux/amd64 \
|
||||||
--cache-from=type=registry,ref=itzcrazykns1337/vane:${VARIANT}-canary-amd64 \
|
--cache-from=type=registry,ref=itzcrazykns1337/perplexica:${VARIANT}-canary-amd64 \
|
||||||
--cache-to=type=inline \
|
--cache-to=type=inline \
|
||||||
--provenance false \
|
--provenance false \
|
||||||
-f $DOCKERFILE \
|
-f $DOCKERFILE \
|
||||||
-t itzcrazykns1337/vane:${VARIANT}-canary-amd64 \
|
-t itzcrazykns1337/perplexica:${VARIANT}-canary-amd64 \
|
||||||
--push .
|
--push .
|
||||||
|
|
||||||
- name: Build and push AMD64 release Docker image
|
- name: Build and push AMD64 release Docker image
|
||||||
@@ -70,11 +70,11 @@ jobs:
|
|||||||
DOCKERFILE=${{ matrix.variant.dockerfile }}
|
DOCKERFILE=${{ matrix.variant.dockerfile }}
|
||||||
VARIANT=${{ matrix.variant.name }}
|
VARIANT=${{ matrix.variant.name }}
|
||||||
docker buildx build --platform linux/amd64 \
|
docker buildx build --platform linux/amd64 \
|
||||||
--cache-from=type=registry,ref=itzcrazykns1337/vane:${VARIANT}-${{ env.RELEASE_VERSION }}-amd64 \
|
--cache-from=type=registry,ref=itzcrazykns1337/perplexica:${VARIANT}-${{ env.RELEASE_VERSION }}-amd64 \
|
||||||
--cache-to=type=inline \
|
--cache-to=type=inline \
|
||||||
--provenance false \
|
--provenance false \
|
||||||
-f $DOCKERFILE \
|
-f $DOCKERFILE \
|
||||||
-t itzcrazykns1337/vane:${VARIANT}-${{ env.RELEASE_VERSION }}-amd64 \
|
-t itzcrazykns1337/perplexica:${VARIANT}-${{ env.RELEASE_VERSION }}-amd64 \
|
||||||
--push .
|
--push .
|
||||||
|
|
||||||
build-arm64:
|
build-arm64:
|
||||||
@@ -112,11 +112,11 @@ jobs:
|
|||||||
DOCKERFILE=${{ matrix.variant.dockerfile }}
|
DOCKERFILE=${{ matrix.variant.dockerfile }}
|
||||||
VARIANT=${{ matrix.variant.name }}
|
VARIANT=${{ matrix.variant.name }}
|
||||||
docker buildx build --platform linux/arm64 \
|
docker buildx build --platform linux/arm64 \
|
||||||
--cache-from=type=registry,ref=itzcrazykns1337/vane:${VARIANT}-arm64 \
|
--cache-from=type=registry,ref=itzcrazykns1337/perplexica:${VARIANT}-arm64 \
|
||||||
--cache-to=type=inline \
|
--cache-to=type=inline \
|
||||||
--provenance false \
|
--provenance false \
|
||||||
-f $DOCKERFILE \
|
-f $DOCKERFILE \
|
||||||
-t itzcrazykns1337/vane:${VARIANT}-arm64 \
|
-t itzcrazykns1337/perplexica:${VARIANT}-arm64 \
|
||||||
--push .
|
--push .
|
||||||
|
|
||||||
- name: Build and push ARM64 Canary Docker image
|
- name: Build and push ARM64 Canary Docker image
|
||||||
@@ -125,11 +125,11 @@ jobs:
|
|||||||
DOCKERFILE=${{ matrix.variant.dockerfile }}
|
DOCKERFILE=${{ matrix.variant.dockerfile }}
|
||||||
VARIANT=${{ matrix.variant.name }}
|
VARIANT=${{ matrix.variant.name }}
|
||||||
docker buildx build --platform linux/arm64 \
|
docker buildx build --platform linux/arm64 \
|
||||||
--cache-from=type=registry,ref=itzcrazykns1337/vane:${VARIANT}-canary-arm64 \
|
--cache-from=type=registry,ref=itzcrazykns1337/perplexica:${VARIANT}-canary-arm64 \
|
||||||
--cache-to=type=inline \
|
--cache-to=type=inline \
|
||||||
--provenance false \
|
--provenance false \
|
||||||
-f $DOCKERFILE \
|
-f $DOCKERFILE \
|
||||||
-t itzcrazykns1337/vane:${VARIANT}-canary-arm64 \
|
-t itzcrazykns1337/perplexica:${VARIANT}-canary-arm64 \
|
||||||
--push .
|
--push .
|
||||||
|
|
||||||
- name: Build and push ARM64 release Docker image
|
- name: Build and push ARM64 release Docker image
|
||||||
@@ -138,11 +138,11 @@ jobs:
|
|||||||
DOCKERFILE=${{ matrix.variant.dockerfile }}
|
DOCKERFILE=${{ matrix.variant.dockerfile }}
|
||||||
VARIANT=${{ matrix.variant.name }}
|
VARIANT=${{ matrix.variant.name }}
|
||||||
docker buildx build --platform linux/arm64 \
|
docker buildx build --platform linux/arm64 \
|
||||||
--cache-from=type=registry,ref=itzcrazykns1337/vane:${VARIANT}-${{ env.RELEASE_VERSION }}-arm64 \
|
--cache-from=type=registry,ref=itzcrazykns1337/perplexica:${VARIANT}-${{ env.RELEASE_VERSION }}-arm64 \
|
||||||
--cache-to=type=inline \
|
--cache-to=type=inline \
|
||||||
--provenance false \
|
--provenance false \
|
||||||
-f $DOCKERFILE \
|
-f $DOCKERFILE \
|
||||||
-t itzcrazykns1337/vane:${VARIANT}-${{ env.RELEASE_VERSION }}-arm64 \
|
-t itzcrazykns1337/perplexica:${VARIANT}-${{ env.RELEASE_VERSION }}-arm64 \
|
||||||
--push .
|
--push .
|
||||||
|
|
||||||
manifest:
|
manifest:
|
||||||
@@ -167,51 +167,51 @@ jobs:
|
|||||||
if: github.ref == 'refs/heads/master' && github.event_name == 'push'
|
if: github.ref == 'refs/heads/master' && github.event_name == 'push'
|
||||||
run: |
|
run: |
|
||||||
VARIANT=${{ matrix.variant }}
|
VARIANT=${{ matrix.variant }}
|
||||||
docker manifest create itzcrazykns1337/vane:${VARIANT}-latest \
|
docker manifest create itzcrazykns1337/perplexica:${VARIANT}-latest \
|
||||||
--amend itzcrazykns1337/vane:${VARIANT}-amd64 \
|
--amend itzcrazykns1337/perplexica:${VARIANT}-amd64 \
|
||||||
--amend itzcrazykns1337/vane:${VARIANT}-arm64
|
--amend itzcrazykns1337/perplexica:${VARIANT}-arm64
|
||||||
docker manifest push itzcrazykns1337/vane:${VARIANT}-latest
|
docker manifest push itzcrazykns1337/perplexica:${VARIANT}-latest
|
||||||
|
|
||||||
if [ "$VARIANT" = "full" ]; then
|
if [ "$VARIANT" = "full" ]; then
|
||||||
docker manifest create itzcrazykns1337/vane:latest \
|
docker manifest create itzcrazykns1337/perplexica:latest \
|
||||||
--amend itzcrazykns1337/vane:${VARIANT}-amd64 \
|
--amend itzcrazykns1337/perplexica:${VARIANT}-amd64 \
|
||||||
--amend itzcrazykns1337/vane:${VARIANT}-arm64
|
--amend itzcrazykns1337/perplexica:${VARIANT}-arm64
|
||||||
docker manifest push itzcrazykns1337/vane:latest
|
docker manifest push itzcrazykns1337/perplexica:latest
|
||||||
|
|
||||||
docker manifest create itzcrazykns1337/vane:main \
|
docker manifest create itzcrazykns1337/perplexica:main \
|
||||||
--amend itzcrazykns1337/vane:${VARIANT}-amd64 \
|
--amend itzcrazykns1337/perplexica:${VARIANT}-amd64 \
|
||||||
--amend itzcrazykns1337/vane:${VARIANT}-arm64
|
--amend itzcrazykns1337/perplexica:${VARIANT}-arm64
|
||||||
docker manifest push itzcrazykns1337/vane:main
|
docker manifest push itzcrazykns1337/perplexica:main
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Create and push manifest for canary
|
- name: Create and push manifest for canary
|
||||||
if: github.ref == 'refs/heads/canary' && github.event_name == 'push'
|
if: github.ref == 'refs/heads/canary' && github.event_name == 'push'
|
||||||
run: |
|
run: |
|
||||||
VARIANT=${{ matrix.variant }}
|
VARIANT=${{ matrix.variant }}
|
||||||
docker manifest create itzcrazykns1337/vane:${VARIANT}-canary \
|
docker manifest create itzcrazykns1337/perplexica:${VARIANT}-canary \
|
||||||
--amend itzcrazykns1337/vane:${VARIANT}-canary-amd64 \
|
--amend itzcrazykns1337/perplexica:${VARIANT}-canary-amd64 \
|
||||||
--amend itzcrazykns1337/vane:${VARIANT}-canary-arm64
|
--amend itzcrazykns1337/perplexica:${VARIANT}-canary-arm64
|
||||||
docker manifest push itzcrazykns1337/vane:${VARIANT}-canary
|
docker manifest push itzcrazykns1337/perplexica:${VARIANT}-canary
|
||||||
|
|
||||||
if [ "$VARIANT" = "full" ]; then
|
if [ "$VARIANT" = "full" ]; then
|
||||||
docker manifest create itzcrazykns1337/vane:canary \
|
docker manifest create itzcrazykns1337/perplexica:canary \
|
||||||
--amend itzcrazykns1337/vane:${VARIANT}-canary-amd64 \
|
--amend itzcrazykns1337/perplexica:${VARIANT}-canary-amd64 \
|
||||||
--amend itzcrazykns1337/vane:${VARIANT}-canary-arm64
|
--amend itzcrazykns1337/perplexica:${VARIANT}-canary-arm64
|
||||||
docker manifest push itzcrazykns1337/vane:canary
|
docker manifest push itzcrazykns1337/perplexica:canary
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Create and push manifest for releases
|
- name: Create and push manifest for releases
|
||||||
if: github.event_name == 'release'
|
if: github.event_name == 'release'
|
||||||
run: |
|
run: |
|
||||||
VARIANT=${{ matrix.variant }}
|
VARIANT=${{ matrix.variant }}
|
||||||
docker manifest create itzcrazykns1337/vane:${VARIANT}-${{ env.RELEASE_VERSION }} \
|
docker manifest create itzcrazykns1337/perplexica:${VARIANT}-${{ env.RELEASE_VERSION }} \
|
||||||
--amend itzcrazykns1337/vane:${VARIANT}-${{ env.RELEASE_VERSION }}-amd64 \
|
--amend itzcrazykns1337/perplexica:${VARIANT}-${{ env.RELEASE_VERSION }}-amd64 \
|
||||||
--amend itzcrazykns1337/vane:${VARIANT}-${{ env.RELEASE_VERSION }}-arm64
|
--amend itzcrazykns1337/perplexica:${VARIANT}-${{ env.RELEASE_VERSION }}-arm64
|
||||||
docker manifest push itzcrazykns1337/vane:${VARIANT}-${{ env.RELEASE_VERSION }}
|
docker manifest push itzcrazykns1337/perplexica:${VARIANT}-${{ env.RELEASE_VERSION }}
|
||||||
|
|
||||||
if [ "$VARIANT" = "full" ]; then
|
if [ "$VARIANT" = "full" ]; then
|
||||||
docker manifest create itzcrazykns1337/vane:${{ env.RELEASE_VERSION }} \
|
docker manifest create itzcrazykns1337/perplexica:${{ env.RELEASE_VERSION }} \
|
||||||
--amend itzcrazykns1337/vane:${VARIANT}-${{ env.RELEASE_VERSION }}-amd64 \
|
--amend itzcrazykns1337/perplexica:${VARIANT}-${{ env.RELEASE_VERSION }}-amd64 \
|
||||||
--amend itzcrazykns1337/vane:${VARIANT}-${{ env.RELEASE_VERSION }}-arm64
|
--amend itzcrazykns1337/perplexica:${VARIANT}-${{ env.RELEASE_VERSION }}-arm64
|
||||||
docker manifest push itzcrazykns1337/vane:${{ env.RELEASE_VERSION }}
|
docker manifest push itzcrazykns1337/perplexica:${{ env.RELEASE_VERSION }}
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# How to Contribute to Vane
|
# How to Contribute to Perplexica
|
||||||
|
|
||||||
Thanks for your interest in contributing to Vane! Your help makes this project better. This guide explains how to contribute effectively.
|
Thanks for your interest in contributing to Perplexica! Your help makes this project better. This guide explains how to contribute effectively.
|
||||||
|
|
||||||
Vane is a modern AI chat application with advanced search capabilities.
|
Perplexica is a modern AI chat application with advanced search capabilities.
|
||||||
|
|
||||||
## Project Structure
|
## Project Structure
|
||||||
|
|
||||||
Vane's codebase is organized as follows:
|
Perplexica's codebase is organized as follows:
|
||||||
|
|
||||||
- **UI Components and Pages**:
|
- **UI Components and Pages**:
|
||||||
- **Components (`src/components`)**: Reusable UI components.
|
- **Components (`src/components`)**: Reusable UI components.
|
||||||
@@ -53,7 +53,7 @@ If you are not sure where to start, use this section as a map.
|
|||||||
|
|
||||||
## API Documentation
|
## API Documentation
|
||||||
|
|
||||||
Vane includes API documentation for programmatic access.
|
Perplexica includes API documentation for programmatic access.
|
||||||
|
|
||||||
- **Search API**: For detailed documentation, see `docs/API/SEARCH.md`.
|
- **Search API**: For detailed documentation, see `docs/API/SEARCH.md`.
|
||||||
|
|
||||||
@@ -79,4 +79,4 @@ Before committing changes:
|
|||||||
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.
|
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.
|
||||||
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.
|
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.
|
||||||
|
|
||||||
Following these steps will help maintain the integrity of Vane's codebase and facilitate a smoother integration of your valuable contributions. Thank you for your support and commitment to improving Vane.
|
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.
|
||||||
|
|||||||
22
Dockerfile
22
Dockerfile
@@ -2,7 +2,7 @@ FROM node:24.5.0-slim AS builder
|
|||||||
|
|
||||||
RUN apt-get update && apt-get install -y python3 python3-pip sqlite3 && rm -rf /var/lib/apt/lists/*
|
RUN apt-get update && apt-get install -y python3 python3-pip sqlite3 && rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
WORKDIR /home/vane
|
WORKDIR /home/perplexica
|
||||||
|
|
||||||
COPY package.json yarn.lock ./
|
COPY package.json yarn.lock ./
|
||||||
RUN yarn install --frozen-lockfile --network-timeout 600000
|
RUN yarn install --frozen-lockfile --network-timeout 600000
|
||||||
@@ -12,7 +12,7 @@ COPY src ./src
|
|||||||
COPY public ./public
|
COPY public ./public
|
||||||
COPY drizzle ./drizzle
|
COPY drizzle ./drizzle
|
||||||
|
|
||||||
RUN mkdir -p /home/vane/data
|
RUN mkdir -p /home/perplexica/data
|
||||||
RUN yarn build
|
RUN yarn build
|
||||||
|
|
||||||
FROM node:24.5.0-slim
|
FROM node:24.5.0-slim
|
||||||
@@ -24,15 +24,15 @@ RUN apt-get update && apt-get install -y \
|
|||||||
curl sudo \
|
curl sudo \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
WORKDIR /home/vane
|
WORKDIR /home/perplexica
|
||||||
|
|
||||||
COPY --from=builder /home/vane/public ./public
|
COPY --from=builder /home/perplexica/public ./public
|
||||||
COPY --from=builder /home/vane/.next/static ./public/_next/static
|
COPY --from=builder /home/perplexica/.next/static ./public/_next/static
|
||||||
COPY --from=builder /home/vane/.next/standalone ./
|
COPY --from=builder /home/perplexica/.next/standalone ./
|
||||||
COPY --from=builder /home/vane/data ./data
|
COPY --from=builder /home/perplexica/data ./data
|
||||||
COPY drizzle ./drizzle
|
COPY drizzle ./drizzle
|
||||||
|
|
||||||
RUN mkdir /home/vane/uploads
|
RUN mkdir /home/perplexica/uploads
|
||||||
|
|
||||||
RUN useradd --shell /bin/bash --system \
|
RUN useradd --shell /bin/bash --system \
|
||||||
--home-dir "/usr/local/searxng" \
|
--home-dir "/usr/local/searxng" \
|
||||||
@@ -54,13 +54,13 @@ RUN git clone "https://github.com/searxng/searxng" \
|
|||||||
"/usr/local/searxng/searxng-src"
|
"/usr/local/searxng/searxng-src"
|
||||||
|
|
||||||
RUN python3 -m venv "/usr/local/searxng/searx-pyenv"
|
RUN python3 -m venv "/usr/local/searxng/searx-pyenv"
|
||||||
RUN "/usr/local/searxng/searx-pyenv/bin/pip" install --upgrade pip setuptools wheel pyyaml msgspec typing_extensions
|
RUN "/usr/local/searxng/searx-pyenv/bin/pip" install --upgrade pip setuptools wheel pyyaml msgspec
|
||||||
RUN cd "/usr/local/searxng/searxng-src" && \
|
RUN cd "/usr/local/searxng/searxng-src" && \
|
||||||
"/usr/local/searxng/searx-pyenv/bin/pip" install --use-pep517 --no-build-isolation -e .
|
"/usr/local/searxng/searx-pyenv/bin/pip" install --use-pep517 --no-build-isolation -e .
|
||||||
|
|
||||||
USER root
|
USER root
|
||||||
|
|
||||||
WORKDIR /home/vane
|
WORKDIR /home/perplexica
|
||||||
COPY entrypoint.sh ./entrypoint.sh
|
COPY entrypoint.sh ./entrypoint.sh
|
||||||
RUN chmod +x ./entrypoint.sh
|
RUN chmod +x ./entrypoint.sh
|
||||||
RUN sed -i 's/\r$//' ./entrypoint.sh || true
|
RUN sed -i 's/\r$//' ./entrypoint.sh || true
|
||||||
@@ -71,4 +71,4 @@ EXPOSE 3000 8080
|
|||||||
|
|
||||||
ENV SEARXNG_API_URL=http://localhost:8080
|
ENV SEARXNG_API_URL=http://localhost:8080
|
||||||
|
|
||||||
CMD ["/home/vane/entrypoint.sh"]
|
CMD ["/home/perplexica/entrypoint.sh"]
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ FROM node:24.5.0-slim AS builder
|
|||||||
|
|
||||||
RUN apt-get update && apt-get install -y python3 python3-pip sqlite3 && rm -rf /var/lib/apt/lists/*
|
RUN apt-get update && apt-get install -y python3 python3-pip sqlite3 && rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
WORKDIR /home/vane
|
WORKDIR /home/perplexica
|
||||||
|
|
||||||
COPY package.json yarn.lock ./
|
COPY package.json yarn.lock ./
|
||||||
RUN yarn install --frozen-lockfile --network-timeout 600000
|
RUN yarn install --frozen-lockfile --network-timeout 600000
|
||||||
@@ -12,23 +12,23 @@ COPY src ./src
|
|||||||
COPY public ./public
|
COPY public ./public
|
||||||
COPY drizzle ./drizzle
|
COPY drizzle ./drizzle
|
||||||
|
|
||||||
RUN mkdir -p /home/vane/data
|
RUN mkdir -p /home/perplexica/data
|
||||||
RUN yarn build
|
RUN yarn build
|
||||||
|
|
||||||
FROM node:24.5.0-slim
|
FROM node:24.5.0-slim
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y python3 python3-pip sqlite3 && rm -rf /var/lib/apt/lists/*
|
RUN apt-get update && apt-get install -y python3 python3-pip sqlite3 && rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
WORKDIR /home/vane
|
WORKDIR /home/perplexica
|
||||||
|
|
||||||
COPY --from=builder /home/vane/public ./public
|
COPY --from=builder /home/perplexica/public ./public
|
||||||
COPY --from=builder /home/vane/.next/static ./public/_next/static
|
COPY --from=builder /home/perplexica/.next/static ./public/_next/static
|
||||||
|
|
||||||
COPY --from=builder /home/vane/.next/standalone ./
|
COPY --from=builder /home/perplexica/.next/standalone ./
|
||||||
COPY --from=builder /home/vane/data ./data
|
COPY --from=builder /home/perplexica/data ./data
|
||||||
COPY drizzle ./drizzle
|
COPY drizzle ./drizzle
|
||||||
|
|
||||||
RUN mkdir /home/vane/uploads
|
RUN mkdir /home/perplexica/uploads
|
||||||
|
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
|
|
||||||
|
|||||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2026 ItzCrazyKns
|
Copyright (c) 2024 ItzCrazyKns
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
93
README.md
93
README.md
@@ -1,18 +1,18 @@
|
|||||||
# Vane 🔍
|
# Perplexica 🔍
|
||||||
|
|
||||||
[](https://github.com/ItzCrazyKns/Vane/stargazers)
|
[](https://github.com/ItzCrazyKns/Perplexica/stargazers)
|
||||||
[](https://github.com/ItzCrazyKns/Vane/network/members)
|
[](https://github.com/ItzCrazyKns/Perplexica/network/members)
|
||||||
[](https://github.com/ItzCrazyKns/Vane/watchers)
|
[](https://github.com/ItzCrazyKns/Perplexica/watchers)
|
||||||
[](https://hub.docker.com/r/itzcrazykns1337/vane)
|
[](https://hub.docker.com/r/itzcrazykns1337/perplexica)
|
||||||
[](https://github.com/ItzCrazyKns/Vane/blob/master/LICENSE)
|
[](https://github.com/ItzCrazyKns/Perplexica/blob/master/LICENSE)
|
||||||
[](https://github.com/ItzCrazyKns/Vane/commits/master)
|
[](https://github.com/ItzCrazyKns/Perplexica/commits/master)
|
||||||
[](https://discord.gg/26aArMy8tT)
|
[](https://discord.gg/26aArMy8tT)
|
||||||
|
|
||||||
Vane 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.
|
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.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
Want to know more about its architecture and how it works? You can read it [here](https://github.com/ItzCrazyKns/Vane/tree/master/docs/architecture/README.md).
|
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).
|
||||||
|
|
||||||
## ✨ Features
|
## ✨ Features
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ Want to know more about its architecture and how it works? You can read it [here
|
|||||||
|
|
||||||
📷 **Image and video search** - Find visual content alongside text results. Search isn't limited to just articles anymore.
|
📷 **Image and video search** - Find visual content alongside text results. Search isn't limited to just articles anymore.
|
||||||
|
|
||||||
📄 **File uploads** - Upload documents and ask questions about them. PDFs, text files, images - Vane understands them all.
|
📄 **File uploads** - Upload documents and ask questions about them. PDFs, text files, images - Perplexica understands them all.
|
||||||
|
|
||||||
🌐 **Search specific domains** - Limit your search to specific websites when you know where to look. Perfect for technical documentation or research papers.
|
🌐 **Search specific domains** - Limit your search to specific websites when you know where to look. Perfect for technical documentation or research papers.
|
||||||
|
|
||||||
@@ -38,11 +38,11 @@ Want to know more about its architecture and how it works? You can read it [here
|
|||||||
|
|
||||||
🕒 **Search history** - Every search is saved locally so you can revisit your discoveries anytime. Your research is never lost.
|
🕒 **Search history** - Every search is saved locally so you can revisit your discoveries anytime. Your research is never lost.
|
||||||
|
|
||||||
✨ **More coming soon** - We're actively developing new features based on community feedback. Join our Discord to help shape Vane's future!
|
✨ **More coming soon** - We're actively developing new features based on community feedback. Join our Discord to help shape Perplexica's future!
|
||||||
|
|
||||||
## Sponsors
|
## Sponsors
|
||||||
|
|
||||||
Vane's development is powered by the generous support of our sponsors. Their contributions help keep this project free, open-source, and accessible to everyone.
|
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.
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ Vane's development is powered by the generous support of our sponsors. Their con
|
|||||||
<img alt="Warp Terminal" src=".assets/sponsers/warp.png" width="100%">
|
<img alt="Warp Terminal" src=".assets/sponsers/warp.png" width="100%">
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
### **✨ [Try Warp - The AI-Powered Terminal →](https://www.warp.dev/vane)**
|
### **✨ [Try Warp - The AI-Powered Terminal →](https://www.warp.dev/perplexica)**
|
||||||
|
|
||||||
Warp is revolutionizing development workflows with AI-powered features, modern UX, and blazing-fast performance. Used by developers at top companies worldwide.
|
Warp is revolutionizing development workflows with AI-powered features, modern UX, and blazing-fast performance. Used by developers at top companies worldwide.
|
||||||
|
|
||||||
@@ -76,26 +76,26 @@ We'd also like to thank the following partners for their generous support:
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
There are mainly 2 ways of installing Vane - With Docker, Without Docker. Using Docker is highly recommended.
|
There are mainly 2 ways of installing Perplexica - With Docker, Without Docker. Using Docker is highly recommended.
|
||||||
|
|
||||||
### Getting Started with Docker (Recommended)
|
### Getting Started with Docker (Recommended)
|
||||||
|
|
||||||
Vane 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 -d -p 3000:3000 -v vane-data:/home/vane/data --name vane itzcrazykns1337/vane:latest
|
docker run -d -p 3000:3000 -v perplexica-data:/home/perplexica/data --name perplexica itzcrazykns1337/perplexica:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
This will pull and start the Vane 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 Vane and SearxNG, so no additional setup is required. The `-v` flags create persistent volumes for your data and uploaded files.
|
**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 Vane 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 Vane:
|
If you already have SearxNG running, you can use the slim version of Perplexica:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run -d -p 3000:3000 -e SEARXNG_API_URL=http://your-searxng-url:8080 -v vane-data:/home/vane/data --name vane itzcrazykns1337/vane:slim-latest
|
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
|
||||||
```
|
```
|
||||||
|
|
||||||
**Important**: Make sure your SearxNG instance has:
|
**Important**: Make sure your SearxNG instance has:
|
||||||
@@ -110,10 +110,10 @@ Replace `http://your-searxng-url:8080` with your actual SearxNG URL. Then config
|
|||||||
If you prefer to build from source or need more control:
|
If you prefer to build from source or need more control:
|
||||||
|
|
||||||
1. Ensure Docker is installed and running on your system.
|
1. Ensure Docker is installed and running on your system.
|
||||||
2. Clone the Vane repository:
|
2. Clone the Perplexica repository:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/ItzCrazyKns/Vane.git
|
git clone https://github.com/ItzCrazyKns/Perplexica.git
|
||||||
```
|
```
|
||||||
|
|
||||||
3. After cloning, navigate to the directory containing the project files.
|
3. After cloning, navigate to the directory containing the project files.
|
||||||
@@ -121,13 +121,13 @@ If you prefer to build from source or need more control:
|
|||||||
4. Build and run using Docker:
|
4. Build and run using Docker:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker build -t vane .
|
docker build -t perplexica .
|
||||||
docker run -d -p 3000:3000 -v vane-data:/home/vane/data --name vane vane
|
docker run -d -p 3000:3000 -v perplexica-data:/home/perplexica/data --name perplexica perplexica
|
||||||
```
|
```
|
||||||
|
|
||||||
5. Access Vane 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.
|
||||||
|
|
||||||
**Note**: After the containers are built, you can start Vane directly from Docker without having to open a terminal.
|
**Note**: After the containers are built, you can start Perplexica directly from Docker without having to open a terminal.
|
||||||
|
|
||||||
### Non-Docker Installation
|
### Non-Docker Installation
|
||||||
|
|
||||||
@@ -135,8 +135,8 @@ If you prefer to build from source or need more control:
|
|||||||
2. Clone the repository:
|
2. Clone the repository:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/ItzCrazyKns/Vane.git
|
git clone https://github.com/ItzCrazyKns/Perplexica.git
|
||||||
cd Vane
|
cd Perplexica
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Install dependencies:
|
3. Install dependencies:
|
||||||
@@ -161,13 +161,13 @@ If you prefer to build from source or need more control:
|
|||||||
|
|
||||||
**Note**: Using Docker is recommended as it simplifies the setup process, especially for managing environment variables and dependencies.
|
**Note**: Using Docker is recommended as it simplifies the setup process, especially for managing environment variables and dependencies.
|
||||||
|
|
||||||
See the [installation documentation](https://github.com/ItzCrazyKns/Vane/tree/master/docs/installation) for more information like updating, etc.
|
See the [installation documentation](https://github.com/ItzCrazyKns/Perplexica/tree/master/docs/installation) for more information like updating, etc.
|
||||||
|
|
||||||
### Troubleshooting
|
### Troubleshooting
|
||||||
|
|
||||||
#### Local OpenAI-API-Compliant Servers
|
#### Local OpenAI-API-Compliant Servers
|
||||||
|
|
||||||
If Vane tells you that you haven't configured any chat model providers, ensure that:
|
If Perplexica tells you that you haven't configured any chat model providers, ensure that:
|
||||||
|
|
||||||
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.
|
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.
|
||||||
2. You have specified the correct model name loaded by your local LLM server.
|
2. You have specified the correct model name loaded by your local LLM server.
|
||||||
@@ -213,39 +213,38 @@ If you're encountering a Lemonade connection error, it is likely due to the back
|
|||||||
|
|
||||||
## Using as a Search Engine
|
## Using as a Search Engine
|
||||||
|
|
||||||
If you wish to use Vane 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:
|
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:
|
||||||
|
|
||||||
1. Open your browser's settings.
|
1. Open your browser's settings.
|
||||||
2. Navigate to the 'Search Engines' section.
|
2. Navigate to the 'Search Engines' section.
|
||||||
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 Vane is not hosted locally.
|
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.
|
||||||
4. Click the add button. Now, you can use Vane directly from your browser's search bar.
|
4. Click the add button. Now, you can use Perplexica directly from your browser's search bar.
|
||||||
|
|
||||||
## Using Vane's API
|
## Using Perplexica's API
|
||||||
|
|
||||||
Vane 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.
|
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.
|
||||||
|
|
||||||
For more details, check out the full documentation [here](https://github.com/ItzCrazyKns/Vane/tree/master/docs/API/SEARCH.md).
|
For more details, check out the full documentation [here](https://github.com/ItzCrazyKns/Perplexica/tree/master/docs/API/SEARCH.md).
|
||||||
|
|
||||||
## Expose Vane to network
|
## Expose Perplexica to network
|
||||||
|
|
||||||
Vane runs on Next.js and handles all API requests. It works right away on the same network and stays accessible even with port forwarding.
|
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.
|
||||||
|
|
||||||
## One-Click Deployment
|
## One-Click Deployment
|
||||||
|
|
||||||
[](https://usw.sealos.io/?openapp=system-template%3FtemplateName%3Dperplexica)
|
[](https://usw.sealos.io/?openapp=system-template%3FtemplateName%3Dperplexica)
|
||||||
[](https://repocloud.io/details/?app_id=267)
|
[](https://repocloud.io/details/?app_id=267)
|
||||||
[](https://template.run.claw.cloud/?referralCode=U11MRQ8U9RM4&openapp=system-fastdeploy%3FtemplateName%3Dperplexica)
|
[](https://template.run.claw.cloud/?referralCode=U11MRQ8U9RM4&openapp=system-fastdeploy%3FtemplateName%3Dperplexica)
|
||||||
[](https://www.hostinger.com/vps/docker-hosting?compose_url=https://raw.githubusercontent.com/ItzCrazyKns/Vane/refs/heads/master/docker-compose.yaml)
|
[](https://www.hostinger.com/vps/docker-hosting?compose_url=https://raw.githubusercontent.com/ItzCrazyKns/Perplexica/refs/heads/master/docker-compose.yaml)
|
||||||
|
|
||||||
## Upcoming Features
|
## Upcoming Features
|
||||||
|
|
||||||
- [ ] Adding more widgets, integrations, search sources
|
- [] Adding more widgets, integrations, search sources
|
||||||
- [ ] Adding ability to create custom agents (name T.B.D.)
|
- [] Adding authentication
|
||||||
- [ ] Adding authentication
|
|
||||||
|
|
||||||
## Support Us
|
## Support Us
|
||||||
|
|
||||||
If you find Vane useful, consider giving us a star on GitHub. This helps more people discover Vane and supports the development of new features. Your support is greatly appreciated.
|
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.
|
||||||
|
|
||||||
### Donations
|
### Donations
|
||||||
|
|
||||||
@@ -257,10 +256,10 @@ We also accept donations to help sustain our project. If you would like to contr
|
|||||||
|
|
||||||
## Contribution
|
## Contribution
|
||||||
|
|
||||||
Vane 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 Vane you can read the [CONTRIBUTING.md](CONTRIBUTING.md) file to learn more about Vane and how you can contribute to it.
|
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.
|
||||||
|
|
||||||
## Help and Support
|
## Help and Support
|
||||||
|
|
||||||
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`.
|
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`.
|
||||||
|
|
||||||
Thank you for exploring Vane, the AI-powered search engine designed to enhance your search experience. We are constantly working to improve Vane and expand its capabilities. We value your feedback and contributions which help us make Vane even better. Don't forget to check back for updates and new features!
|
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!
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
services:
|
services:
|
||||||
vane:
|
perplexica:
|
||||||
image: itzcrazykns1337/vane:latest
|
image: itzcrazykns1337/perplexica:latest
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
ports:
|
ports:
|
||||||
- '3000:3000'
|
- '3000:3000'
|
||||||
volumes:
|
volumes:
|
||||||
- data:/home/vane/data
|
- data:/home/perplexica/data
|
||||||
|
- uploads:/home/perplexica/uploads
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
data:
|
data:
|
||||||
name: 'vane-data'
|
name: 'perplexica-data'
|
||||||
|
uploads:
|
||||||
|
name: 'perplexica-uploads'
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
# Vane Search API Documentation
|
# Perplexica Search API Documentation
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
Vane'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 Vane's search API.
|
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.
|
||||||
|
|
||||||
## Endpoints
|
## Endpoints
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ Use the `id` field as the `providerId` and the `key` field from the models array
|
|||||||
|
|
||||||
**Full URL**: `http://localhost:3000/api/search`
|
**Full URL**: `http://localhost:3000/api/search`
|
||||||
|
|
||||||
**Note**: Replace `localhost:3000` with your Vane instance URL if running on a different host or port
|
**Note**: Replace `localhost:3000` with your Perplexica instance URL if running on a different host or port
|
||||||
|
|
||||||
### Request
|
### Request
|
||||||
|
|
||||||
@@ -73,12 +73,12 @@ The API accepts a JSON object in the request body, where you define the enabled
|
|||||||
},
|
},
|
||||||
"optimizationMode": "speed",
|
"optimizationMode": "speed",
|
||||||
"sources": ["web"],
|
"sources": ["web"],
|
||||||
"query": "What is Vane",
|
"query": "What is Perplexica",
|
||||||
"history": [
|
"history": [
|
||||||
["human", "Hi, how are you?"],
|
["human", "Hi, how are you?"],
|
||||||
["assistant", "I am doing well, how can I help you today?"]
|
["assistant", "I am doing well, how can I help you today?"]
|
||||||
],
|
],
|
||||||
"systemInstructions": "Focus on providing technical details about Vane's architecture.",
|
"systemInstructions": "Focus on providing technical details about Perplexica's architecture.",
|
||||||
"stream": false
|
"stream": false
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -115,8 +115,8 @@ The API accepts a JSON object in the request body, where you define the enabled
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
[
|
[
|
||||||
["human", "What is Vane?"],
|
["human", "What is Perplexica?"],
|
||||||
["assistant", "Vane is an AI-powered search engine..."]
|
["assistant", "Perplexica is an AI-powered search engine..."]
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -130,20 +130,20 @@ The response from the API includes both the final message and the sources used t
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"message": "Vane 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 Vane:\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, Vane offers flexibility and transparency, allowing users to explore its functionalities without the constraints of proprietary software [3][10].",
|
"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].",
|
||||||
"sources": [
|
"sources": [
|
||||||
{
|
{
|
||||||
"content": "Vane is an innovative, open-source AI-powered search engine designed to enhance the way users search for information online.",
|
"content": "Perplexica is an innovative, open-source AI-powered search engine designed to enhance the way users search for information online.",
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"title": "What is Vane, and how does it function as an AI-powered search ...",
|
"title": "What is Perplexica, and how does it function as an AI-powered search ...",
|
||||||
"url": "https://askai.glarity.app/search/What-is-Vane--and-how-does-it-function-as-an-AI-powered-search-engine"
|
"url": "https://askai.glarity.app/search/What-is-Perplexica--and-how-does-it-function-as-an-AI-powered-search-engine"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"content": "Vane is an open-source AI-powered search tool that dives deep into the internet to find precise answers.",
|
"content": "Perplexica is an open-source AI-powered search tool that dives deep into the internet to find precise answers.",
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"title": "Sahar Mor's Post",
|
"title": "Sahar Mor's Post",
|
||||||
"url": "https://www.linkedin.com/posts/sahar-mor_a-new-open-source-project-called-vane-activity-7204489745668694016-ncja"
|
"url": "https://www.linkedin.com/posts/sahar-mor_a-new-open-source-project-called-perplexica-activity-7204489745668694016-ncja"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
....
|
....
|
||||||
@@ -160,7 +160,7 @@ Example of streamed response objects:
|
|||||||
```
|
```
|
||||||
{"type":"init","data":"Stream connected"}
|
{"type":"init","data":"Stream connected"}
|
||||||
{"type":"sources","data":[{"content":"...","metadata":{"title":"...","url":"..."}},...]}
|
{"type":"sources","data":[{"content":"...","metadata":{"title":"...","url":"..."}},...]}
|
||||||
{"type":"response","data":"Vane is an "}
|
{"type":"response","data":"Perplexica is an "}
|
||||||
{"type":"response","data":"innovative, open-source "}
|
{"type":"response","data":"innovative, open-source "}
|
||||||
{"type":"response","data":"AI-powered search engine..."}
|
{"type":"response","data":"AI-powered search engine..."}
|
||||||
{"type":"done"}
|
{"type":"done"}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Vane Architecture
|
# Perplexica Architecture
|
||||||
|
|
||||||
Vane is a Next.js application that combines an AI chat experience with search.
|
Perplexica is a Next.js application that combines an AI chat experience with search.
|
||||||
|
|
||||||
For a high level flow, see [WORKING.md](WORKING.md). For deeper implementation details, see [CONTRIBUTING.md](../../CONTRIBUTING.md).
|
For a high level flow, see [WORKING.md](WORKING.md). For deeper implementation details, see [CONTRIBUTING.md](../../CONTRIBUTING.md).
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# How Vane Works
|
# How Perplexica Works
|
||||||
|
|
||||||
This is a high level overview of how Vane answers a question.
|
This is a high level overview of how Perplexica answers a question.
|
||||||
|
|
||||||
If you want a component level overview, see [README.md](README.md).
|
If you want a component level overview, see [README.md](README.md).
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@ We prompt the model to cite the references it used. The UI then renders those ci
|
|||||||
|
|
||||||
## Search API
|
## Search API
|
||||||
|
|
||||||
If you are integrating Vane into another product, you can call `POST /api/search`.
|
If you are integrating Perplexica into another product, you can call `POST /api/search`.
|
||||||
|
|
||||||
It returns:
|
It returns:
|
||||||
|
|
||||||
|
|||||||
@@ -1,60 +1,60 @@
|
|||||||
# Update Vane to the latest version
|
# Update Perplexica to the latest version
|
||||||
|
|
||||||
To update Vane to the latest version, follow these steps:
|
To update Perplexica to the latest version, follow these steps:
|
||||||
|
|
||||||
## For Docker users (Using pre-built images)
|
## For Docker users (Using pre-built images)
|
||||||
|
|
||||||
Simply pull the latest image and restart your container:
|
Simply pull the latest image and restart your container:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker pull itzcrazykns1337/vane:latest
|
docker pull itzcrazykns1337/perplexica:latest
|
||||||
docker stop vane
|
docker stop perplexica
|
||||||
docker rm vane
|
docker rm perplexica
|
||||||
docker run -d -p 3000:3000 -v vane-data:/home/vane/data --name vane itzcrazykns1337/vane:latest
|
docker run -d -p 3000:3000 -v perplexica-data:/home/perplexica/data --name perplexica itzcrazykns1337/perplexica:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
For slim version:
|
For slim version:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker pull itzcrazykns1337/vane:slim-latest
|
docker pull itzcrazykns1337/perplexica:slim-latest
|
||||||
docker stop vane
|
docker stop perplexica
|
||||||
docker rm vane
|
docker rm perplexica
|
||||||
docker run -d -p 3000:3000 -e SEARXNG_API_URL=http://your-searxng-url:8080 -v vane-data:/home/vane/data --name vane itzcrazykns1337/vane:slim-latest
|
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
|
||||||
```
|
```
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
## For Docker users (Building from source)
|
## For Docker users (Building from source)
|
||||||
|
|
||||||
1. Navigate to your Vane directory and pull the latest changes:
|
1. Navigate to your Perplexica directory and pull the latest changes:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd Vane
|
cd Perplexica
|
||||||
git pull origin master
|
git pull origin master
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Rebuild the Docker image:
|
2. Rebuild the Docker image:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker build -t vane .
|
docker build -t perplexica .
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Stop and remove the old container, then start the new one:
|
3. Stop and remove the old container, then start the new one:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker stop vane
|
docker stop perplexica
|
||||||
docker rm vane
|
docker rm perplexica
|
||||||
docker run -p 3000:3000 -p 8080:8080 --name vane vane
|
docker run -p 3000:3000 -p 8080:8080 --name perplexica perplexica
|
||||||
```
|
```
|
||||||
|
|
||||||
4. Once the command completes, go to http://localhost:3000 and verify the latest changes.
|
4. Once the command completes, go to http://localhost:3000 and verify the latest changes.
|
||||||
|
|
||||||
## For non-Docker users
|
## For non-Docker users
|
||||||
|
|
||||||
1. Navigate to your Vane directory and pull the latest changes:
|
1. Navigate to your Perplexica directory and pull the latest changes:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd Vane
|
cd Perplexica
|
||||||
git pull origin master
|
git pull origin master
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ else
|
|||||||
echo "SearXNG may not be fully ready, but continuing (PID: $SEARXNG_PID)"
|
echo "SearXNG may not be fully ready, but continuing (PID: $SEARXNG_PID)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cd /home/vane
|
cd /home/perplexica
|
||||||
echo "Starting Vane..."
|
echo "Starting Perplexica..."
|
||||||
|
|
||||||
exec node server.js
|
exec node server.js
|
||||||
2
next-env.d.ts
vendored
2
next-env.d.ts
vendored
@@ -1,6 +1,6 @@
|
|||||||
/// <reference types="next" />
|
/// <reference types="next" />
|
||||||
/// <reference types="next/image-types/global" />
|
/// <reference types="next/image-types/global" />
|
||||||
import './.next/dev/types/routes.d.ts';
|
import "./.next/dev/types/routes.d.ts";
|
||||||
|
|
||||||
// NOTE: This file should not be edited
|
// NOTE: This file should not be edited
|
||||||
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
||||||
|
|||||||
@@ -11,13 +11,6 @@ const nextConfig = {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
serverExternalPackages: ['pdf-parse'],
|
serverExternalPackages: ['pdf-parse'],
|
||||||
outputFileTracingIncludes: {
|
|
||||||
'/api/**': [
|
|
||||||
'./node_modules/@napi-rs/canvas/**',
|
|
||||||
'./node_modules/@napi-rs/canvas-linux-x64-gnu/**',
|
|
||||||
'./node_modules/@napi-rs/canvas-linux-x64-musl/**',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
env: {
|
env: {
|
||||||
NEXT_PUBLIC_VERSION: pkg.version,
|
NEXT_PUBLIC_VERSION: pkg.version,
|
||||||
},
|
},
|
||||||
|
|||||||
14
package.json
14
package.json
@@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "vane",
|
"name": "perplexica-frontend",
|
||||||
"version": "1.12.1",
|
"version": "1.11.2",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"author": "ItzCrazyKns",
|
"author": "ItzCrazyKns",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev --webpack",
|
"dev": "next dev",
|
||||||
"build": "next build --webpack",
|
"build": "next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
"format:write": "prettier . --write"
|
"format:write": "prettier . --write"
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
"@phosphor-icons/react": "^2.1.10",
|
"@phosphor-icons/react": "^2.1.10",
|
||||||
"@radix-ui/react-tooltip": "^1.2.8",
|
"@radix-ui/react-tooltip": "^1.2.8",
|
||||||
"@tailwindcss/typography": "^0.5.12",
|
"@tailwindcss/typography": "^0.5.12",
|
||||||
"@toolsycc/json-repair": "^0.1.22",
|
"@types/jspdf": "^2.0.0",
|
||||||
"axios": "^1.8.3",
|
"axios": "^1.8.3",
|
||||||
"better-sqlite3": "^11.9.1",
|
"better-sqlite3": "^11.9.1",
|
||||||
"clsx": "^2.1.0",
|
"clsx": "^2.1.0",
|
||||||
@@ -54,7 +54,6 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/better-sqlite3": "^7.6.12",
|
"@types/better-sqlite3": "^7.6.12",
|
||||||
"@types/jspdf": "^2.0.0",
|
|
||||||
"@types/node": "^24.8.1",
|
"@types/node": "^24.8.1",
|
||||||
"@types/pdf-parse": "^1.1.4",
|
"@types/pdf-parse": "^1.1.4",
|
||||||
"@types/react": "^18",
|
"@types/react": "^18",
|
||||||
@@ -69,8 +68,5 @@
|
|||||||
"prettier": "^3.2.5",
|
"prettier": "^3.2.5",
|
||||||
"tailwindcss": "^3.3.0",
|
"tailwindcss": "^3.3.0",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3"
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"@napi-rs/canvas": "^0.1.87"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,10 +21,7 @@ export const POST = async (req: Request) => {
|
|||||||
|
|
||||||
const images = await searchImages(
|
const images = await searchImages(
|
||||||
{
|
{
|
||||||
chatHistory: body.chatHistory.map(([role, content]) => ({
|
chatHistory: body.chatHistory,
|
||||||
role: role === 'human' ? 'user' : 'assistant',
|
|
||||||
content,
|
|
||||||
})),
|
|
||||||
query: body.query,
|
query: body.query,
|
||||||
},
|
},
|
||||||
llm,
|
llm,
|
||||||
|
|||||||
@@ -20,10 +20,7 @@ export const POST = async (req: Request) => {
|
|||||||
|
|
||||||
const suggestions = await generateSuggestions(
|
const suggestions = await generateSuggestions(
|
||||||
{
|
{
|
||||||
chatHistory: body.chatHistory.map(([role, content]) => ({
|
chatHistory: body.chatHistory,
|
||||||
role: role === 'human' ? 'user' : 'assistant',
|
|
||||||
content,
|
|
||||||
})),
|
|
||||||
},
|
},
|
||||||
llm,
|
llm,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -21,10 +21,7 @@ export const POST = async (req: Request) => {
|
|||||||
|
|
||||||
const videos = await handleVideoSearch(
|
const videos = await handleVideoSearch(
|
||||||
{
|
{
|
||||||
chatHistory: body.chatHistory.map(([role, content]) => ({
|
chatHistory: body.chatHistory,
|
||||||
role: role === 'human' ? 'user' : 'assistant',
|
|
||||||
content,
|
|
||||||
})),
|
|
||||||
query: body.query,
|
query: body.query,
|
||||||
},
|
},
|
||||||
llm,
|
llm,
|
||||||
|
|||||||
@@ -19,8 +19,9 @@ const montserrat = Montserrat({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'Vane - Direct your curiosity',
|
title: 'Perplexica - Chat with the internet',
|
||||||
description: 'Vane is an AI powered answering engine.',
|
description:
|
||||||
|
'Perplexica is an AI powered chatbot that is connected to the internet.',
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function RootLayout({
|
export default function RootLayout({
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Metadata } from 'next';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'Library - Vane',
|
title: 'Library - Perplexica',
|
||||||
};
|
};
|
||||||
|
|
||||||
const Layout = ({ children }: { children: React.ReactNode }) => {
|
const Layout = ({ children }: { children: React.ReactNode }) => {
|
||||||
|
|||||||
@@ -2,9 +2,10 @@ import type { MetadataRoute } from 'next';
|
|||||||
|
|
||||||
export default function manifest(): MetadataRoute.Manifest {
|
export default function manifest(): MetadataRoute.Manifest {
|
||||||
return {
|
return {
|
||||||
name: 'Vane - Direct Your Curiosity',
|
name: 'Perplexica - Chat with the internet',
|
||||||
short_name: 'Vane',
|
short_name: 'Perplexica',
|
||||||
description: 'Vane is an AI powered answering engine.',
|
description:
|
||||||
|
'Perplexica is an AI powered chatbot that is connected to the internet.',
|
||||||
start_url: '/',
|
start_url: '/',
|
||||||
display: 'standalone',
|
display: 'standalone',
|
||||||
background_color: '#0a0a0a',
|
background_color: '#0a0a0a',
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import ChatWindow from '@/components/ChatWindow';
|
|||||||
import { Metadata } from 'next';
|
import { Metadata } from 'next';
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'Chat - Vane',
|
title: 'Chat - Perplexica',
|
||||||
description: 'Chat with the internet, chat with Vane.',
|
description: 'Chat with the internet, chat with Perplexica.',
|
||||||
};
|
};
|
||||||
|
|
||||||
const Home = () => {
|
const Home = () => {
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ const Chat = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (messages.length === 1) {
|
if (messages.length === 1) {
|
||||||
document.title = `${messages[0].query.substring(0, 30)} - Vane`;
|
document.title = `${messages[0].query.substring(0, 30)} - Perplexica`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sections.length > lastScrolledRef.current) {
|
if (sections.length > lastScrolledRef.current) {
|
||||||
@@ -80,10 +80,7 @@ const Chat = () => {
|
|||||||
{loading && !messageAppeared && <MessageBoxLoading />}
|
{loading && !messageAppeared && <MessageBoxLoading />}
|
||||||
<div ref={messageEnd} className="h-0" />
|
<div ref={messageEnd} className="h-0" />
|
||||||
{dividerWidth > 0 && (
|
{dividerWidth > 0 && (
|
||||||
<div
|
<div className="fixed z-40 bottom-24 lg:bottom-6" style={{ width: dividerWidth }}>
|
||||||
className="fixed z-40 bottom-24 lg:bottom-6"
|
|
||||||
style={{ width: dividerWidth }}
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
className="pointer-events-none absolute -bottom-6 left-0 right-0 h-[calc(100%+24px+24px)] dark:hidden"
|
className="pointer-events-none absolute -bottom-6 left-0 right-0 h-[calc(100%+24px+24px)] dark:hidden"
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@@ -50,14 +50,7 @@ const MessageBox = ({
|
|||||||
dividerRef?: MutableRefObject<HTMLDivElement | null>;
|
dividerRef?: MutableRefObject<HTMLDivElement | null>;
|
||||||
isLast: boolean;
|
isLast: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const { loading, sendMessage, rewrite, messages, researchEnded } = useChat();
|
||||||
loading,
|
|
||||||
sendMessage,
|
|
||||||
rewrite,
|
|
||||||
messages,
|
|
||||||
researchEnded,
|
|
||||||
chatHistory,
|
|
||||||
} = useChat();
|
|
||||||
|
|
||||||
const parsedMessage = section.parsedTextBlocks.join('\n\n');
|
const parsedMessage = section.parsedTextBlocks.join('\n\n');
|
||||||
const speechMessage = section.speechMessage || '';
|
const speechMessage = section.speechMessage || '';
|
||||||
@@ -272,11 +265,11 @@ const MessageBox = ({
|
|||||||
<div className="lg:sticky lg:top-20 flex flex-col items-center space-y-3 w-full lg:w-3/12 z-30 h-full pb-4">
|
<div className="lg:sticky lg:top-20 flex flex-col items-center space-y-3 w-full lg:w-3/12 z-30 h-full pb-4">
|
||||||
<SearchImages
|
<SearchImages
|
||||||
query={section.message.query}
|
query={section.message.query}
|
||||||
chatHistory={chatHistory}
|
chatHistory={messages}
|
||||||
messageId={section.message.messageId}
|
messageId={section.message.messageId}
|
||||||
/>
|
/>
|
||||||
<SearchVideos
|
<SearchVideos
|
||||||
chatHistory={chatHistory}
|
chatHistory={messages}
|
||||||
query={section.message.query}
|
query={section.message.query}
|
||||||
messageId={section.message.messageId}
|
messageId={section.message.messageId}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ const MessageSources = ({ sources }: { sources: Chunk[] }) => {
|
|||||||
>
|
>
|
||||||
<div className="flex flex-row items-center space-x-1">
|
<div className="flex flex-row items-center space-x-1">
|
||||||
{sources.slice(3, 6).map((source, i) => {
|
{sources.slice(3, 6).map((source, i) => {
|
||||||
return source.metadata.url === 'File' ? (
|
return source.metadata.includes('file_id://') ? (
|
||||||
<div
|
<div
|
||||||
key={i}
|
key={i}
|
||||||
className="bg-dark-200 hover:bg-dark-100 transition duration-200 flex items-center justify-center w-6 h-6 rounded-full"
|
className="bg-dark-200 hover:bg-dark-100 transition duration-200 flex items-center justify-center w-6 h-6 rounded-full"
|
||||||
@@ -124,7 +124,7 @@ const MessageSources = ({ sources }: { sources: Chunk[] }) => {
|
|||||||
</p>
|
</p>
|
||||||
<div className="flex flex-row items-center justify-between">
|
<div className="flex flex-row items-center justify-between">
|
||||||
<div className="flex flex-row items-center space-x-1">
|
<div className="flex flex-row items-center space-x-1">
|
||||||
{source.metadata.url === 'File' ? (
|
{source.metadata.url.includes('file_id://') ? (
|
||||||
<div className="bg-dark-200 hover:bg-dark-100 transition duration-200 flex items-center justify-center w-6 h-6 rounded-full">
|
<div className="bg-dark-200 hover:bg-dark-100 transition duration-200 flex items-center justify-center w-6 h-6 rounded-full">
|
||||||
<File size={12} className="text-white/70" />
|
<File size={12} className="text-white/70" />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ const SearchImages = ({
|
|||||||
messageId,
|
messageId,
|
||||||
}: {
|
}: {
|
||||||
query: string;
|
query: string;
|
||||||
chatHistory: [string, string][];
|
chatHistory: Message[];
|
||||||
messageId: string;
|
messageId: string;
|
||||||
}) => {
|
}) => {
|
||||||
const [images, setImages] = useState<Image[] | null>(null);
|
const [images, setImages] = useState<Image[] | null>(null);
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ const Searchvideos = ({
|
|||||||
messageId,
|
messageId,
|
||||||
}: {
|
}: {
|
||||||
query: string;
|
query: string;
|
||||||
chatHistory: [string, string][];
|
chatHistory: Message[];
|
||||||
messageId: string;
|
messageId: string;
|
||||||
}) => {
|
}) => {
|
||||||
const [videos, setVideos] = useState<Video[] | null>(null);
|
const [videos, setVideos] = useState<Video[] | null>(null);
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ const SettingsDialogue = ({
|
|||||||
Version: {process.env.NEXT_PUBLIC_VERSION}
|
Version: {process.env.NEXT_PUBLIC_VERSION}
|
||||||
</p>
|
</p>
|
||||||
<a
|
<a
|
||||||
href="https://github.com/itzcrazykns/vane"
|
href="https://github.com/itzcrazykns/perplexica"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="text-xs text-black/70 dark:text-white/70 flex flex-row space-x-1 items-center transition duration-200 hover:text-black/90 hover:dark:text-white/90"
|
className="text-xs text-black/70 dark:text-white/70 flex flex-row space-x-1 items-center transition duration-200 hover:text-black/90 hover:dark:text-white/90"
|
||||||
|
|||||||
@@ -46,9 +46,9 @@ const SetupWizard = ({
|
|||||||
animate={{ opacity: 1, translateY: '0px' }}
|
animate={{ opacity: 1, translateY: '0px' }}
|
||||||
className="text-4xl md:text-6xl xl:text-8xl font-normal font-['Instrument_Serif'] tracking-tight"
|
className="text-4xl md:text-6xl xl:text-8xl font-normal font-['Instrument_Serif'] tracking-tight"
|
||||||
>
|
>
|
||||||
Welcome to
|
Welcome to{' '}
|
||||||
<span className="text-[#24A0ED] italic font-['PP_Editorial']">
|
<span className="text-[#24A0ED] italic font-['PP_Editorial']">
|
||||||
Vane
|
Perplexica
|
||||||
</span>
|
</span>
|
||||||
</motion.h2>
|
</motion.h2>
|
||||||
<motion.p
|
<motion.p
|
||||||
@@ -91,9 +91,9 @@ const SetupWizard = ({
|
|||||||
}}
|
}}
|
||||||
className="text-2xl md:text-4xl xl:text-6xl font-normal font-['Instrument_Serif'] tracking-tight"
|
className="text-2xl md:text-4xl xl:text-6xl font-normal font-['Instrument_Serif'] tracking-tight"
|
||||||
>
|
>
|
||||||
Let us get
|
Let us get{' '}
|
||||||
<span className="text-[#24A0ED] italic font-['PP_Editorial']">
|
<span className="text-[#24A0ED] italic font-['PP_Editorial']">
|
||||||
Vane
|
Perplexica
|
||||||
</span>{' '}
|
</span>{' '}
|
||||||
set up for you
|
set up for you
|
||||||
</motion.p>
|
</motion.p>
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
export const getSuggestions = async (chatHistory: [string, string][]) => {
|
export const getSuggestions = async (chatHistory: [string, string][]) => {
|
||||||
|
const chatTurns = chatHistory.map(([role, content]) => {
|
||||||
|
if (role === 'human') {
|
||||||
|
return { role: 'user', content };
|
||||||
|
} else {
|
||||||
|
return { role: 'assistant', content };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const chatModel = localStorage.getItem('chatModelKey');
|
const chatModel = localStorage.getItem('chatModelKey');
|
||||||
const chatModelProvider = localStorage.getItem('chatModelProviderId');
|
const chatModelProvider = localStorage.getItem('chatModelProviderId');
|
||||||
|
|
||||||
@@ -8,7 +16,7 @@ export const getSuggestions = async (chatHistory: [string, string][]) => {
|
|||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
chatHistory,
|
chatHistory: chatTurns,
|
||||||
chatModel: {
|
chatModel: {
|
||||||
providerId: chatModelProvider,
|
providerId: chatModelProvider,
|
||||||
key: chatModel,
|
key: chatModel,
|
||||||
|
|||||||
@@ -19,9 +19,6 @@ class APISearchAgent {
|
|||||||
chatHistory: input.chatHistory,
|
chatHistory: input.chatHistory,
|
||||||
followUp: input.followUp,
|
followUp: input.followUp,
|
||||||
llm: input.config.llm,
|
llm: input.config.llm,
|
||||||
}).catch((err) => {
|
|
||||||
console.error(`Error executing widgets: ${err}`);
|
|
||||||
return [];
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let searchPromise: Promise<ResearcherOutput> | null = null;
|
let searchPromise: Promise<ResearcherOutput> | null = null;
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ const weatherWidget: Widget = {
|
|||||||
|
|
||||||
const locationRes = await fetch(openStreetMapUrl, {
|
const locationRes = await fetch(openStreetMapUrl, {
|
||||||
headers: {
|
headers: {
|
||||||
'User-Agent': 'Vane',
|
'User-Agent': 'Perplexica',
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -109,7 +109,7 @@ const weatherWidget: Widget = {
|
|||||||
`https://api.open-meteo.com/v1/forecast?latitude=${location.lat}&longitude=${location.lon}¤t=temperature_2m,relative_humidity_2m,apparent_temperature,is_day,precipitation,rain,showers,snowfall,weather_code,cloud_cover,pressure_msl,surface_pressure,wind_speed_10m,wind_direction_10m,wind_gusts_10m&hourly=temperature_2m,precipitation_probability,precipitation,weather_code&daily=weather_code,temperature_2m_max,temperature_2m_min,precipitation_sum,precipitation_probability_max&timezone=auto&forecast_days=7`,
|
`https://api.open-meteo.com/v1/forecast?latitude=${location.lat}&longitude=${location.lon}¤t=temperature_2m,relative_humidity_2m,apparent_temperature,is_day,precipitation,rain,showers,snowfall,weather_code,cloud_cover,pressure_msl,surface_pressure,wind_speed_10m,wind_direction_10m,wind_gusts_10m&hourly=temperature_2m,precipitation_probability,precipitation,weather_code&daily=weather_code,temperature_2m_max,temperature_2m_min,precipitation_sum,precipitation_probability_max&timezone=auto&forecast_days=7`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
'User-Agent': 'Vane',
|
'User-Agent': 'Perplexica',
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -143,7 +143,7 @@ const weatherWidget: Widget = {
|
|||||||
`https://api.open-meteo.com/v1/forecast?latitude=${params.lat}&longitude=${params.lon}¤t=temperature_2m,relative_humidity_2m,apparent_temperature,is_day,precipitation,rain,showers,snowfall,weather_code,cloud_cover,pressure_msl,surface_pressure,wind_speed_10m,wind_direction_10m,wind_gusts_10m&hourly=temperature_2m,precipitation_probability,precipitation,weather_code&daily=weather_code,temperature_2m_max,temperature_2m_min,precipitation_sum,precipitation_probability_max&timezone=auto&forecast_days=7`,
|
`https://api.open-meteo.com/v1/forecast?latitude=${params.lat}&longitude=${params.lon}¤t=temperature_2m,relative_humidity_2m,apparent_temperature,is_day,precipitation,rain,showers,snowfall,weather_code,cloud_cover,pressure_msl,surface_pressure,wind_speed_10m,wind_direction_10m,wind_gusts_10m&hourly=temperature_2m,precipitation_probability,precipitation,weather_code&daily=weather_code,temperature_2m_max,temperature_2m_min,precipitation_sum,precipitation_probability_max&timezone=auto&forecast_days=7`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
'User-Agent': 'Vane',
|
'User-Agent': 'Perplexica',
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -152,7 +152,7 @@ const weatherWidget: Widget = {
|
|||||||
`https://nominatim.openstreetmap.org/reverse?lat=${params.lat}&lon=${params.lon}&format=json`,
|
`https://nominatim.openstreetmap.org/reverse?lat=${params.lat}&lon=${params.lon}&format=json`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
'User-Agent': 'Vane',
|
'User-Agent': 'Perplexica',
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { suggestionGeneratorPrompt } from '@/lib/prompts/suggestions';
|
|||||||
import { ChatTurnMessage } from '@/lib/types';
|
import { ChatTurnMessage } from '@/lib/types';
|
||||||
import z from 'zod';
|
import z from 'zod';
|
||||||
import BaseLLM from '@/lib/models/base/llm';
|
import BaseLLM from '@/lib/models/base/llm';
|
||||||
|
import { i } from 'mathjs';
|
||||||
|
|
||||||
type SuggestionGeneratorInput = {
|
type SuggestionGeneratorInput = {
|
||||||
chatHistory: ChatTurnMessage[];
|
chatHistory: ChatTurnMessage[];
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ const loadMessages = async (
|
|||||||
chatId: string,
|
chatId: string,
|
||||||
setMessages: (messages: Message[]) => void,
|
setMessages: (messages: Message[]) => void,
|
||||||
setIsMessagesLoaded: (loaded: boolean) => void,
|
setIsMessagesLoaded: (loaded: boolean) => void,
|
||||||
chatHistory: React.MutableRefObject<[string, string][]>,
|
setChatHistory: (history: [string, string][]) => void,
|
||||||
setSources: (sources: string[]) => void,
|
setSources: (sources: string[]) => void,
|
||||||
setNotFound: (notFound: boolean) => void,
|
setNotFound: (notFound: boolean) => void,
|
||||||
setFiles: (files: File[]) => void,
|
setFiles: (files: File[]) => void,
|
||||||
@@ -233,7 +233,7 @@ const loadMessages = async (
|
|||||||
setFiles(files);
|
setFiles(files);
|
||||||
setFileIds(files.map((file: File) => file.fileId));
|
setFileIds(files.map((file: File) => file.fileId));
|
||||||
|
|
||||||
chatHistory.current = history;
|
setChatHistory(history);
|
||||||
setSources(data.chat.sources);
|
setSources(data.chat.sources);
|
||||||
setIsMessagesLoaded(true);
|
setIsMessagesLoaded(true);
|
||||||
};
|
};
|
||||||
@@ -281,7 +281,7 @@ export const ChatProvider = ({ children }: { children: React.ReactNode }) => {
|
|||||||
|
|
||||||
const [researchEnded, setResearchEnded] = useState(false);
|
const [researchEnded, setResearchEnded] = useState(false);
|
||||||
|
|
||||||
const chatHistory = useRef<[string, string][]>([]);
|
const [chatHistory, setChatHistory] = useState<[string, string][]>([]);
|
||||||
const [messages, setMessages] = useState<Message[]>([]);
|
const [messages, setMessages] = useState<Message[]>([]);
|
||||||
|
|
||||||
const [files, setFiles] = useState<File[]>([]);
|
const [files, setFiles] = useState<File[]>([]);
|
||||||
@@ -402,12 +402,7 @@ export const ChatProvider = ({ children }: { children: React.ReactNode }) => {
|
|||||||
});
|
});
|
||||||
}, [messages]);
|
}, [messages]);
|
||||||
|
|
||||||
const isReconnectingRef = useRef(false);
|
|
||||||
const handledMessageEndRef = useRef<Set<string>>(new Set());
|
|
||||||
|
|
||||||
const checkReconnect = async () => {
|
const checkReconnect = async () => {
|
||||||
if (isReconnectingRef.current) return;
|
|
||||||
|
|
||||||
setIsReady(true);
|
setIsReady(true);
|
||||||
console.debug(new Date(), 'app:ready');
|
console.debug(new Date(), 'app:ready');
|
||||||
|
|
||||||
@@ -419,8 +414,6 @@ export const ChatProvider = ({ children }: { children: React.ReactNode }) => {
|
|||||||
setResearchEnded(false);
|
setResearchEnded(false);
|
||||||
setMessageAppeared(false);
|
setMessageAppeared(false);
|
||||||
|
|
||||||
isReconnectingRef.current = true;
|
|
||||||
|
|
||||||
const res = await fetch(`/api/reconnect/${lastMsg.backendId}`, {
|
const res = await fetch(`/api/reconnect/${lastMsg.backendId}`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
});
|
});
|
||||||
@@ -434,7 +427,6 @@ export const ChatProvider = ({ children }: { children: React.ReactNode }) => {
|
|||||||
|
|
||||||
const messageHandler = getMessageHandler(lastMsg);
|
const messageHandler = getMessageHandler(lastMsg);
|
||||||
|
|
||||||
try {
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const { value, done } = await reader.read();
|
const { value, done } = await reader.read();
|
||||||
if (done) break;
|
if (done) break;
|
||||||
@@ -453,9 +445,6 @@ export const ChatProvider = ({ children }: { children: React.ReactNode }) => {
|
|||||||
console.warn('Incomplete JSON, waiting for next chunk...');
|
console.warn('Incomplete JSON, waiting for next chunk...');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
|
||||||
isReconnectingRef.current = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -474,7 +463,7 @@ export const ChatProvider = ({ children }: { children: React.ReactNode }) => {
|
|||||||
if (params.chatId && params.chatId !== chatId) {
|
if (params.chatId && params.chatId !== chatId) {
|
||||||
setChatId(params.chatId);
|
setChatId(params.chatId);
|
||||||
setMessages([]);
|
setMessages([]);
|
||||||
chatHistory.current = [];
|
setChatHistory([]);
|
||||||
setFiles([]);
|
setFiles([]);
|
||||||
setFileIds([]);
|
setFileIds([]);
|
||||||
setIsMessagesLoaded(false);
|
setIsMessagesLoaded(false);
|
||||||
@@ -494,7 +483,7 @@ export const ChatProvider = ({ children }: { children: React.ReactNode }) => {
|
|||||||
chatId,
|
chatId,
|
||||||
setMessages,
|
setMessages,
|
||||||
setIsMessagesLoaded,
|
setIsMessagesLoaded,
|
||||||
chatHistory,
|
setChatHistory,
|
||||||
setSources,
|
setSources,
|
||||||
setNotFound,
|
setNotFound,
|
||||||
setFiles,
|
setFiles,
|
||||||
@@ -530,7 +519,9 @@ export const ChatProvider = ({ children }: { children: React.ReactNode }) => {
|
|||||||
|
|
||||||
setMessages((prev) => prev.slice(0, index));
|
setMessages((prev) => prev.slice(0, index));
|
||||||
|
|
||||||
chatHistory.current = chatHistory.current.slice(0, index * 2);
|
setChatHistory((prev) => {
|
||||||
|
return prev.slice(0, index * 2);
|
||||||
|
});
|
||||||
|
|
||||||
const messageToRewrite = messages[index];
|
const messageToRewrite = messages[index];
|
||||||
sendMessage(messageToRewrite.query, messageToRewrite.messageId, true);
|
sendMessage(messageToRewrite.query, messageToRewrite.messageId, true);
|
||||||
@@ -579,20 +570,6 @@ export const ChatProvider = ({ children }: { children: React.ReactNode }) => {
|
|||||||
setMessages((prev) =>
|
setMessages((prev) =>
|
||||||
prev.map((msg) => {
|
prev.map((msg) => {
|
||||||
if (msg.messageId === messageId) {
|
if (msg.messageId === messageId) {
|
||||||
const exists = msg.responseBlocks.findIndex(
|
|
||||||
(b) => b.id === data.block.id,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (exists !== -1) {
|
|
||||||
const existingBlocks = [...msg.responseBlocks];
|
|
||||||
existingBlocks[exists] = data.block;
|
|
||||||
|
|
||||||
return {
|
|
||||||
...msg,
|
|
||||||
responseBlocks: existingBlocks,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...msg,
|
...msg,
|
||||||
responseBlocks: [...msg.responseBlocks, data.block],
|
responseBlocks: [...msg.responseBlocks, data.block],
|
||||||
@@ -630,18 +607,12 @@ export const ChatProvider = ({ children }: { children: React.ReactNode }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (data.type === 'messageEnd') {
|
if (data.type === 'messageEnd') {
|
||||||
if (handledMessageEndRef.current.has(messageId)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
handledMessageEndRef.current.add(messageId);
|
|
||||||
|
|
||||||
const currentMsg = messagesRef.current.find(
|
const currentMsg = messagesRef.current.find(
|
||||||
(msg) => msg.messageId === messageId,
|
(msg) => msg.messageId === messageId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const newHistory: [string, string][] = [
|
const newHistory: [string, string][] = [
|
||||||
...chatHistory.current,
|
...chatHistory,
|
||||||
['human', message.query],
|
['human', message.query],
|
||||||
[
|
[
|
||||||
'assistant',
|
'assistant',
|
||||||
@@ -650,7 +621,7 @@ export const ChatProvider = ({ children }: { children: React.ReactNode }) => {
|
|||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
chatHistory.current = newHistory;
|
setChatHistory(newHistory);
|
||||||
|
|
||||||
setMessages((prev) =>
|
setMessages((prev) =>
|
||||||
prev.map((msg) =>
|
prev.map((msg) =>
|
||||||
@@ -667,7 +638,6 @@ export const ChatProvider = ({ children }: { children: React.ReactNode }) => {
|
|||||||
const autoMediaSearch = getAutoMediaSearch();
|
const autoMediaSearch = getAutoMediaSearch();
|
||||||
|
|
||||||
if (autoMediaSearch) {
|
if (autoMediaSearch) {
|
||||||
setTimeout(() => {
|
|
||||||
document
|
document
|
||||||
.getElementById(`search-images-${lastMsg.messageId}`)
|
.getElementById(`search-images-${lastMsg.messageId}`)
|
||||||
?.click();
|
?.click();
|
||||||
@@ -675,7 +645,6 @@ export const ChatProvider = ({ children }: { children: React.ReactNode }) => {
|
|||||||
document
|
document
|
||||||
.getElementById(`search-videos-${lastMsg.messageId}`)
|
.getElementById(`search-videos-${lastMsg.messageId}`)
|
||||||
?.click();
|
?.click();
|
||||||
}, 200);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if there are sources and no suggestions
|
// Check if there are sources and no suggestions
|
||||||
@@ -759,11 +728,8 @@ export const ChatProvider = ({ children }: { children: React.ReactNode }) => {
|
|||||||
sources: sources,
|
sources: sources,
|
||||||
optimizationMode: optimizationMode,
|
optimizationMode: optimizationMode,
|
||||||
history: rewrite
|
history: rewrite
|
||||||
? chatHistory.current.slice(
|
? chatHistory.slice(0, messageIndex === -1 ? undefined : messageIndex)
|
||||||
0,
|
: chatHistory,
|
||||||
messageIndex === -1 ? undefined : messageIndex,
|
|
||||||
)
|
|
||||||
: chatHistory.current,
|
|
||||||
chatModel: {
|
chatModel: {
|
||||||
key: chatModelProvider.key,
|
key: chatModelProvider.key,
|
||||||
providerId: chatModelProvider.providerId,
|
providerId: chatModelProvider.providerId,
|
||||||
@@ -810,7 +776,7 @@ export const ChatProvider = ({ children }: { children: React.ReactNode }) => {
|
|||||||
value={{
|
value={{
|
||||||
messages,
|
messages,
|
||||||
sections,
|
sections,
|
||||||
chatHistory: chatHistory.current,
|
chatHistory,
|
||||||
files,
|
files,
|
||||||
fileIds,
|
fileIds,
|
||||||
sources,
|
sources,
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import TransformersProvider from './transformers';
|
|||||||
import GroqProvider from './groq';
|
import GroqProvider from './groq';
|
||||||
import LemonadeProvider from './lemonade';
|
import LemonadeProvider from './lemonade';
|
||||||
import AnthropicProvider from './anthropic';
|
import AnthropicProvider from './anthropic';
|
||||||
import LMStudioProvider from './lmstudio';
|
|
||||||
|
|
||||||
export const providers: Record<string, ProviderConstructor<any>> = {
|
export const providers: Record<string, ProviderConstructor<any>> = {
|
||||||
openai: OpenAIProvider,
|
openai: OpenAIProvider,
|
||||||
@@ -17,7 +16,6 @@ export const providers: Record<string, ProviderConstructor<any>> = {
|
|||||||
groq: GroqProvider,
|
groq: GroqProvider,
|
||||||
lemonade: LemonadeProvider,
|
lemonade: LemonadeProvider,
|
||||||
anthropic: AnthropicProvider,
|
anthropic: AnthropicProvider,
|
||||||
lmstudio: LMStudioProvider,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getModelProvidersUIConfigSection =
|
export const getModelProvidersUIConfigSection =
|
||||||
|
|||||||
@@ -1,143 +0,0 @@
|
|||||||
import { UIConfigField } from '@/lib/config/types';
|
|
||||||
import { getConfiguredModelProviderById } from '@/lib/config/serverRegistry';
|
|
||||||
import BaseModelProvider from '../../base/provider';
|
|
||||||
import { Model, ModelList, ProviderMetadata } from '../../types';
|
|
||||||
import LMStudioLLM from './lmstudioLLM';
|
|
||||||
import BaseLLM from '../../base/llm';
|
|
||||||
import BaseEmbedding from '../../base/embedding';
|
|
||||||
import LMStudioEmbedding from './lmstudioEmbedding';
|
|
||||||
|
|
||||||
interface LMStudioConfig {
|
|
||||||
baseURL: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const providerConfigFields: UIConfigField[] = [
|
|
||||||
{
|
|
||||||
type: 'string',
|
|
||||||
name: 'Base URL',
|
|
||||||
key: 'baseURL',
|
|
||||||
description: 'The base URL for LM Studio server',
|
|
||||||
required: true,
|
|
||||||
placeholder: 'http://localhost:1234',
|
|
||||||
env: 'LM_STUDIO_BASE_URL',
|
|
||||||
scope: 'server',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
class LMStudioProvider extends BaseModelProvider<LMStudioConfig> {
|
|
||||||
constructor(id: string, name: string, config: LMStudioConfig) {
|
|
||||||
super(id, name, config);
|
|
||||||
}
|
|
||||||
|
|
||||||
private normalizeBaseURL(url: string): string {
|
|
||||||
const trimmed = url.trim().replace(/\/+$/, '');
|
|
||||||
return trimmed.endsWith('/v1') ? trimmed : `${trimmed}/v1`;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getDefaultModels(): Promise<ModelList> {
|
|
||||||
try {
|
|
||||||
const baseURL = this.normalizeBaseURL(this.config.baseURL);
|
|
||||||
|
|
||||||
const res = await fetch(`${baseURL}/models`, {
|
|
||||||
method: 'GET',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await res.json();
|
|
||||||
|
|
||||||
const models: Model[] = data.data.map((m: any) => {
|
|
||||||
return {
|
|
||||||
name: m.id,
|
|
||||||
key: m.id,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
embedding: models,
|
|
||||||
chat: models,
|
|
||||||
};
|
|
||||||
} catch (err) {
|
|
||||||
if (err instanceof TypeError) {
|
|
||||||
throw new Error(
|
|
||||||
'Error connecting to LM Studio. Please ensure the base URL is correct and the LM Studio server is running.',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async getModelList(): Promise<ModelList> {
|
|
||||||
const defaultModels = await this.getDefaultModels();
|
|
||||||
const configProvider = getConfiguredModelProviderById(this.id)!;
|
|
||||||
|
|
||||||
return {
|
|
||||||
embedding: [
|
|
||||||
...defaultModels.embedding,
|
|
||||||
...configProvider.embeddingModels,
|
|
||||||
],
|
|
||||||
chat: [...defaultModels.chat, ...configProvider.chatModels],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async loadChatModel(key: string): Promise<BaseLLM<any>> {
|
|
||||||
const modelList = await this.getModelList();
|
|
||||||
|
|
||||||
const exists = modelList.chat.find((m) => m.key === key);
|
|
||||||
|
|
||||||
if (!exists) {
|
|
||||||
throw new Error(
|
|
||||||
'Error Loading LM Studio Chat Model. Invalid Model Selected',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new LMStudioLLM({
|
|
||||||
apiKey: 'lm-studio',
|
|
||||||
model: key,
|
|
||||||
baseURL: this.normalizeBaseURL(this.config.baseURL),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async loadEmbeddingModel(key: string): Promise<BaseEmbedding<any>> {
|
|
||||||
const modelList = await this.getModelList();
|
|
||||||
const exists = modelList.embedding.find((m) => m.key === key);
|
|
||||||
|
|
||||||
if (!exists) {
|
|
||||||
throw new Error(
|
|
||||||
'Error Loading LM Studio Embedding Model. Invalid Model Selected.',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new LMStudioEmbedding({
|
|
||||||
apiKey: 'lm-studio',
|
|
||||||
model: key,
|
|
||||||
baseURL: this.normalizeBaseURL(this.config.baseURL),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static parseAndValidate(raw: any): LMStudioConfig {
|
|
||||||
if (!raw || typeof raw !== 'object')
|
|
||||||
throw new Error('Invalid config provided. Expected object');
|
|
||||||
if (!raw.baseURL)
|
|
||||||
throw new Error('Invalid config provided. Base URL must be provided');
|
|
||||||
|
|
||||||
return {
|
|
||||||
baseURL: String(raw.baseURL),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static getProviderConfigFields(): UIConfigField[] {
|
|
||||||
return providerConfigFields;
|
|
||||||
}
|
|
||||||
|
|
||||||
static getProviderMetadata(): ProviderMetadata {
|
|
||||||
return {
|
|
||||||
key: 'lmstudio',
|
|
||||||
name: 'LM Studio',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default LMStudioProvider;
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
import OpenAIEmbedding from '../openai/openaiEmbedding';
|
|
||||||
|
|
||||||
class LMStudioEmbedding extends OpenAIEmbedding {}
|
|
||||||
|
|
||||||
export default LMStudioEmbedding;
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
import OpenAILLM from '../openai/openaiLLM';
|
|
||||||
|
|
||||||
class LMStudioLLM extends OpenAILLM {}
|
|
||||||
|
|
||||||
export default LMStudioLLM;
|
|
||||||
@@ -11,7 +11,6 @@ import { Ollama, Tool as OllamaTool, Message as OllamaMessage } from 'ollama';
|
|||||||
import { parse } from 'partial-json';
|
import { parse } from 'partial-json';
|
||||||
import crypto from 'crypto';
|
import crypto from 'crypto';
|
||||||
import { Message } from '@/lib/types';
|
import { Message } from '@/lib/types';
|
||||||
import { repairJson } from '@toolsycc/json-repair';
|
|
||||||
|
|
||||||
type OllamaConfig = {
|
type OllamaConfig = {
|
||||||
baseURL: string;
|
baseURL: string;
|
||||||
@@ -206,13 +205,7 @@ class OllamaLLM extends BaseLLM<OllamaConfig> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return input.schema.parse(
|
return input.schema.parse(JSON.parse(response.message.content)) as T;
|
||||||
JSON.parse(
|
|
||||||
repairJson(response.message.content, {
|
|
||||||
extractJson: true,
|
|
||||||
}) as string,
|
|
||||||
),
|
|
||||||
) as T;
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new Error(`Error parsing response from Ollama: ${err}`);
|
throw new Error(`Error parsing response from Ollama: ${err}`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,22 +61,6 @@ const defaultChatModels: Model[] = [
|
|||||||
name: 'GPT 5 Mini',
|
name: 'GPT 5 Mini',
|
||||||
key: 'gpt-5-mini',
|
key: 'gpt-5-mini',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: 'GPT 5 Pro',
|
|
||||||
key: 'gpt-5-pro',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'GPT 5.1',
|
|
||||||
key: 'gpt-5.1',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'GPT 5.2',
|
|
||||||
key: 'gpt-5.2',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'GPT 5.2 Pro',
|
|
||||||
key: 'gpt-5.2-pro',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: 'o1',
|
name: 'o1',
|
||||||
key: 'o1',
|
key: 'o1',
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import {
|
|||||||
ChatCompletionToolMessageParam,
|
ChatCompletionToolMessageParam,
|
||||||
} from 'openai/resources/index.mjs';
|
} from 'openai/resources/index.mjs';
|
||||||
import { Message } from '@/lib/types';
|
import { Message } from '@/lib/types';
|
||||||
import { repairJson } from '@toolsycc/json-repair';
|
|
||||||
|
|
||||||
type OpenAIConfig = {
|
type OpenAIConfig = {
|
||||||
apiKey: string;
|
apiKey: string;
|
||||||
@@ -168,7 +167,7 @@ class OpenAILLM extends BaseLLM<OpenAIConfig> {
|
|||||||
contentChunk: chunk.choices[0].delta.content || '',
|
contentChunk: chunk.choices[0].delta.content || '',
|
||||||
toolCallChunk:
|
toolCallChunk:
|
||||||
toolCalls?.map((tc) => {
|
toolCalls?.map((tc) => {
|
||||||
if (!recievedToolCalls[tc.index]) {
|
if (tc.type === 'function') {
|
||||||
const call = {
|
const call = {
|
||||||
name: tc.function?.name!,
|
name: tc.function?.name!,
|
||||||
id: tc.id!,
|
id: tc.id!,
|
||||||
@@ -214,13 +213,7 @@ class OpenAILLM extends BaseLLM<OpenAIConfig> {
|
|||||||
|
|
||||||
if (response.choices && response.choices.length > 0) {
|
if (response.choices && response.choices.length > 0) {
|
||||||
try {
|
try {
|
||||||
return input.schema.parse(
|
return input.schema.parse(response.choices[0].message.parsed) as T;
|
||||||
JSON.parse(
|
|
||||||
repairJson(response.choices[0].message.content!, {
|
|
||||||
extractJson: true,
|
|
||||||
}) as string,
|
|
||||||
),
|
|
||||||
) as T;
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new Error(`Error parsing response from OpenAI: ${err}`);
|
throw new Error(`Error parsing response from OpenAI: ${err}`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Chunk } from '@/lib/types';
|
import { Chunk } from '@/lib/types';
|
||||||
import BaseEmbedding from '../../base/embedding';
|
import BaseEmbedding from '../../base/embedding';
|
||||||
import { FeatureExtractionPipeline } from '@huggingface/transformers';
|
import { FeatureExtractionPipeline, pipeline } from '@huggingface/transformers';
|
||||||
|
|
||||||
type TransformerConfig = {
|
type TransformerConfig = {
|
||||||
model: string;
|
model: string;
|
||||||
@@ -21,19 +21,21 @@ class TransformerEmbedding extends BaseEmbedding<TransformerConfig> {
|
|||||||
return this.embed(chunks.map((c) => c.content));
|
return this.embed(chunks.map((c) => c.content));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async embed(texts: string[]) {
|
async embed(texts: string[]): Promise<number[][]> {
|
||||||
if (!this.pipelinePromise) {
|
if (!this.pipelinePromise) {
|
||||||
this.pipelinePromise = (async () => {
|
this.pipelinePromise = (async () => {
|
||||||
const { pipeline } = await import('@huggingface/transformers');
|
const transformers = await import('@huggingface/transformers');
|
||||||
const result = await pipeline('feature-extraction', this.config.model, {
|
return (await transformers.pipeline(
|
||||||
dtype: 'fp32',
|
'feature-extraction',
|
||||||
});
|
this.config.model,
|
||||||
return result as FeatureExtractionPipeline;
|
)) as unknown as FeatureExtractionPipeline;
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
|
|
||||||
const pipe = await this.pipelinePromise;
|
const pipeline = await this.pipelinePromise;
|
||||||
const output = await pipe(texts, { pooling: 'mean', normalize: true });
|
|
||||||
|
const output = await pipeline(texts, { pooling: 'mean', normalize: true });
|
||||||
|
|
||||||
return output.tolist() as number[][];
|
return output.tolist() as number[][];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { ChatTurnMessage } from '@/lib/types';
|
|||||||
export const imageSearchPrompt = `
|
export const imageSearchPrompt = `
|
||||||
You will be given a conversation below and a follow up question. You need to rephrase the follow-up question so it is a standalone question that can be used by the LLM to search the web for images.
|
You will be given a conversation below and a follow up question. You need to rephrase the follow-up question so it is a standalone question that can be used by the LLM to search the web for images.
|
||||||
You need to make sure the rephrased question agrees with the conversation and is relevant to the conversation.
|
You need to make sure the rephrased question agrees with the conversation and is relevant to the conversation.
|
||||||
Make sure to make the querey standalone and not something very broad, use context from the answers in the conversation to make it specific so user can get best image search results.
|
|
||||||
Output only the rephrased query in query key JSON format. Do not include any explanation or additional text.
|
Output only the rephrased query in query key JSON format. Do not include any explanation or additional text.
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { ChatTurnMessage } from '@/lib/types';
|
|||||||
export const videoSearchPrompt = `
|
export const videoSearchPrompt = `
|
||||||
You will be given a conversation below and a follow up question. You need to rephrase the follow-up question so it is a standalone question that can be used by the LLM to search Youtube for videos.
|
You will be given a conversation below and a follow up question. You need to rephrase the follow-up question so it is a standalone question that can be used by the LLM to search Youtube for videos.
|
||||||
You need to make sure the rephrased question agrees with the conversation and is relevant to the conversation.
|
You need to make sure the rephrased question agrees with the conversation and is relevant to the conversation.
|
||||||
Make sure to make the querey standalone and not something very broad, use context from the answers in the conversation to make it specific so user can get best video search results.
|
|
||||||
Output only the rephrased query in query key JSON format. Do not include any explanation or additional text.
|
Output only the rephrased query in query key JSON format. Do not include any explanation or additional text.
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ export const getWriterPrompt = (
|
|||||||
mode: 'speed' | 'balanced' | 'quality',
|
mode: 'speed' | 'balanced' | 'quality',
|
||||||
) => {
|
) => {
|
||||||
return `
|
return `
|
||||||
You are Vane, an AI model skilled in web search and crafting detailed, engaging, and well-structured answers. You excel at summarizing web pages and extracting relevant information to create professional, blog-style responses.
|
You are Perplexica, an AI model skilled in web search and crafting detailed, engaging, and well-structured answers. You excel at summarizing web pages and extracting relevant information to create professional, blog-style responses.
|
||||||
|
|
||||||
Your task is to provide answers that are:
|
Your task is to provide answers that are:
|
||||||
- **Informative and relevant**: Thoroughly address the user's query using the given context.
|
- **Informative and relevant**: Thoroughly address the user's query using the given context.
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import axios from 'axios';
|
||||||
import { getSearxngURL } from './config/serverRegistry';
|
import { getSearxngURL } from './config/serverRegistry';
|
||||||
|
|
||||||
interface SearxngSearchOptions {
|
interface SearxngSearchOptions {
|
||||||
@@ -38,30 +39,11 @@ export const searchSearxng = async (
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const controller = new AbortController();
|
const res = await fetch(url);
|
||||||
const timeoutId = setTimeout(() => controller.abort(), 10000);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const res = await fetch(url, {
|
|
||||||
signal: controller.signal,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!res.ok) {
|
|
||||||
throw new Error(`SearXNG error: ${res.statusText}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
|
|
||||||
const results: SearxngSearchResult[] = data.results;
|
const results: SearxngSearchResult[] = data.results;
|
||||||
const suggestions: string[] = data.suggestions;
|
const suggestions: string[] = data.suggestions;
|
||||||
|
|
||||||
return { results, suggestions };
|
return { results, suggestions };
|
||||||
} catch (err: any) {
|
|
||||||
if (err.name === 'AbortError') {
|
|
||||||
throw new Error('SearXNG search timed out');
|
|
||||||
}
|
|
||||||
throw err;
|
|
||||||
} finally {
|
|
||||||
clearTimeout(timeoutId);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import crypto from "crypto"
|
|||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import { splitText } from "../utils/splitText";
|
import { splitText } from "../utils/splitText";
|
||||||
import { PDFParse } from 'pdf-parse';
|
import { PDFParse } from 'pdf-parse';
|
||||||
import { CanvasFactory } from 'pdf-parse/worker';
|
|
||||||
import officeParser from 'officeparser'
|
import officeParser from 'officeparser'
|
||||||
|
import { Chunk } from "../types";
|
||||||
|
|
||||||
const supportedMimeTypes = ['application/pdf', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'text/plain'] as const
|
const supportedMimeTypes = ['application/pdf', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'text/plain'] as const
|
||||||
|
|
||||||
@@ -116,8 +116,7 @@ class UploadManager {
|
|||||||
const pdfBuffer = fs.readFileSync(filePath);
|
const pdfBuffer = fs.readFileSync(filePath);
|
||||||
|
|
||||||
const parser = new PDFParse({
|
const parser = new PDFParse({
|
||||||
data: pdfBuffer,
|
data: pdfBuffer
|
||||||
CanvasFactory
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const pdfText = await parser.getText().then(res => res.text)
|
const pdfText = await parser.getText().then(res => res.text)
|
||||||
|
|||||||
77
yarn.lock
77
yarn.lock
@@ -797,11 +797,6 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-0.1.84.tgz#7b476e3003be0aca08ab27962fd0d6e803939bec"
|
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-0.1.84.tgz#7b476e3003be0aca08ab27962fd0d6e803939bec"
|
||||||
integrity sha512-pdvuqvj3qtwVryqgpAGornJLV6Ezpk39V6wT4JCnRVGy8I3Tk1au8qOalFGrx/r0Ig87hWslysPpHBxVpBMIww==
|
integrity sha512-pdvuqvj3qtwVryqgpAGornJLV6Ezpk39V6wT4JCnRVGy8I3Tk1au8qOalFGrx/r0Ig87hWslysPpHBxVpBMIww==
|
||||||
|
|
||||||
"@napi-rs/canvas-android-arm64@0.1.87":
|
|
||||||
version "0.1.87"
|
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-0.1.87.tgz#6adce7741baa56e75dcf72076e4bf249f9bc4b8e"
|
|
||||||
integrity sha512-uW7NxJXPvZft9fers4oBhdCsBRVe77DLQS3eXEOxndFzGKiwmjIbZpQqj4QPvrg3I0FM3UfHatz1+17P5SeCOQ==
|
|
||||||
|
|
||||||
"@napi-rs/canvas-darwin-arm64@0.1.80":
|
"@napi-rs/canvas-darwin-arm64@0.1.80":
|
||||||
version "0.1.80"
|
version "0.1.80"
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.80.tgz#638eaa2d0a2a373c7d15748743182718dcd95c4b"
|
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.80.tgz#638eaa2d0a2a373c7d15748743182718dcd95c4b"
|
||||||
@@ -812,11 +807,6 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.84.tgz#0f131722f9f66316cea5f5ed7cfb9ad1290683cd"
|
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.84.tgz#0f131722f9f66316cea5f5ed7cfb9ad1290683cd"
|
||||||
integrity sha512-A8IND3Hnv0R6abc6qCcCaOCujTLMmGxtucMTZ5vbQUrEN/scxi378MyTLtyWg+MRr6bwQJ6v/orqMS9datIcww==
|
integrity sha512-A8IND3Hnv0R6abc6qCcCaOCujTLMmGxtucMTZ5vbQUrEN/scxi378MyTLtyWg+MRr6bwQJ6v/orqMS9datIcww==
|
||||||
|
|
||||||
"@napi-rs/canvas-darwin-arm64@0.1.87":
|
|
||||||
version "0.1.87"
|
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.87.tgz#54f82dc0cd032f85e770abcddbeafc855005931a"
|
|
||||||
integrity sha512-S6YbpXwajDKLTsYftEqR+Ne1lHpeC78okI3IqctVdFexN31Taprn6mdV4CkPY/4S8eGNuReBHvXNyWbGqBZ1eQ==
|
|
||||||
|
|
||||||
"@napi-rs/canvas-darwin-x64@0.1.80":
|
"@napi-rs/canvas-darwin-x64@0.1.80":
|
||||||
version "0.1.80"
|
version "0.1.80"
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.80.tgz#bd6bc048dbd4b02b9620d9d07117ed93e6970978"
|
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.80.tgz#bd6bc048dbd4b02b9620d9d07117ed93e6970978"
|
||||||
@@ -827,11 +817,6 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.84.tgz#e6ab8c534172d8a8d434fa090da8a205359d8769"
|
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.84.tgz#e6ab8c534172d8a8d434fa090da8a205359d8769"
|
||||||
integrity sha512-AUW45lJhYWwnA74LaNeqhvqYKK/2hNnBBBl03KRdqeCD4tKneUSrxUqIv8d22CBweOvrAASyKN3W87WO2zEr/A==
|
integrity sha512-AUW45lJhYWwnA74LaNeqhvqYKK/2hNnBBBl03KRdqeCD4tKneUSrxUqIv8d22CBweOvrAASyKN3W87WO2zEr/A==
|
||||||
|
|
||||||
"@napi-rs/canvas-darwin-x64@0.1.87":
|
|
||||||
version "0.1.87"
|
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.87.tgz#54c2be73ce69a65e70f3d94fb879907479cc12c5"
|
|
||||||
integrity sha512-OJLwP2WIUmRSqWTyV/NZ2TnvBzUsbNqQu6IL7oshwfxYg4BELPV279wrfQ/xZFqzr7wybfIzKaPF4du5ZdA2Cg==
|
|
||||||
|
|
||||||
"@napi-rs/canvas-linux-arm-gnueabihf@0.1.80":
|
"@napi-rs/canvas-linux-arm-gnueabihf@0.1.80":
|
||||||
version "0.1.80"
|
version "0.1.80"
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.80.tgz#ce6bfbeb19d9234c42df5c384e5989aa7d734789"
|
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.80.tgz#ce6bfbeb19d9234c42df5c384e5989aa7d734789"
|
||||||
@@ -842,11 +827,6 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.84.tgz#5898daa3050a8ba4619c1d6cea3a3217d46c5ffd"
|
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.84.tgz#5898daa3050a8ba4619c1d6cea3a3217d46c5ffd"
|
||||||
integrity sha512-8zs5ZqOrdgs4FioTxSBrkl/wHZB56bJNBqaIsfPL4ZkEQCinOkrFF7xIcXiHiKp93J3wUtbIzeVrhTIaWwqk+A==
|
integrity sha512-8zs5ZqOrdgs4FioTxSBrkl/wHZB56bJNBqaIsfPL4ZkEQCinOkrFF7xIcXiHiKp93J3wUtbIzeVrhTIaWwqk+A==
|
||||||
|
|
||||||
"@napi-rs/canvas-linux-arm-gnueabihf@0.1.87":
|
|
||||||
version "0.1.87"
|
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.87.tgz#1bc3c9280db381cc3893c3d13d7320666ce47ebe"
|
|
||||||
integrity sha512-Io3tY6ogc+oyvIGK9rQlnfH4gKiS35P7W6s22x3WCrLFR0dXzZP2IBBoEFEHd6FY6FR1ky5u9cRmADaiLRdX3g==
|
|
||||||
|
|
||||||
"@napi-rs/canvas-linux-arm64-gnu@0.1.80":
|
"@napi-rs/canvas-linux-arm64-gnu@0.1.80":
|
||||||
version "0.1.80"
|
version "0.1.80"
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.80.tgz#3b7a7832fef763826fa5fb740d5757204e52607d"
|
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.80.tgz#3b7a7832fef763826fa5fb740d5757204e52607d"
|
||||||
@@ -857,11 +837,6 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.84.tgz#fbbde94c04278259f1f40b4c199dfd9f95c82e66"
|
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.84.tgz#fbbde94c04278259f1f40b4c199dfd9f95c82e66"
|
||||||
integrity sha512-i204vtowOglJUpbAFWU5mqsJgH0lVpNk/Ml4mQtB4Lndd86oF+Otr6Mr5KQnZHqYGhlSIKiU2SYnUbhO28zGQA==
|
integrity sha512-i204vtowOglJUpbAFWU5mqsJgH0lVpNk/Ml4mQtB4Lndd86oF+Otr6Mr5KQnZHqYGhlSIKiU2SYnUbhO28zGQA==
|
||||||
|
|
||||||
"@napi-rs/canvas-linux-arm64-gnu@0.1.87":
|
|
||||||
version "0.1.87"
|
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.87.tgz#70af2d77d58d65559a43c55f6c37906c220af39e"
|
|
||||||
integrity sha512-Zq7h/PQzs37gaSR/gNRZOAaCC1kGt6NmDjA1PcqpONITh/rAfAwAeP98emrbBJ4FDoPkYRkxmxHlmXNLlsQIBw==
|
|
||||||
|
|
||||||
"@napi-rs/canvas-linux-arm64-musl@0.1.80":
|
"@napi-rs/canvas-linux-arm64-musl@0.1.80":
|
||||||
version "0.1.80"
|
version "0.1.80"
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.80.tgz#d8ccd91f31d70760628623cd575134ada17690a3"
|
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.80.tgz#d8ccd91f31d70760628623cd575134ada17690a3"
|
||||||
@@ -872,11 +847,6 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.84.tgz#8b02c46c5dbb0a58de87885c61ca1681b1199697"
|
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.84.tgz#8b02c46c5dbb0a58de87885c61ca1681b1199697"
|
||||||
integrity sha512-VyZq0EEw+OILnWk7G3ZgLLPaz1ERaPP++jLjeyLMbFOF+Tr4zHzWKiKDsEV/cT7btLPZbVoR3VX+T9/QubnURQ==
|
integrity sha512-VyZq0EEw+OILnWk7G3ZgLLPaz1ERaPP++jLjeyLMbFOF+Tr4zHzWKiKDsEV/cT7btLPZbVoR3VX+T9/QubnURQ==
|
||||||
|
|
||||||
"@napi-rs/canvas-linux-arm64-musl@0.1.87":
|
|
||||||
version "0.1.87"
|
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.87.tgz#31355f0debf35848851be97aa1136905db9cef2a"
|
|
||||||
integrity sha512-CUa5YJjpsFcUxJbtfoQ4bqO/Rq+JU/2RfTNFxx07q1AjuDjCM8+MOOLCvVOV1z3qhl6nKAtjJT0pA0J8EbnK8Q==
|
|
||||||
|
|
||||||
"@napi-rs/canvas-linux-riscv64-gnu@0.1.80":
|
"@napi-rs/canvas-linux-riscv64-gnu@0.1.80":
|
||||||
version "0.1.80"
|
version "0.1.80"
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-0.1.80.tgz#927a3b859a0e3c691beaf52a19bc4736c4ffc9b8"
|
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-0.1.80.tgz#927a3b859a0e3c691beaf52a19bc4736c4ffc9b8"
|
||||||
@@ -887,11 +857,6 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-0.1.84.tgz#787c9c207f69aaa51b852c7063a6eed2985b7fca"
|
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-0.1.84.tgz#787c9c207f69aaa51b852c7063a6eed2985b7fca"
|
||||||
integrity sha512-PSMTh8DiThvLRsbtc/a065I/ceZk17EXAATv9uNvHgkgo7wdEfTh2C3aveNkBMGByVO3tvnvD5v/YFtZL07cIg==
|
integrity sha512-PSMTh8DiThvLRsbtc/a065I/ceZk17EXAATv9uNvHgkgo7wdEfTh2C3aveNkBMGByVO3tvnvD5v/YFtZL07cIg==
|
||||||
|
|
||||||
"@napi-rs/canvas-linux-riscv64-gnu@0.1.87":
|
|
||||||
version "0.1.87"
|
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-0.1.87.tgz#031d3d30cf667586ad742c5846a0e086c7ada950"
|
|
||||||
integrity sha512-5KM4dBFEzFMNkJV2rheIQWpd+mRZA7VNDnxTT7nsCEf6DUjUnf6Hssq9bAwjVYTe4jqraDHbWRbF4uXLBLRFJg==
|
|
||||||
|
|
||||||
"@napi-rs/canvas-linux-x64-gnu@0.1.80":
|
"@napi-rs/canvas-linux-x64-gnu@0.1.80":
|
||||||
version "0.1.80"
|
version "0.1.80"
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.80.tgz#25c0416bcedd6fadc15295e9afa8d9697232050c"
|
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.80.tgz#25c0416bcedd6fadc15295e9afa8d9697232050c"
|
||||||
@@ -902,11 +867,6 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.84.tgz#fb6eaea81ce679575b5004bc2177ce2d9222642b"
|
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.84.tgz#fb6eaea81ce679575b5004bc2177ce2d9222642b"
|
||||||
integrity sha512-N1GY3noO1oqgEo3rYQIwY44kfM11vA0lDbN0orTOHfCSUZTUyiYCY0nZ197QMahZBm1aR/vYgsWpV74MMMDuNA==
|
integrity sha512-N1GY3noO1oqgEo3rYQIwY44kfM11vA0lDbN0orTOHfCSUZTUyiYCY0nZ197QMahZBm1aR/vYgsWpV74MMMDuNA==
|
||||||
|
|
||||||
"@napi-rs/canvas-linux-x64-gnu@0.1.87":
|
|
||||||
version "0.1.87"
|
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.87.tgz#9fcc1dd2574aebe7e57797196712106665948dd0"
|
|
||||||
integrity sha512-zSv+ozz9elT5YhocyogX5LwVYURChO4QGD6CQIW6OnuNA0UOMDD/b4wDzlJiMphISy3EVTntlKFhe4W3EuKcxw==
|
|
||||||
|
|
||||||
"@napi-rs/canvas-linux-x64-musl@0.1.80":
|
"@napi-rs/canvas-linux-x64-musl@0.1.80":
|
||||||
version "0.1.80"
|
version "0.1.80"
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.80.tgz#de85d644e09120a60996bbe165cc2efee804551b"
|
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.80.tgz#de85d644e09120a60996bbe165cc2efee804551b"
|
||||||
@@ -917,16 +877,6 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.84.tgz#54a37352a0be7f2a7218b6f11d8ae9b5cdbb3d6c"
|
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.84.tgz#54a37352a0be7f2a7218b6f11d8ae9b5cdbb3d6c"
|
||||||
integrity sha512-vUZmua6ADqTWyHyei81aXIt9wp0yjeNwTH0KdhdeoBb6azHmFR8uKTukZMXfLCC3bnsW0t4lW7K78KNMknmtjg==
|
integrity sha512-vUZmua6ADqTWyHyei81aXIt9wp0yjeNwTH0KdhdeoBb6azHmFR8uKTukZMXfLCC3bnsW0t4lW7K78KNMknmtjg==
|
||||||
|
|
||||||
"@napi-rs/canvas-linux-x64-musl@0.1.87":
|
|
||||||
version "0.1.87"
|
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.87.tgz#170b7fe76f1b52a947bc287cd3c84f15d210b863"
|
|
||||||
integrity sha512-jTNmicAZQ70X+cbjZz6G6w8lmORwxRBmj/U20ECNYvcWVLshgyCKWPFL2I0Z6pkJve0vZWls6oZ15iccm1sv8w==
|
|
||||||
|
|
||||||
"@napi-rs/canvas-win32-arm64-msvc@0.1.87":
|
|
||||||
version "0.1.87"
|
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-win32-arm64-msvc/-/canvas-win32-arm64-msvc-0.1.87.tgz#6536946c5a1796b0781700ee6b39ac18fc0e96b2"
|
|
||||||
integrity sha512-p6J7UNAxKHYc7AL0glEtYuW/E0OLLUNnLti8dA2OT51p08Il4T7yZCl+iNo6f73HntFP+dgOHh2cTXUhmk8GuA==
|
|
||||||
|
|
||||||
"@napi-rs/canvas-win32-x64-msvc@0.1.80":
|
"@napi-rs/canvas-win32-x64-msvc@0.1.80":
|
||||||
version "0.1.80"
|
version "0.1.80"
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.80.tgz#6bb95885d9377912d71f1372fc1916fb54d6ef0a"
|
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.80.tgz#6bb95885d9377912d71f1372fc1916fb54d6ef0a"
|
||||||
@@ -937,11 +887,6 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.84.tgz#e0039b89f8e04287c77bd1fb5e6fa671d6c9d3c8"
|
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.84.tgz#e0039b89f8e04287c77bd1fb5e6fa671d6c9d3c8"
|
||||||
integrity sha512-YSs8ncurc1xzegUMNnQUTYrdrAuaXdPMOa+iYYyAxydOtg0ppV386hyYMsy00Yip1NlTgLCseRG4sHSnjQx6og==
|
integrity sha512-YSs8ncurc1xzegUMNnQUTYrdrAuaXdPMOa+iYYyAxydOtg0ppV386hyYMsy00Yip1NlTgLCseRG4sHSnjQx6og==
|
||||||
|
|
||||||
"@napi-rs/canvas-win32-x64-msvc@0.1.87":
|
|
||||||
version "0.1.87"
|
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.87.tgz#058b13a9dd3a6180bdfa976b7c8814cfb9df9c8f"
|
|
||||||
integrity sha512-WrwfETMLBRFWkGU8fXU50gCpA2eIjR4NE9JyTKl86Kz5g6SDp0CcuqS2phYtB66TI2HDUhTPbNrk4V7Qf1FOLA==
|
|
||||||
|
|
||||||
"@napi-rs/canvas@0.1.80":
|
"@napi-rs/canvas@0.1.80":
|
||||||
version "0.1.80"
|
version "0.1.80"
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/canvas/-/canvas-0.1.80.tgz#53615bea56fd94e07331ab13caa7a39efc4914ab"
|
resolved "https://registry.yarnpkg.com/@napi-rs/canvas/-/canvas-0.1.80.tgz#53615bea56fd94e07331ab13caa7a39efc4914ab"
|
||||||
@@ -974,23 +919,6 @@
|
|||||||
"@napi-rs/canvas-linux-x64-musl" "0.1.84"
|
"@napi-rs/canvas-linux-x64-musl" "0.1.84"
|
||||||
"@napi-rs/canvas-win32-x64-msvc" "0.1.84"
|
"@napi-rs/canvas-win32-x64-msvc" "0.1.84"
|
||||||
|
|
||||||
"@napi-rs/canvas@^0.1.87":
|
|
||||||
version "0.1.87"
|
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/canvas/-/canvas-0.1.87.tgz#028e581af4499ee4ca569eb10cb5705526fee68d"
|
|
||||||
integrity sha512-Zb5tePmPMOYBcuNW3NQaVM1sIkvIfel39euiOab/XMjC5Oc/AnPJLa/BacJcToGyIvehecS6eqcsF7i0Wqe1Sw==
|
|
||||||
optionalDependencies:
|
|
||||||
"@napi-rs/canvas-android-arm64" "0.1.87"
|
|
||||||
"@napi-rs/canvas-darwin-arm64" "0.1.87"
|
|
||||||
"@napi-rs/canvas-darwin-x64" "0.1.87"
|
|
||||||
"@napi-rs/canvas-linux-arm-gnueabihf" "0.1.87"
|
|
||||||
"@napi-rs/canvas-linux-arm64-gnu" "0.1.87"
|
|
||||||
"@napi-rs/canvas-linux-arm64-musl" "0.1.87"
|
|
||||||
"@napi-rs/canvas-linux-riscv64-gnu" "0.1.87"
|
|
||||||
"@napi-rs/canvas-linux-x64-gnu" "0.1.87"
|
|
||||||
"@napi-rs/canvas-linux-x64-musl" "0.1.87"
|
|
||||||
"@napi-rs/canvas-win32-arm64-msvc" "0.1.87"
|
|
||||||
"@napi-rs/canvas-win32-x64-msvc" "0.1.87"
|
|
||||||
|
|
||||||
"@next/env@16.0.7":
|
"@next/env@16.0.7":
|
||||||
version "16.0.7"
|
version "16.0.7"
|
||||||
resolved "https://registry.yarnpkg.com/@next/env/-/env-16.0.7.tgz#eda56377a865d890d25122257d2b8a85b81d6d3d"
|
resolved "https://registry.yarnpkg.com/@next/env/-/env-16.0.7.tgz#eda56377a865d890d25122257d2b8a85b81d6d3d"
|
||||||
@@ -1384,11 +1312,6 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@tokenizer/token/-/token-0.3.0.tgz#fe98a93fe789247e998c75e74e9c7c63217aa276"
|
resolved "https://registry.yarnpkg.com/@tokenizer/token/-/token-0.3.0.tgz#fe98a93fe789247e998c75e74e9c7c63217aa276"
|
||||||
integrity sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==
|
integrity sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==
|
||||||
|
|
||||||
"@toolsycc/json-repair@^0.1.22":
|
|
||||||
version "0.1.22"
|
|
||||||
resolved "https://registry.yarnpkg.com/@toolsycc/json-repair/-/json-repair-0.1.22.tgz#7ad0eb30c4ef1c4286ad3487dc1bbda562f09986"
|
|
||||||
integrity sha512-IMrsxovS9a5pWGRxMCDQDW8FKKEZI/yK/HMcyJlbnd/s+Mk0dRtGr1BFicL276gDsPvb/JfNHtHSi1oc0eY1jA==
|
|
||||||
|
|
||||||
"@types/better-sqlite3@^7.6.12":
|
"@types/better-sqlite3@^7.6.12":
|
||||||
version "7.6.12"
|
version "7.6.12"
|
||||||
resolved "https://registry.yarnpkg.com/@types/better-sqlite3/-/better-sqlite3-7.6.12.tgz#e5712d46d71097dcc2775c0b068072eadc15deb7"
|
resolved "https://registry.yarnpkg.com/@types/better-sqlite3/-/better-sqlite3-7.6.12.tgz#e5712d46d71097dcc2775c0b068072eadc15deb7"
|
||||||
|
|||||||
Reference in New Issue
Block a user