Skip to content

Commit

Permalink
Merge branch 'feat/workflow-add-block-shortcut' into deploy/dev
Browse files Browse the repository at this point in the history
  • Loading branch information
YIXIAO0 committed Aug 23, 2024
2 parents e6c6a31 + 4fcb048 commit 845d31b
Show file tree
Hide file tree
Showing 72 changed files with 688 additions and 197 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
model: text-embedding-v3
model_type: text-embedding
model_properties:
context_size: 8192
max_chunks: 25
pricing:
input: "0.0007"
unit: "0.001"
currency: RMB
1 change: 1 addition & 0 deletions api/core/model_runtime/model_providers/zhipuai/llm/llm.py
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,7 @@ def _handle_generate_stream_response(self, model: str,
delta=LLMResultChunkDelta(
index=delta.index,
message=assistant_prompt_message,
finish_reason=delta.finish_reason
)
)

Expand Down
1 change: 1 addition & 0 deletions api/core/ops/entities/config_entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
8 changes: 8 additions & 0 deletions api/core/ops/langfuse_trace/langfuse_trace.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)}")
16 changes: 14 additions & 2 deletions api/core/ops/ops_trace_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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__(
Expand Down
11 changes: 10 additions & 1 deletion api/services/ops_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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'], \
Expand All @@ -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
Expand All @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ 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'

type Props = {
type: TracingProvider
readOnly: boolean
isChosen: boolean
Config: any
onChoose: () => void
hasConfigured: boolean
onConfig: () => void
Expand All @@ -29,6 +31,7 @@ const ProviderPanel: FC<Props> = ({
type,
readOnly,
isChosen,
Config,
onChoose,
hasConfigured,
onConfig,
Expand All @@ -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)
Expand All @@ -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>
)}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,19 @@ const ConfigModal: FC<IConfigModalProps> = ({
const { type, label, variable, options, max_length } = tempPayload

const isStringInput = type === InputVarType.textInput || type === InputVarType.paragraph
const checkVariableName = useCallback((value: string) => {
const { isValid, errorMessageKey } = checkKeys([value], false)
if (!isValid) {
Toast.notify({
type: 'error',
message: t(`appDebug.varKeyError.${errorMessageKey}`, { key: t('appDebug.variableConig.varName') }),
})
return false
}
return true
}, [t])
const handlePayloadChange = useCallback((key: string) => {
return (value: any) => {
if (key === 'variable') {
const { isValid, errorKey, errorMessageKey } = checkKeys([value], true)
if (!isValid) {
Toast.notify({
type: 'error',
message: t(`appDebug.varKeyError.${errorMessageKey}`, { key: errorKey }),
})
return
}
}
setTempPayload((prev) => {
const newPayload = {
...prev,
Expand All @@ -63,19 +64,20 @@ const ConfigModal: FC<IConfigModalProps> = ({
return newPayload
})
}
}, [t])
}, [])

const handleVarKeyBlur = useCallback((e: any) => {
if (tempPayload.label)
const varName = e.target.value
if (!checkVariableName(varName) || tempPayload.label)
return

setTempPayload((prev) => {
return {
...prev,
label: e.target.value,
label: varName,
}
})
}, [tempPayload])
}, [checkVariableName, tempPayload.label])

const handleConfirm = () => {
const moreInfo = tempPayload.variable === payload?.variable
Expand All @@ -84,10 +86,11 @@ const ConfigModal: FC<IConfigModalProps> = ({
type: ChangeType.changeVarName,
payload: { beforeKey: payload?.variable || '', afterKey: tempPayload.variable },
}
if (!tempPayload.variable) {
Toast.notify({ type: 'error', message: t('appDebug.variableConig.errorMsg.varNameRequired') })

const isVariableNameValid = checkVariableName(tempPayload.variable)
if (!isVariableNameValid)
return
}

// TODO: check if key already exists. should the consider the edit case
// if (varKeys.map(key => key?.trim()).includes(tempPayload.variable.trim())) {
// Toast.notify({
Expand Down
30 changes: 20 additions & 10 deletions web/app/components/workflow/hooks/use-nodes-interactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1012,7 +1012,7 @@ export const useNodesInteractions = () => {
handleNodeSelect(node.id)
}, [workflowStore, handleNodeSelect])

const handleNodesCopy = useCallback(() => {
const handleNodesCopy = useCallback((nodeId?: string) => {
if (getNodesReadOnly())
return

Expand All @@ -1023,17 +1023,27 @@ export const useNodesInteractions = () => {
} = store.getState()

const nodes = getNodes()
const bundledNodes = nodes.filter(node => node.data._isBundled && node.data.type !== BlockEnum.Start && !node.data.isInIteration)

if (bundledNodes.length) {
setClipboardElements(bundledNodes)
return
if (nodeId) {
// If nodeId is provided, copy that specific node
const nodeToCopy = nodes.find(node => node.id === nodeId && node.data.type !== BlockEnum.Start)
if (nodeToCopy)
setClipboardElements([nodeToCopy])
}
else {
// If no nodeId is provided, fall back to the current behavior
const bundledNodes = nodes.filter(node => node.data._isBundled && node.data.type !== BlockEnum.Start && !node.data.isInIteration)

const selectedNode = nodes.find(node => node.data.selected && node.data.type !== BlockEnum.Start)
if (bundledNodes.length) {
setClipboardElements(bundledNodes)
return
}

if (selectedNode)
setClipboardElements([selectedNode])
const selectedNode = nodes.find(node => node.data.selected && node.data.type !== BlockEnum.Start)

if (selectedNode)
setClipboardElements([selectedNode])
}
}, [getNodesReadOnly, store, workflowStore])

const handleNodesPaste = useCallback(() => {
Expand Down Expand Up @@ -1113,11 +1123,11 @@ export const useNodesInteractions = () => {
}
}, [getNodesReadOnly, workflowStore, store, reactflow, saveStateToHistory, handleSyncWorkflowDraft, handleNodeIterationChildrenCopy])

const handleNodesDuplicate = useCallback(() => {
const handleNodesDuplicate = useCallback((nodeId?: string) => {
if (getNodesReadOnly())
return

handleNodesCopy()
handleNodesCopy(nodeId)
handleNodesPaste()
}, [getNodesReadOnly, handleNodesCopy, handleNodesPaste])

Expand Down
8 changes: 4 additions & 4 deletions web/app/components/workflow/hooks/use-panel-interactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useWorkflowStore } from '../store'
export const usePanelInteractions = () => {
const workflowStore = useWorkflowStore()

const handlePaneContextMenu = useCallback((e: MouseEvent) => {
const handlePanelContextMenu = useCallback((e: MouseEvent) => {
e.preventDefault()
const container = document.querySelector('#workflow-container')
const { x, y } = container!.getBoundingClientRect()
Expand All @@ -17,7 +17,7 @@ export const usePanelInteractions = () => {
})
}, [workflowStore])

const handlePaneContextmenuCancel = useCallback(() => {
const handlePanelContextmenuCancel = useCallback(() => {
workflowStore.setState({
panelMenu: undefined,
})
Expand All @@ -30,8 +30,8 @@ export const usePanelInteractions = () => {
}, [workflowStore])

return {
handlePaneContextMenu,
handlePaneContextmenuCancel,
handlePanelContextMenu,
handlePanelContextmenuCancel,
handleNodeContextmenuCancel,
}
}
7 changes: 7 additions & 0 deletions web/app/components/workflow/hooks/use-shortcuts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,13 @@ export const useShortcuts = (): void => {
}
}, { exactMatch: true, useCapture: true })

useKeyPress(`${getKeyboardKeyCodeBySystem('shift')}.a`, (e) => {
if (shouldHandleShortcut(e)) {
e.preventDefault()
workflowStore.setState({ showAddBlock: true })
}
}, { exactMatch: true, useCapture: true })

useKeyPress(`${getKeyboardKeyCodeBySystem('alt')}.r`, (e) => {
if (shouldHandleShortcut(e)) {
e.preventDefault()
Expand Down
8 changes: 4 additions & 4 deletions web/app/components/workflow/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,8 @@ const Workflow: FC<WorkflowProps> = memo(({
handleSelectionDrag,
} = useSelectionInteractions()
const {
handlePaneContextMenu,
handlePaneContextmenuCancel,
handlePanelContextMenu,
handlePanelContextmenuCancel,
} = usePanelInteractions()
const {
isValidConnection,
Expand Down Expand Up @@ -304,7 +304,7 @@ const Workflow: FC<WorkflowProps> = memo(({
<UpdateDSLModal
onCancel={() => setShowImportDSLModal(false)}
onBackup={exportCheck}
onImport={handlePaneContextmenuCancel}
onImport={handlePanelContextmenuCancel}
/>
)
}
Expand Down Expand Up @@ -338,7 +338,7 @@ const Workflow: FC<WorkflowProps> = memo(({
onSelectionStart={handleSelectionStart}
onSelectionChange={handleSelectionChange}
onSelectionDrag={handleSelectionDrag}
onPaneContextMenu={handlePaneContextMenu}
onPaneContextMenu={handlePanelContextMenu}
connectionLineComponent={CustomConnectionLine}
connectionLineContainerStyle={{ zIndex: ITERATION_CHILDREN_Z_INDEX }}
defaultViewport={viewport}
Expand Down
Loading

0 comments on commit 845d31b

Please sign in to comment.