From 6cec141acc07eae4e890e951cee38bdf3831c50b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BD=97=E5=A8=81?= Date: Fri, 23 Aug 2024 14:54:44 +0800 Subject: [PATCH 1/3] langfuser add view button --- api/core/ops/entities/config_entity.py | 1 + api/core/ops/langfuse_trace/langfuse_trace.py | 8 +++++ api/core/ops/ops_trace_manager.py | 16 +++++++-- api/services/ops_service.py | 11 +++++- .../overview/tracing/provider-panel.tsx | 32 +++++++++++++---- .../icons/assets/vender/line/general/view.svg | 4 +++ .../icons/src/vender/line/general/View.json | 36 +++++++++++++++++++ .../icons/src/vender/line/general/View.tsx | 16 +++++++++ .../icons/src/vender/line/general/index.ts | 1 + 9 files changed, 115 insertions(+), 10 deletions(-) create mode 100644 web/app/components/base/icons/assets/vender/line/general/view.svg create mode 100644 web/app/components/base/icons/src/vender/line/general/View.json create mode 100644 web/app/components/base/icons/src/vender/line/general/View.tsx diff --git a/api/core/ops/entities/config_entity.py b/api/core/ops/entities/config_entity.py index 221e6239ab9302..447f668e26557a 100644 --- a/api/core/ops/entities/config_entity.py +++ b/api/core/ops/entities/config_entity.py @@ -21,6 +21,7 @@ class LangfuseConfig(BaseTracingConfig): """ public_key: str secret_key: str + project_key: str host: str = 'https://api.langfuse.com' @field_validator("host") diff --git a/api/core/ops/langfuse_trace/langfuse_trace.py b/api/core/ops/langfuse_trace/langfuse_trace.py index 698398e0cb8c16..a21c67ed503da6 100644 --- a/api/core/ops/langfuse_trace/langfuse_trace.py +++ b/api/core/ops/langfuse_trace/langfuse_trace.py @@ -419,3 +419,11 @@ def api_check(self): except Exception as e: logger.debug(f"LangFuse API check failed: {str(e)}") raise ValueError(f"LangFuse API check failed: {str(e)}") + + def get_project_key(self): + try: + projects = self.langfuse_client.client.projects.get() + return projects.data[0].id + except Exception as e: + logger.debug(f"LangFuse get project key failed: {str(e)}") + raise ValueError(f"LangFuse get project key failed: {str(e)}") diff --git a/api/core/ops/ops_trace_manager.py b/api/core/ops/ops_trace_manager.py index 068b490ec887bd..1416d6bd2d6685 100644 --- a/api/core/ops/ops_trace_manager.py +++ b/api/core/ops/ops_trace_manager.py @@ -38,7 +38,7 @@ TracingProviderEnum.LANGFUSE.value: { 'config_class': LangfuseConfig, 'secret_keys': ['public_key', 'secret_key'], - 'other_keys': ['host'], + 'other_keys': ['host', 'project_key'], 'trace_instance': LangFuseDataTrace }, TracingProviderEnum.LANGSMITH.value: { @@ -123,7 +123,6 @@ def obfuscated_decrypt_token(cls, tracing_provider: str, decrypt_tracing_config: for key in other_keys: new_config[key] = decrypt_tracing_config.get(key, "") - return config_class(**new_config).model_dump() @classmethod @@ -252,6 +251,19 @@ def check_trace_config_is_effective(tracing_config: dict, tracing_provider: str) tracing_config = config_type(**tracing_config) return trace_instance(tracing_config).api_check() + @staticmethod + def get_trace_config_project_key(tracing_config: dict, tracing_provider: str): + """ + get trace config is project key + :param tracing_config: tracing config + :param tracing_provider: tracing provider + :return: + """ + config_type, trace_instance = provider_config_map[tracing_provider]['config_class'], \ + provider_config_map[tracing_provider]['trace_instance'] + tracing_config = config_type(**tracing_config) + return trace_instance(tracing_config).get_project_key() + class TraceTask: def __init__( diff --git a/api/services/ops_service.py b/api/services/ops_service.py index ffc12a9acdb42c..7b2edcf7cb26d0 100644 --- a/api/services/ops_service.py +++ b/api/services/ops_service.py @@ -22,6 +22,10 @@ def get_tracing_app_config(cls, app_id: str, tracing_provider: str): # decrypt_token and obfuscated_token tenant_id = db.session.query(App).filter(App.id == app_id).first().tenant_id decrypt_tracing_config = OpsTraceManager.decrypt_tracing_config(tenant_id, tracing_provider, trace_config_data.tracing_config) + if tracing_provider == 'langfuse' and ('project_key' not in decrypt_tracing_config or not decrypt_tracing_config.get('project_key')): + project_key = OpsTraceManager.get_trace_config_project_key(decrypt_tracing_config, tracing_provider) + decrypt_tracing_config['project_key'] = project_key + decrypt_tracing_config = OpsTraceManager.obfuscated_decrypt_token(tracing_provider, decrypt_tracing_config) trace_config_data.tracing_config = decrypt_tracing_config @@ -37,7 +41,7 @@ def create_tracing_app_config(cls, app_id: str, tracing_provider: str, tracing_c :param tracing_config: tracing config :return: """ - if tracing_provider not in provider_config_map.keys() and tracing_provider != None: + if tracing_provider not in provider_config_map.keys() and tracing_provider: return {"error": f"Invalid tracing provider: {tracing_provider}"} config_class, other_keys = provider_config_map[tracing_provider]['config_class'], \ @@ -51,6 +55,9 @@ def create_tracing_app_config(cls, app_id: str, tracing_provider: str, tracing_c if not OpsTraceManager.check_trace_config_is_effective(tracing_config, tracing_provider): return {"error": "Invalid Credentials"} + # get project key + project_key = OpsTraceManager.get_trace_config_project_key(tracing_config, tracing_provider) + # check if trace config already exists trace_config_data: TraceAppConfig = db.session.query(TraceAppConfig).filter( TraceAppConfig.app_id == app_id, TraceAppConfig.tracing_provider == tracing_provider @@ -62,6 +69,8 @@ def create_tracing_app_config(cls, app_id: str, tracing_provider: str, tracing_c # get tenant id tenant_id = db.session.query(App).filter(App.id == app_id).first().tenant_id tracing_config = OpsTraceManager.encrypt_tracing_config(tenant_id, tracing_provider, tracing_config) + if tracing_provider == 'langfuse': + tracing_config['project_key'] = project_key trace_config_data = TraceAppConfig( app_id=app_id, tracing_provider=tracing_provider, diff --git a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/provider-panel.tsx b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/provider-panel.tsx index 120fe29dff0f01..e54455690e4762 100644 --- a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/provider-panel.tsx +++ b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/provider-panel.tsx @@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next' import { TracingProvider } from './type' import cn from '@/utils/classnames' import { LangfuseIconBig, LangsmithIconBig } from '@/app/components/base/icons/src/public/tracing' -import { Settings04 } from '@/app/components/base/icons/src/vender/line/general' +import { Settings04, View } from '@/app/components/base/icons/src/vender/line/general' const I18N_PREFIX = 'app.tracing' @@ -13,6 +13,7 @@ type Props = { type: TracingProvider readOnly: boolean isChosen: boolean + Config: any onChoose: () => void hasConfigured: boolean onConfig: () => void @@ -29,6 +30,7 @@ const ProviderPanel: FC = ({ type, readOnly, isChosen, + Config, onChoose, hasConfigured, onConfig, @@ -41,6 +43,14 @@ const ProviderPanel: FC = ({ onConfig() }, [onConfig]) + const viewBtnClick = useCallback((e: React.MouseEvent) => { + e.preventDefault() + e.stopPropagation() + + const url = `${Config?.host}/project/${Config?.project_key}` + window.open(url, '_blank', 'noopener,noreferrer') + }, [Config?.host, Config?.project_key]) + const handleChosen = useCallback((e: React.MouseEvent) => { e.stopPropagation() if (isChosen || !hasConfigured || readOnly) @@ -58,12 +68,20 @@ const ProviderPanel: FC = ({ {isChosen &&
{t(`${I18N_PREFIX}.inUse`)}
} {!readOnly && ( -
- -
{t(`${I18N_PREFIX}.config`)}
+
+ {hasConfigured && ( +
+ +
{t(`${I18N_PREFIX}.view`)}
+
+ )} +
+ +
{t(`${I18N_PREFIX}.config`)}
+
)} diff --git a/web/app/components/base/icons/assets/vender/line/general/view.svg b/web/app/components/base/icons/assets/vender/line/general/view.svg new file mode 100644 index 00000000000000..5c3b28d59e59f5 --- /dev/null +++ b/web/app/components/base/icons/assets/vender/line/general/view.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/web/app/components/base/icons/src/vender/line/general/View.json b/web/app/components/base/icons/src/vender/line/general/View.json new file mode 100644 index 00000000000000..46d43e021fb58c --- /dev/null +++ b/web/app/components/base/icons/src/vender/line/general/View.json @@ -0,0 +1,36 @@ +{ + "icon": { + "type": "element", + "isRootNode": true, + "name": "svg", + "attributes": { + "class": "icon", + "viewBox": "0 0 1024 1024", + "version": "1.1", + "xmlns": "http://www.w3.org/2000/svg", + "xmlns:xlink": "http://www.w3.org/1999/xlink", + "width": "200", + "height": "200", + "opacity": "0.5" + }, + "children": [ + { + "type": "element", + "name": "path", + "attributes": { + "d": "M999.722667 449.024C886.912 324.864 699.733333 193.621333 512 196.266667 324.266667 193.578667 137.088 324.906667 24.234667 449.024a94.336 94.336 0 0 0 0 125.781333C135.722667 697.642667 320.298667 827.733333 505.130667 827.733333h13.141333c185.472 0 369.962667-130.090667 481.578667-252.970666a94.293333 94.293333 0 0 0-0.128-125.738667zM315.733333 512a196.266667 196.266667 0 1 1 196.266667 196.266667A196.266667 196.266667 0 0 1 315.733333 512z" + }, + "children": [] + }, + { + "type": "element", + "name": "path", + "attributes": { + "d": "M512 512m-85.333333 0a85.333333 85.333333 0 1 0 170.666666 0 85.333333 85.333333 0 1 0-170.666666 0Z" + }, + "children": [] + } + ] + }, + "name": "View" +} \ No newline at end of file diff --git a/web/app/components/base/icons/src/vender/line/general/View.tsx b/web/app/components/base/icons/src/vender/line/general/View.tsx new file mode 100644 index 00000000000000..9313d01e1f20e2 --- /dev/null +++ b/web/app/components/base/icons/src/vender/line/general/View.tsx @@ -0,0 +1,16 @@ +// GENERATE BY script +// DON NOT EDIT IT MANUALLY + +import * as React from 'react' +import data from './View.json' +import IconBase from '@/app/components/base/icons/IconBase' +import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase' + +const Icon = React.forwardRef, Omit>(( + props, + ref, +) => ) + +Icon.displayName = 'View' + +export default Icon diff --git a/web/app/components/base/icons/src/vender/line/general/index.ts b/web/app/components/base/icons/src/vender/line/general/index.ts index c1af2e49948a41..e028e213a06866 100644 --- a/web/app/components/base/icons/src/vender/line/general/index.ts +++ b/web/app/components/base/icons/src/vender/line/general/index.ts @@ -23,4 +23,5 @@ export { default as Settings04 } from './Settings04' export { default as Target04 } from './Target04' export { default as Upload03 } from './Upload03' export { default as UploadCloud01 } from './UploadCloud01' +export { default as View } from './View' export { default as X } from './X' From ed90b091ab430cce737a9bd0b7374e4b928a33de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BD=97=E5=A8=81?= Date: Fri, 23 Aug 2024 15:00:47 +0800 Subject: [PATCH 2/3] add langfuser view language --- web/i18n/en-US/app.ts | 1 + web/i18n/zh-Hans/app.ts | 1 + web/i18n/zh-Hant/app.ts | 1 + 3 files changed, 3 insertions(+) diff --git a/web/i18n/en-US/app.ts b/web/i18n/en-US/app.ts index 39b47c8eb4e513..90724098de1bb6 100644 --- a/web/i18n/en-US/app.ts +++ b/web/i18n/en-US/app.ts @@ -95,6 +95,7 @@ const translation = { title: 'Tracing app performance', description: 'Configuring a Third-Party LLMOps provider and tracing app performance.', config: 'Config', + view: 'View', collapse: 'Collapse', expand: 'Expand', tracing: 'Tracing', diff --git a/web/i18n/zh-Hans/app.ts b/web/i18n/zh-Hans/app.ts index 6703e1ca95a8ae..e12ed1b35d7d25 100644 --- a/web/i18n/zh-Hans/app.ts +++ b/web/i18n/zh-Hans/app.ts @@ -94,6 +94,7 @@ const translation = { title: '追踪应用性能', description: '配置第三方 LLMOps 提供商并跟踪应用程序性能。', config: '配置', + view: '查看', collapse: '折叠', expand: '展开', tracing: '追踪', diff --git a/web/i18n/zh-Hant/app.ts b/web/i18n/zh-Hant/app.ts index 4b915b7f2d4e45..ff162c5b612f3d 100644 --- a/web/i18n/zh-Hant/app.ts +++ b/web/i18n/zh-Hant/app.ts @@ -90,6 +90,7 @@ const translation = { title: '追蹤應用程式效能', description: '配置第三方LLMOps提供商並追蹤應用程式效能。', config: '配置', + view: '查看', collapse: '收起', expand: '展開', tracing: '追蹤', From ff72fe212b64d9c049efa80c33d2aa878436e45b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BD=97=E5=A8=81?= Date: Fri, 23 Aug 2024 15:27:15 +0800 Subject: [PATCH 3/3] Optimize icon reference --- .../overview/tracing/provider-panel.tsx | 3 +- .../icons/assets/vender/line/general/view.svg | 4 --- .../icons/src/vender/line/general/View.json | 36 ------------------- .../icons/src/vender/line/general/View.tsx | 16 --------- .../icons/src/vender/line/general/index.ts | 1 - 5 files changed, 2 insertions(+), 58 deletions(-) delete mode 100644 web/app/components/base/icons/assets/vender/line/general/view.svg delete mode 100644 web/app/components/base/icons/src/vender/line/general/View.json delete mode 100644 web/app/components/base/icons/src/vender/line/general/View.tsx diff --git a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/provider-panel.tsx b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/provider-panel.tsx index e54455690e4762..4a395860648601 100644 --- a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/provider-panel.tsx +++ b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/provider-panel.tsx @@ -5,7 +5,8 @@ import { useTranslation } from 'react-i18next' import { TracingProvider } from './type' import cn from '@/utils/classnames' import { LangfuseIconBig, LangsmithIconBig } from '@/app/components/base/icons/src/public/tracing' -import { Settings04, View } from '@/app/components/base/icons/src/vender/line/general' +import { Settings04 } from '@/app/components/base/icons/src/vender/line/general' +import { Eye as View } from '@/app/components/base/icons/src/vender/solid/general' const I18N_PREFIX = 'app.tracing' diff --git a/web/app/components/base/icons/assets/vender/line/general/view.svg b/web/app/components/base/icons/assets/vender/line/general/view.svg deleted file mode 100644 index 5c3b28d59e59f5..00000000000000 --- a/web/app/components/base/icons/assets/vender/line/general/view.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/web/app/components/base/icons/src/vender/line/general/View.json b/web/app/components/base/icons/src/vender/line/general/View.json deleted file mode 100644 index 46d43e021fb58c..00000000000000 --- a/web/app/components/base/icons/src/vender/line/general/View.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "icon": { - "type": "element", - "isRootNode": true, - "name": "svg", - "attributes": { - "class": "icon", - "viewBox": "0 0 1024 1024", - "version": "1.1", - "xmlns": "http://www.w3.org/2000/svg", - "xmlns:xlink": "http://www.w3.org/1999/xlink", - "width": "200", - "height": "200", - "opacity": "0.5" - }, - "children": [ - { - "type": "element", - "name": "path", - "attributes": { - "d": "M999.722667 449.024C886.912 324.864 699.733333 193.621333 512 196.266667 324.266667 193.578667 137.088 324.906667 24.234667 449.024a94.336 94.336 0 0 0 0 125.781333C135.722667 697.642667 320.298667 827.733333 505.130667 827.733333h13.141333c185.472 0 369.962667-130.090667 481.578667-252.970666a94.293333 94.293333 0 0 0-0.128-125.738667zM315.733333 512a196.266667 196.266667 0 1 1 196.266667 196.266667A196.266667 196.266667 0 0 1 315.733333 512z" - }, - "children": [] - }, - { - "type": "element", - "name": "path", - "attributes": { - "d": "M512 512m-85.333333 0a85.333333 85.333333 0 1 0 170.666666 0 85.333333 85.333333 0 1 0-170.666666 0Z" - }, - "children": [] - } - ] - }, - "name": "View" -} \ No newline at end of file diff --git a/web/app/components/base/icons/src/vender/line/general/View.tsx b/web/app/components/base/icons/src/vender/line/general/View.tsx deleted file mode 100644 index 9313d01e1f20e2..00000000000000 --- a/web/app/components/base/icons/src/vender/line/general/View.tsx +++ /dev/null @@ -1,16 +0,0 @@ -// GENERATE BY script -// DON NOT EDIT IT MANUALLY - -import * as React from 'react' -import data from './View.json' -import IconBase from '@/app/components/base/icons/IconBase' -import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase' - -const Icon = React.forwardRef, Omit>(( - props, - ref, -) => ) - -Icon.displayName = 'View' - -export default Icon diff --git a/web/app/components/base/icons/src/vender/line/general/index.ts b/web/app/components/base/icons/src/vender/line/general/index.ts index e028e213a06866..c1af2e49948a41 100644 --- a/web/app/components/base/icons/src/vender/line/general/index.ts +++ b/web/app/components/base/icons/src/vender/line/general/index.ts @@ -23,5 +23,4 @@ export { default as Settings04 } from './Settings04' export { default as Target04 } from './Target04' export { default as Upload03 } from './Upload03' export { default as UploadCloud01 } from './UploadCloud01' -export { default as View } from './View' export { default as X } from './X'