update aliyun trace

pull/21471/head
hieheihei 1 year ago
parent f65c2fcb1d
commit 2806edb70b

@ -1,4 +1,3 @@
import os
import sys
@ -17,20 +16,20 @@ else:
# It seems that JetBrains Python debugger does not work well with gevent,
# so we need to disable gevent in debug mode.
# If you are using debugpy and set GEVENT_SUPPORT=True, you can debug with gevent.
if (flask_debug := os.environ.get("FLASK_DEBUG", "0")) and flask_debug.lower() in {"false", "0", "no"}:
from gevent import monkey
# gevent
monkey.patch_all()
from grpc.experimental import gevent as grpc_gevent # type: ignore
# grpc gevent
grpc_gevent.init_gevent()
import psycogreen.gevent # type: ignore
psycogreen.gevent.patch_psycopg()
# if (flask_debug := os.environ.get("FLASK_DEBUG", "0")) and flask_debug.lower() in {"false", "0", "no"}:
# from gevent import monkey
#
# # gevent
# monkey.patch_all()
#
# from grpc.experimental import gevent as grpc_gevent # type: ignore
#
# # grpc gevent
# grpc_gevent.init_gevent()
#
# import psycogreen.gevent # type: ignore
#
# psycogreen.gevent.patch_psycopg()
from app_factory import create_app

@ -0,0 +1,192 @@
import datetime
import json
import uuid
from typing import Optional
from core.ops.aliyun_trace.data_exporter.traceclient import TraceClient
from core.ops.aliyun_trace.entities.aliyun_trace_entity import SpanData
from core.ops.base_trace_instance import BaseTraceInstance
from core.ops.entities.config_entity import AliyunConfig
from core.ops.entities.trace_entity import (
BaseTraceInfo,
DatasetRetrievalTraceInfo,
GenerateNameTraceInfo,
MessageTraceInfo,
ModerationTraceInfo,
SuggestedQuestionTraceInfo,
ToolTraceInfo,
WorkflowTraceInfo,
)
from models import EndUser, db
def convert_to_trace_id(uuid_v4:str) -> int:
try:
uuid_obj = uuid.UUID(uuid_v4)
return uuid_obj.int
except Exception as e:
raise ValueError(f"Invalid UUID input: {e}")
def convert_to_span_id(uuid_v4:str, span_type:str) -> int:
try:
uuid_obj = uuid.UUID(uuid_v4)
except Exception as e:
raise ValueError(f"Invalid UUID input: {e}")
type_hash = hash(span_type) & 0xFFFFFFFFFFFFFFFF
span_id = (uuid_obj.int & 0xFFFFFFFFFFFFFFFF) ^ type_hash
return span_id
def convert_datetime_to_nanoseconds(start_time_a: Optional[datetime]) -> Optional[int]:
if start_time_a is None:
return None
timestamp_in_seconds = start_time_a.timestamp()
timestamp_in_nanoseconds = int(timestamp_in_seconds * 1e9)
return timestamp_in_nanoseconds
class AliyunDataTrace(BaseTraceInstance):
def __init__(
self,
aliyun_config: AliyunConfig,
):
super().__init__(aliyun_config)
endpoint = aliyun_config.endpoint+aliyun_config.license_key+'/api/otlp/traces'
self.trace_client = TraceClient(service_name=aliyun_config.app_name,endpoint=endpoint)
def trace(self, trace_info: BaseTraceInfo):
if isinstance(trace_info, WorkflowTraceInfo):
self.workflow_trace(trace_info)
if isinstance(trace_info, MessageTraceInfo):
self.message_trace(trace_info)
if isinstance(trace_info, ModerationTraceInfo):
pass
if isinstance(trace_info, SuggestedQuestionTraceInfo):
pass
if isinstance(trace_info, DatasetRetrievalTraceInfo):
self.dataset_retrieval_trace(trace_info)
if isinstance(trace_info, ToolTraceInfo):
self.tool_trace(trace_info)
if isinstance(trace_info, GenerateNameTraceInfo):
pass
def api_check(self):
# todo
return True
def workflow_trace(self, trace_info: WorkflowTraceInfo):
pass
def message_trace(self, trace_info: MessageTraceInfo):
# get message file data
file_list = trace_info.file_list
metadata = trace_info.metadata
message_data = trace_info.message_data
if message_data is None:
return
message_id = trace_info.message_id
user_id = message_data.from_account_id
if message_data.from_end_user_id:
end_user_data: Optional[EndUser] = (
db.session.query(EndUser).filter(EndUser.id == message_data.from_end_user_id).first()
)
if end_user_data is not None:
user_id = end_user_data.session_id
message_span = SpanData(
trace_id=convert_to_trace_id(message_id),
parent_span_id=None,
span_id=convert_to_span_id(message_id,'message'),
name='message',
start_time=convert_datetime_to_nanoseconds(trace_info.start_time),
end_time=convert_datetime_to_nanoseconds(trace_info.end_time),
attributes={
'gen_ai.session.id': trace_info.metadata.get('conversation_id',''),
'gen_ai.user.id':str(user_id),
'gen_ai.span.kind':'CHAIN',
'gen_ai.framework': 'dify',
'input.value':json.dumps(trace_info.inputs),
'output.value': str(trace_info.outputs),
}
)
self.trace_client.add_span(message_span)
llm_span = SpanData(
trace_id=convert_to_trace_id(message_id),
parent_span_id=convert_to_span_id(message_id,'message'),
span_id=convert_to_span_id(message_id,'llm'),
name='llm',
start_time=convert_datetime_to_nanoseconds(trace_info.start_time),
end_time=convert_datetime_to_nanoseconds(trace_info.end_time),
attributes={
'gen_ai.session.id': trace_info.metadata.get('conversation_id',''),
'gen_ai.user.id': str(user_id),
'gen_ai.span.kind':'LLM',
'gen_ai.framework': 'dify',
'gen_ai.prompt_template.template': 'todo',
'gen_ai.model_name':trace_info.message_data.model_id,
'input.value':json.dumps(trace_info.inputs),
'output.value': str(trace_info.outputs),
}
)
self.trace_client.add_span(llm_span)
def dataset_retrieval_trace(self, trace_info: DatasetRetrievalTraceInfo):
if trace_info.message_data is None:
return
message_id = trace_info.message_id
span_data = SpanData(
trace_id=convert_to_trace_id(message_id),
parent_span_id=convert_to_span_id(message_id,'message'),
span_id=convert_to_span_id(message_id,'dataset_retrieval'),
name='dataset_retrieval',
start_time=convert_datetime_to_nanoseconds(trace_info.start_time),
end_time=convert_datetime_to_nanoseconds(trace_info.end_time),
attributes={
'gen_ai.session.id': 'todo',
'gen_ai.user.id': 'todo',
'gen_ai.span.kind': 'RETRIEVER',
'gen_ai.framework': 'dify',
'gen_ai.operation.name': 'TASK',
'retrieval.query':str(trace_info.inputs),
'retrieval.document ':str(trace_info.documents)
}
)
self.trace_client.add_span(span_data)
def tool_trace(self, trace_info: ToolTraceInfo):
if trace_info.message_data is None:
return
message_id = trace_info.message_id
span_data = SpanData(
trace_id=convert_to_trace_id(message_id),
parent_span_id=convert_to_span_id(message_id,'message'),
span_id=convert_to_span_id(message_id,'tool'),
name='tool',
start_time=convert_datetime_to_nanoseconds(trace_info.start_time),
end_time=convert_datetime_to_nanoseconds(trace_info.end_time),
attributes={
'gen_ai.session.id': 'todo',
'gen_ai.user.id': 'todo',
'gen_ai.span.kind': 'Tool',
'gen_ai.framework': 'dify',
'tool.name': trace_info.tool_name,
'tool.description': trace_info.tool_name,
'tool.parameters': json.dumps(trace_info.tool_inputs),
'input.value': json.dumps(trace_info.inputs),
'output.value': str(trace_info.tool_outputs),
}
)
self.trace_client.add_span(span_data)

@ -0,0 +1,80 @@
import socket
from collections.abc import Sequence
from opentelemetry import trace as trace_api
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import ReadableSpan
from opentelemetry.sdk.util.instrumentation import InstrumentationScope
from opentelemetry.semconv.resource import ResourceAttributes
from configs import dify_config
from core.ops.aliyun_trace.entities.aliyun_trace_entity import SpanData
class TraceClient:
def __init__(self,service_name,endpoint):
self.endpoint = endpoint
self.resource = Resource(
attributes={
ResourceAttributes.SERVICE_NAME: service_name,
ResourceAttributes.SERVICE_VERSION: f"dify-{dify_config.CURRENT_VERSION}-{dify_config.COMMIT_SHA}",
ResourceAttributes.DEPLOYMENT_ENVIRONMENT: f"{dify_config.DEPLOY_ENV}-{dify_config.EDITION}",
ResourceAttributes.HOST_NAME: socket.gethostname(),
}
)
self.span_builder = SpanBuilder(self.resource)
self.exporter = OTLPSpanExporter(endpoint=endpoint)
def add_span(self,span_data:SpanData):
span:ReadableSpan = self.span_builder.build_span(span_data)
self.export([span])
def export(self,spans:Sequence[ReadableSpan]):
self.exporter.export(spans)
class SpanBuilder:
def __init__(self, resource):
self.resource = resource
self.instrumentation_scope = InstrumentationScope(
__name__,
"",
None,
None,
)
def build_span(self, span_data: SpanData) -> ReadableSpan:
span_context = trace_api.SpanContext(
trace_id=span_data.trace_id,
span_id=span_data.span_id,
is_remote=False,
trace_flags=trace_api.TraceFlags(trace_api.TraceFlags.SAMPLED),
trace_state=None,
)
parent_span_context = None
if span_data.parent_span_id is not None:
parent_span_context = trace_api.SpanContext(
trace_id=span_data.trace_id,
span_id=span_data.parent_span_id,
is_remote=False,
trace_flags=trace_api.TraceFlags(trace_api.TraceFlags.SAMPLED),
trace_state=None,
)
span = ReadableSpan(
name=span_data.name,
context=span_context,
parent=parent_span_context,
resource=self.resource,
attributes=span_data.attributes,
events=span_data.events,
links=span_data.links,
kind=trace_api.SpanKind.INTERNAL,
status=span_data.status,
start_time=span_data.start_time,
end_time=span_data.end_time,
instrumentation_scope=self.instrumentation_scope,
)
return span

@ -0,0 +1,21 @@
from collections.abc import Sequence
from typing import Optional
from opentelemetry import trace as trace_api
from opentelemetry.sdk.trace import Event, Status, StatusCode
from pydantic import BaseModel, Field
class SpanData(BaseModel):
model_config = {"arbitrary_types_allowed": True}
trace_id: int = Field(..., description="The unique identifier for the trace.")
parent_span_id: Optional[int] = Field(None, description="The ID of the parent span, if any.")
span_id: int = Field(..., description="The unique identifier for this span.")
name: str = Field(..., description="The name of the span.")
attributes: dict[str, str] = Field(default_factory=dict, description="Attributes associated with the span.")
events: Sequence[Event] = Field(default_factory=list, description="Events recorded in the span.")
links: Sequence[trace_api.Link] = Field(default_factory=list, description="Links to other spans.")
status: Status = Field(default=Status(StatusCode.UNSET), description="The status of the span.")
start_time: int = Field(..., description="The start time of the span in nanoseconds.")
end_time: int = Field(..., description="The end time of the span in nanoseconds.")

@ -8,6 +8,7 @@ class TracingProviderEnum(StrEnum):
LANGSMITH = "langsmith"
OPIK = "opik"
WEAVE = "weave"
ALIYUN = "aliyun"
class BaseTracingConfig(BaseModel):
@ -109,6 +110,15 @@ class WeaveConfig(BaseTracingConfig):
return v
class AliyunConfig(BaseTracingConfig):
"""
Model class for Aliyun tracing config.
"""
app_name: str = "dify_app"
license_key: str
endpoint: str
OPS_FILE_PATH = "ops_trace/"
OPS_TRACE_FAILED_KEY = "FAILED_OPS_TRACE"

@ -85,6 +85,17 @@ class OpsTraceProviderConfigMap(dict[str, dict[str, Any]]):
"trace_instance": WeaveDataTrace,
}
case TracingProviderEnum.ALIYUN:
from core.ops.aliyun_trace.aliyun_trace import AliyunDataTrace
from core.ops.entities.config_entity import AliyunConfig
return {
"config_class": AliyunConfig,
"secret_keys": ["license_key"],
"other_keys": ["endpoint","app_name"],
"trace_instance": AliyunDataTrace,
}
case _:
raise KeyError(f"Unsupported tracing provider: {provider}")

@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next'
import { useBoolean } from 'ahooks'
import TracingIcon from './tracing-icon'
import ProviderPanel from './provider-panel'
import type { LangFuseConfig, LangSmithConfig, OpikConfig, WeaveConfig } from './type'
import type { AliyunConfig, LangFuseConfig, LangSmithConfig, OpikConfig, WeaveConfig } from './type'
import { TracingProvider } from './type'
import ProviderConfigModal from './provider-config-modal'
import Indicator from '@/app/components/header/indicator'
@ -27,7 +27,8 @@ export type PopupProps = {
langFuseConfig: LangFuseConfig | null
opikConfig: OpikConfig | null
weaveConfig: WeaveConfig | null
onConfigUpdated: (provider: TracingProvider, payload: LangSmithConfig | LangFuseConfig | OpikConfig | WeaveConfig) => void
aliyunConfig: AliyunConfig | null
onConfigUpdated: (provider: TracingProvider, payload: LangSmithConfig | LangFuseConfig | OpikConfig | WeaveConfig | AliyunConfig) => void
onConfigRemoved: (provider: TracingProvider) => void
}
@ -42,6 +43,7 @@ const ConfigPopup: FC<PopupProps> = ({
langFuseConfig,
opikConfig,
weaveConfig,
aliyunConfig,
onConfigUpdated,
onConfigRemoved,
}) => {
@ -65,7 +67,7 @@ const ConfigPopup: FC<PopupProps> = ({
}
}, [onChooseProvider])
const handleConfigUpdated = useCallback((payload: LangSmithConfig | LangFuseConfig | OpikConfig | WeaveConfig) => {
const handleConfigUpdated = useCallback((payload: LangSmithConfig | LangFuseConfig | OpikConfig | WeaveConfig | AliyunConfig) => {
onConfigUpdated(currentProvider!, payload)
hideConfigModal()
}, [currentProvider, hideConfigModal, onConfigUpdated])
@ -75,8 +77,8 @@ const ConfigPopup: FC<PopupProps> = ({
hideConfigModal()
}, [currentProvider, hideConfigModal, onConfigRemoved])
const providerAllConfigured = langSmithConfig && langFuseConfig && opikConfig && weaveConfig
const providerAllNotConfigured = !langSmithConfig && !langFuseConfig && !opikConfig && !weaveConfig
const providerAllConfigured = langSmithConfig && langFuseConfig && opikConfig && weaveConfig && aliyunConfig
const providerAllNotConfigured = !langSmithConfig && !langFuseConfig && !opikConfig && !weaveConfig && !aliyunConfig
const switchContent = (
<Switch
@ -137,6 +139,19 @@ const ConfigPopup: FC<PopupProps> = ({
key="weave-provider-panel"
/>
)
const aliyunPanel = (
<ProviderPanel
type={TracingProvider.aliyun}
readOnly={readOnly}
config={aliyunConfig}
hasConfigured={!!aliyunConfig}
onConfig={handleOnConfig(TracingProvider.aliyun)}
isChosen={chosenProvider === TracingProvider.aliyun}
onChoose={handleOnChoose(TracingProvider.aliyun)}
key="alyun-provider-panel"
/>
)
const configuredProviderPanel = () => {
const configuredPanels: JSX.Element[] = []
@ -152,6 +167,9 @@ const ConfigPopup: FC<PopupProps> = ({
if (weaveConfig)
configuredPanels.push(weavePanel)
if (aliyunConfig)
configuredPanels.push(aliyunPanel)
return configuredPanels
}
@ -170,6 +188,9 @@ const ConfigPopup: FC<PopupProps> = ({
if (!weaveConfig)
notConfiguredPanels.push(weavePanel)
if (!aliyunConfig)
notConfiguredPanels.push(aliyunPanel)
return notConfiguredPanels
}
@ -180,6 +201,8 @@ const ConfigPopup: FC<PopupProps> = ({
return langFuseConfig
if (currentProvider === TracingProvider.opik)
return opikConfig
if (currentProvider === TracingProvider.aliyun)
return aliyunConfig
return weaveConfig
}
@ -225,6 +248,7 @@ const ConfigPopup: FC<PopupProps> = ({
{langSmithPanel}
{opikPanel}
{weavePanel}
{aliyunPanel}
</div>
</>
)

@ -5,4 +5,5 @@ export const docURL = {
[TracingProvider.langfuse]: 'https://docs.langfuse.com',
[TracingProvider.opik]: 'https://www.comet.com/docs/opik/tracing/integrations/dify#setup-instructions',
[TracingProvider.weave]: 'https://weave-docs.wandb.ai/',
[TracingProvider.aliyun]: 'https://arms.console.aliyun.com/',
}

@ -1,18 +1,22 @@
'use client'
import type { FC } from 'react'
import React, { useCallback, useEffect, useState } from 'react'
import {
RiArrowDownDoubleLine,
} from '@remixicon/react'
import { RiArrowDownDoubleLine } from '@remixicon/react'
import { useTranslation } from 'react-i18next'
import { usePathname } from 'next/navigation'
import { useBoolean } from 'ahooks'
import type { LangFuseConfig, LangSmithConfig, OpikConfig, WeaveConfig } from './type'
import type { AliyunConfig, LangFuseConfig, LangSmithConfig, OpikConfig, WeaveConfig } from './type'
import { TracingProvider } from './type'
import TracingIcon from './tracing-icon'
import ConfigButton from './config-button'
import cn from '@/utils/classnames'
import { LangfuseIcon, LangsmithIcon, OpikIcon, WeaveIcon } from '@/app/components/base/icons/src/public/tracing'
import {
AliyunIcon,
LangfuseIcon,
LangsmithIcon,
OpikIcon,
WeaveIcon,
} from '@/app/components/base/icons/src/public/tracing'
import Indicator from '@/app/components/header/indicator'
import { fetchTracingConfig as doFetchTracingConfig, fetchTracingStatus, updateTracingStatus } from '@/service/apps'
import type { TracingStatus } from '@/models/app'
@ -84,13 +88,16 @@ const Panel: FC = () => {
? OpikIcon
: inUseTracingProvider === TracingProvider.weave
? WeaveIcon
: inUseTracingProvider === TracingProvider.aliyun
? AliyunIcon
: LangsmithIcon
const [langSmithConfig, setLangSmithConfig] = useState<LangSmithConfig | null>(null)
const [langFuseConfig, setLangFuseConfig] = useState<LangFuseConfig | null>(null)
const [opikConfig, setOpikConfig] = useState<OpikConfig | null>(null)
const [weaveConfig, setWeaveConfig] = useState<WeaveConfig | null>(null)
const hasConfiguredTracing = !!(langSmithConfig || langFuseConfig || opikConfig || weaveConfig)
const [aliyunConfig, setAliyunConfig] = useState<AliyunConfig | null>(null)
const hasConfiguredTracing = !!(langSmithConfig || langFuseConfig || opikConfig || weaveConfig || aliyunConfig)
const fetchTracingConfig = async () => {
const { tracing_config: langSmithConfig, has_not_configured: langSmithHasNotConfig } = await doFetchTracingConfig({ appId, provider: TracingProvider.langSmith })
@ -105,6 +112,9 @@ const Panel: FC = () => {
const { tracing_config: weaveConfig, has_not_configured: weaveHasNotConfig } = await doFetchTracingConfig({ appId, provider: TracingProvider.weave })
if (!weaveHasNotConfig)
setWeaveConfig(weaveConfig as WeaveConfig)
const { tracing_config: aliyunConfig, has_not_configured: aliyunHasNotConfig } = await doFetchTracingConfig({ appId, provider: TracingProvider.aliyun })
if (!aliyunHasNotConfig)
setAliyunConfig(aliyunConfig as AliyunConfig)
}
const handleTracingConfigUpdated = async (provider: TracingProvider) => {
@ -118,6 +128,8 @@ const Panel: FC = () => {
setOpikConfig(tracing_config as OpikConfig)
else if (provider === TracingProvider.weave)
setWeaveConfig(tracing_config as WeaveConfig)
else if (provider === TracingProvider.aliyun)
setAliyunConfig(tracing_config as AliyunConfig)
}
const handleTracingConfigRemoved = (provider: TracingProvider) => {
@ -129,6 +141,8 @@ const Panel: FC = () => {
setOpikConfig(null)
else if (provider === TracingProvider.weave)
setWeaveConfig(null)
else if (provider === TracingProvider.aliyun)
setAliyunConfig(null)
if (provider === inUseTracingProvider) {
handleTracingStatusChange({
enabled: false,
@ -189,6 +203,7 @@ const Panel: FC = () => {
langFuseConfig={langFuseConfig}
opikConfig={opikConfig}
weaveConfig={weaveConfig}
aliyunConfig={aliyunConfig}
onConfigUpdated={handleTracingConfigUpdated}
onConfigRemoved={handleTracingConfigRemoved}
controlShowPopup={controlShowPopup}
@ -224,6 +239,7 @@ const Panel: FC = () => {
langFuseConfig={langFuseConfig}
opikConfig={opikConfig}
weaveConfig={weaveConfig}
aliyunConfig={aliyunConfig}
onConfigUpdated={handleTracingConfigUpdated}
onConfigRemoved={handleTracingConfigRemoved}
controlShowPopup={controlShowPopup}

@ -4,7 +4,7 @@ import React, { useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useBoolean } from 'ahooks'
import Field from './field'
import type { LangFuseConfig, LangSmithConfig, OpikConfig, WeaveConfig } from './type'
import type { AliyunConfig, LangFuseConfig, LangSmithConfig, OpikConfig, WeaveConfig } from './type'
import { TracingProvider } from './type'
import { docURL } from './config'
import {
@ -22,10 +22,10 @@ import Divider from '@/app/components/base/divider'
type Props = {
appId: string
type: TracingProvider
payload?: LangSmithConfig | LangFuseConfig | OpikConfig | WeaveConfig | null
payload?: LangSmithConfig | LangFuseConfig | OpikConfig | WeaveConfig | AliyunConfig | null
onRemoved: () => void
onCancel: () => void
onSaved: (payload: LangSmithConfig | LangFuseConfig | OpikConfig | WeaveConfig) => void
onSaved: (payload: LangSmithConfig | LangFuseConfig | OpikConfig | WeaveConfig | AliyunConfig) => void
onChosen: (provider: TracingProvider) => void
}
@ -57,6 +57,12 @@ const weaveConfigTemplate = {
endpoint: '',
}
const aliyunConfigTemplate = {
app_name: '',
license_key: '',
endpoint: '',
}
const ProviderConfigModal: FC<Props> = ({
appId,
type,
@ -70,7 +76,7 @@ const ProviderConfigModal: FC<Props> = ({
const isEdit = !!payload
const isAdd = !isEdit
const [isSaving, setIsSaving] = useState(false)
const [config, setConfig] = useState<LangSmithConfig | LangFuseConfig | OpikConfig | WeaveConfig>((() => {
const [config, setConfig] = useState<LangSmithConfig | LangFuseConfig | OpikConfig | WeaveConfig | AliyunConfig>((() => {
if (isEdit)
return payload
@ -83,6 +89,9 @@ const ProviderConfigModal: FC<Props> = ({
else if (type === TracingProvider.opik)
return opikConfigTemplate
else if (type === TracingProvider.aliyun)
return aliyunConfigTemplate
return weaveConfigTemplate
})())
const [isShowRemoveConfirm, {
@ -145,6 +154,11 @@ const ProviderConfigModal: FC<Props> = ({
errorMessage = t('common.errorMsg.fieldRequired', { field: t(`${I18N_PREFIX}.project`) })
}
if (type === TracingProvider.aliyun) {
// todo: check
// const postData = config as AliyunConfig
}
return errorMessage
}, [config, t, type])
const handleSave = useCallback(async () => {
@ -194,6 +208,31 @@ const ProviderConfigModal: FC<Props> = ({
</div>
<div className='space-y-4'>
{type === TracingProvider.aliyun && (
<>
<Field
label='License Key'
labelClassName='!text-sm'
isRequired
value={(config as AliyunConfig).license_key}
onChange={handleConfigChange('license_key')}
placeholder={t(`${I18N_PREFIX}.placeholder`, { key: 'License Key' })!}
/>
<Field
label='Endpoint'
labelClassName='!text-sm'
value={(config as AliyunConfig).endpoint}
onChange={handleConfigChange('endpoint')}
placeholder={'https://arms.console.aliyun.com/'}
/>
<Field
label='App Name'
labelClassName='!text-sm'
value={(config as AliyunConfig).app_name}
onChange={handleConfigChange('app_name')}
/>
</>
)}
{type === TracingProvider.weave && (
<>
<Field

@ -7,7 +7,7 @@ import {
import { useTranslation } from 'react-i18next'
import { TracingProvider } from './type'
import cn from '@/utils/classnames'
import { LangfuseIconBig, LangsmithIconBig, OpikIconBig, WeaveIconBig } from '@/app/components/base/icons/src/public/tracing'
import { AliyunIconBig, LangfuseIconBig, LangsmithIconBig, OpikIconBig, WeaveIconBig } from '@/app/components/base/icons/src/public/tracing'
import { Eye as View } from '@/app/components/base/icons/src/vender/solid/general'
const I18N_PREFIX = 'app.tracing'
@ -28,6 +28,7 @@ const getIcon = (type: TracingProvider) => {
[TracingProvider.langfuse]: LangfuseIconBig,
[TracingProvider.opik]: OpikIconBig,
[TracingProvider.weave]: WeaveIconBig,
[TracingProvider.aliyun]: AliyunIconBig,
})[type]
}

@ -3,6 +3,7 @@ export enum TracingProvider {
langfuse = 'langfuse',
opik = 'opik',
weave = 'weave',
aliyun = 'aliyun',
}
export type LangSmithConfig = {
@ -30,3 +31,9 @@ export type WeaveConfig = {
project: string
endpoint: string
}
export type AliyunConfig = {
app_name: string
license_key: string
endpoint: string
}

@ -0,0 +1,7 @@
<svg width="800" height="600" xmlns="http://www.w3.org/2000/svg">
<g>
<title>Layer 1</title>
<text transform="matrix(5.69286 0 0 3.7385 -1737.67 -722.766)" stroke="#000" xml:space="preserve" text-anchor="start" font-family="Noto Sans JP" font-size="24" id="svg_2" y="285" x="369" stroke-width="0" fill="#000000">A</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 340 B

@ -0,0 +1,7 @@
<svg width="800" height="600" xmlns="http://www.w3.org/2000/svg">
<g>
<title>Layer 1</title>
<text transform="matrix(5.69286 0 0 3.7385 -1737.67 -722.766)" stroke="#000" xml:space="preserve" text-anchor="start" font-family="Noto Sans JP" font-size="24" id="svg_2" y="285" x="369" stroke-width="0" fill="#000000">A</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 340 B

@ -0,0 +1,18 @@
{
"icon": {
"type": "element",
"isRootNode": true,
"name": "svg",
"attributes": {
"xmlns": "http://www.w3.org/2000/svg",
"xmlns:xlink": "http://www.w3.org/1999/xlink",
"width": "120px",
"height": "16px",
"viewBox": "0 0 120 16",
"version": "1.1"
},
"children": [
]
},
"name": "WeaveIcon"
}

@ -0,0 +1,16 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './AliyunIcon.json'
import IconBase from '@/app/components/base/icons/IconBase'
import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase'
const Icon = React.forwardRef<React.MutableRefObject<SVGElement>, Omit<IconBaseProps, 'data'>>((
props,
ref,
) => <IconBase {...props} ref={ref} data={data as IconData} />)
Icon.displayName = 'AliyunIcon'
export default Icon

@ -0,0 +1,18 @@
{
"icon": {
"type": "element",
"isRootNode": true,
"name": "svg",
"attributes": {
"xmlns": "http://www.w3.org/2000/svg",
"xmlns:xlink": "http://www.w3.org/1999/xlink",
"width": "124px",
"height": "16px",
"viewBox": "0 0 120 16",
"version": "1.1"
},
"children": [
]
},
"name": "WeaveIconBig"
}

@ -0,0 +1,16 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './AliyunIconBig.json'
import IconBase from '@/app/components/base/icons/IconBase'
import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase'
const Icon = React.forwardRef<React.MutableRefObject<SVGElement>, Omit<IconBaseProps, 'data'>>((
props,
ref,
) => <IconBase {...props} ref={ref} data={data as IconData} />)
Icon.displayName = 'AliyunIconBig'
export default Icon

@ -7,3 +7,5 @@ export { default as OpikIcon } from './OpikIcon'
export { default as TracingIcon } from './TracingIcon'
export { default as WeaveIconBig } from './WeaveIconBig'
export { default as WeaveIcon } from './WeaveIcon'
export { default as AliyunIconBig } from './AliyunIconBig'
export { default as AliyunIcon } from './AliyunIcon'

@ -165,6 +165,10 @@ const translation = {
title: 'Weave',
description: 'Weave is an open-source platform for evaluating, testing, and monitoring LLM applications.',
},
cms: {
title: 'Aliyun',
description: 'Aliyun Demo',
},
inUse: 'In use',
configProvider: {
title: 'Config ',

@ -176,6 +176,10 @@ const translation = {
title: '编织',
description: 'Weave是一个开源平台用于评估、测试和监控大型语言模型应用程序。',
},
aliyun: {
title: '阿里云可观测',
description: '阿里云可观测 Demo',
},
},
appSelector: {
label: '应用',

@ -1,4 +1,4 @@
import type { LangFuseConfig, LangSmithConfig, OpikConfig, TracingProvider, WeaveConfig } from '@/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/type'
import type { AliyunConfig, LangFuseConfig, LangSmithConfig, OpikConfig, TracingProvider, WeaveConfig } from '@/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/type'
import type { App, AppTemplate, SiteConfig } from '@/types/app'
import type { Dependency } from '@/app/components/plugins/types'
@ -166,5 +166,5 @@ export type TracingStatus = {
export type TracingConfig = {
tracing_provider: TracingProvider
tracing_config: LangSmithConfig | LangFuseConfig | OpikConfig | WeaveConfig
tracing_config: LangSmithConfig | LangFuseConfig | OpikConfig | WeaveConfig | AliyunConfig
}

Loading…
Cancel
Save