Merge branch 'main' into feature/Pinecone

# Conflicts:
#	pnpm-lock.yaml
pull/2708/head
Henry 2024-06-24 02:03:25 +01:00
commit ffdca5ddf3
28 changed files with 1230 additions and 299 deletions

View File

@ -1,2 +0,0 @@
node_modules
dist

View File

@ -1,3 +0,0 @@
**/node_modules
**/dist
**/build

View File

@ -1,9 +0,0 @@
module.exports = {
printWidth: 140,
singleQuote: true,
jsxSingleQuote: true,
trailingComma: 'none',
tabWidth: 4,
semi: false,
endOfLine: 'auto'
}

View File

@ -1,13 +0,0 @@
module.exports = {
presets: [
'@babel/preset-typescript',
[
'@babel/preset-env',
{
targets: {
node: 'current'
}
}
]
]
}

View File

@ -65,6 +65,34 @@
"resolutions": {
"@qdrant/openapi-typescript-fetch": "1.2.1",
"@google/generative-ai": "^0.7.0",
"openai": "4.38.3"
"openai": "4.51.0"
},
"eslintIgnore": [
"**/dist",
"**/node_modules",
"**/build",
"**/package-lock.json"
],
"prettier": {
"printWidth": 140,
"singleQuote": true,
"jsxSingleQuote": true,
"trailingComma": "none",
"tabWidth": 4,
"semi": false,
"endOfLine": "auto"
},
"babel": {
"presets": [
"@babel/preset-typescript",
[
"@babel/preset-env",
{
"targets": {
"node": "current"
}
}
]
]
}
}

View File

@ -0,0 +1,33 @@
import { INodeParams, INodeCredential } from '../src/Interface'
class LangWatchApi implements INodeCredential {
label: string
name: string
version: number
description: string
inputs: INodeParams[]
constructor() {
this.label = 'LangWatch API'
this.name = 'langwatchApi'
this.version = 1.0
this.description =
'Refer to <a target="_blank" href="https://docs.langwatch.ai/integration/python/guide">integration guide</a> on how to get API keys on LangWatch'
this.inputs = [
{
label: 'API Key',
name: 'langWatchApiKey',
type: 'password',
placeholder: '<LANGWATCH_API_KEY>'
},
{
label: 'Endpoint',
name: 'langWatchEndpoint',
type: 'string',
default: 'https://app.langwatch.ai'
}
]
}
}
module.exports = { credClass: LangWatchApi }

View File

@ -8,6 +8,11 @@
"name": "anthropic.claude-3-haiku-20240307-v1:0",
"description": "Image to text, conversation, chat optimized"
},
{
"label": "anthropic.claude-3.5-sonnet",
"name": "anthropic.claude-3-5-sonnet-20240620-v1:0",
"description": "3.5 version of Claude Sonnet model"
},
{
"label": "anthropic.claude-3-sonnet",
"name": "anthropic.claude-3-sonnet-20240229-v1:0",
@ -291,6 +296,11 @@
"name": "claude-3-opus-20240229",
"description": "Most powerful model for highly complex tasks"
},
{
"label": "claude-3.5-sonnet",
"name": "claude-3-5-sonnet-20240620",
"description": "3.5 version of Claude Sonnet model"
},
{
"label": "claude-3-sonnet",
"name": "claude-3-sonnet-20240229",
@ -1037,22 +1047,42 @@
{
"label": "voyage-2",
"name": "voyage-2",
"description": "Base generalist embedding model optimized for both latency and quality"
"description": "General-purpose embedding model optimized for a balance between cost, latency, and retrieval quality."
},
{
"label": "voyage-code-2",
"name": "voyage-code-2",
"description": "Optimized for code retrieval"
"description": "Optimized for code retrieval."
},
{
"label": "voyage-finance-2",
"name": "voyage-finance-2",
"description": "Optimized for finance retrieval and RAG."
},
{
"label": "voyage-large-2",
"name": "voyage-large-2",
"description": "Powerful generalist embedding model"
"description": "General-purpose embedding model that is optimized for retrieval quality."
},
{
"label": "voyage-large-2-instruct",
"name": "voyage-large-2-instruct",
"description": "Instruction-tuned general-purpose embedding model optimized for clustering, classification, and retrieval."
},
{
"label": "voyage-law-2",
"name": "voyage-law-2",
"description": "Optimized for legal and long-context retrieval and RAG. Also improved performance across all domains."
},
{
"label": "voyage-lite-02-instruct",
"name": "voyage-lite-02-instruct",
"description": "Instruction-tuned for classification, clustering, and sentence textual similarity tasks"
},
{
"label": "voyage-multilingual-2",
"name": "voyage-multilingual-2",
"description": "Optimized for multilingual retrieval and RAG."
}
]
},

View File

@ -27,7 +27,7 @@ class OpenAIAssistant_Agents implements INode {
constructor() {
this.label = 'OpenAI Assistant'
this.name = 'openAIAssistant'
this.version = 3.0
this.version = 4.0
this.type = 'OpenAIAssistant'
this.category = 'Agents'
this.icon = 'assistant.svg'
@ -54,6 +54,25 @@ class OpenAIAssistant_Agents implements INode {
optional: true,
list: true
},
{
label: 'Tool Choice',
name: 'toolChoice',
type: 'string',
description:
'Controls which (if any) tool is called by the model. Can be "none", "auto", "required", or the name of a tool. Refer <a href="https://platform.openai.com/docs/api-reference/runs/createRun#runs-createrun-tool_choice" target="_blank">here</a> for more information',
placeholder: 'file_search',
optional: true,
additionalParams: true
},
{
label: 'Parallel Tool Calls',
name: 'parallelToolCalls',
type: 'boolean',
description: 'Whether to enable parallel function calling during tool use. Defaults to true',
default: true,
optional: true,
additionalParams: true
},
{
label: 'Disable File Download',
name: 'disableFileDownload',
@ -155,6 +174,8 @@ class OpenAIAssistant_Agents implements INode {
const databaseEntities = options.databaseEntities as IDatabaseEntity
const disableFileDownload = nodeData.inputs?.disableFileDownload as boolean
const moderations = nodeData.inputs?.inputModeration as Moderation[]
const _toolChoice = nodeData.inputs?.toolChoice as string
const parallelToolCalls = nodeData.inputs?.parallelToolCalls as boolean
const isStreaming = options.socketIO && options.socketIOClientId
const socketIO = isStreaming ? options.socketIO : undefined
const socketIOClientId = isStreaming ? options.socketIOClientId : ''
@ -273,10 +294,25 @@ class OpenAIAssistant_Agents implements INode {
let runThreadId = ''
let isStreamingStarted = false
let toolChoice: any
if (_toolChoice) {
if (_toolChoice === 'file_search') {
toolChoice = { type: 'file_search' }
} else if (_toolChoice === 'code_interpreter') {
toolChoice = { type: 'code_interpreter' }
} else if (_toolChoice === 'none' || _toolChoice === 'auto' || _toolChoice === 'required') {
toolChoice = _toolChoice
} else {
toolChoice = { type: 'function', function: { name: _toolChoice } }
}
}
if (isStreaming) {
const streamThread = await openai.beta.threads.runs.create(threadId, {
assistant_id: retrievedAssistant.id,
stream: true
stream: true,
tool_choice: toolChoice,
parallel_tool_calls: parallelToolCalls
})
for await (const event of streamThread) {
@ -599,7 +635,9 @@ class OpenAIAssistant_Agents implements INode {
// Polling run status
const runThread = await openai.beta.threads.runs.create(threadId, {
assistant_id: retrievedAssistant.id
assistant_id: retrievedAssistant.id,
tool_choice: toolChoice,
parallel_tool_calls: parallelToolCalls
})
runThreadId = runThread.id
let state = await promise(threadId, runThread.id)
@ -612,7 +650,9 @@ class OpenAIAssistant_Agents implements INode {
if (retries > 0) {
retries -= 1
const newRunThread = await openai.beta.threads.runs.create(threadId, {
assistant_id: retrievedAssistant.id
assistant_id: retrievedAssistant.id,
tool_choice: toolChoice,
parallel_tool_calls: parallelToolCalls
})
runThreadId = newRunThread.id
state = await promise(threadId, newRunThread.id)

View File

@ -0,0 +1,3 @@
<svg width="38" height="52" viewBox="0 0 38 52" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 12.383V41.035C0 41.392 0.190002 41.723 0.500002 41.901L17.095 51.481C17.25 51.571 17.422 51.616 17.595 51.616C17.768 51.616 17.94 51.571 18.095 51.481L37.279 40.409C37.589 40.23 37.779 39.9 37.779 39.543V10.887C37.779 10.53 37.589 10.199 37.279 10.021L31.168 6.49498C31.014 6.40598 30.841 6.36098 30.669 6.36098C30.496 6.36098 30.323 6.40498 30.169 6.49498L27.295 8.15398V4.83698C27.295 4.47998 27.105 4.14898 26.795 3.97098L20.684 0.441982C20.529 0.352982 20.357 0.307983 20.184 0.307983C20.011 0.307983 19.839 0.352982 19.684 0.441982L13.781 3.85098C13.471 4.02998 13.281 4.35998 13.281 4.71698V12.157L12.921 12.365V11.872C12.921 11.515 12.731 11.185 12.421 11.006L7.405 8.10698C7.25 8.01798 7.077 7.97298 6.905 7.97298C6.733 7.97298 6.56 8.01798 6.405 8.10698L0.501001 11.517C0.191001 11.695 0 12.025 0 12.383ZM1.5 13.248L5.519 15.566V23.294C5.519 23.304 5.524 23.313 5.525 23.323C5.526 23.345 5.529 23.366 5.534 23.388C5.538 23.411 5.544 23.433 5.552 23.455C5.559 23.476 5.567 23.496 5.577 23.516C5.582 23.525 5.581 23.535 5.587 23.544C5.591 23.551 5.6 23.554 5.604 23.561C5.617 23.581 5.63 23.6 5.646 23.618C5.669 23.644 5.695 23.665 5.724 23.686C5.741 23.698 5.751 23.716 5.77 23.727L11.236 26.886C11.243 26.89 11.252 26.888 11.26 26.892C11.328 26.927 11.402 26.952 11.484 26.952C11.566 26.952 11.641 26.928 11.709 26.893C11.728 26.883 11.743 26.87 11.761 26.858C11.812 26.823 11.855 26.781 11.89 26.731C11.898 26.719 11.911 26.715 11.919 26.702C11.924 26.693 11.924 26.682 11.929 26.674C11.944 26.644 11.951 26.613 11.96 26.58C11.969 26.547 11.978 26.515 11.98 26.481C11.98 26.471 11.986 26.462 11.986 26.452V20.138V19.302L17.096 22.251V49.749L1.5 40.747V13.248ZM35.778 10.887L30.879 13.718L25.768 10.766L26.544 10.317L30.668 7.93698L35.778 10.887ZM25.293 4.83598L20.391 7.66498L15.281 4.71598L20.183 1.88398L25.293 4.83598ZM10.92 11.872L6.019 14.701L2.001 12.383L6.904 9.55098L10.92 11.872ZM20.956 16.51L24.268 14.601V18.788C24.268 18.809 24.278 18.827 24.28 18.848C24.284 18.883 24.29 18.917 24.301 18.95C24.311 18.98 24.325 19.007 24.342 19.034C24.358 19.061 24.373 19.088 24.395 19.112C24.417 19.138 24.444 19.159 24.471 19.18C24.489 19.193 24.499 19.21 24.518 19.221L29.878 22.314L23.998 25.708V18.557C23.998 18.547 23.993 18.538 23.992 18.528C23.991 18.506 23.988 18.485 23.984 18.463C23.979 18.44 23.973 18.418 23.965 18.396C23.958 18.375 23.95 18.355 23.941 18.336C23.936 18.327 23.937 18.316 23.931 18.308C23.925 18.299 23.917 18.294 23.911 18.286C23.898 18.267 23.886 18.251 23.871 18.234C23.855 18.216 23.84 18.2 23.822 18.185C23.805 18.17 23.788 18.157 23.769 18.144C23.76 18.138 23.756 18.129 23.747 18.124L20.956 16.51ZM25.268 11.633L30.379 14.585V21.448L25.268 18.499V13.736V11.633ZM12.486 18.437L17.389 15.604L22.498 18.556L17.595 21.385L12.486 18.437ZM10.985 25.587L7.019 23.295L10.985 21.005V25.587ZM12.42 14.385L14.28 13.311L16.822 14.777L12.42 17.32V14.385ZM14.78 5.58198L19.891 8.53098V15.394L14.78 12.445V5.58198Z" fill="#213B41"/>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -0,0 +1,33 @@
import { INode, INodeParams } from '../../../src/Interface'
class LangWatch_Analytic implements INode {
label: string
name: string
version: number
description: string
type: string
icon: string
category: string
baseClasses: string[]
inputs?: INodeParams[]
credential: INodeParams
constructor() {
this.label = 'LangWatch'
this.name = 'LangWatch'
this.version = 1.0
this.type = 'LangWatch'
this.icon = 'LangWatch.svg'
this.category = 'Analytic'
this.baseClasses = [this.type]
this.inputs = []
this.credential = {
label: 'Connect Credential',
name: 'credential',
type: 'credential',
credentialNames: ['langwatchApi']
}
}
}
module.exports = { nodeClass: LangWatch_Analytic }

View File

@ -49,6 +49,10 @@ class VoyageAIRerankRetriever_Retrievers implements INode {
{
label: 'rerank-lite-1',
name: 'rerank-lite-1'
},
{
label: 'rerank-1',
name: 'rerank-1'
}
],
default: 'rerank-lite-1',

View File

@ -6,6 +6,7 @@ import { CallbackManagerForToolRun, Callbacks, CallbackManager, parseCallbackCon
import { StructuredTool } from '@langchain/core/tools'
import { ICommonObject, IDatabaseEntity, INode, INodeData, INodeOptionsValue, INodeParams } from '../../../src/Interface'
import { availableDependencies, defaultAllowBuiltInDep, getCredentialData, getCredentialParam } from '../../../src/utils'
import { v4 as uuidv4 } from 'uuid'
class ChatflowTool_Tools implements INode {
label: string
@ -22,7 +23,7 @@ class ChatflowTool_Tools implements INode {
constructor() {
this.label = 'Chatflow Tool'
this.name = 'ChatflowTool'
this.version = 2.0
this.version = 3.0
this.type = 'ChatflowTool'
this.icon = 'chatflowTool.svg'
this.category = 'Tools'
@ -66,6 +67,16 @@ class ChatflowTool_Tools implements INode {
optional: true,
additionalParams: true
},
{
label: 'Start new session per message',
name: 'startNewSession',
type: 'boolean',
description:
'Whether to continue the session with the Chatflow tool or start a new one with each interaction. Useful for Chatflows with memory if you want to avoid it.',
default: false,
optional: true,
additionalParams: true
},
{
label: 'Use Question from Chat',
name: 'useQuestionFromChat',
@ -117,6 +128,8 @@ class ChatflowTool_Tools implements INode {
const useQuestionFromChat = nodeData.inputs?.useQuestionFromChat as boolean
const customInput = nodeData.inputs?.customInput as string
const startNewSession = nodeData.inputs?.startNewSession as boolean
const baseURL = (nodeData.inputs?.baseURL as string) || (options.baseURL as string)
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
@ -136,7 +149,7 @@ class ChatflowTool_Tools implements INode {
let name = _name || 'chatflow_tool'
return new ChatflowTool({ name, baseURL, description, chatflowid: selectedChatflowId, headers, input: toolInput })
return new ChatflowTool({ name, baseURL, description, chatflowid: selectedChatflowId, startNewSession, headers, input: toolInput })
}
}
@ -153,6 +166,8 @@ class ChatflowTool extends StructuredTool {
chatflowid = ''
startNewSession = false
baseURL = 'http://localhost:3000'
headers = {}
@ -166,6 +181,7 @@ class ChatflowTool extends StructuredTool {
description,
input,
chatflowid,
startNewSession,
baseURL,
headers
}: {
@ -173,6 +189,7 @@ class ChatflowTool extends StructuredTool {
description: string
input: string
chatflowid: string
startNewSession: boolean
baseURL: string
headers: ICommonObject
}) {
@ -181,6 +198,7 @@ class ChatflowTool extends StructuredTool {
this.description = description
this.input = input
this.baseURL = baseURL
this.startNewSession = startNewSession
this.headers = headers
this.chatflowid = chatflowid
}
@ -240,9 +258,9 @@ class ChatflowTool extends StructuredTool {
const body = {
question: inputQuestion,
chatId: flowConfig?.chatId,
chatId: this.startNewSession ? uuidv4() : flowConfig?.chatId,
overrideConfig: {
sessionId: flowConfig?.sessionId
sessionId: this.startNewSession ? uuidv4() : flowConfig?.sessionId
}
}

View File

@ -96,6 +96,9 @@ export class DynamicStructuredTool<
await runManager?.handleToolError(e)
throw e
}
if (result && typeof result !== 'string') {
result = JSON.stringify(result)
}
await runManager?.handleToolEnd(result)
return result
}

View File

@ -76,7 +76,7 @@ class Retriever_Tools implements INode {
}
const schema = z.object({
input: z.string().describe('query to look up in retriever')
input: z.string().describe('input to look up in retriever')
})
const tool = new DynamicStructuredTool({ ...input, func, schema })

View File

@ -156,7 +156,7 @@ class Pinecone_VectorStores implements INode {
const obj: PineconeStoreParams = {
pineconeIndex,
textKey: pineconeTextKey ?? 'text'
textKey: pineconeTextKey || 'text'
}
if (pineconeNamespace) obj.namespace = pineconeNamespace
@ -203,7 +203,7 @@ class Pinecone_VectorStores implements INode {
const obj: PineconeStoreParams = {
pineconeIndex,
textKey: pineconeTextKey ?? 'text'
textKey: pineconeTextKey || 'text'
}
if (pineconeNamespace) obj.namespace = pineconeNamespace

View File

@ -84,6 +84,7 @@
"langfuse": "3.3.4",
"langfuse-langchain": "^3.3.4",
"langsmith": "0.1.6",
"langwatch": "^0.1.1",
"linkifyjs": "^4.1.1",
"llamaindex": "^0.3.13",
"lodash": "^4.17.21",
@ -96,7 +97,7 @@
"node-html-markdown": "^1.3.0",
"notion-to-md": "^3.1.1",
"object-hash": "^3.0.0",
"openai": "^4.38.3",
"openai": "^4.51.0",
"pdf-parse": "^1.1.1",
"pdfjs-dist": "^3.7.107",
"pg": "^8.11.2",

View File

@ -16,6 +16,7 @@ import { LunaryHandler } from '@langchain/community/callbacks/handlers/lunary'
import { getCredentialData, getCredentialParam, getEnvironmentVariable } from './utils'
import { ICommonObject, INodeData } from './Interface'
import { LangWatch, LangWatchSpan, LangWatchTrace, autoconvertTypedValues } from 'langwatch'
interface AgentRun extends Run {
actions: AgentAction[]
@ -293,6 +294,17 @@ export const additionalCallbacks = async (nodeData: INodeData, options: ICommonO
const handler = new LunaryHandler(lunaryFields)
callbacks.push(handler)
} else if (provider === 'langWatch') {
const langWatchApiKey = getCredentialParam('langWatchApiKey', credentialData, nodeData)
const langWatchEndpoint = getCredentialParam('langWatchEndpoint', credentialData, nodeData)
const langwatch = new LangWatch({
apiKey: langWatchApiKey,
endpoint: langWatchEndpoint
})
const trace = langwatch.getTrace()
callbacks.push(trace.getLangChainCallback())
}
}
}
@ -360,6 +372,16 @@ export class AnalyticHandler {
})
this.handlers['lunary'] = { client: lunary }
} else if (provider === 'langWatch') {
const langWatchApiKey = getCredentialParam('langWatchApiKey', credentialData, this.nodeData)
const langWatchEndpoint = getCredentialParam('langWatchEndpoint', credentialData, this.nodeData)
const langwatch = new LangWatch({
apiKey: langWatchApiKey,
endpoint: langWatchEndpoint
})
this.handlers['langWatch'] = { client: langwatch }
}
}
}
@ -372,7 +394,8 @@ export class AnalyticHandler {
const returnIds: ICommonObject = {
langSmith: {},
langFuse: {},
lunary: {}
lunary: {},
langWatch: {}
}
if (Object.prototype.hasOwnProperty.call(this.handlers, 'langSmith')) {
@ -460,6 +483,33 @@ export class AnalyticHandler {
}
}
if (Object.prototype.hasOwnProperty.call(this.handlers, 'langWatch')) {
let langwatchTrace: LangWatchTrace
if (!parentIds || !Object.keys(parentIds).length) {
const langwatch: LangWatch = this.handlers['langWatch'].client
langwatchTrace = langwatch.getTrace({
name,
metadata: { tags: ['openai-assistant'], threadId: this.options.chatId },
...this.nodeData?.inputs?.analytics?.langWatch
})
} else {
langwatchTrace = this.handlers['langWatch'].trace[parentIds['langWatch']]
}
if (langwatchTrace) {
const span = langwatchTrace.startSpan({
name,
type: 'chain',
input: autoconvertTypedValues(input)
})
this.handlers['langWatch'].trace = { [langwatchTrace.traceId]: langwatchTrace }
this.handlers['langWatch'].span = { [span.spanId]: span }
returnIds['langWatch'].trace = langwatchTrace.traceId
returnIds['langWatch'].span = span.spanId
}
}
return returnIds
}
@ -508,6 +558,15 @@ export class AnalyticHandler {
})
}
}
if (Object.prototype.hasOwnProperty.call(this.handlers, 'langWatch')) {
const span: LangWatchSpan | undefined = this.handlers['langWatch'].span[returnIds['langWatch'].span]
if (span) {
span.end({
output: autoconvertTypedValues(output)
})
}
}
}
async onChainError(returnIds: ICommonObject, error: string | object, shutdown = false) {
@ -557,6 +616,15 @@ export class AnalyticHandler {
})
}
}
if (Object.prototype.hasOwnProperty.call(this.handlers, 'langWatch')) {
const span: LangWatchSpan | undefined = this.handlers['langWatch'].span[returnIds['langWatch'].span]
if (span) {
span.end({
error
})
}
}
}
async onLLMStart(name: string, input: string, parentIds: ICommonObject) {
@ -612,6 +680,18 @@ export class AnalyticHandler {
}
}
if (Object.prototype.hasOwnProperty.call(this.handlers, 'langWatch')) {
const trace: LangWatchTrace | undefined = this.handlers['langWatch'].trace[parentIds['langWatch'].trace]
if (trace) {
const span = trace.startLLMSpan({
name,
input: autoconvertTypedValues(input)
})
this.handlers['langWatch'].span = { [span.spanId]: span }
returnIds['langWatch'].span = span.spanId
}
}
return returnIds
}
@ -648,6 +728,15 @@ export class AnalyticHandler {
})
}
}
if (Object.prototype.hasOwnProperty.call(this.handlers, 'langWatch')) {
const span: LangWatchSpan | undefined = this.handlers['langWatch'].span[returnIds['langWatch'].span]
if (span) {
span.end({
output: autoconvertTypedValues(output)
})
}
}
}
async onLLMError(returnIds: ICommonObject, error: string | object) {
@ -683,6 +772,15 @@ export class AnalyticHandler {
})
}
}
if (Object.prototype.hasOwnProperty.call(this.handlers, 'langWatch')) {
const span: LangWatchSpan | undefined = this.handlers['langWatch'].span[returnIds['langWatch'].span]
if (span) {
span.end({
error
})
}
}
}
async onToolStart(name: string, input: string | object, parentIds: ICommonObject) {
@ -738,6 +836,19 @@ export class AnalyticHandler {
}
}
if (Object.prototype.hasOwnProperty.call(this.handlers, 'langWatch')) {
const trace: LangWatchTrace | undefined = this.handlers['langWatch'].trace[parentIds['langWatch'].trace]
if (trace) {
const span = trace.startSpan({
name,
type: 'tool',
input: autoconvertTypedValues(input)
})
this.handlers['langWatch'].span = { [span.spanId]: span }
returnIds['langWatch'].span = span.spanId
}
}
return returnIds
}
@ -774,6 +885,15 @@ export class AnalyticHandler {
})
}
}
if (Object.prototype.hasOwnProperty.call(this.handlers, 'langWatch')) {
const span: LangWatchSpan | undefined = this.handlers['langWatch'].span[returnIds['langWatch'].span]
if (span) {
span.end({
output: autoconvertTypedValues(output)
})
}
}
}
async onToolError(returnIds: ICommonObject, error: string | object) {
@ -809,5 +929,14 @@ export class AnalyticHandler {
})
}
}
if (Object.prototype.hasOwnProperty.call(this.handlers, 'langWatch')) {
const span: LangWatchSpan | undefined = this.handlers['langWatch'].span[returnIds['langWatch'].span]
if (span) {
span.end({
error
})
}
}
}
}

View File

@ -20,6 +20,14 @@ export const addImagesToMessages = async (
// as the image is stored in the server, read the file and convert it to base64
bf = 'data:' + upload.mime + ';base64,' + contents.toString('base64')
imageContent.push({
type: 'image_url',
image_url: {
url: bf,
detail: multiModalOption.image.imageResolution ?? 'low'
}
})
} else if (upload.type == 'url' && bf) {
imageContent.push({
type: 'image_url',
image_url: {

View File

@ -48,6 +48,7 @@ export const availableDependencies = [
'langchain',
'langfuse',
'langsmith',
'langwatch',
'linkifyjs',
'lunary',
'mammoth',

View File

@ -75,7 +75,7 @@
"moment-timezone": "^0.5.34",
"multer": "^1.4.5-lts.1",
"mysql2": "^3.9.2",
"openai": "^4.20.0",
"openai": "^4.51.0",
"pg": "^8.11.1",
"posthog-node": "^3.5.0",
"reflect-metadata": "^0.1.13",

View File

@ -198,6 +198,7 @@ export async function getAllChatFlow(): Promise<IChatFlow[]> {
export async function start(): Promise<void> {
serverApp = new App()
const host = process.env.HOST
const port = parseInt(process.env.PORT || '', 10) || 3000
const server = http.createServer(serverApp.app)
@ -208,8 +209,8 @@ export async function start(): Promise<void> {
await serverApp.initDatabase()
await serverApp.config(io)
server.listen(port, () => {
logger.info(`⚡️ [server]: Flowise Server is listening at ${port}`)
server.listen(port, host, () => {
logger.info(`⚡️ [server]: Flowise Server is listening at ${host ? 'http://' + host : ''}:${port}`)
})
}

View File

@ -94,6 +94,12 @@ export const utilBuildChatflow = async (req: Request, socketIO?: Server, isInter
fileUploads[i] = omit(upload, ['data'])
}
if (upload.type === 'url' && upload.data) {
const filename = upload.name
const urlData = upload.data
fileUploads[i] = { data: urlData, name: filename, type: 'url', mime: upload.mime ?? 'image/png' }
}
// Run Speech to Text conversion
if (upload.mime === 'audio/webm' || upload.mime === 'audio/mp4' || upload.mime === 'audio/ogg') {
logger.debug(`Attempting a speech to text conversion...`)

View File

@ -0,0 +1,3 @@
<svg width="38" height="52" viewBox="0 0 38 52" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 12.383V41.035C0 41.392 0.190002 41.723 0.500002 41.901L17.095 51.481C17.25 51.571 17.422 51.616 17.595 51.616C17.768 51.616 17.94 51.571 18.095 51.481L37.279 40.409C37.589 40.23 37.779 39.9 37.779 39.543V10.887C37.779 10.53 37.589 10.199 37.279 10.021L31.168 6.49498C31.014 6.40598 30.841 6.36098 30.669 6.36098C30.496 6.36098 30.323 6.40498 30.169 6.49498L27.295 8.15398V4.83698C27.295 4.47998 27.105 4.14898 26.795 3.97098L20.684 0.441982C20.529 0.352982 20.357 0.307983 20.184 0.307983C20.011 0.307983 19.839 0.352982 19.684 0.441982L13.781 3.85098C13.471 4.02998 13.281 4.35998 13.281 4.71698V12.157L12.921 12.365V11.872C12.921 11.515 12.731 11.185 12.421 11.006L7.405 8.10698C7.25 8.01798 7.077 7.97298 6.905 7.97298C6.733 7.97298 6.56 8.01798 6.405 8.10698L0.501001 11.517C0.191001 11.695 0 12.025 0 12.383ZM1.5 13.248L5.519 15.566V23.294C5.519 23.304 5.524 23.313 5.525 23.323C5.526 23.345 5.529 23.366 5.534 23.388C5.538 23.411 5.544 23.433 5.552 23.455C5.559 23.476 5.567 23.496 5.577 23.516C5.582 23.525 5.581 23.535 5.587 23.544C5.591 23.551 5.6 23.554 5.604 23.561C5.617 23.581 5.63 23.6 5.646 23.618C5.669 23.644 5.695 23.665 5.724 23.686C5.741 23.698 5.751 23.716 5.77 23.727L11.236 26.886C11.243 26.89 11.252 26.888 11.26 26.892C11.328 26.927 11.402 26.952 11.484 26.952C11.566 26.952 11.641 26.928 11.709 26.893C11.728 26.883 11.743 26.87 11.761 26.858C11.812 26.823 11.855 26.781 11.89 26.731C11.898 26.719 11.911 26.715 11.919 26.702C11.924 26.693 11.924 26.682 11.929 26.674C11.944 26.644 11.951 26.613 11.96 26.58C11.969 26.547 11.978 26.515 11.98 26.481C11.98 26.471 11.986 26.462 11.986 26.452V20.138V19.302L17.096 22.251V49.749L1.5 40.747V13.248ZM35.778 10.887L30.879 13.718L25.768 10.766L26.544 10.317L30.668 7.93698L35.778 10.887ZM25.293 4.83598L20.391 7.66498L15.281 4.71598L20.183 1.88398L25.293 4.83598ZM10.92 11.872L6.019 14.701L2.001 12.383L6.904 9.55098L10.92 11.872ZM20.956 16.51L24.268 14.601V18.788C24.268 18.809 24.278 18.827 24.28 18.848C24.284 18.883 24.29 18.917 24.301 18.95C24.311 18.98 24.325 19.007 24.342 19.034C24.358 19.061 24.373 19.088 24.395 19.112C24.417 19.138 24.444 19.159 24.471 19.18C24.489 19.193 24.499 19.21 24.518 19.221L29.878 22.314L23.998 25.708V18.557C23.998 18.547 23.993 18.538 23.992 18.528C23.991 18.506 23.988 18.485 23.984 18.463C23.979 18.44 23.973 18.418 23.965 18.396C23.958 18.375 23.95 18.355 23.941 18.336C23.936 18.327 23.937 18.316 23.931 18.308C23.925 18.299 23.917 18.294 23.911 18.286C23.898 18.267 23.886 18.251 23.871 18.234C23.855 18.216 23.84 18.2 23.822 18.185C23.805 18.17 23.788 18.157 23.769 18.144C23.76 18.138 23.756 18.129 23.747 18.124L20.956 16.51ZM25.268 11.633L30.379 14.585V21.448L25.268 18.499V13.736V11.633ZM12.486 18.437L17.389 15.604L22.498 18.556L17.595 21.385L12.486 18.437ZM10.985 25.587L7.019 23.295L10.985 21.005V25.587ZM12.42 14.385L14.28 13.311L16.822 14.777L12.42 17.32V14.385ZM14.78 5.58198L19.891 8.53098V15.394L14.78 12.445V5.58198Z" fill="#213B41"/>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -27,6 +27,7 @@ import { StyledButton } from '@/ui-component/button/StyledButton'
import langsmithPNG from '@/assets/images/langchain.png'
import langfuseSVG from '@/assets/images/langfuse.svg'
import lunarySVG from '@/assets/images/lunary.svg'
import langwatchSVG from '@/assets/images/langwatch.svg'
// store
import useNotifier from '@/utils/useNotifier'
@ -109,6 +110,26 @@ const analyticProviders = [
optional: true
}
]
},
{
label: 'LangWatch',
name: 'langWatch',
icon: langwatchSVG,
url: 'https://langwatch.com',
inputs: [
{
label: 'Connect Credential',
name: 'credential',
type: 'credential',
credentialNames: ['langwatchApi']
},
{
label: 'On/Off',
name: 'status',
type: 'boolean',
optional: true
}
]
}
]

View File

@ -693,7 +693,7 @@ export const getConfigExamplesForCurl = (configData, bodyType, isMultiple, stopN
const loop = Math.min(configData.length, 4)
for (let i = 0; i < loop; i += 1) {
const config = configData[i]
let exampleVal = `example`
let exampleVal = `"example"`
if (config.type === 'string') exampleVal = bodyType === 'json' ? `"example"` : `example`
else if (config.type === 'boolean') exampleVal = `true`
else if (config.type === 'number') exampleVal = `1`

View File

@ -104,6 +104,24 @@ const buttonConfig = (isReact = false) => {
}`
}
const tooltipConfig = (isReact = false) => {
return isReact
? `tooltip: {
showTooltip: true,
tooltipMessage: 'Hi There 👋!',
tooltipBackgroundColor: 'black',
tooltipTextColor: 'white',
tooltipFontSize: 16,
}`
: `tooltip: {
showTooltip: true,
tooltipMessage: 'Hi There 👋!',
tooltipBackgroundColor: 'black',
tooltipTextColor: 'white',
tooltipFontSize: 16,
}`
}
const chatwindowConfig = (isReact = false) => {
return isReact
? `chatWindow: {
@ -136,6 +154,7 @@ const chatwindowConfig = (isReact = false) => {
sendButtonColor: '#3B81F6',
maxChars: 50,
maxCharsWarningMessage: 'You exceeded the characters limit. Please input less than 50 characters.',
autoFocus: true, // If not used, autofocus is disabled on mobile and enabled on desktop. true enables it on both, false disables it on both.
},
feedback: {
color: '#303235',
@ -177,6 +196,7 @@ const chatwindowConfig = (isReact = false) => {
sendButtonColor: '#3B81F6',
maxChars: 50,
maxCharsWarningMessage: 'You exceeded the characters limit. Please input less than 50 characters.',
autoFocus: true, // If not used, autofocus is disabled on mobile and enabled on desktop. true enables it on both, false disables it on both.
},
feedback: {
color: '#303235',
@ -201,6 +221,7 @@ const embedPopupHtmlCodeCustomization = (chatflowid) => {
},
theme: {
${buttonConfig()},
${tooltipConfig()},
${chatwindowConfig()}
}
})
@ -217,6 +238,7 @@ const App = () => {
apiHost="${baseURL}"
theme={{
${buttonConfig(true)},
${tooltipConfig(true)},
${chatwindowConfig(true)}
}}
/>

View File

@ -6,15 +6,17 @@ import dotenv from 'dotenv'
export default defineConfig(async ({ mode }) => {
let proxy = undefined
if (mode === 'development') {
const serverPort = parseInt(dotenv.config({ processEnv: {}, path: '../server/.env' }).parsed?.['PORT'])
const serverEnv = dotenv.config({ processEnv: {}, path: '../server/.env' }).parsed
const serverHost = serverEnv?.['HOST'] ?? 'localhost'
const serverPort = parseInt(serverEnv?.['PORT'] ?? 3000)
if (!Number.isNaN(serverPort) && serverPort > 0 && serverPort < 65535) {
proxy = {
'/api': {
target: `http://localhost:${serverPort}`,
target: `http://${serverHost}:${serverPort}`,
changeOrigin: true
},
'/socket.io': {
target: `http://localhost:${serverPort}`,
target: `http://${serverHost}:${serverPort}`,
changeOrigin: true
}
}

File diff suppressed because it is too large Load Diff