From dd56d03b783a8aedc3f9fcd5c9f07a6765f2fbeb Mon Sep 17 00:00:00 2001 From: Boris Feld Date: Thu, 3 Apr 2025 09:57:54 +0200 Subject: [PATCH] feat: Add Opik Tracer integration (#4194) This update adds support for Opik tracer in Flowise. It includes new credential components, analytic nodes, and UI assets for both tracers. The changes enhance observability by allowing users to integrate Opik for better model monitoring, analysis and evaluation. --- .../credentials/OpikApi.credential.ts | 39 ++++ .../components/nodes/analytic/Opik/Opik.ts | 33 +++ .../components/nodes/analytic/Opik/opik.png | Bin 0 -> 10427 bytes packages/components/src/handler.ts | 213 +++++++++++++++++- packages/ui/src/assets/images/opik.png | Bin 0 -> 10427 bytes .../src/ui-component/extended/AnalyseFlow.jsx | 28 +++ 6 files changed, 311 insertions(+), 2 deletions(-) create mode 100644 packages/components/credentials/OpikApi.credential.ts create mode 100644 packages/components/nodes/analytic/Opik/Opik.ts create mode 100644 packages/components/nodes/analytic/Opik/opik.png create mode 100644 packages/ui/src/assets/images/opik.png diff --git a/packages/components/credentials/OpikApi.credential.ts b/packages/components/credentials/OpikApi.credential.ts new file mode 100644 index 000000000..db5d66077 --- /dev/null +++ b/packages/components/credentials/OpikApi.credential.ts @@ -0,0 +1,39 @@ +import { INodeParams, INodeCredential } from '../src/Interface' + +class OpikApi implements INodeCredential { + label: string + name: string + version: number + description: string + inputs: INodeParams[] + + constructor() { + this.label = 'Opik API' + this.name = 'opikApi' + this.version = 1.0 + this.description = + 'Refer to Opik documentation on how to configure Opik credentials' + this.inputs = [ + { + label: 'API Key', + name: 'opikApiKey', + type: 'password', + placeholder: '' + }, + { + label: 'URL', + name: 'opikUrl', + type: 'string', + placeholder: 'https://www.comet.com/opik/api' + }, + { + label: 'Workspace', + name: 'opikWorkspace', + type: 'string', + placeholder: 'default' + } + ] + } +} + +module.exports = { credClass: OpikApi } diff --git a/packages/components/nodes/analytic/Opik/Opik.ts b/packages/components/nodes/analytic/Opik/Opik.ts new file mode 100644 index 000000000..c620bdcc1 --- /dev/null +++ b/packages/components/nodes/analytic/Opik/Opik.ts @@ -0,0 +1,33 @@ +import { INode, INodeParams } from '../../../src/Interface' + +class Opik_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 = 'Opik' + this.name = 'opik' + this.version = 1.0 + this.type = 'Opik' + this.icon = 'opik.png' + this.category = 'Analytic' + this.baseClasses = [this.type] + this.inputs = [] + this.credential = { + label: 'Connect Credential', + name: 'credential', + type: 'credential', + credentialNames: ['opikApi'] + } + } +} + +module.exports = { nodeClass: Opik_Analytic } diff --git a/packages/components/nodes/analytic/Opik/opik.png b/packages/components/nodes/analytic/Opik/opik.png new file mode 100644 index 0000000000000000000000000000000000000000..20de0c39d47047636a513d4f2fa07e793f2d89a5 GIT binary patch literal 10427 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 WPODC*Pk@&ai5_X_Kd4fNMg1Q*ER^~H literal 0 HcmV?d00001 diff --git a/packages/components/src/handler.ts b/packages/components/src/handler.ts index 48236f2be..a4cafe19b 100644 --- a/packages/components/src/handler.ts +++ b/packages/components/src/handler.ts @@ -121,6 +121,50 @@ function getPhoenixTracer(options: PhoenixTracerOptions): Tracer | undefined { } } +interface OpikTracerOptions { + apiKey: string + baseUrl: string + projectName: string + workspace: string + sdkIntegration?: string + sessionId?: string + enableCallback?: boolean +} + +function getOpikTracer(options: OpikTracerOptions): Tracer | undefined { + const SEMRESATTRS_PROJECT_NAME = 'openinference.project.name' + try { + const traceExporter = new ProtoOTLPTraceExporter({ + url: `${options.baseUrl}/v1/private/otel/v1/traces`, + headers: { + Authorization: options.apiKey, + projectName: options.projectName, + 'Comet-Workspace': options.workspace + } + }) + const tracerProvider = new NodeTracerProvider({ + resource: new Resource({ + [ATTR_SERVICE_NAME]: options.projectName, + [ATTR_SERVICE_VERSION]: '1.0.0', + [SEMRESATTRS_PROJECT_NAME]: options.projectName + }) + }) + tracerProvider.addSpanProcessor(new SimpleSpanProcessor(traceExporter)) + if (options.enableCallback) { + registerInstrumentations({ + instrumentations: [] + }) + const lcInstrumentation = new LangChainInstrumentation() + lcInstrumentation.manuallyInstrument(CallbackManagerModule) + tracerProvider.register() + } + return tracerProvider.getTracer(`opik-tracer-${uuidv4().toString()}`) + } catch (err) { + if (process.env.DEBUG === 'true') console.error(`Error setting up Opik tracer: ${err.message}`) + return undefined + } +} + function tryGetJsonSpaces() { try { return parseInt(getEnvironmentVariable('LOG_JSON_SPACES') ?? '2') @@ -559,6 +603,28 @@ export const additionalCallbacks = async (nodeData: INodeData, options: ICommonO const tracer: Tracer | undefined = getPhoenixTracer(phoenixOptions) callbacks.push(tracer) + } else if (provider === 'opik') { + const opikApiKey = getCredentialParam('opikApiKey', credentialData, nodeData) + const opikEndpoint = getCredentialParam('opikUrl', credentialData, nodeData) + const opikWorkspace = getCredentialParam('opikWorkspace', credentialData, nodeData) + const opikProject = analytic[provider].opikProjectName as string + + let opikOptions: OpikTracerOptions = { + apiKey: opikApiKey, + baseUrl: opikEndpoint ?? 'https://www.comet.com/opik/api', + projectName: opikProject ?? 'default', + workspace: opikWorkspace ?? 'default', + sdkIntegration: 'Flowise', + enableCallback: true + } + + if (options.chatId) opikOptions.sessionId = options.chatId + if (nodeData?.inputs?.analytics?.opik) { + opikOptions = { ...opikOptions, ...nodeData?.inputs?.analytics?.opik } + } + + const tracer: Tracer | undefined = getOpikTracer(opikOptions) + callbacks.push(tracer) } } } @@ -673,6 +739,25 @@ export class AnalyticHandler { const rootSpan: Span | undefined = undefined this.handlers['phoenix'] = { client: phoenix, phoenixProject, rootSpan } + } else if (provider === 'opik') { + const opikApiKey = getCredentialParam('opikApiKey', credentialData, this.nodeData) + const opikEndpoint = getCredentialParam('opikUrl', credentialData, this.nodeData) + const opikWorkspace = getCredentialParam('opikWorkspace', credentialData, this.nodeData) + const opikProject = analytic[provider].opikProjectName as string + + let opikOptions: OpikTracerOptions = { + apiKey: opikApiKey, + baseUrl: opikEndpoint ?? 'https://www.comet.com/opik/api', + projectName: opikProject ?? 'default', + workspace: opikWorkspace ?? 'default', + sdkIntegration: 'Flowise', + enableCallback: false + } + + const opik: Tracer | undefined = getOpikTracer(opikOptions) + const rootSpan: Span | undefined = undefined + + this.handlers['opik'] = { client: opik, opikProject, rootSpan } } } } @@ -688,7 +773,8 @@ export class AnalyticHandler { lunary: {}, langWatch: {}, arize: {}, - phoenix: {} + phoenix: {}, + opik: {} } if (Object.prototype.hasOwnProperty.call(this.handlers, 'langSmith')) { @@ -870,6 +956,40 @@ export class AnalyticHandler { returnIds['phoenix'].chainSpan = chainSpanId } + if (Object.prototype.hasOwnProperty.call(this.handlers, 'opik')) { + const tracer: Tracer | undefined = this.handlers['opik'].client + let rootSpan: Span | undefined = this.handlers['opik'].rootSpan + + if (!parentIds || !Object.keys(parentIds).length) { + rootSpan = tracer ? tracer.startSpan('Flowise') : undefined + if (rootSpan) { + rootSpan.setAttribute('session.id', this.options.chatId) + rootSpan.setAttribute('openinference.span.kind', 'CHAIN') + rootSpan.setAttribute('input.value', input) + rootSpan.setAttribute('input.mime_type', 'text/plain') + rootSpan.setAttribute('output.value', '[Object]') + rootSpan.setAttribute('output.mime_type', 'text/plain') + rootSpan.setStatus({ code: SpanStatusCode.OK }) + rootSpan.end() + } + this.handlers['opik'].rootSpan = rootSpan + } + + const rootSpanContext = rootSpan + ? opentelemetry.trace.setSpan(opentelemetry.context.active(), rootSpan as Span) + : opentelemetry.context.active() + const chainSpan = tracer?.startSpan(name, undefined, rootSpanContext) + if (chainSpan) { + chainSpan.setAttribute('openinference.span.kind', 'CHAIN') + chainSpan.setAttribute('input.value', JSON.stringify(input)) + chainSpan.setAttribute('input.mime_type', 'application/json') + } + const chainSpanId: any = chainSpan?.spanContext().spanId + + this.handlers['opik'].chainSpan = { [chainSpanId]: chainSpan } + returnIds['opik'].chainSpan = chainSpanId + } + return returnIds } @@ -947,6 +1067,16 @@ export class AnalyticHandler { chainSpan.end() } } + + if (Object.prototype.hasOwnProperty.call(this.handlers, 'opik')) { + const chainSpan: Span | undefined = this.handlers['opik'].chainSpan[returnIds['opik'].chainSpan] + if (chainSpan) { + chainSpan.setAttribute('output.value', JSON.stringify(output)) + chainSpan.setAttribute('output.mime_type', 'application/json') + chainSpan.setStatus({ code: SpanStatusCode.OK }) + chainSpan.end() + } + } } async onChainError(returnIds: ICommonObject, error: string | object, shutdown = false) { @@ -1132,6 +1262,25 @@ export class AnalyticHandler { returnIds['phoenix'].llmSpan = llmSpanId } + if (Object.prototype.hasOwnProperty.call(this.handlers, 'opik')) { + const tracer: Tracer | undefined = this.handlers['opik'].client + const rootSpan: Span | undefined = this.handlers['opik'].rootSpan + + const rootSpanContext = rootSpan + ? opentelemetry.trace.setSpan(opentelemetry.context.active(), rootSpan as Span) + : opentelemetry.context.active() + const llmSpan = tracer?.startSpan(name, undefined, rootSpanContext) + if (llmSpan) { + llmSpan.setAttribute('openinference.span.kind', 'LLM') + llmSpan.setAttribute('input.value', JSON.stringify(input)) + llmSpan.setAttribute('input.mime_type', 'application/json') + } + const llmSpanId: any = llmSpan?.spanContext().spanId + + this.handlers['opik'].llmSpan = { [llmSpanId]: llmSpan } + returnIds['opik'].llmSpan = llmSpanId + } + return returnIds } @@ -1197,6 +1346,16 @@ export class AnalyticHandler { llmSpan.end() } } + + if (Object.prototype.hasOwnProperty.call(this.handlers, 'opik')) { + const llmSpan: Span | undefined = this.handlers['opik'].llmSpan[returnIds['opik'].llmSpan] + if (llmSpan) { + llmSpan.setAttribute('output.value', JSON.stringify(output)) + llmSpan.setAttribute('output.mime_type', 'application/json') + llmSpan.setStatus({ code: SpanStatusCode.OK }) + llmSpan.end() + } + } } async onLLMError(returnIds: ICommonObject, error: string | object) { @@ -1261,6 +1420,16 @@ export class AnalyticHandler { llmSpan.end() } } + + if (Object.prototype.hasOwnProperty.call(this.handlers, 'opik')) { + const llmSpan: Span | undefined = this.handlers['opik'].llmSpan[returnIds['opik'].llmSpan] + if (llmSpan) { + llmSpan.setAttribute('error.value', JSON.stringify(error)) + llmSpan.setAttribute('error.mime_type', 'application/json') + llmSpan.setStatus({ code: SpanStatusCode.ERROR, message: error.toString() }) + llmSpan.end() + } + } } async onToolStart(name: string, input: string | object, parentIds: ICommonObject) { @@ -1270,7 +1439,8 @@ export class AnalyticHandler { lunary: {}, langWatch: {}, arize: {}, - phoenix: {} + phoenix: {}, + opik: {} } if (Object.prototype.hasOwnProperty.call(this.handlers, 'langSmith')) { @@ -1369,6 +1539,25 @@ export class AnalyticHandler { returnIds['phoenix'].toolSpan = toolSpanId } + if (Object.prototype.hasOwnProperty.call(this.handlers, 'opik')) { + const tracer: Tracer | undefined = this.handlers['opik'].client + const rootSpan: Span | undefined = this.handlers['opik'].rootSpan + + const rootSpanContext = rootSpan + ? opentelemetry.trace.setSpan(opentelemetry.context.active(), rootSpan as Span) + : opentelemetry.context.active() + const toolSpan = tracer?.startSpan(name, undefined, rootSpanContext) + if (toolSpan) { + toolSpan.setAttribute('openinference.span.kind', 'TOOL') + toolSpan.setAttribute('input.value', JSON.stringify(input)) + toolSpan.setAttribute('input.mime_type', 'application/json') + } + const toolSpanId: any = toolSpan?.spanContext().spanId + + this.handlers['opik'].toolSpan = { [toolSpanId]: toolSpan } + returnIds['opik'].toolSpan = toolSpanId + } + return returnIds } @@ -1434,6 +1623,16 @@ export class AnalyticHandler { toolSpan.end() } } + + if (Object.prototype.hasOwnProperty.call(this.handlers, 'opik')) { + const toolSpan: Span | undefined = this.handlers['opik'].toolSpan[returnIds['opik'].toolSpan] + if (toolSpan) { + toolSpan.setAttribute('output.value', JSON.stringify(output)) + toolSpan.setAttribute('output.mime_type', 'application/json') + toolSpan.setStatus({ code: SpanStatusCode.OK }) + toolSpan.end() + } + } } async onToolError(returnIds: ICommonObject, error: string | object) { @@ -1498,6 +1697,16 @@ export class AnalyticHandler { toolSpan.end() } } + + if (Object.prototype.hasOwnProperty.call(this.handlers, 'opik')) { + const toolSpan: Span | undefined = this.handlers['opik'].toolSpan[returnIds['opik'].toolSpan] + if (toolSpan) { + toolSpan.setAttribute('error.value', JSON.stringify(error)) + toolSpan.setAttribute('error.mime_type', 'application/json') + toolSpan.setStatus({ code: SpanStatusCode.ERROR, message: error.toString() }) + toolSpan.end() + } + } } } diff --git a/packages/ui/src/assets/images/opik.png b/packages/ui/src/assets/images/opik.png new file mode 100644 index 0000000000000000000000000000000000000000..20de0c39d47047636a513d4f2fa07e793f2d89a5 GIT binary patch literal 10427 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 WPODC*Pk@&ai5_X_Kd4fNMg1Q*ER^~H literal 0 HcmV?d00001 diff --git a/packages/ui/src/ui-component/extended/AnalyseFlow.jsx b/packages/ui/src/ui-component/extended/AnalyseFlow.jsx index d9001368e..de162e51a 100644 --- a/packages/ui/src/ui-component/extended/AnalyseFlow.jsx +++ b/packages/ui/src/ui-component/extended/AnalyseFlow.jsx @@ -30,6 +30,7 @@ import lunarySVG from '@/assets/images/lunary.svg' import langwatchSVG from '@/assets/images/langwatch.svg' import arizePNG from '@/assets/images/arize.png' import phoenixPNG from '@/assets/images/phoenix.png' +import opikPNG from '@/assets/images/opik.png' // store import useNotifier from '@/utils/useNotifier' @@ -188,6 +189,33 @@ const analyticProviders = [ optional: true } ] + }, + { + label: 'Opik', + name: 'opik', + icon: opikPNG, + url: 'https://www.comet.com/opik', + inputs: [ + { + label: 'Connect Credential', + name: 'credential', + type: 'credential', + credentialNames: ['opikApi'] + }, + { + label: 'Project Name', + name: 'opikProjectName', + type: 'string', + description: 'Name of your Opik project', + placeholder: 'default' + }, + { + label: 'On/Off', + name: 'status', + type: 'boolean', + optional: true + } + ] } ]