Merge branch 'main' into feature/output-parsers

# Conflicts:
#	packages/ui/src/views/chatmessage/ChatMessage.js
This commit is contained in:
Henry
2023-11-03 13:10:06 +00:00
82 changed files with 3193 additions and 444 deletions
@@ -45,7 +45,7 @@
"id": "fewShotPromptTemplate_1-input-suffix-string"
},
{
"label": "Example Seperator",
"label": "Example Separator",
"name": "exampleSeparator",
"type": "string",
"placeholder": "\n\n",
@@ -0,0 +1,669 @@
{
"description": "Engage with data sources such as YouTube Transcripts, Google, and more through intelligent Q&A interactions",
"nodes": [
{
"width": 300,
"height": 483,
"id": "conversationalRetrievalQAChain_0",
"position": {
"x": 1499.2693059023254,
"y": 430.03911199833317
},
"type": "customNode",
"data": {
"id": "conversationalRetrievalQAChain_0",
"label": "Conversational Retrieval QA Chain",
"version": 1,
"name": "conversationalRetrievalQAChain",
"type": "ConversationalRetrievalQAChain",
"baseClasses": ["ConversationalRetrievalQAChain", "BaseChain", "Runnable"],
"category": "Chains",
"description": "Document QA - built on RetrievalQAChain to provide a chat history component",
"inputParams": [
{
"label": "Return Source Documents",
"name": "returnSourceDocuments",
"type": "boolean",
"optional": true,
"id": "conversationalRetrievalQAChain_0-input-returnSourceDocuments-boolean"
},
{
"label": "System Message",
"name": "systemMessagePrompt",
"type": "string",
"rows": 4,
"additionalParams": true,
"optional": true,
"placeholder": "I want you to act as a document that I am having a conversation with. Your name is \"AI Assistant\". You will provide me with answers from the given info. If the answer is not included, say exactly \"Hmm, I am not sure.\" and stop after that. Refuse to answer any question not about the info. Never break character.",
"id": "conversationalRetrievalQAChain_0-input-systemMessagePrompt-string"
},
{
"label": "Chain Option",
"name": "chainOption",
"type": "options",
"options": [
{
"label": "MapReduceDocumentsChain",
"name": "map_reduce",
"description": "Suitable for QA tasks over larger documents and can run the preprocessing step in parallel, reducing the running time"
},
{
"label": "RefineDocumentsChain",
"name": "refine",
"description": "Suitable for QA tasks over a large number of documents."
},
{
"label": "StuffDocumentsChain",
"name": "stuff",
"description": "Suitable for QA tasks over a small number of documents."
}
],
"additionalParams": true,
"optional": true,
"id": "conversationalRetrievalQAChain_0-input-chainOption-options"
}
],
"inputAnchors": [
{
"label": "Language Model",
"name": "model",
"type": "BaseLanguageModel",
"id": "conversationalRetrievalQAChain_0-input-model-BaseLanguageModel"
},
{
"label": "Vector Store Retriever",
"name": "vectorStoreRetriever",
"type": "BaseRetriever",
"id": "conversationalRetrievalQAChain_0-input-vectorStoreRetriever-BaseRetriever"
},
{
"label": "Memory",
"name": "memory",
"type": "BaseMemory",
"optional": true,
"description": "If left empty, a default BufferMemory will be used",
"id": "conversationalRetrievalQAChain_0-input-memory-BaseMemory"
}
],
"inputs": {
"model": "{{chatOpenAI_0.data.instance}}",
"vectorStoreRetriever": "{{memoryVectorStore_0.data.instance}}",
"memory": "",
"returnSourceDocuments": "",
"systemMessagePrompt": "",
"chainOption": ""
},
"outputAnchors": [
{
"id": "conversationalRetrievalQAChain_0-output-conversationalRetrievalQAChain-ConversationalRetrievalQAChain|BaseChain|Runnable",
"name": "conversationalRetrievalQAChain",
"label": "ConversationalRetrievalQAChain",
"type": "ConversationalRetrievalQAChain | BaseChain | Runnable"
}
],
"outputs": {},
"selected": false
},
"selected": false,
"positionAbsolute": {
"x": 1499.2693059023254,
"y": 430.03911199833317
},
"dragging": false
},
{
"width": 300,
"height": 408,
"id": "memoryVectorStore_0",
"position": {
"x": 1082.0280622332507,
"y": 589.9990964387842
},
"type": "customNode",
"data": {
"id": "memoryVectorStore_0",
"label": "In-Memory Vector Store",
"version": 1,
"name": "memoryVectorStore",
"type": "Memory",
"baseClasses": ["Memory", "VectorStoreRetriever", "BaseRetriever"],
"category": "Vector Stores",
"description": "In-memory vectorstore that stores embeddings and does an exact, linear search for the most similar embeddings.",
"inputParams": [
{
"label": "Top K",
"name": "topK",
"description": "Number of top results to fetch. Default to 4",
"placeholder": "4",
"type": "number",
"optional": true,
"id": "memoryVectorStore_0-input-topK-number"
}
],
"inputAnchors": [
{
"label": "Document",
"name": "document",
"type": "Document",
"list": true,
"id": "memoryVectorStore_0-input-document-Document"
},
{
"label": "Embeddings",
"name": "embeddings",
"type": "Embeddings",
"id": "memoryVectorStore_0-input-embeddings-Embeddings"
}
],
"inputs": {
"document": ["{{searchApi_0.data.instance}}", "{{searchApi_0.data.instance}}", "{{searchApi_0.data.instance}}"],
"embeddings": "{{openAIEmbeddings_0.data.instance}}",
"topK": ""
},
"outputAnchors": [
{
"name": "output",
"label": "Output",
"type": "options",
"options": [
{
"id": "memoryVectorStore_0-output-retriever-Memory|VectorStoreRetriever|BaseRetriever",
"name": "retriever",
"label": "Memory Retriever",
"type": "Memory | VectorStoreRetriever | BaseRetriever"
},
{
"id": "memoryVectorStore_0-output-vectorStore-Memory|VectorStore",
"name": "vectorStore",
"label": "Memory Vector Store",
"type": "Memory | VectorStore"
}
],
"default": "retriever"
}
],
"outputs": {
"output": "retriever"
},
"selected": false
},
"positionAbsolute": {
"x": 1082.0280622332507,
"y": 589.9990964387842
},
"selected": false,
"dragging": false
},
{
"width": 300,
"height": 577,
"id": "chatOpenAI_0",
"position": {
"x": 1056.2788608917747,
"y": -60.59149112477064
},
"type": "customNode",
"data": {
"id": "chatOpenAI_0",
"label": "ChatOpenAI",
"version": 2,
"name": "chatOpenAI",
"type": "ChatOpenAI",
"baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"],
"category": "Chat Models",
"description": "Wrapper around OpenAI large language models that use the Chat endpoint",
"inputParams": [
{
"label": "Connect Credential",
"name": "credential",
"type": "credential",
"credentialNames": ["openAIApi"],
"id": "chatOpenAI_0-input-credential-credential"
},
{
"label": "Model Name",
"name": "modelName",
"type": "options",
"options": [
{
"label": "gpt-4",
"name": "gpt-4"
},
{
"label": "gpt-4-0613",
"name": "gpt-4-0613"
},
{
"label": "gpt-4-32k",
"name": "gpt-4-32k"
},
{
"label": "gpt-4-32k-0613",
"name": "gpt-4-32k-0613"
},
{
"label": "gpt-3.5-turbo",
"name": "gpt-3.5-turbo"
},
{
"label": "gpt-3.5-turbo-0613",
"name": "gpt-3.5-turbo-0613"
},
{
"label": "gpt-3.5-turbo-16k",
"name": "gpt-3.5-turbo-16k"
},
{
"label": "gpt-3.5-turbo-16k-0613",
"name": "gpt-3.5-turbo-16k-0613"
}
],
"default": "gpt-3.5-turbo",
"optional": true,
"id": "chatOpenAI_0-input-modelName-options"
},
{
"label": "Temperature",
"name": "temperature",
"type": "number",
"step": 0.1,
"default": 0.9,
"optional": true,
"id": "chatOpenAI_0-input-temperature-number"
},
{
"label": "Max Tokens",
"name": "maxTokens",
"type": "number",
"step": 1,
"optional": true,
"additionalParams": true,
"id": "chatOpenAI_0-input-maxTokens-number"
},
{
"label": "Top Probability",
"name": "topP",
"type": "number",
"step": 0.1,
"optional": true,
"additionalParams": true,
"id": "chatOpenAI_0-input-topP-number"
},
{
"label": "Frequency Penalty",
"name": "frequencyPenalty",
"type": "number",
"step": 0.1,
"optional": true,
"additionalParams": true,
"id": "chatOpenAI_0-input-frequencyPenalty-number"
},
{
"label": "Presence Penalty",
"name": "presencePenalty",
"type": "number",
"step": 0.1,
"optional": true,
"additionalParams": true,
"id": "chatOpenAI_0-input-presencePenalty-number"
},
{
"label": "Timeout",
"name": "timeout",
"type": "number",
"step": 1,
"optional": true,
"additionalParams": true,
"id": "chatOpenAI_0-input-timeout-number"
},
{
"label": "BasePath",
"name": "basepath",
"type": "string",
"optional": true,
"additionalParams": true,
"id": "chatOpenAI_0-input-basepath-string"
},
{
"label": "BaseOptions",
"name": "baseOptions",
"type": "json",
"optional": true,
"additionalParams": true,
"id": "chatOpenAI_0-input-baseOptions-json"
}
],
"inputAnchors": [
{
"label": "Cache",
"name": "cache",
"type": "BaseCache",
"optional": true,
"id": "chatOpenAI_0-input-cache-BaseCache"
}
],
"inputs": {
"cache": "",
"modelName": "gpt-3.5-turbo",
"temperature": "0.5",
"maxTokens": "",
"topP": "",
"frequencyPenalty": "",
"presencePenalty": "",
"timeout": "",
"basepath": "",
"baseOptions": ""
},
"outputAnchors": [
{
"id": "chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable",
"name": "chatOpenAI",
"label": "ChatOpenAI",
"type": "ChatOpenAI | BaseChatModel | BaseLanguageModel | Runnable"
}
],
"outputs": {},
"selected": false
},
"selected": false,
"positionAbsolute": {
"x": 1056.2788608917747,
"y": -60.59149112477064
},
"dragging": false
},
{
"width": 300,
"height": 478,
"id": "characterTextSplitter_0",
"position": {
"x": 260.5475803279806,
"y": -65.1647664861618
},
"type": "customNode",
"data": {
"id": "characterTextSplitter_0",
"label": "Character Text Splitter",
"version": 1,
"name": "characterTextSplitter",
"type": "CharacterTextSplitter",
"baseClasses": ["CharacterTextSplitter", "TextSplitter", "BaseDocumentTransformer", "Runnable"],
"category": "Text Splitters",
"description": "splits only on one type of character (defaults to \"\\n\\n\").",
"inputParams": [
{
"label": "Chunk Size",
"name": "chunkSize",
"type": "number",
"default": 1000,
"optional": true,
"id": "characterTextSplitter_0-input-chunkSize-number"
},
{
"label": "Chunk Overlap",
"name": "chunkOverlap",
"type": "number",
"optional": true,
"id": "characterTextSplitter_0-input-chunkOverlap-number"
},
{
"label": "Custom Separator",
"name": "separator",
"type": "string",
"placeholder": "\" \"",
"description": "Seperator to determine when to split the text, will override the default separator",
"optional": true,
"id": "characterTextSplitter_0-input-separator-string"
}
],
"inputAnchors": [],
"inputs": {
"chunkSize": "2000",
"chunkOverlap": "200",
"separator": ""
},
"outputAnchors": [
{
"id": "characterTextSplitter_0-output-characterTextSplitter-CharacterTextSplitter|TextSplitter|BaseDocumentTransformer|Runnable",
"name": "characterTextSplitter",
"label": "CharacterTextSplitter",
"type": "CharacterTextSplitter | TextSplitter | BaseDocumentTransformer | Runnable"
}
],
"outputs": {},
"selected": false
},
"selected": false,
"positionAbsolute": {
"x": 260.5475803279806,
"y": -65.1647664861618
},
"dragging": false
},
{
"width": 300,
"height": 332,
"id": "openAIEmbeddings_0",
"position": {
"x": 666.3950526535211,
"y": 777.4191705193945
},
"type": "customNode",
"data": {
"id": "openAIEmbeddings_0",
"label": "OpenAI Embeddings",
"version": 1,
"name": "openAIEmbeddings",
"type": "OpenAIEmbeddings",
"baseClasses": ["OpenAIEmbeddings", "Embeddings"],
"category": "Embeddings",
"description": "OpenAI API to generate embeddings for a given text",
"inputParams": [
{
"label": "Connect Credential",
"name": "credential",
"type": "credential",
"credentialNames": ["openAIApi"],
"id": "openAIEmbeddings_0-input-credential-credential"
},
{
"label": "Strip New Lines",
"name": "stripNewLines",
"type": "boolean",
"optional": true,
"additionalParams": true,
"id": "openAIEmbeddings_0-input-stripNewLines-boolean"
},
{
"label": "Batch Size",
"name": "batchSize",
"type": "number",
"optional": true,
"additionalParams": true,
"id": "openAIEmbeddings_0-input-batchSize-number"
},
{
"label": "Timeout",
"name": "timeout",
"type": "number",
"optional": true,
"additionalParams": true,
"id": "openAIEmbeddings_0-input-timeout-number"
},
{
"label": "BasePath",
"name": "basepath",
"type": "string",
"optional": true,
"additionalParams": true,
"id": "openAIEmbeddings_0-input-basepath-string"
}
],
"inputAnchors": [],
"inputs": {
"stripNewLines": "",
"batchSize": "",
"timeout": "",
"basepath": ""
},
"outputAnchors": [
{
"id": "openAIEmbeddings_0-output-openAIEmbeddings-OpenAIEmbeddings|Embeddings",
"name": "openAIEmbeddings",
"label": "OpenAIEmbeddings",
"type": "OpenAIEmbeddings | Embeddings"
}
],
"outputs": {},
"selected": false
},
"selected": false,
"dragging": false,
"positionAbsolute": {
"x": 666.3950526535211,
"y": 777.4191705193945
}
},
{
"width": 300,
"height": 482,
"id": "searchApi_0",
"position": {
"x": 680.1258121447145,
"y": 144.9905217023999
},
"type": "customNode",
"data": {
"id": "searchApi_0",
"label": "SearchApi",
"version": 1,
"name": "searchApi",
"type": "Document",
"baseClasses": ["Document"],
"category": "Document Loaders",
"description": "Load data from real-time search results",
"inputParams": [
{
"label": "Connect Credential",
"name": "credential",
"type": "credential",
"optional": false,
"credentialNames": ["searchApi"],
"id": "searchApi_0-input-credential-credential"
},
{
"label": "Query",
"name": "query",
"type": "string",
"optional": true,
"id": "searchApi_0-input-query-string"
},
{
"label": "Custom Parameters",
"name": "customParameters",
"type": "json",
"optional": true,
"additionalParams": true,
"id": "searchApi_0-input-customParameters-json"
},
{
"label": "Metadata",
"name": "metadata",
"type": "json",
"optional": true,
"additionalParams": true,
"id": "searchApi_0-input-metadata-json"
}
],
"inputAnchors": [
{
"label": "Text Splitter",
"name": "textSplitter",
"type": "TextSplitter",
"optional": true,
"id": "searchApi_0-input-textSplitter-TextSplitter"
}
],
"inputs": {
"query": "",
"customParameters": "{\"engine\":\"youtube_transcripts\",\"video_id\":\"0e3GPea1Tyg\"}",
"textSplitter": "{{characterTextSplitter_0.data.instance}}",
"metadata": ""
},
"outputAnchors": [
{
"id": "searchApi_0-output-searchApi-Document",
"name": "searchApi",
"label": "Document",
"type": "Document"
}
],
"outputs": {},
"selected": false
},
"selected": false,
"positionAbsolute": {
"x": 680.1258121447145,
"y": 144.9905217023999
},
"dragging": false
}
],
"edges": [
{
"source": "memoryVectorStore_0",
"sourceHandle": "memoryVectorStore_0-output-retriever-Memory|VectorStoreRetriever|BaseRetriever",
"target": "conversationalRetrievalQAChain_0",
"targetHandle": "conversationalRetrievalQAChain_0-input-vectorStoreRetriever-BaseRetriever",
"type": "buttonedge",
"id": "memoryVectorStore_0-memoryVectorStore_0-output-retriever-Memory|VectorStoreRetriever|BaseRetriever-conversationalRetrievalQAChain_0-conversationalRetrievalQAChain_0-input-vectorStoreRetriever-BaseRetriever",
"data": {
"label": ""
}
},
{
"source": "chatOpenAI_0",
"sourceHandle": "chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable",
"target": "conversationalRetrievalQAChain_0",
"targetHandle": "conversationalRetrievalQAChain_0-input-model-BaseLanguageModel",
"type": "buttonedge",
"id": "chatOpenAI_0-chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable-conversationalRetrievalQAChain_0-conversationalRetrievalQAChain_0-input-model-BaseLanguageModel",
"data": {
"label": ""
}
},
{
"source": "openAIEmbeddings_0",
"sourceHandle": "openAIEmbeddings_0-output-openAIEmbeddings-OpenAIEmbeddings|Embeddings",
"target": "memoryVectorStore_0",
"targetHandle": "memoryVectorStore_0-input-embeddings-Embeddings",
"type": "buttonedge",
"id": "openAIEmbeddings_0-openAIEmbeddings_0-output-openAIEmbeddings-OpenAIEmbeddings|Embeddings-memoryVectorStore_0-memoryVectorStore_0-input-embeddings-Embeddings",
"data": {
"label": ""
}
},
{
"source": "characterTextSplitter_0",
"sourceHandle": "characterTextSplitter_0-output-characterTextSplitter-CharacterTextSplitter|TextSplitter|BaseDocumentTransformer|Runnable",
"target": "searchApi_0",
"targetHandle": "searchApi_0-input-textSplitter-TextSplitter",
"type": "buttonedge",
"id": "characterTextSplitter_0-characterTextSplitter_0-output-characterTextSplitter-CharacterTextSplitter|TextSplitter|BaseDocumentTransformer|Runnable-searchApi_0-searchApi_0-input-textSplitter-TextSplitter",
"data": {
"label": ""
}
},
{
"source": "searchApi_0",
"sourceHandle": "searchApi_0-output-searchApi-Document",
"target": "memoryVectorStore_0",
"targetHandle": "memoryVectorStore_0-input-document-Document",
"type": "buttonedge",
"id": "searchApi_0-searchApi_0-output-searchApi-Document-memoryVectorStore_0-memoryVectorStore_0-input-document-Document",
"data": {
"label": ""
}
}
]
}
@@ -368,7 +368,7 @@
"id": "recursiveCharacterTextSplitter_0",
"label": "Recursive Character Text Splitter",
"name": "recursiveCharacterTextSplitter",
"version": 1,
"version": 2,
"type": "RecursiveCharacterTextSplitter",
"baseClasses": ["RecursiveCharacterTextSplitter", "TextSplitter"],
"category": "Text Splitters",
@@ -388,6 +388,17 @@
"type": "number",
"optional": true,
"id": "recursiveCharacterTextSplitter_0-input-chunkOverlap-number"
},
{
"label": "Custom Separators",
"name": "separators",
"type": "string",
"rows": 4,
"description": "Array of custom separators to determine when to split the text, will override the default separators",
"placeholder": "[\"|\", \"##\", \">\", \"-\"]",
"additionalParams": true,
"optional": true,
"id": "recursiveCharacterTextSplitter_0-input-separators-string"
}
],
"inputAnchors": [],
@@ -426,7 +437,7 @@
"id": "textFile_0",
"label": "Text File",
"name": "textFile",
"version": 2,
"version": 3,
"type": "Document",
"baseClasses": ["Document"],
"category": "Document Loaders",
@@ -436,7 +447,7 @@
"label": "Txt File",
"name": "txtFile",
"type": "file",
"fileType": ".txt",
"fileType": ".txt, .html, .aspx, .asp, .cpp, .c, .cs, .css, .go, .h, .java, .js, .less, .ts, .php, .proto, .python, .py, .rst, .ruby, .rb, .rs, .scala, .sc, .scss, .sol, .sql, .swift, .markdown, .md, .tex, .ltx, .vb, .xml",
"id": "textFile_0-input-txtFile-file"
},
{
@@ -14,7 +14,7 @@
"id": "recursiveCharacterTextSplitter_1",
"label": "Recursive Character Text Splitter",
"name": "recursiveCharacterTextSplitter",
"version": 1,
"version": 2,
"type": "RecursiveCharacterTextSplitter",
"baseClasses": ["RecursiveCharacterTextSplitter", "TextSplitter"],
"category": "Text Splitters",
@@ -34,6 +34,17 @@
"type": "number",
"optional": true,
"id": "recursiveCharacterTextSplitter_1-input-chunkOverlap-number"
},
{
"label": "Custom Separators",
"name": "separators",
"type": "string",
"rows": 4,
"description": "Array of custom separators to determine when to split the text, will override the default separators",
"placeholder": "[\"|\", \"##\", \">\", \"-\"]",
"additionalParams": true,
"optional": true,
"id": "recursiveCharacterTextSplitter_1-input-separators-string"
}
],
"inputAnchors": [],
@@ -373,7 +384,7 @@
"id": "textFile_0",
"label": "Text File",
"name": "textFile",
"version": 1,
"version": 3,
"type": "Document",
"baseClasses": ["Document"],
"category": "Document Loaders",
@@ -383,7 +394,7 @@
"label": "Txt File",
"name": "txtFile",
"type": "file",
"fileType": ".txt",
"fileType": ".txt, .html, .aspx, .asp, .cpp, .c, .cs, .css, .go, .h, .java, .js, .less, .ts, .php, .proto, .python, .py, .rst, .ruby, .rb, .rs, .scala, .sc, .scss, .sol, .sql, .swift, .markdown, .md, .tex, .ltx, .vb, .xml",
"id": "textFile_0-input-txtFile-file"
},
{
@@ -14,7 +14,7 @@
"id": "recursiveCharacterTextSplitter_1",
"label": "Recursive Character Text Splitter",
"name": "recursiveCharacterTextSplitter",
"version": 1,
"version": 2,
"type": "RecursiveCharacterTextSplitter",
"baseClasses": ["RecursiveCharacterTextSplitter", "TextSplitter"],
"category": "Text Splitters",
@@ -34,6 +34,17 @@
"type": "number",
"optional": true,
"id": "recursiveCharacterTextSplitter_1-input-chunkOverlap-number"
},
{
"label": "Custom Separators",
"name": "separators",
"type": "string",
"rows": 4,
"description": "Array of custom separators to determine when to split the text, will override the default separators",
"placeholder": "[\"|\", \"##\", \">\", \"-\"]",
"additionalParams": true,
"optional": true,
"id": "recursiveCharacterTextSplitter_1-input-separators-string"
}
],
"inputAnchors": [],
@@ -72,7 +83,7 @@
"id": "textFile_0",
"label": "Text File",
"name": "textFile",
"version": 1,
"version": 3,
"type": "Document",
"baseClasses": ["Document"],
"category": "Document Loaders",
@@ -82,7 +93,7 @@
"label": "Txt File",
"name": "txtFile",
"type": "file",
"fileType": ".txt",
"fileType": ".txt, .html, .aspx, .asp, .cpp, .c, .cs, .css, .go, .h, .java, .js, .less, .ts, .php, .proto, .python, .py, .rst, .ruby, .rb, .rs, .scala, .sc, .scss, .sol, .sql, .swift, .markdown, .md, .tex, .ltx, .vb, .xml",
"id": "textFile_0-input-txtFile-file"
},
{
@@ -3,120 +3,11 @@
"nodes": [
{
"width": 300,
"height": 503,
"id": "pineconeExistingIndex_0",
"position": {
"x": 1062.7418678410986,
"y": -109.27680365777141
},
"type": "customNode",
"data": {
"id": "pineconeExistingIndex_0",
"label": "Pinecone Load Existing Index",
"version": 1,
"name": "pineconeExistingIndex",
"type": "Pinecone",
"baseClasses": ["Pinecone", "VectorStoreRetriever", "BaseRetriever"],
"category": "Vector Stores",
"description": "Load existing index from Pinecone (i.e: Document has been upserted)",
"inputParams": [
{
"label": "Connect Credential",
"name": "credential",
"type": "credential",
"credentialNames": ["pineconeApi"],
"id": "pineconeExistingIndex_0-input-credential-credential"
},
{
"label": "Pinecone Index",
"name": "pineconeIndex",
"type": "string",
"id": "pineconeExistingIndex_0-input-pineconeIndex-string"
},
{
"label": "Pinecone Namespace",
"name": "pineconeNamespace",
"type": "string",
"placeholder": "my-first-namespace",
"additionalParams": true,
"optional": true,
"id": "pineconeExistingIndex_0-input-pineconeNamespace-string"
},
{
"label": "Pinecone Metadata Filter",
"name": "pineconeMetadataFilter",
"type": "json",
"optional": true,
"additionalParams": true,
"id": "pineconeExistingIndex_0-input-pineconeMetadataFilter-json"
},
{
"label": "Top K",
"name": "topK",
"description": "Number of top results to fetch. Default to 4",
"placeholder": "4",
"type": "number",
"additionalParams": true,
"optional": true,
"id": "pineconeExistingIndex_0-input-topK-number"
}
],
"inputAnchors": [
{
"label": "Embeddings",
"name": "embeddings",
"type": "Embeddings",
"id": "pineconeExistingIndex_0-input-embeddings-Embeddings"
}
],
"inputs": {
"embeddings": "{{openAIEmbeddings_0.data.instance}}",
"pineconeIndex": "newindex",
"pineconeNamespace": "",
"pineconeMetadataFilter": "{}",
"topK": ""
},
"outputAnchors": [
{
"name": "output",
"label": "Output",
"type": "options",
"options": [
{
"id": "pineconeExistingIndex_0-output-retriever-Pinecone|VectorStoreRetriever|BaseRetriever",
"name": "retriever",
"label": "Pinecone Retriever",
"type": "Pinecone | VectorStoreRetriever | BaseRetriever"
},
{
"id": "pineconeExistingIndex_0-output-vectorStore-Pinecone|VectorStore",
"name": "vectorStore",
"label": "Pinecone Vector Store",
"type": "Pinecone | VectorStore"
}
],
"default": "retriever"
}
],
"outputs": {
"output": "vectorStore"
},
"selected": false
},
"selected": false,
"positionAbsolute": {
"x": 1062.7418678410986,
"y": -109.27680365777141
},
"dragging": false
},
{
"width": 300,
"height": 327,
"height": 329,
"id": "openAIEmbeddings_0",
"position": {
"x": 711.3971966563331,
"y": 7.7184225021727
"x": 1198.6643452533754,
"y": -584.4233173804803
},
"type": "customNode",
"data": {
@@ -189,18 +80,18 @@
},
"selected": false,
"positionAbsolute": {
"x": 711.3971966563331,
"y": 7.7184225021727
"x": 1198.6643452533754,
"y": -584.4233173804803
},
"dragging": false
},
{
"width": 300,
"height": 473,
"height": 475,
"id": "promptTemplate_0",
"position": {
"x": 348.2881107399286,
"y": -97.74510214137423
"x": 354.2706973608643,
"y": -122.34815000085804
},
"type": "customNode",
"data": {
@@ -249,18 +140,18 @@
},
"selected": false,
"positionAbsolute": {
"x": 348.2881107399286,
"y": -97.74510214137423
"x": 354.2706973608643,
"y": -122.34815000085804
},
"dragging": false
},
{
"width": 300,
"height": 522,
"height": 574,
"id": "chatOpenAI_0",
"position": {
"x": 335.7621848973805,
"y": -721.7411273245009
"x": 353.5672832154869,
"y": -730.6436764835541
},
"type": "customNode",
"data": {
@@ -396,7 +287,7 @@
],
"inputs": {
"modelName": "gpt-3.5-turbo-16k",
"temperature": 0.9,
"temperature": "0",
"maxTokens": "",
"topP": "",
"frequencyPenalty": "",
@@ -418,17 +309,17 @@
"selected": false,
"dragging": false,
"positionAbsolute": {
"x": 335.7621848973805,
"y": -721.7411273245009
"x": 353.5672832154869,
"y": -730.6436764835541
}
},
{
"width": 300,
"height": 522,
"height": 574,
"id": "chatOpenAI_1",
"position": {
"x": 1765.2801848172305,
"y": -737.9261054149061
"x": 2281.9246645710673,
"y": -778.8379360672121
},
"type": "customNode",
"data": {
@@ -564,7 +455,7 @@
],
"inputs": {
"modelName": "gpt-3.5-turbo-16k",
"temperature": 0.9,
"temperature": "0",
"maxTokens": "",
"topP": "",
"frequencyPenalty": "",
@@ -586,36 +477,153 @@
"selected": false,
"dragging": false,
"positionAbsolute": {
"x": 1765.2801848172305,
"y": -737.9261054149061
"x": 2281.9246645710673,
"y": -778.8379360672121
}
},
{
"width": 300,
"height": 473,
"id": "promptTemplate_1",
"height": 505,
"id": "pineconeExistingIndex_0",
"position": {
"x": 1773.720934090435,
"y": -116.71323227575395
"x": 1544.4998097474581,
"y": -628.8477510577202
},
"type": "customNode",
"data": {
"id": "promptTemplate_1",
"label": "Prompt Template",
"id": "pineconeExistingIndex_0",
"label": "Pinecone Load Existing Index",
"version": 1,
"name": "promptTemplate",
"type": "PromptTemplate",
"baseClasses": ["PromptTemplate", "BaseStringPromptTemplate", "BasePromptTemplate", "Runnable"],
"category": "Prompts",
"description": "Schema to represent a basic prompt for an LLM",
"name": "pineconeExistingIndex",
"type": "Pinecone",
"baseClasses": ["Pinecone", "VectorStoreRetriever", "BaseRetriever"],
"category": "Vector Stores",
"description": "Load existing index from Pinecone (i.e: Document has been upserted)",
"inputParams": [
{
"label": "Template",
"name": "template",
"label": "Connect Credential",
"name": "credential",
"type": "credential",
"credentialNames": ["pineconeApi"],
"id": "pineconeExistingIndex_0-input-credential-credential"
},
{
"label": "Pinecone Index",
"name": "pineconeIndex",
"type": "string",
"id": "pineconeExistingIndex_0-input-pineconeIndex-string"
},
{
"label": "Pinecone Namespace",
"name": "pineconeNamespace",
"type": "string",
"placeholder": "my-first-namespace",
"additionalParams": true,
"optional": true,
"id": "pineconeExistingIndex_0-input-pineconeNamespace-string"
},
{
"label": "Pinecone Metadata Filter",
"name": "pineconeMetadataFilter",
"type": "json",
"optional": true,
"additionalParams": true,
"id": "pineconeExistingIndex_0-input-pineconeMetadataFilter-json"
},
{
"label": "Top K",
"name": "topK",
"description": "Number of top results to fetch. Default to 4",
"placeholder": "4",
"type": "number",
"additionalParams": true,
"optional": true,
"id": "pineconeExistingIndex_0-input-topK-number"
}
],
"inputAnchors": [
{
"label": "Embeddings",
"name": "embeddings",
"type": "Embeddings",
"id": "pineconeExistingIndex_0-input-embeddings-Embeddings"
}
],
"inputs": {
"embeddings": "{{openAIEmbeddings_0.data.instance}}",
"pineconeIndex": "",
"pineconeNamespace": "",
"pineconeMetadataFilter": "",
"topK": ""
},
"outputAnchors": [
{
"name": "output",
"label": "Output",
"type": "options",
"options": [
{
"id": "pineconeExistingIndex_0-output-retriever-Pinecone|VectorStoreRetriever|BaseRetriever",
"name": "retriever",
"label": "Pinecone Retriever",
"type": "Pinecone | VectorStoreRetriever | BaseRetriever"
},
{
"id": "pineconeExistingIndex_0-output-vectorStore-Pinecone|VectorStore",
"name": "vectorStore",
"label": "Pinecone Vector Store",
"type": "Pinecone | VectorStore"
}
],
"default": "retriever"
}
],
"outputs": {
"output": "vectorStore"
},
"selected": false
},
"selected": false,
"positionAbsolute": {
"x": 1544.4998097474581,
"y": -628.8477510577202
},
"dragging": false
},
{
"width": 300,
"height": 652,
"id": "chatPromptTemplate_0",
"position": {
"x": 2290.8365353040026,
"y": -168.49082887954518
},
"type": "customNode",
"data": {
"id": "chatPromptTemplate_0",
"label": "Chat Prompt Template",
"version": 1,
"name": "chatPromptTemplate",
"type": "ChatPromptTemplate",
"baseClasses": ["ChatPromptTemplate", "BaseChatPromptTemplate", "BasePromptTemplate", "Runnable"],
"category": "Prompts",
"description": "Schema to represent a chat prompt",
"inputParams": [
{
"label": "System Message",
"name": "systemMessagePrompt",
"type": "string",
"rows": 4,
"placeholder": "What is a good name for a company that makes {product}?",
"id": "promptTemplate_1-input-template-string"
"placeholder": "You are a helpful assistant that translates {input_language} to {output_language}.",
"id": "chatPromptTemplate_0-input-systemMessagePrompt-string"
},
{
"label": "Human Message",
"name": "humanMessagePrompt",
"type": "string",
"rows": 4,
"placeholder": "{text}",
"id": "chatPromptTemplate_0-input-humanMessagePrompt-string"
},
{
"label": "Format Prompt Values",
@@ -624,20 +632,21 @@
"optional": true,
"acceptVariable": true,
"list": true,
"id": "promptTemplate_1-input-promptValues-json"
"id": "chatPromptTemplate_0-input-promptValues-json"
}
],
"inputAnchors": [],
"inputs": {
"template": "Use the following pieces of context to answer the question at the end.\n\n{context}\n\nQuestion: {question}\nHelpful Answer:",
"promptValues": "{\"context\":\"{{vectorStoreToDocument_0.data.instance}}\",\"question\":\"{{llmChain_0.data.instance}}\"}"
"systemMessagePrompt": "Using the provided context, answer the user's question to the best of your ability using the resources provided. If there is nothing in the context relevant to the question at hand, just say \"Hmm, I'm not sure.\" Don't try to make up an answer.\n\nAnything between the following \\`context\\` html blocks is retrieved from a knowledge bank, not part of the conversation with the user.\n\n<context>\n {context}\n<context/>\n\nREMEMBER: If there is no relevant information within the context, just say \"Hmm, I'm not sure.\" Don't try to make up an answer. Anything between the preceding 'context' html blocks is retrieved from a knowledge bank, not part of the conversation with the user.",
"humanMessagePrompt": "{text}",
"promptValues": "{\"context\":\"{{vectorStoreToDocument_0.data.instance}}\",\"text\":\"{{question}}\"}"
},
"outputAnchors": [
{
"id": "promptTemplate_1-output-promptTemplate-PromptTemplate|BaseStringPromptTemplate|BasePromptTemplate|Runnable",
"name": "promptTemplate",
"label": "PromptTemplate",
"type": "PromptTemplate | BaseStringPromptTemplate | BasePromptTemplate | Runnable"
"id": "chatPromptTemplate_0-output-chatPromptTemplate-ChatPromptTemplate|BaseChatPromptTemplate|BasePromptTemplate|Runnable",
"name": "chatPromptTemplate",
"label": "ChatPromptTemplate",
"type": "ChatPromptTemplate | BaseChatPromptTemplate | BasePromptTemplate | Runnable"
}
],
"outputs": {},
@@ -645,18 +654,18 @@
},
"selected": false,
"positionAbsolute": {
"x": 1773.720934090435,
"y": -116.71323227575395
"x": 2290.8365353040026,
"y": -168.49082887954518
},
"dragging": false
},
{
"width": 300,
"height": 404,
"height": 405,
"id": "llmChain_0",
"position": {
"x": 756.1670091985342,
"y": -592.5151355056942
"x": 747.1299875516488,
"y": -267.01184813798244
},
"type": "customNode",
"data": {
@@ -695,7 +704,7 @@
"inputs": {
"model": "{{chatOpenAI_0.data.instance}}",
"prompt": "{{promptTemplate_0.data.instance}}",
"chainName": "QuestionChain"
"chainName": "RephraseQuestion"
},
"outputAnchors": [
{
@@ -726,18 +735,18 @@
},
"selected": false,
"positionAbsolute": {
"x": 756.1670091985342,
"y": -592.5151355056942
"x": 747.1299875516488,
"y": -267.01184813798244
},
"dragging": false
},
{
"width": 300,
"height": 404,
"height": 405,
"id": "llmChain_1",
"position": {
"x": 2200.1274896215496,
"y": -144.29167974642334
"x": 2694.8707655351186,
"y": -308.59150355411236
},
"type": "customNode",
"data": {
@@ -775,8 +784,8 @@
],
"inputs": {
"model": "{{chatOpenAI_1.data.instance}}",
"prompt": "{{promptTemplate_1.data.instance}}",
"chainName": ""
"prompt": "{{chatPromptTemplate_0.data.instance}}",
"chainName": "FinalResponse"
},
"outputAnchors": [
{
@@ -807,30 +816,39 @@
},
"selected": false,
"positionAbsolute": {
"x": 2200.1274896215496,
"y": -144.29167974642334
"x": 2694.8707655351186,
"y": -308.59150355411236
},
"dragging": false
},
{
"width": 300,
"height": 353,
"height": 454,
"id": "vectorStoreToDocument_0",
"position": {
"x": 1407.7038120189868,
"y": -26.16468811205081
"x": 1906.6871314089658,
"y": -157.0046189166955
},
"type": "customNode",
"data": {
"id": "vectorStoreToDocument_0",
"label": "VectorStore To Document",
"version": 1,
"version": 2,
"name": "vectorStoreToDocument",
"type": "Document",
"baseClasses": ["Document"],
"category": "Document Loaders",
"description": "Search documents with scores from vector store",
"inputParams": [
{
"label": "Query",
"name": "query",
"type": "string",
"description": "Query to retrieve documents from vector database. If not specified, user question will be used",
"optional": true,
"acceptVariable": true,
"id": "vectorStoreToDocument_0-input-query-string"
},
{
"label": "Minimum Score (%)",
"name": "minScore",
@@ -852,6 +870,7 @@
],
"inputs": {
"vectorStore": "{{pineconeExistingIndex_0.data.instance}}",
"query": "{{llmChain_0.data.instance}}",
"minScore": ""
},
"outputAnchors": [
@@ -883,8 +902,8 @@
},
"selected": false,
"positionAbsolute": {
"x": 1407.7038120189868,
"y": -26.16468811205081
"x": 1906.6871314089658,
"y": -157.0046189166955
},
"dragging": false
}
@@ -901,6 +920,50 @@
"label": ""
}
},
{
"source": "promptTemplate_0",
"sourceHandle": "promptTemplate_0-output-promptTemplate-PromptTemplate|BaseStringPromptTemplate|BasePromptTemplate|Runnable",
"target": "llmChain_0",
"targetHandle": "llmChain_0-input-prompt-BasePromptTemplate",
"type": "buttonedge",
"id": "promptTemplate_0-promptTemplate_0-output-promptTemplate-PromptTemplate|BaseStringPromptTemplate|BasePromptTemplate|Runnable-llmChain_0-llmChain_0-input-prompt-BasePromptTemplate",
"data": {
"label": ""
}
},
{
"source": "chatOpenAI_0",
"sourceHandle": "chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable",
"target": "llmChain_0",
"targetHandle": "llmChain_0-input-model-BaseLanguageModel",
"type": "buttonedge",
"id": "chatOpenAI_0-chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable-llmChain_0-llmChain_0-input-model-BaseLanguageModel",
"data": {
"label": ""
}
},
{
"source": "chatPromptTemplate_0",
"sourceHandle": "chatPromptTemplate_0-output-chatPromptTemplate-ChatPromptTemplate|BaseChatPromptTemplate|BasePromptTemplate|Runnable",
"target": "llmChain_1",
"targetHandle": "llmChain_1-input-prompt-BasePromptTemplate",
"type": "buttonedge",
"id": "chatPromptTemplate_0-chatPromptTemplate_0-output-chatPromptTemplate-ChatPromptTemplate|BaseChatPromptTemplate|BasePromptTemplate|Runnable-llmChain_1-llmChain_1-input-prompt-BasePromptTemplate",
"data": {
"label": ""
}
},
{
"source": "chatOpenAI_1",
"sourceHandle": "chatOpenAI_1-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable",
"target": "llmChain_1",
"targetHandle": "llmChain_1-input-model-BaseLanguageModel",
"type": "buttonedge",
"id": "chatOpenAI_1-chatOpenAI_1-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable-llmChain_1-llmChain_1-input-model-BaseLanguageModel",
"data": {
"label": ""
}
},
{
"source": "pineconeExistingIndex_0",
"sourceHandle": "pineconeExistingIndex_0-output-vectorStore-Pinecone|VectorStore",
@@ -915,32 +978,10 @@
{
"source": "vectorStoreToDocument_0",
"sourceHandle": "vectorStoreToDocument_0-output-text-string|json",
"target": "promptTemplate_1",
"targetHandle": "promptTemplate_1-input-promptValues-json",
"target": "chatPromptTemplate_0",
"targetHandle": "chatPromptTemplate_0-input-promptValues-json",
"type": "buttonedge",
"id": "vectorStoreToDocument_0-vectorStoreToDocument_0-output-text-string|json-promptTemplate_1-promptTemplate_1-input-promptValues-json",
"data": {
"label": ""
}
},
{
"source": "chatOpenAI_0",
"sourceHandle": "chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable",
"target": "llmChain_0",
"targetHandle": "llmChain_0-input-model-BaseLanguageModel",
"type": "buttonedge",
"id": "chatOpenAI_0-chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable-llmChain_0-llmChain_0-input-model-BaseLanguageModel",
"data": {
"label": ""
}
},
{
"source": "promptTemplate_0",
"sourceHandle": "promptTemplate_0-output-promptTemplate-PromptTemplate|BaseStringPromptTemplate|BasePromptTemplate|Runnable",
"target": "llmChain_0",
"targetHandle": "llmChain_0-input-prompt-BasePromptTemplate",
"type": "buttonedge",
"id": "promptTemplate_0-promptTemplate_0-output-promptTemplate-PromptTemplate|BaseStringPromptTemplate|BasePromptTemplate|Runnable-llmChain_0-llmChain_0-input-prompt-BasePromptTemplate",
"id": "vectorStoreToDocument_0-vectorStoreToDocument_0-output-text-string|json-chatPromptTemplate_0-chatPromptTemplate_0-input-promptValues-json",
"data": {
"label": ""
}
@@ -948,32 +989,10 @@
{
"source": "llmChain_0",
"sourceHandle": "llmChain_0-output-outputPrediction-string|json",
"target": "promptTemplate_1",
"targetHandle": "promptTemplate_1-input-promptValues-json",
"target": "vectorStoreToDocument_0",
"targetHandle": "vectorStoreToDocument_0-input-query-string",
"type": "buttonedge",
"id": "llmChain_0-llmChain_0-output-outputPrediction-string|json-promptTemplate_1-promptTemplate_1-input-promptValues-json",
"data": {
"label": ""
}
},
{
"source": "chatOpenAI_1",
"sourceHandle": "chatOpenAI_1-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable",
"target": "llmChain_1",
"targetHandle": "llmChain_1-input-model-BaseLanguageModel",
"type": "buttonedge",
"id": "chatOpenAI_1-chatOpenAI_1-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable-llmChain_1-llmChain_1-input-model-BaseLanguageModel",
"data": {
"label": ""
}
},
{
"source": "promptTemplate_1",
"sourceHandle": "promptTemplate_1-output-promptTemplate-PromptTemplate|BaseStringPromptTemplate|BasePromptTemplate|Runnable",
"target": "llmChain_1",
"targetHandle": "llmChain_1-input-prompt-BasePromptTemplate",
"type": "buttonedge",
"id": "promptTemplate_1-promptTemplate_1-output-promptTemplate-PromptTemplate|BaseStringPromptTemplate|BasePromptTemplate|Runnable-llmChain_1-llmChain_1-input-prompt-BasePromptTemplate",
"id": "llmChain_0-llmChain_0-output-outputPrediction-string|json-vectorStoreToDocument_0-vectorStoreToDocument_0-input-query-string",
"data": {
"label": ""
}
+1
View File
@@ -64,6 +64,7 @@
"socket.io": "^4.6.1",
"sqlite3": "^5.1.6",
"typeorm": "^0.3.6",
"uuid": "^9.0.1",
"winston": "^3.9.0"
},
"devDependencies": {
+10 -1
View File
@@ -2,6 +2,10 @@ import { ICommonObject, INode, INodeData as INodeDataFromComponent, INodeParams
export type MessageType = 'apiMessage' | 'userMessage'
export enum chatType {
INTERNAL = 'INTERNAL',
EXTERNAL = 'EXTERNAL'
}
/**
* Databases
*/
@@ -24,8 +28,12 @@ export interface IChatMessage {
role: MessageType
content: string
chatflowid: string
createdDate: Date
sourceDocuments?: string
chatType: string
chatId: string
memoryType?: string
sessionId?: string
createdDate: Date
}
export interface ITool {
@@ -146,6 +154,7 @@ export interface IncomingInput {
history: IMessage[]
overrideConfig?: ICommonObject
socketIOClientId?: string
chatId?: string
}
export interface IActiveChatflows {
@@ -20,6 +20,18 @@ export class ChatMessage implements IChatMessage {
@Column({ nullable: true, type: 'text' })
sourceDocuments?: string
@Column()
chatType: string
@Column()
chatId: string
@Column({ nullable: true })
memoryType?: string
@Column({ nullable: true })
sessionId?: string
@CreateDateColumn()
createdDate: Date
}
@@ -2,7 +2,8 @@ import { MigrationInterface, QueryRunner } from 'typeorm'
export class AddApiConfig1694099200729 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE \`chat_flow\` ADD COLUMN \`apiConfig\` TEXT;`)
const columnExists = await queryRunner.hasColumn('chat_flow', 'apiConfig')
if (!columnExists) queryRunner.query(`ALTER TABLE \`chat_flow\` ADD COLUMN \`apiConfig\` TEXT;`)
}
public async down(queryRunner: QueryRunner): Promise<void> {
@@ -2,7 +2,8 @@ import { MigrationInterface, QueryRunner } from 'typeorm'
export class AddAnalytic1694432361423 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE \`chat_flow\` ADD COLUMN \`analytic\` TEXT;`)
const columnExists = await queryRunner.hasColumn('chat_flow', 'analytic')
if (!columnExists) queryRunner.query(`ALTER TABLE \`chat_flow\` ADD COLUMN \`analytic\` TEXT;`)
}
public async down(queryRunner: QueryRunner): Promise<void> {
@@ -0,0 +1,41 @@
import { MigrationInterface, QueryRunner } from 'typeorm'
export class AddChatHistory1694658767766 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
const chatTypeColumnExists = await queryRunner.hasColumn('chat_message', 'chatType')
if (!chatTypeColumnExists)
await queryRunner.query(`ALTER TABLE \`chat_message\` ADD COLUMN \`chatType\` VARCHAR(255) NOT NULL DEFAULT 'INTERNAL';`)
const chatIdColumnExists = await queryRunner.hasColumn('chat_message', 'chatId')
if (!chatIdColumnExists) await queryRunner.query(`ALTER TABLE \`chat_message\` ADD COLUMN \`chatId\` VARCHAR(255);`)
const results: { id: string; chatflowid: string }[] = await queryRunner.query(`WITH RankedMessages AS (
SELECT
\`chatflowid\`,
\`id\`,
\`createdDate\`,
ROW_NUMBER() OVER (PARTITION BY \`chatflowid\` ORDER BY \`createdDate\`) AS row_num
FROM \`chat_message\`
)
SELECT \`chatflowid\`, \`id\`
FROM RankedMessages
WHERE row_num = 1;`)
for (const chatMessage of results) {
await queryRunner.query(
`UPDATE \`chat_message\` SET \`chatId\` = '${chatMessage.id}' WHERE \`chatflowid\` = '${chatMessage.chatflowid}'`
)
}
await queryRunner.query(`ALTER TABLE \`chat_message\` MODIFY \`chatId\` VARCHAR(255) NOT NULL;`)
const memoryTypeColumnExists = await queryRunner.hasColumn('chat_message', 'memoryType')
if (!memoryTypeColumnExists) await queryRunner.query(`ALTER TABLE \`chat_message\` ADD COLUMN \`memoryType\` VARCHAR(255);`)
const sessionIdColumnExists = await queryRunner.hasColumn('chat_message', 'sessionId')
if (!sessionIdColumnExists) await queryRunner.query(`ALTER TABLE \`chat_message\` ADD COLUMN \`sessionId\` VARCHAR(255);`)
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE \`chat_message\` DROP COLUMN \`chatType\`, DROP COLUMN \`chatId\`, DROP COLUMN \`memoryType\`, DROP COLUMN \`sessionId\`;`
)
}
}
@@ -5,6 +5,7 @@ import { ModifyCredential1693999261583 } from './1693999261583-ModifyCredential'
import { ModifyTool1694001465232 } from './1694001465232-ModifyTool'
import { AddApiConfig1694099200729 } from './1694099200729-AddApiConfig'
import { AddAnalytic1694432361423 } from './1694432361423-AddAnalytic'
import { AddChatHistory1694658767766 } from './1694658767766-AddChatHistory'
export const mysqlMigrations = [
Init1693840429259,
@@ -13,5 +14,6 @@ export const mysqlMigrations = [
ModifyCredential1693999261583,
ModifyTool1694001465232,
AddApiConfig1694099200729,
AddAnalytic1694432361423
AddAnalytic1694432361423,
AddChatHistory1694658767766
]
@@ -2,7 +2,7 @@ import { MigrationInterface, QueryRunner } from 'typeorm'
export class AddApiConfig1694099183389 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "chat_flow" ADD COLUMN "apiConfig" TEXT;`)
await queryRunner.query(`ALTER TABLE "chat_flow" ADD COLUMN IF NOT EXISTS "apiConfig" TEXT;`)
}
public async down(queryRunner: QueryRunner): Promise<void> {
@@ -2,7 +2,7 @@ import { MigrationInterface, QueryRunner } from 'typeorm'
export class AddAnalytic1694432361423 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "chat_flow" ADD COLUMN "analytic" TEXT;`)
await queryRunner.query(`ALTER TABLE "chat_flow" ADD COLUMN IF NOT EXISTS "analytic" TEXT;`)
}
public async down(queryRunner: QueryRunner): Promise<void> {
@@ -0,0 +1,32 @@
import { MigrationInterface, QueryRunner } from 'typeorm'
export class AddChatHistory1694658756136 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "chat_message" ADD COLUMN IF NOT EXISTS "chatType" VARCHAR NOT NULL DEFAULT 'INTERNAL', ADD COLUMN IF NOT EXISTS "chatId" VARCHAR, ADD COLUMN IF NOT EXISTS "memoryType" VARCHAR, ADD COLUMN IF NOT EXISTS "sessionId" VARCHAR;`
)
const results: { id: string; chatflowid: string }[] = await queryRunner.query(`WITH RankedMessages AS (
SELECT
"chatflowid",
"id",
"createdDate",
ROW_NUMBER() OVER (PARTITION BY "chatflowid" ORDER BY "createdDate") AS row_num
FROM "chat_message"
)
SELECT "chatflowid", "id"
FROM RankedMessages
WHERE row_num = 1;`)
for (const chatMessage of results) {
await queryRunner.query(
`UPDATE "chat_message" SET "chatId" = '${chatMessage.id}' WHERE "chatflowid" = '${chatMessage.chatflowid}'`
)
}
await queryRunner.query(`ALTER TABLE "chat_message" ALTER COLUMN "chatId" SET NOT NULL;`)
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "chat_message" DROP COLUMN "chatType", DROP COLUMN "chatId", DROP COLUMN "memoryType", DROP COLUMN "sessionId";`
)
}
}
@@ -5,6 +5,7 @@ import { ModifyCredential1693997070000 } from './1693997070000-ModifyCredential'
import { ModifyTool1693997339912 } from './1693997339912-ModifyTool'
import { AddApiConfig1694099183389 } from './1694099183389-AddApiConfig'
import { AddAnalytic1694432361423 } from './1694432361423-AddAnalytic'
import { AddChatHistory1694658756136 } from './1694658756136-AddChatHistory'
export const postgresMigrations = [
Init1693891895163,
@@ -13,5 +14,6 @@ export const postgresMigrations = [
ModifyCredential1693997070000,
ModifyTool1693997339912,
AddApiConfig1694099183389,
AddAnalytic1694432361423
AddAnalytic1694432361423,
AddChatHistory1694658756136
]
@@ -0,0 +1,40 @@
import { MigrationInterface, QueryRunner } from 'typeorm'
export class AddChatHistory1694657778173 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "chat_message" ADD COLUMN "chatId" VARCHAR;`)
const results: { id: string; chatflowid: string }[] = await queryRunner.query(`WITH RankedMessages AS (
SELECT
"chatflowid",
"id",
"createdDate",
ROW_NUMBER() OVER (PARTITION BY "chatflowid" ORDER BY "createdDate") AS row_num
FROM "chat_message"
)
SELECT "chatflowid", "id"
FROM RankedMessages
WHERE row_num = 1;`)
for (const chatMessage of results) {
await queryRunner.query(
`UPDATE "chat_message" SET "chatId" = '${chatMessage.id}' WHERE "chatflowid" = '${chatMessage.chatflowid}'`
)
}
await queryRunner.query(
`CREATE TABLE "temp_chat_message" ("id" varchar PRIMARY KEY NOT NULL, "role" varchar NOT NULL, "chatflowid" varchar NOT NULL, "content" text NOT NULL, "sourceDocuments" text, "createdDate" datetime NOT NULL DEFAULT (datetime('now')), "chatType" VARCHAR NOT NULL DEFAULT 'INTERNAL', "chatId" VARCHAR NOT NULL, "memoryType" VARCHAR, "sessionId" VARCHAR);`
)
await queryRunner.query(
`INSERT INTO "temp_chat_message" ("id", "role", "chatflowid", "content", "sourceDocuments", "createdDate", "chatId") SELECT "id", "role", "chatflowid", "content", "sourceDocuments", "createdDate", "chatId" FROM "chat_message";`
)
await queryRunner.query(`DROP TABLE "chat_message";`)
await queryRunner.query(`ALTER TABLE "temp_chat_message" RENAME TO "chat_message";`)
await queryRunner.query(`CREATE INDEX "IDX_e574527322272fd838f4f0f3d3" ON "chat_message" ("chatflowid") ;`)
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP TABLE IF EXISTS "temp_chat_message";`)
await queryRunner.query(`ALTER TABLE "chat_message" DROP COLUMN "chatType";`)
await queryRunner.query(`ALTER TABLE "chat_message" DROP COLUMN "chatId";`)
await queryRunner.query(`ALTER TABLE "chat_message" DROP COLUMN "memoryType";`)
await queryRunner.query(`ALTER TABLE "chat_message" DROP COLUMN "sessionId";`)
}
}
@@ -5,6 +5,7 @@ import { ModifyCredential1693923551694 } from './1693923551694-ModifyCredential'
import { ModifyTool1693924207475 } from './1693924207475-ModifyTool'
import { AddApiConfig1694090982460 } from './1694090982460-AddApiConfig'
import { AddAnalytic1694432361423 } from './1694432361423-AddAnalytic'
import { AddChatHistory1694657778173 } from './1694657778173-AddChatHistory'
export const sqliteMigrations = [
Init1693835579790,
@@ -13,5 +14,6 @@ export const sqliteMigrations = [
ModifyCredential1693923551694,
ModifyTool1693924207475,
AddApiConfig1694090982460,
AddAnalytic1694432361423
AddAnalytic1694432361423,
AddChatHistory1694657778173
]
+204 -36
View File
@@ -8,7 +8,8 @@ import basicAuth from 'express-basic-auth'
import { Server } from 'socket.io'
import logger from './utils/logger'
import { expressRequestLogger } from './utils/logger'
import { v4 as uuidv4 } from 'uuid'
import { Between, IsNull, FindOptionsWhere } from 'typeorm'
import {
IChatFlow,
IncomingInput,
@@ -16,7 +17,10 @@ import {
IReactFlowObject,
INodeData,
IDatabaseExport,
ICredentialReturnResponse
ICredentialReturnResponse,
chatType,
IChatMessage,
IReactFlowEdge
} from './Interface'
import {
getNodeModulesPackagePath,
@@ -40,10 +44,11 @@ import {
getApiKey,
transformToCredentialEntity,
decryptCredentialData,
clearSessionMemory,
clearAllSessionMemory,
replaceInputsWithConfig,
getEncryptionKey,
checkMemorySessionId
checkMemorySessionId,
clearSessionMemoryFromViewMessageDialog
} from './utils'
import { cloneDeep, omit } from 'lodash'
import { getDataSource } from './DataSource'
@@ -395,45 +400,92 @@ export class App {
// Get all chatmessages from chatflowid
this.app.get('/api/v1/chatmessage/:id', async (req: Request, res: Response) => {
const chatmessages = await this.AppDataSource.getRepository(ChatMessage).find({
where: {
chatflowid: req.params.id
},
order: {
createdDate: 'ASC'
const sortOrder = req.query?.order as string | undefined
const chatId = req.query?.chatId as string | undefined
const memoryType = req.query?.memoryType as string | undefined
const sessionId = req.query?.sessionId as string | undefined
const startDate = req.query?.startDate as string | undefined
const endDate = req.query?.endDate as string | undefined
let chatTypeFilter = req.query?.chatType as chatType | undefined
if (chatTypeFilter) {
try {
const chatTypeFilterArray = JSON.parse(chatTypeFilter)
if (chatTypeFilterArray.includes(chatType.EXTERNAL) && chatTypeFilterArray.includes(chatType.INTERNAL)) {
chatTypeFilter = undefined
} else if (chatTypeFilterArray.includes(chatType.EXTERNAL)) {
chatTypeFilter = chatType.EXTERNAL
} else if (chatTypeFilterArray.includes(chatType.INTERNAL)) {
chatTypeFilter = chatType.INTERNAL
}
} catch (e) {
return res.status(500).send(e)
}
})
}
const chatmessages = await this.getChatMessage(
req.params.id,
chatTypeFilter,
sortOrder,
chatId,
memoryType,
sessionId,
startDate,
endDate
)
return res.json(chatmessages)
})
// Get internal chatmessages from chatflowid
this.app.get('/api/v1/internal-chatmessage/:id', async (req: Request, res: Response) => {
const chatmessages = await this.getChatMessage(req.params.id, chatType.INTERNAL)
return res.json(chatmessages)
})
// Add chatmessages for chatflowid
this.app.post('/api/v1/chatmessage/:id', async (req: Request, res: Response) => {
const body = req.body
const newChatMessage = new ChatMessage()
Object.assign(newChatMessage, body)
const chatmessage = this.AppDataSource.getRepository(ChatMessage).create(newChatMessage)
const results = await this.AppDataSource.getRepository(ChatMessage).save(chatmessage)
const results = await this.addChatMessage(body)
return res.json(results)
})
// Delete all chatmessages from chatflowid
// Delete all chatmessages from chatId
this.app.delete('/api/v1/chatmessage/:id', async (req: Request, res: Response) => {
const chatflowid = req.params.id
const chatflow = await this.AppDataSource.getRepository(ChatFlow).findOneBy({
id: req.params.id
id: chatflowid
})
if (!chatflow) {
res.status(404).send(`Chatflow ${req.params.id} not found`)
res.status(404).send(`Chatflow ${chatflowid} not found`)
return
}
const chatId = (req.query?.chatId as string) ?? (await getChatId(chatflowid))
const memoryType = req.query?.memoryType as string | undefined
const sessionId = req.query?.sessionId as string | undefined
const chatType = req.query?.chatType as string | undefined
const isClearFromViewMessageDialog = req.query?.isClearFromViewMessageDialog as string | undefined
const flowData = chatflow.flowData
const parsedFlowData: IReactFlowObject = JSON.parse(flowData)
const nodes = parsedFlowData.nodes
let chatId = await getChatId(chatflow.id)
if (!chatId) chatId = chatflow.id
clearSessionMemory(nodes, this.nodesPool.componentNodes, chatId, this.AppDataSource, req.query.sessionId as string)
const results = await this.AppDataSource.getRepository(ChatMessage).delete({ chatflowid: req.params.id })
if (isClearFromViewMessageDialog)
clearSessionMemoryFromViewMessageDialog(
nodes,
this.nodesPool.componentNodes,
chatId,
this.AppDataSource,
sessionId,
memoryType
)
else clearAllSessionMemory(nodes, this.nodesPool.componentNodes, chatId, this.AppDataSource, sessionId)
const deleteOptions: FindOptionsWhere<ChatMessage> = { chatflowid, chatId }
if (memoryType) deleteOptions.memoryType = memoryType
if (sessionId) deleteOptions.sessionId = sessionId
if (chatType) deleteOptions.chatType = chatType
const results = await this.AppDataSource.getRepository(ChatMessage).delete(deleteOptions)
return res.json(results)
})
@@ -809,18 +861,95 @@ export class App {
* @param {Response} res
* @param {ChatFlow} chatflow
*/
async validateKey(req: Request, res: Response, chatflow: ChatFlow) {
async validateKey(req: Request, chatflow: ChatFlow) {
const chatFlowApiKeyId = chatflow.apikeyid
const authorizationHeader = (req.headers['Authorization'] as string) ?? (req.headers['authorization'] as string) ?? ''
if (!chatFlowApiKeyId) return true
if (chatFlowApiKeyId && !authorizationHeader) return res.status(401).send(`Unauthorized`)
const authorizationHeader = (req.headers['Authorization'] as string) ?? (req.headers['authorization'] as string) ?? ''
if (chatFlowApiKeyId && !authorizationHeader) return false
const suppliedKey = authorizationHeader.split(`Bearer `).pop()
if (chatFlowApiKeyId && suppliedKey) {
if (suppliedKey) {
const keys = await getAPIKeys()
const apiSecret = keys.find((key) => key.id === chatFlowApiKeyId)?.apiSecret
if (!compareKeys(apiSecret, suppliedKey)) return res.status(401).send(`Unauthorized`)
if (!compareKeys(apiSecret, suppliedKey)) return false
return true
}
return false
}
/**
* Method that get chat messages.
* @param {string} chatflowid
* @param {chatType} chatType
* @param {string} sortOrder
* @param {string} chatId
* @param {string} memoryType
* @param {string} sessionId
* @param {string} startDate
* @param {string} endDate
*/
async getChatMessage(
chatflowid: string,
chatType: chatType | undefined,
sortOrder: string = 'ASC',
chatId?: string,
memoryType?: string,
sessionId?: string,
startDate?: string,
endDate?: string
): Promise<ChatMessage[]> {
let fromDate
if (startDate) fromDate = new Date(startDate)
let toDate
if (endDate) toDate = new Date(endDate)
return await this.AppDataSource.getRepository(ChatMessage).find({
where: {
chatflowid,
chatType,
chatId,
memoryType: memoryType ?? (chatId ? IsNull() : undefined),
sessionId: sessionId ?? (chatId ? IsNull() : undefined),
createdDate: toDate && fromDate ? Between(fromDate, toDate) : undefined
},
order: {
createdDate: sortOrder === 'DESC' ? 'DESC' : 'ASC'
}
})
}
/**
* Method that add chat messages.
* @param {Partial<IChatMessage>} chatMessage
*/
async addChatMessage(chatMessage: Partial<IChatMessage>): Promise<ChatMessage> {
const newChatMessage = new ChatMessage()
Object.assign(newChatMessage, chatMessage)
const chatmessage = this.AppDataSource.getRepository(ChatMessage).create(newChatMessage)
return await this.AppDataSource.getRepository(ChatMessage).save(chatmessage)
}
/**
* Method that find memory label that is connected within chatflow
* In a chatflow, there should only be 1 memory node
* @param {IReactFlowNode[]} nodes
* @param {IReactFlowEdge[]} edges
* @returns {string | undefined}
*/
findMemoryLabel(nodes: IReactFlowNode[], edges: IReactFlowEdge[]): string | undefined {
const memoryNodes = nodes.filter((node) => node.data.category === 'Memory')
const memoryNodeIds = memoryNodes.map((mem) => mem.data.id)
for (const edge of edges) {
if (memoryNodeIds.includes(edge.source)) {
const memoryNode = nodes.find((node) => node.data.id === edge.source)
return memoryNode ? memoryNode.data.label : undefined
}
}
return undefined
}
/**
@@ -830,7 +959,7 @@ export class App {
* @param {Server} socketIO
* @param {boolean} isInternal
*/
async processPrediction(req: Request, res: Response, socketIO?: Server, isInternal = false) {
async processPrediction(req: Request, res: Response, socketIO?: Server, isInternal: boolean = false) {
try {
const chatflowid = req.params.id
let incomingInput: IncomingInput = req.body
@@ -842,11 +971,12 @@ export class App {
})
if (!chatflow) return res.status(404).send(`Chatflow ${chatflowid} not found`)
let chatId = await getChatId(chatflow.id)
if (!chatId) chatId = chatflowid
const chatId = incomingInput.chatId ?? incomingInput.overrideConfig?.sessionId ?? uuidv4()
const userMessageDateTime = new Date()
if (!isInternal) {
await this.validateKey(req, res, chatflow)
const isKeyValidated = await this.validateKey(req, chatflow)
if (!isKeyValidated) return res.status(401).send('Unauthorized')
}
let isStreamValid = false
@@ -978,9 +1108,12 @@ export class App {
logger.debug(`[server]: Running ${nodeToExecuteData.label} (${nodeToExecuteData.id})`)
if (nodeToExecuteData.instance) checkMemorySessionId(nodeToExecuteData.instance, chatId)
let sessionId = undefined
if (nodeToExecuteData.instance) sessionId = checkMemorySessionId(nodeToExecuteData.instance, chatId)
const result = isStreamValid
const memoryType = this.findMemoryLabel(nodes, edges)
let result = isStreamValid
? await nodeInstance.run(nodeToExecuteData, incomingInput.question, {
chatHistory: incomingInput.history,
socketIO,
@@ -998,7 +1131,42 @@ export class App {
analytic: chatflow.analytic
})
result = typeof result === 'string' ? { text: result } : result
const userMessage: Omit<IChatMessage, 'id'> = {
role: 'userMessage',
content: incomingInput.question,
chatflowid,
chatType: isInternal ? chatType.INTERNAL : chatType.EXTERNAL,
chatId,
memoryType,
sessionId,
createdDate: userMessageDateTime
}
await this.addChatMessage(userMessage)
let resultText = ''
if (result.text) resultText = result.text
else if (result.json) resultText = '```json\n' + JSON.stringify(result.json, null, 2)
else resultText = JSON.stringify(result, null, 2)
const apiMessage: Omit<IChatMessage, 'id' | 'createdDate'> = {
role: 'apiMessage',
content: resultText,
chatflowid,
chatType: isInternal ? chatType.INTERNAL : chatType.EXTERNAL,
chatId,
memoryType,
sessionId
}
if (result?.sourceDocuments) apiMessage.sourceDocuments = JSON.stringify(result.sourceDocuments)
await this.addChatMessage(apiMessage)
logger.debug(`[server]: Finished running ${nodeToExecuteData.label} (${nodeToExecuteData.id})`)
// Only return ChatId when its Internal OR incoming input has ChatId, to avoid confusion when calling API
if (incomingInput.chatId || isInternal) result.chatId = chatId
return res.json(result)
} catch (e: any) {
logger.error('[server]: Error:', e)
@@ -1021,7 +1189,7 @@ export class App {
* @param {string} chatflowid
* @returns {string}
*/
export async function getChatId(chatflowid: string) {
export async function getChatId(chatflowid: string): Promise<string> {
// first chatmessage id as the unique chat id
const firstChatMessage = await getDataSource()
.getRepository(ChatMessage)
+43 -4
View File
@@ -298,14 +298,14 @@ export const buildLangchain = async (
}
/**
* Clear memory
* Clear all session memories on the canvas
* @param {IReactFlowNode[]} reactFlowNodes
* @param {IComponentNodes} componentNodes
* @param {string} chatId
* @param {DataSource} appDataSource
* @param {string} sessionId
*/
export const clearSessionMemory = async (
export const clearAllSessionMemory = async (
reactFlowNodes: IReactFlowNode[],
componentNodes: IComponentNodes,
chatId: string,
@@ -317,9 +317,46 @@ export const clearSessionMemory = async (
const nodeInstanceFilePath = componentNodes[node.data.name].filePath as string
const nodeModule = await import(nodeInstanceFilePath)
const newNodeInstance = new nodeModule.nodeClass()
if (sessionId && node.data.inputs) node.data.inputs.sessionId = sessionId
if (newNodeInstance.clearSessionMemory)
if (newNodeInstance.clearSessionMemory) {
await newNodeInstance?.clearSessionMemory(node.data, { chatId, appDataSource, databaseEntities, logger })
}
}
}
/**
* Clear specific session memory from View Message Dialog UI
* @param {IReactFlowNode[]} reactFlowNodes
* @param {IComponentNodes} componentNodes
* @param {string} chatId
* @param {DataSource} appDataSource
* @param {string} sessionId
* @param {string} memoryType
*/
export const clearSessionMemoryFromViewMessageDialog = async (
reactFlowNodes: IReactFlowNode[],
componentNodes: IComponentNodes,
chatId: string,
appDataSource: DataSource,
sessionId?: string,
memoryType?: string
) => {
if (!sessionId) return
for (const node of reactFlowNodes) {
if (node.data.category !== 'Memory') continue
if (node.data.label !== memoryType) continue
const nodeInstanceFilePath = componentNodes[node.data.name].filePath as string
const nodeModule = await import(nodeInstanceFilePath)
const newNodeInstance = new nodeModule.nodeClass()
if (sessionId && node.data.inputs) node.data.inputs.sessionId = sessionId
if (newNodeInstance.clearSessionMemory) {
await newNodeInstance?.clearSessionMemory(node.data, { chatId, appDataSource, databaseEntities, logger })
return
}
}
}
@@ -937,8 +974,10 @@ export const redactCredentialWithPasswordType = (
* @param {any} instance
* @param {string} chatId
*/
export const checkMemorySessionId = (instance: any, chatId: string) => {
export const checkMemorySessionId = (instance: any, chatId: string): string => {
if (instance.memory && instance.memory.isSessionIdUsingChatMessageId && chatId) {
instance.memory.sessionId = chatId
instance.memory.chatHistory.sessionId = chatId
}
return instance.memory ? instance.memory.sessionId ?? instance.memory.chatHistory.sessionId : undefined
}