2024-04-09 16:21:05 +05:30
|
|
|
import {
|
|
|
|
RunnableSequence,
|
|
|
|
RunnableMap,
|
|
|
|
RunnableLambda,
|
|
|
|
} from '@langchain/core/runnables';
|
|
|
|
import { PromptTemplate } from '@langchain/core/prompts';
|
2024-04-18 18:15:17 +05:30
|
|
|
import { ChatOpenAI } from '@langchain/openai';
|
2024-04-09 16:21:05 +05:30
|
|
|
import formatChatHistoryAsString from '../utils/formatHistory';
|
|
|
|
import { BaseMessage } from '@langchain/core/messages';
|
|
|
|
import { StringOutputParser } from '@langchain/core/output_parsers';
|
|
|
|
import { searchSearxng } from '../core/searxng';
|
|
|
|
|
2024-04-18 18:15:17 +05:30
|
|
|
const llm = new ChatOpenAI({
|
2024-04-16 21:05:57 +05:30
|
|
|
modelName: process.env.MODEL_NAME,
|
2024-04-18 18:15:17 +05:30
|
|
|
temperature: 0.7,
|
2024-04-09 16:21:05 +05:30
|
|
|
});
|
|
|
|
|
|
|
|
const imageSearchChainPrompt = `
|
|
|
|
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.
|
|
|
|
|
|
|
|
Example:
|
|
|
|
1. Follow up question: What is a cat?
|
|
|
|
Rephrased: A cat
|
|
|
|
|
|
|
|
2. Follow up question: What is a car? How does it works?
|
|
|
|
Rephrased: Car working
|
|
|
|
|
|
|
|
3. Follow up question: How does an AC work?
|
|
|
|
Rephrased: AC working
|
|
|
|
|
|
|
|
Conversation:
|
|
|
|
{chat_history}
|
|
|
|
|
|
|
|
Follow up question: {query}
|
|
|
|
Rephrased question:
|
|
|
|
`;
|
|
|
|
|
|
|
|
type ImageSearchChainInput = {
|
|
|
|
chat_history: BaseMessage[];
|
|
|
|
query: string;
|
|
|
|
};
|
|
|
|
|
|
|
|
const strParser = new StringOutputParser();
|
|
|
|
|
|
|
|
const imageSearchChain = RunnableSequence.from([
|
|
|
|
RunnableMap.from({
|
|
|
|
chat_history: (input: ImageSearchChainInput) => {
|
|
|
|
return formatChatHistoryAsString(input.chat_history);
|
|
|
|
},
|
|
|
|
query: (input: ImageSearchChainInput) => {
|
|
|
|
return input.query;
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
PromptTemplate.fromTemplate(imageSearchChainPrompt),
|
|
|
|
llm,
|
|
|
|
strParser,
|
|
|
|
RunnableLambda.from(async (input: string) => {
|
|
|
|
const res = await searchSearxng(input, {
|
|
|
|
categories: ['images'],
|
|
|
|
engines: ['bing_images', 'google_images'],
|
|
|
|
});
|
|
|
|
|
|
|
|
const images = [];
|
|
|
|
|
|
|
|
res.results.forEach((result) => {
|
|
|
|
if (result.img_src && result.url && result.title) {
|
|
|
|
images.push({
|
|
|
|
img_src: result.img_src,
|
|
|
|
url: result.url,
|
|
|
|
title: result.title,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return images.slice(0, 10);
|
|
|
|
}),
|
|
|
|
]);
|
|
|
|
|
|
|
|
export default imageSearchChain;
|