langfuser add view button (#7571)

This commit is contained in:
Charlie.Wei 2024-08-23 15:53:49 +08:00 committed by GitHub
parent 6025002971
commit 9864b35465
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 61 additions and 9 deletions

View File

@ -21,6 +21,7 @@ class LangfuseConfig(BaseTracingConfig):
""" """
public_key: str public_key: str
secret_key: str secret_key: str
project_key: str
host: str = 'https://api.langfuse.com' host: str = 'https://api.langfuse.com'
@field_validator("host") @field_validator("host")

View File

@ -419,3 +419,11 @@ class LangFuseDataTrace(BaseTraceInstance):
except Exception as e: except Exception as e:
logger.debug(f"LangFuse API check failed: {str(e)}") logger.debug(f"LangFuse API check failed: {str(e)}")
raise ValueError(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)}")

View File

@ -38,7 +38,7 @@ provider_config_map = {
TracingProviderEnum.LANGFUSE.value: { TracingProviderEnum.LANGFUSE.value: {
'config_class': LangfuseConfig, 'config_class': LangfuseConfig,
'secret_keys': ['public_key', 'secret_key'], 'secret_keys': ['public_key', 'secret_key'],
'other_keys': ['host'], 'other_keys': ['host', 'project_key'],
'trace_instance': LangFuseDataTrace 'trace_instance': LangFuseDataTrace
}, },
TracingProviderEnum.LANGSMITH.value: { TracingProviderEnum.LANGSMITH.value: {
@ -123,7 +123,6 @@ class OpsTraceManager:
for key in other_keys: for key in other_keys:
new_config[key] = decrypt_tracing_config.get(key, "") new_config[key] = decrypt_tracing_config.get(key, "")
return config_class(**new_config).model_dump() return config_class(**new_config).model_dump()
@classmethod @classmethod
@ -252,6 +251,19 @@ class OpsTraceManager:
tracing_config = config_type(**tracing_config) tracing_config = config_type(**tracing_config)
return trace_instance(tracing_config).api_check() 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: class TraceTask:
def __init__( def __init__(

View File

@ -22,6 +22,10 @@ class OpsService:
# decrypt_token and obfuscated_token # decrypt_token and obfuscated_token
tenant_id = db.session.query(App).filter(App.id == app_id).first().tenant_id 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) 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) decrypt_tracing_config = OpsTraceManager.obfuscated_decrypt_token(tracing_provider, decrypt_tracing_config)
trace_config_data.tracing_config = decrypt_tracing_config trace_config_data.tracing_config = decrypt_tracing_config
@ -37,7 +41,7 @@ class OpsService:
:param tracing_config: tracing config :param tracing_config: tracing config
:return: :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}"} return {"error": f"Invalid tracing provider: {tracing_provider}"}
config_class, other_keys = provider_config_map[tracing_provider]['config_class'], \ 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): if not OpsTraceManager.check_trace_config_is_effective(tracing_config, tracing_provider):
return {"error": "Invalid Credentials"} 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 # check if trace config already exists
trace_config_data: TraceAppConfig = db.session.query(TraceAppConfig).filter( trace_config_data: TraceAppConfig = db.session.query(TraceAppConfig).filter(
TraceAppConfig.app_id == app_id, TraceAppConfig.tracing_provider == tracing_provider TraceAppConfig.app_id == app_id, TraceAppConfig.tracing_provider == tracing_provider
@ -62,6 +69,8 @@ class OpsService:
# get tenant id # get tenant id
tenant_id = db.session.query(App).filter(App.id == app_id).first().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) 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( trace_config_data = TraceAppConfig(
app_id=app_id, app_id=app_id,
tracing_provider=tracing_provider, tracing_provider=tracing_provider,

View File

@ -6,6 +6,7 @@ import { TracingProvider } from './type'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import { LangfuseIconBig, LangsmithIconBig } from '@/app/components/base/icons/src/public/tracing' import { LangfuseIconBig, LangsmithIconBig } from '@/app/components/base/icons/src/public/tracing'
import { Settings04 } 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' const I18N_PREFIX = 'app.tracing'
@ -13,6 +14,7 @@ type Props = {
type: TracingProvider type: TracingProvider
readOnly: boolean readOnly: boolean
isChosen: boolean isChosen: boolean
Config: any
onChoose: () => void onChoose: () => void
hasConfigured: boolean hasConfigured: boolean
onConfig: () => void onConfig: () => void
@ -29,6 +31,7 @@ const ProviderPanel: FC<Props> = ({
type, type,
readOnly, readOnly,
isChosen, isChosen,
Config,
onChoose, onChoose,
hasConfigured, hasConfigured,
onConfig, onConfig,
@ -41,6 +44,14 @@ const ProviderPanel: FC<Props> = ({
onConfig() onConfig()
}, [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) => { const handleChosen = useCallback((e: React.MouseEvent) => {
e.stopPropagation() e.stopPropagation()
if (isChosen || !hasConfigured || readOnly) if (isChosen || !hasConfigured || readOnly)
@ -58,6 +69,13 @@ 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>} {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> </div>
{!readOnly && ( {!readOnly && (
<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 <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' 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} onClick={handleConfigBtnClick}
@ -65,6 +83,7 @@ const ProviderPanel: FC<Props> = ({
<Settings04 className='w-3 h-3' /> <Settings04 className='w-3 h-3' />
<div className='text-xs font-medium'>{t(`${I18N_PREFIX}.config`)}</div> <div className='text-xs font-medium'>{t(`${I18N_PREFIX}.config`)}</div>
</div> </div>
</div>
)} )}
</div> </div>

View File

@ -95,6 +95,7 @@ const translation = {
title: 'Tracing app performance', title: 'Tracing app performance',
description: 'Configuring a Third-Party LLMOps provider and tracing app performance.', description: 'Configuring a Third-Party LLMOps provider and tracing app performance.',
config: 'Config', config: 'Config',
view: 'View',
collapse: 'Collapse', collapse: 'Collapse',
expand: 'Expand', expand: 'Expand',
tracing: 'Tracing', tracing: 'Tracing',

View File

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

View File

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