mirror of
https://github.com/ItzCrazyKns/Perplexica.git
synced 2025-06-19 16:28:42 +00:00
Compare commits
7 Commits
admin-pass
...
562a6e890d
Author | SHA1 | Date | |
---|---|---|---|
562a6e890d | |||
64d2a467b0 | |||
9a2c4fe3b6 | |||
060c68a900 | |||
e6b87f89ec | |||
47c7bb688f | |||
dd2f4effca |
@ -18,9 +18,13 @@ API_KEY = ""
|
|||||||
[MODELS.CUSTOM_OPENAI]
|
[MODELS.CUSTOM_OPENAI]
|
||||||
API_KEY = ""
|
API_KEY = ""
|
||||||
API_URL = ""
|
API_URL = ""
|
||||||
|
MODEL_NAME = ""
|
||||||
|
|
||||||
[MODELS.OLLAMA]
|
[MODELS.OLLAMA]
|
||||||
API_URL = "" # Ollama API URL - http://host.docker.internal:11434
|
API_URL = "" # Ollama API URL - http://host.docker.internal:11434
|
||||||
|
|
||||||
[API_ENDPOINTS]
|
[API_ENDPOINTS]
|
||||||
SEARXNG = "http://localhost:32768" # SearxNG API URL
|
SEARXNG = "http://localhost:32768" # SearxNG API URL
|
||||||
|
|
||||||
|
[API_KEYS]
|
||||||
|
JINA = ""
|
||||||
|
@ -35,6 +35,9 @@ interface Config {
|
|||||||
API_ENDPOINTS: {
|
API_ENDPOINTS: {
|
||||||
SEARXNG: string;
|
SEARXNG: string;
|
||||||
};
|
};
|
||||||
|
API_KEYS: {
|
||||||
|
JINA: string;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type RecursivePartial<T> = {
|
type RecursivePartial<T> = {
|
||||||
@ -75,6 +78,9 @@ export const getCustomOpenaiApiUrl = () =>
|
|||||||
export const getCustomOpenaiModelName = () =>
|
export const getCustomOpenaiModelName = () =>
|
||||||
loadConfig().MODELS.CUSTOM_OPENAI.MODEL_NAME;
|
loadConfig().MODELS.CUSTOM_OPENAI.MODEL_NAME;
|
||||||
|
|
||||||
|
export const getJinaApiKey = () =>
|
||||||
|
loadConfig().API_KEYS.JINA;
|
||||||
|
|
||||||
const mergeConfigs = (current: any, update: any): any => {
|
const mergeConfigs = (current: any, update: any): any => {
|
||||||
if (update === null || update === undefined) {
|
if (update === null || update === undefined) {
|
||||||
return current;
|
return current;
|
||||||
|
@ -1,22 +1,30 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { htmlToText } from 'html-to-text';
|
import { htmlToText } from 'html-to-text';
|
||||||
import { RecursiveCharacterTextSplitter } from 'langchain/text_splitter';
|
import { RecursiveCharacterTextSplitter, MarkdownTextSplitter } from 'langchain/text_splitter';
|
||||||
import { Document } from '@langchain/core/documents';
|
import { Document } from '@langchain/core/documents';
|
||||||
import pdfParse from 'pdf-parse';
|
import pdfParse from 'pdf-parse';
|
||||||
import logger from './logger';
|
import logger from './logger';
|
||||||
|
import { getJinaApiKey } from '../config';
|
||||||
|
|
||||||
export const getDocumentsFromLinks = async ({ links }: { links: string[] }) => {
|
export const getDocumentsFromLinks = async ({ links }: { links: string[] }) => {
|
||||||
const splitter = new RecursiveCharacterTextSplitter();
|
|
||||||
|
|
||||||
|
links = links.map(link => link.startsWith('http://') || link.startsWith('https://')
|
||||||
|
? link
|
||||||
|
: `https://${link}`)
|
||||||
|
|
||||||
|
if (getJinaApiKey()) {
|
||||||
|
return await getDocumentsFromJinaReader({ links });
|
||||||
|
}
|
||||||
|
|
||||||
|
return await getDocumentsFromLocal({ links });
|
||||||
|
};
|
||||||
|
|
||||||
|
const getDocumentsFromLocal = async ({links}: {links: string[]}) => {
|
||||||
|
const splitter = new RecursiveCharacterTextSplitter();
|
||||||
let docs: Document[] = [];
|
let docs: Document[] = [];
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
links.map(async (link) => {
|
links.map(async (link) => {
|
||||||
link =
|
|
||||||
link.startsWith('http://') || link.startsWith('https://')
|
|
||||||
? link
|
|
||||||
: `https://${link}`;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await axios.get(link, {
|
const res = await axios.get(link, {
|
||||||
responseType: 'arraybuffer',
|
responseType: 'arraybuffer',
|
||||||
@ -94,6 +102,62 @@ export const getDocumentsFromLinks = async ({ links }: { links: string[] }) => {
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
return docs;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getDocumentsFromJinaReader = async ({links}: { links: string[] }) => {
|
||||||
|
const splitter = new MarkdownTextSplitter();
|
||||||
|
let docs: Document[] = [];
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
links.map(async link => {
|
||||||
|
try {
|
||||||
|
const res = await axios.get(`https://r.jina.ai/${link}`, {
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': `Bearer ${getJinaApiKey()}`,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if(res.data.code === 200) {
|
||||||
|
const data = res.data.data
|
||||||
|
const splittedText = await splitter.splitText(data.content);
|
||||||
|
const linkDocs = splittedText.map((text) => {
|
||||||
|
return new Document({
|
||||||
|
pageContent: text,
|
||||||
|
metadata: {
|
||||||
|
title: data.title,
|
||||||
|
url: link,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
docs.push(...linkDocs);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
docs.push(
|
||||||
|
new Document({
|
||||||
|
pageContent: `Failed to retrieve content from the link in the Jina reader API, code: ${res.data.code}`,
|
||||||
|
metadata: {
|
||||||
|
title: 'Failed to retrieve content',
|
||||||
|
url: link,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
docs.push(
|
||||||
|
new Document({
|
||||||
|
pageContent: `Failed to retrieve content from the link: ${err.message}`,
|
||||||
|
metadata: {
|
||||||
|
title: 'Failed to retrieve content',
|
||||||
|
url: link,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
return docs;
|
return docs;
|
||||||
};
|
};
|
||||||
|
@ -48,11 +48,17 @@ const Chat = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
messageEnd.current?.scrollIntoView({ behavior: 'smooth' });
|
const scroll = () => {
|
||||||
|
messageEnd.current?.scrollIntoView({ behavior: 'smooth' });
|
||||||
|
};
|
||||||
|
|
||||||
if (messages.length === 1) {
|
if (messages.length === 1) {
|
||||||
document.title = `${messages[0].content.substring(0, 30)} - Perplexica`;
|
document.title = `${messages[0].content.substring(0, 30)} - Perplexica`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (messages[messages.length - 1]?.role == 'user') {
|
||||||
|
scroll();
|
||||||
|
}
|
||||||
}, [messages]);
|
}, [messages]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -68,7 +68,13 @@ const MessageBox = ({
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{message.role === 'user' && (
|
{message.role === 'user' && (
|
||||||
<div className={cn('w-full', messageIndex === 0 ? 'pt-16' : 'pt-8', 'break-words')}>
|
<div
|
||||||
|
className={cn(
|
||||||
|
'w-full',
|
||||||
|
messageIndex === 0 ? 'pt-16' : 'pt-8',
|
||||||
|
'break-words',
|
||||||
|
)}
|
||||||
|
>
|
||||||
<h2 className="text-black dark:text-white font-medium text-3xl lg:w-9/12">
|
<h2 className="text-black dark:text-white font-medium text-3xl lg:w-9/12">
|
||||||
{message.content}
|
{message.content}
|
||||||
</h2>
|
</h2>
|
||||||
|
Reference in New Issue
Block a user