Compare commits

..

15 Commits

Author SHA1 Message Date
ItzCrazyKns
7c97df98c7 Update perplexica-screenshot.png 2025-10-07 16:45:55 +05:30
ItzCrazyKns
b084c42aca Update perplexica-screenshot.png 2025-10-07 16:21:31 +05:30
ItzCrazyKns
fdfa2f3ea6 Update perplexica-screenshot.png 2025-10-07 16:13:56 +05:30
ItzCrazyKns
3323e7a0ed feat(package): bump version, update screenshot 2025-10-07 16:11:10 +05:30
ItzCrazyKns
d4f9da34c6 feat(tailwind-config): update theme 2025-10-07 15:07:26 +05:30
ItzCrazyKns
10ed67c753 feat(workflow): build images for canary 2025-10-06 20:00:31 +05:30
ItzCrazyKns
cf3cc4e638 feat(migrator): use DATA_DIR env var 2025-10-06 10:13:34 +05:30
ItzCrazyKns
46b9e41100 feat(db-table): add default values for createdAt 2025-10-06 08:59:01 +05:30
sjiampojamarn
02adafbd4b Handling double stringify JSON parsing 2025-10-05 10:46:01 -07:00
ItzCrazyKns
f141d4719c feat(assets): update preview image 2025-10-05 22:32:17 +05:30
ItzCrazyKns
f18e132d1b feat(news-widget): fix loading animation 2025-10-02 17:55:56 +05:30
ItzCrazyKns
37317992b4 feat(app): lint & beautify 2025-10-02 17:17:52 +05:30
ItzCrazyKns
8b588824f2 feat(css): add line-clamp-2 class 2025-10-02 17:17:44 +05:30
ItzCrazyKns
a19cf00873 feat(lineOutputParser): return undefined on invalid tags 2025-10-02 17:17:31 +05:30
ItzCrazyKns
5cc11ac0bf feat(message-handling): fix repeated first token, think tag handling
closes #889
2025-10-02 17:15:54 +05:30
11 changed files with 93 additions and 45 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 641 KiB

After

Width:  |  Height:  |  Size: 2.1 MiB

View File

@@ -4,6 +4,7 @@ on:
push:
branches:
- master
- canary
release:
types: [published]
@@ -43,6 +44,19 @@ jobs:
-t itzcrazykns1337/${IMAGE_NAME}:amd64 \
--push .
- name: Build and push AMD64 Canary Docker image
if: github.ref == 'refs/heads/canary' && github.event_name == 'push'
run: |
DOCKERFILE=app.dockerfile
IMAGE_NAME=perplexica
docker buildx build --platform linux/amd64 \
--cache-from=type=registry,ref=itzcrazykns1337/${IMAGE_NAME}:canary-amd64 \
--cache-to=type=inline \
--provenance false \
-f $DOCKERFILE \
-t itzcrazykns1337/${IMAGE_NAME}:canary-amd64 \
--push .
- name: Build and push AMD64 release Docker image
if: github.event_name == 'release'
run: |
@@ -91,6 +105,19 @@ jobs:
-t itzcrazykns1337/${IMAGE_NAME}:arm64 \
--push .
- name: Build and push ARM64 Canary Docker image
if: github.ref == 'refs/heads/canary' && github.event_name == 'push'
run: |
DOCKERFILE=app.dockerfile
IMAGE_NAME=perplexica
docker buildx build --platform linux/arm64 \
--cache-from=type=registry,ref=itzcrazykns1337/${IMAGE_NAME}:canary-arm64 \
--cache-to=type=inline \
--provenance false \
-f $DOCKERFILE \
-t itzcrazykns1337/${IMAGE_NAME}:canary-arm64 \
--push .
- name: Build and push ARM64 release Docker image
if: github.event_name == 'release'
run: |
@@ -128,6 +155,15 @@ jobs:
--amend itzcrazykns1337/${IMAGE_NAME}:arm64
docker manifest push itzcrazykns1337/${IMAGE_NAME}:main
- name: Create and push multi-arch manifest for canary
if: github.ref == 'refs/heads/canary' && github.event_name == 'push'
run: |
IMAGE_NAME=perplexica
docker manifest create itzcrazykns1337/${IMAGE_NAME}:canary \
--amend itzcrazykns1337/${IMAGE_NAME}:canary-amd64 \
--amend itzcrazykns1337/${IMAGE_NAME}:canary-arm64
docker manifest push itzcrazykns1337/${IMAGE_NAME}:canary
- name: Create and push multi-arch manifest for releases
if: github.event_name == 'release'
run: |

View File

@@ -1,6 +1,6 @@
{
"name": "perplexica-frontend",
"version": "1.11.0-rc2",
"version": "1.11.0-rc3",
"license": "MIT",
"author": "ItzCrazyKns",
"scripts": {

View File

@@ -20,6 +20,15 @@
}
}
@layer utilities {
.line-clamp-2 {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
}
@media screen and (-webkit-min-device-pixel-ratio: 0) {
select,
textarea,

View File

@@ -69,9 +69,7 @@ const MessageBox = ({
return (
<div className="space-y-6">
<div
className={'w-full pt-8 break-words'}
>
<div className={'w-full pt-8 break-words'}>
<h2 className="text-black dark:text-white font-medium text-3xl lg:w-9/12">
{section.userMessage.content}
</h2>

View File

@@ -29,15 +29,13 @@ const NewsArticleWidget = () => {
return (
<div className="bg-light-secondary dark:bg-dark-secondary rounded-2xl border border-light-200 dark:border-dark-200 shadow-sm shadow-light-200/10 dark:shadow-black/25 flex flex-row items-stretch w-full h-24 min-h-[96px] max-h-[96px] p-0 overflow-hidden">
{loading ? (
<>
<div className="animate-pulse flex flex-row items-center w-full h-full">
<div className="rounded-lg w-16 min-w-16 max-w-16 h-16 min-h-16 max-h-16 bg-light-200 dark:bg-dark-200 mr-3" />
<div className="flex flex-col justify-center flex-1 h-full w-0 gap-2">
<div className="h-4 w-3/4 rounded bg-light-200 dark:bg-dark-200" />
<div className="h-3 w-1/2 rounded bg-light-200 dark:bg-dark-200" />
</div>
<div className="animate-pulse flex flex-row items-stretch w-full h-full">
<div className="w-24 min-w-24 max-w-24 h-full bg-light-200 dark:bg-dark-200" />
<div className="flex flex-col justify-center flex-1 px-3 py-2 gap-2">
<div className="h-4 w-3/4 rounded bg-light-200 dark:bg-dark-200" />
<div className="h-3 w-1/2 rounded bg-light-200 dark:bg-dark-200" />
</div>
</>
</div>
) : error ? (
<div className="w-full text-xs text-red-400">Could not load news.</div>
) : article ? (

View File

@@ -2,9 +2,12 @@ import Database from 'better-sqlite3';
import path from 'path';
import fs from 'fs';
const db = new Database(path.join(process.cwd(), 'data', 'db.sqlite'));
const DATA_DIR = process.env.DATA_DIR || process.cwd();
const dbPath = path.join(DATA_DIR, './data/db.sqlite');
const migrationsFolder = path.join(process.cwd(), 'drizzle');
const db = new Database(dbPath);
const migrationsFolder = path.join(DATA_DIR, 'drizzle');
db.exec(`
CREATE TABLE IF NOT EXISTS ran_migrations (
@@ -54,7 +57,7 @@ fs.readdirSync(migrationsFolder)
id INTEGER PRIMARY KEY,
type TEXT NOT NULL,
chatId TEXT NOT NULL,
createdAt TEXT NOT NULL,
createdAt TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
messageId TEXT NOT NULL,
content TEXT,
sources TEXT DEFAULT '[]'
@@ -67,8 +70,10 @@ fs.readdirSync(migrationsFolder)
`);
messages.forEach((msg: any) => {
if (msg.type === 'user') {
while (typeof msg.metadata === 'string') {
msg.metadata = JSON.parse(msg.metadata || '{}');
}
if (msg.type === 'user') {
insertMessage.run(
'user',
msg.chatId,
@@ -78,7 +83,6 @@ fs.readdirSync(migrationsFolder)
'[]',
);
} else if (msg.type === 'assistant') {
msg.metadata = JSON.parse(msg.metadata || '{}');
insertMessage.run(
'assistant',
msg.chatId,

View File

@@ -399,6 +399,7 @@ export const ChatProvider = ({
(m, j) =>
j > i &&
m.role === 'source' &&
m.sources &&
(nextUserMessageIndex === -1 || j < nextUserMessageIndex),
) as SourceMessage | undefined;
@@ -417,7 +418,7 @@ export const ChatProvider = ({
const closeThinkTag =
processedMessage.match(/<\/think>/g)?.length || 0;
if (openThinkTag > closeThinkTag) {
if (openThinkTag && !closeThinkTag) {
processedMessage += '</think> <a> </a>';
}
}
@@ -426,7 +427,11 @@ export const ChatProvider = ({
thinkingEnded = true;
}
if (sourceMessage && sourceMessage.sources.length > 0) {
if (
sourceMessage &&
sourceMessage.sources &&
sourceMessage.sources.length > 0
) {
processedMessage = processedMessage.replace(
citationRegex,
(_, capturedContent: string) => {
@@ -635,23 +640,22 @@ export const ChatProvider = ({
},
]);
added = true;
setMessageAppeared(true);
} else {
setMessages((prev) =>
prev.map((message) => {
if (
message.messageId === data.messageId &&
message.role === 'assistant'
) {
return { ...message, content: message.content + data.data };
}
return message;
}),
);
}
setMessages((prev) =>
prev.map((message) => {
if (
message.messageId === data.messageId &&
message.role === 'assistant'
) {
return { ...message, content: message.content + data.data };
}
return message;
}),
);
recievedMessage += data.data;
setMessageAppeared(true);
}
if (data.type === 'messageEnd') {

View File

@@ -4,7 +4,7 @@ interface LineOutputParserArgs {
key?: string;
}
class LineOutputParser extends BaseOutputParser<string> {
class LineOutputParser extends BaseOutputParser<string | undefined> {
private key = 'questions';
constructor(args?: LineOutputParserArgs) {
@@ -18,7 +18,7 @@ class LineOutputParser extends BaseOutputParser<string> {
lc_namespace = ['langchain', 'output_parsers', 'line_output_parser'];
async parse(text: string): Promise<string> {
async parse(text: string): Promise<string | undefined> {
text = text.trim() || '';
const regex = /^(\s*(-|\*|\d+\.\s|\d+\)\s|\u2022)\s*)+/;
@@ -26,7 +26,7 @@ class LineOutputParser extends BaseOutputParser<string> {
const endKeyIndex = text.indexOf(`</${this.key}>`);
if (startKeyIndex === -1 || endKeyIndex === -1) {
return '';
return undefined;
}
const questionsStartIndex =

View File

@@ -453,7 +453,6 @@ class MetaSearchAgent implements MetaSearchAgentType {
event.event === 'on_chain_end' &&
event.name === 'FinalSourceRetriever'
) {
``;
emitter.emit(
'data',
JSON.stringify({ type: 'sources', data: event.data.output }),

View File

@@ -2,17 +2,17 @@ import type { Config } from 'tailwindcss';
import type { DefaultColors } from 'tailwindcss/types/generated/colors';
const themeDark = (colors: DefaultColors) => ({
50: '#111116',
100: '#1f202b',
200: '#2d2f3f',
300: '#3a3c4c',
50: '#0d1117',
100: '#161b22',
200: '#21262d',
300: '#30363d',
});
const themeLight = (colors: DefaultColors) => ({
50: '#ffffff',
100: '#f1f5f9',
200: '#c4c7c5',
300: '#9ca3af',
100: '#f6f8fa',
200: '#d0d7de',
300: '#afb8c1',
});
const config: Config = {