Explorar o código

langfuser add view button (#7571)

Charlie.Wei hai 8 meses
pai
achega
9864b35465

+ 1 - 0
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")

+ 8 - 0
api/core/ops/langfuse_trace/langfuse_trace.py

@@ -419,3 +419,11 @@ class LangFuseDataTrace(BaseTraceInstance):
         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)}")

+ 14 - 2
api/core/ops/ops_trace_manager.py

@@ -38,7 +38,7 @@ provider_config_map = {
     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 @@ class OpsTraceManager:
 
         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 @@ class OpsTraceManager:
         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__(

+ 10 - 1
api/services/ops_service.py

@@ -22,6 +22,10 @@ class OpsService:
         # 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 @@ class OpsService:
         :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 @@ class OpsService:
         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 @@ class OpsService:
         # 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,

+ 25 - 6
web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/provider-panel.tsx

@@ -6,6 +6,7 @@ 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 { Eye as View } from '@/app/components/base/icons/src/vender/solid/general'
 
 const I18N_PREFIX = 'app.tracing'
 
@@ -13,6 +14,7 @@ type Props = {
   type: TracingProvider
   readOnly: boolean
   isChosen: boolean
+  Config: any
   onChoose: () => void
   hasConfigured: boolean
   onConfig: () => void
@@ -29,6 +31,7 @@ const ProviderPanel: FC<Props> = ({
   type,
   readOnly,
   isChosen,
+  Config,
   onChoose,
   hasConfigured,
   onConfig,
@@ -41,6 +44,14 @@ const ProviderPanel: FC<Props> = ({
     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 +69,20 @@ const ProviderPanel: FC<Props> = ({
           {isChosen && <div className='ml-1 flex items-center h-4  px-1 rounded-[4px] border border-primary-500 leading-4 text-xs font-medium text-primary-500 uppercase '>{t(`${I18N_PREFIX}.inUse`)}</div>}
         </div>
         {!readOnly && (
-          <div
-            className='flex px-2 items-center h-6 bg-white rounded-md border-[0.5px] border-gray-200 shadow-xs cursor-pointer text-gray-700 space-x-1'
-            onClick={handleConfigBtnClick}
-          >
-            <Settings04 className='w-3 h-3' />
-            <div className='text-xs font-medium'>{t(`${I18N_PREFIX}.config`)}</div>
+          <div className={'flex justify-between items-center space-x-1'}>
+            {hasConfigured && (
+              <div className='flex px-2 items-center h-6 bg-white rounded-md border-[0.5px] border-gray-200 shadow-xs cursor-pointer text-gray-700 space-x-1' onClick={viewBtnClick} >
+                <View className='w-3 h-3'/>
+                <div className='text-xs font-medium'>{t(`${I18N_PREFIX}.view`)}</div>
+              </div>
+            )}
+            <div
+              className='flex px-2 items-center h-6 bg-white rounded-md border-[0.5px] border-gray-200 shadow-xs cursor-pointer text-gray-700 space-x-1'
+              onClick={handleConfigBtnClick}
+            >
+              <Settings04 className='w-3 h-3' />
+              <div className='text-xs font-medium'>{t(`${I18N_PREFIX}.config`)}</div>
+            </div>
           </div>
         )}
 

+ 1 - 0
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',

+ 1 - 0
web/i18n/zh-Hans/app.ts

@@ -94,6 +94,7 @@ const translation = {
     title: '追踪应用性能',
     description: '配置第三方 LLMOps 提供商并跟踪应用程序性能。',
     config: '配置',
+    view: '查看',
     collapse: '折叠',
     expand: '展开',
     tracing: '追踪',

+ 1 - 0
web/i18n/zh-Hant/app.ts

@@ -90,6 +90,7 @@ const translation = {
     title: '追蹤應用程式效能',
     description: '配置第三方LLMOps提供商並追蹤應用程式效能。',
     config: '配置',
+    view: '查看',
     collapse: '收起',
     expand: '展開',
     tracing: '追蹤',