feat: code generate use prompt editor

feat/enchance-prompt-and-code-fe
Joel 9 months ago
parent 635e92d762
commit ba8129cf73

@ -27,7 +27,6 @@ import { PROMPT_EDITOR_UPDATE_VALUE_BY_EVENT_EMITTER } from '@/app/components/ba
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
import { useFeaturesStore } from '@/app/components/base/features/hooks'
import { noop } from 'lodash-es'
import { GeneratorType } from '../config/automatic/types'
export type ISimplePromptInput = {
mode: AppType
@ -278,7 +277,6 @@ const Prompt: FC<ISimplePromptInput> = ({
onClose={showAutomaticFalse}
onFinished={handleAutomaticRes}
isBasicMode
generatorType={GeneratorType.prompt}
/>
)}
</div>

@ -14,11 +14,9 @@ import {
RiTranslate,
RiUser2Line,
} from '@remixicon/react'
import cn from 'classnames'
import s from './style.module.css'
import Modal from '@/app/components/base/modal'
import Button from '@/app/components/base/button'
import Textarea from '@/app/components/base/textarea'
import Toast from '@/app/components/base/toast'
import { generateBasicAppFistTimeRule, generateRule } from '@/service/debug'
import type { CompletionParams, Model } from '@/types/app'
@ -35,13 +33,13 @@ import { ModelTypeEnum } from '@/app/components/header/account-setting/model-pro
import { useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
import type { ModelModeType } from '@/types/app'
import type { FormValue } from '@/app/components/header/account-setting/model-provider-page/declarations'
import InstructionEditor from './instruction-editor'
import type { Node, NodeOutPutVar } from '@/app/components/workflow/types'
import type { GeneratorType } from './types'
import { ArrowDownRoundFill } from '@/app/components/base/icons/src/vender/solid/general'
import InstructionEditorInWorkflow from './instruction-editor-in-workflow'
import InstructionEditorInBasic from './instruction-editor'
import { GeneratorType } from './types'
import Link from 'next/link'
import Result from './result'
import useGenData from './use-gen-data'
import IdeaOutput from './idea-output'
const i18nPrefix = 'appDebug.generate'
export type IGetAutomaticResProps = {
@ -49,9 +47,6 @@ export type IGetAutomaticResProps = {
isShow: boolean
onClose: () => void
onFinished: (res: GenRes) => void
nodesOutputVars?: NodeOutPutVar[]
availableNodes?: Node[]
generatorType: GeneratorType
flowId?: string
nodeId?: string
currentPrompt?: string
@ -78,9 +73,6 @@ const GetAutomaticRes: FC<IGetAutomaticResProps> = ({
mode,
isShow,
onClose,
nodesOutputVars,
availableNodes,
generatorType,
flowId,
nodeId,
currentPrompt,
@ -141,9 +133,6 @@ const GetAutomaticRes: FC<IGetAutomaticResProps> = ({
const [instruction, setInstruction] = useState<string>('The travel plan to Anshun of Guizhou Province in China') // TODO: test value
const [ideaOutput, setIdeaOutput] = useState<string>('use json format to output the result. Content in result uses Chinese. Format: {"summary: "summary content", "result": "result content"}')
const [isFoldIdeaOutput, {
toggle: toggleFoldIdeaOutput,
}] = useBoolean(true)
const handleChooseTemplate = useCallback((key: string) => {
return () => {
@ -341,32 +330,27 @@ const GetAutomaticRes: FC<IGetAutomaticResProps> = ({
<div className='mt-4'>
<div>
<div className='system-sm-semibold-uppercase mb-1.5 text-text-secondary'>{t('appDebug.generate.instruction')}</div>
<InstructionEditor
value={instruction}
onChange={setInstruction}
nodesOutputVars={nodesOutputVars}
availableNodes={availableNodes}
generatorType={generatorType}
/>
</div>
<div className='mt-4 text-[0px]'>
<div
className='mb-1.5 flex cursor-pointer items-center text-sm font-medium leading-5 text-text-primary'
onClick={toggleFoldIdeaOutput}
>
<div className='system-sm-semibold-uppercase mr-1 text-text-secondary'>{t(`${i18nPrefix}.ideaOutput`)}</div>
<div className='system-xs-regular text-text-tertiary'>({t(`${i18nPrefix}.optional`)})</div>
<ArrowDownRoundFill className={cn('size text-text-quaternary', isFoldIdeaOutput && 'relative top-[1px] rotate-[-90deg]')} />
</div>
{!isFoldIdeaOutput && (
<Textarea
className="h-[80px]"
placeholder={t(`${i18nPrefix}.ideaOutputPlaceholder`)}
value={ideaOutput}
onChange={e => setIdeaOutput(e.target.value)}
{isBasicMode ? (
<InstructionEditorInBasic
generatorType={GeneratorType.prompt}
value={instruction}
onChange={setInstruction}
availableVars={[]}
availableNodes={[]}
/>
) : (
<InstructionEditorInWorkflow
generatorType={GeneratorType.prompt}
value={instruction}
onChange={setInstruction}
nodeId={nodeId || ''}
/>
)}
</div>
<IdeaOutput
value={ideaOutput}
onChange={setIdeaOutput}
/>
<div className='mt-7 flex justify-end space-x-2'>
<Button onClick={onClose}>{t(`${i18nPrefix}.dismiss`)}</Button>
@ -377,7 +361,7 @@ const GetAutomaticRes: FC<IGetAutomaticResProps> = ({
disabled={isLoading}
>
<Generator className='h-4 w-4 text-white' />
<span className='text-xs font-semibold text-white'>{t('appDebug.generate.generate')}</span>
<span className='text-xs font-semibold'>{t('appDebug.generate.generate')}</span>
</Button>
</div>
</div>
@ -392,7 +376,7 @@ const GetAutomaticRes: FC<IGetAutomaticResProps> = ({
setCurrentVersionIndex={setCurrentVersionIndex}
versions={versions || []}
onApply={showConfirmOverwrite}
generatorType={generatorType}
generatorType={GeneratorType.prompt}
/>
</div>
}

@ -0,0 +1,48 @@
'use client'
import { ArrowDownRoundFill } from '@/app/components/base/icons/src/vender/solid/general'
import { useBoolean } from 'ahooks'
import type { FC } from 'react'
import React from 'react'
import cn from '@/utils/classnames'
import Textarea from '@/app/components/base/textarea'
import { useTranslation } from 'react-i18next'
const i18nPrefix = 'appDebug.generate'
type Props = {
value: string
onChange: (value: string) => void
}
const IdeaOutput: FC<Props> = ({
value,
onChange,
}) => {
const { t } = useTranslation()
const [isFoldIdeaOutput, {
toggle: toggleFoldIdeaOutput,
}] = useBoolean(true)
return (
<div className='mt-4 text-[0px]'>
<div
className='mb-1.5 flex cursor-pointer items-center text-sm font-medium leading-5 text-text-primary'
onClick={toggleFoldIdeaOutput}
>
<div className='system-sm-semibold-uppercase mr-1 text-text-secondary'>{t(`${i18nPrefix}.ideaOutput`)}</div>
<div className='system-xs-regular text-text-tertiary'>({t(`${i18nPrefix}.optional`)})</div>
<ArrowDownRoundFill className={cn('size text-text-quaternary', isFoldIdeaOutput && 'relative top-[1px] rotate-[-90deg]')} />
</div>
{!isFoldIdeaOutput && (
<Textarea
className="h-[80px]"
placeholder={t(`${i18nPrefix}.ideaOutputPlaceholder`)}
value={value}
onChange={e => onChange(e.target.value)}
/>
)}
</div>
)
}
export default React.memo(IdeaOutput)

@ -0,0 +1,48 @@
'use client'
import type { FC } from 'react'
import React, { useCallback } from 'react'
import type { GeneratorType } from './types'
import type { Var } from '@/app/components/workflow/types'
import { VarType } from '@/app/components/workflow/types'
import useAvailableVarList from '@/app/components/workflow/nodes/_base/hooks/use-available-var-list'
import InstructionEditor from './instruction-editor'
import { useWorkflowVariableType } from '@/app/components/workflow/hooks'
type Props = {
nodeId: string
value: string
onChange: (text: string) => void
generatorType: GeneratorType
}
const InstructionEditorInWorkflow: FC<Props> = ({
nodeId,
value,
onChange,
generatorType,
}) => {
const filterVar = useCallback((payload: Var) => {
return payload.type !== VarType.file && payload.type !== VarType.arrayFile
}, [])
const {
availableVars,
availableNodes,
} = useAvailableVarList(nodeId, {
onlyLeafNodeVar: false,
filterVar,
})
const getVarType = useWorkflowVariableType()
console.log(availableVars)
return (
<InstructionEditor
value={value}
onChange={onChange}
generatorType={generatorType}
availableVars={availableVars}
availableNodes={availableNodes}
getVarType={getVarType}
/>
)
}
export default React.memo(InstructionEditorInWorkflow)

@ -4,32 +4,36 @@ import React from 'react'
import PromptEditor from '@/app/components/base/prompt-editor'
import type { GeneratorType } from './types'
import cn from '@/utils/classnames'
import { useStore } from '@/app/components/workflow/store'
import type { Node, NodeOutPutVar } from '@/app/components/workflow/types'
import type { Node, NodeOutPutVar, ValueSelector } from '@/app/components/workflow/types'
import { BlockEnum } from '@/app/components/workflow/types'
import { useWorkflowVariableType } from '@/app/components/workflow/hooks'
import { useTranslation } from 'react-i18next'
import { Type } from '@/app/components/workflow/nodes/llm/types'
type Props = {
value: string
onChange: (text: string) => void
nodesOutputVars?: NodeOutPutVar[]
availableNodes?: Node[]
generatorType: GeneratorType
availableVars: NodeOutPutVar[]
availableNodes: Node[]
getVarType?: (params: {
nodeId: string,
valueSelector: ValueSelector,
}) => Type
}
const i18nPrefix = 'appDebug.generate'
const InstructionEditor: FC<Props> = ({
generatorType,
nodesOutputVars = [],
availableNodes = [],
value,
onChange,
availableVars,
availableNodes,
getVarType = () => Type.string,
}) => {
const { t } = useTranslation()
const controlPromptEditorRerenderKey = useStore(s => s.controlPromptEditorRerenderKey)
const getVarType = useWorkflowVariableType()
const isBasicMode = !!getVarType
// const [controlPromptEditorRerenderKey] =
const isCode = generatorType === 'code'
const placeholder = (
<div className='system-sm-regular text-text-placeholder'>
@ -46,14 +50,14 @@ const InstructionEditor: FC<Props> = ({
<div>
<PromptEditor
wrapperClassName='border !border-components-input-bg-normal bg-components-input-bg-normal hover:!border-components-input-bg-hover rounded-[10px] px-4 pt-3'
key={controlPromptEditorRerenderKey}
// key={controlPromptEditorRerenderKey}
placeholder={placeholder}
placeholderClassName='px-4 pt-3'
className={cn('min-h-[240px] ')}
value={value}
workflowVariableBlock={{
show: true,
variables: nodesOutputVars,
variables: availableVars,
getVarType,
workflowNodesMap: availableNodes.reduce((acc, node) => {
acc[node.id] = {

@ -1,5 +1,5 @@
import type { FC } from 'react'
import React, { useCallback, useEffect } from 'react'
import React, { useCallback, useEffect, useState } from 'react'
import cn from 'classnames'
import useBoolean from 'ahooks/lib/useBoolean'
import { useTranslation } from 'react-i18next'
@ -10,7 +10,6 @@ import type { CodeGenRes } from '@/service/debug'
import type { ModelModeType } from '@/types/app'
import type { AppType, CompletionParams, Model } from '@/types/app'
import Modal from '@/app/components/base/modal'
import Textarea from '@/app/components/base/textarea'
import Button from '@/app/components/base/button'
import { Generator } from '@/app/components/base/icons/src/vender/other'
import Toast from '@/app/components/base/toast'
@ -21,8 +20,14 @@ import { useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/com
import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
import ModelParameterModal from '@/app/components/header/account-setting/model-provider-page/model-parameter-modal'
import type { FormValue } from '@/app/components/header/account-setting/model-provider-page/declarations'
import IdeaOutput from '../automatic/idea-output'
import { GeneratorType } from '../automatic/types'
import InstructionEditor from '../automatic/instruction-editor-in-workflow'
const i18nPrefix = 'appDebug.generate'
export type IGetCodeGeneratorResProps = {
// flowId: string
nodeId: string
mode: AppType
isShow: boolean
codeLanguages: CodeLanguage
@ -32,6 +37,7 @@ export type IGetCodeGeneratorResProps = {
export const GetCodeGeneratorResModal: FC<IGetCodeGeneratorResProps> = (
{
nodeId,
mode,
isShow,
codeLanguages,
@ -61,9 +67,12 @@ export const GetCodeGeneratorResModal: FC<IGetCodeGeneratorResProps> = (
const {
defaultModel,
} = useModelListAndDefaultModelAndCurrentProviderAndModel(ModelTypeEnum.textGeneration)
const [instruction, setInstruction] = React.useState<string>('')
const [instruction, setInstruction] = useState<string>('')
const [ideaOutput, setIdeaOutput] = useState<string>('Write comment in Janpanese')
const [isLoading, { setTrue: setLoadingTrue, setFalse: setLoadingFalse }] = useBoolean(false)
const [res, setRes] = React.useState<CodeGenRes | null>(null)
const [res, setRes] = useState<CodeGenRes | null>(null)
const isValid = () => {
if (instruction.trim() === '') {
Toast.notify({
@ -195,23 +204,34 @@ export const GetCodeGeneratorResModal: FC<IGetCodeGeneratorResProps> = (
<div>
<div className='text-[0px]'>
<div className='mb-2 text-sm font-medium leading-5 text-text-primary'>{t('appDebug.codegen.instruction')}</div>
<Textarea
{/* <Textarea
className="h-[200px] resize-none"
placeholder={t('appDebug.codegen.instructionPlaceholder') || ''}
value={instruction}
onChange={e => setInstruction(e.target.value)}
/> */}
<InstructionEditor
value={instruction}
onChange={setInstruction}
nodeId={nodeId}
generatorType={GeneratorType.code}
/>
</div>
<IdeaOutput
value={ideaOutput}
onChange={setIdeaOutput}
/>
<div className='mt-5 flex justify-end'>
<div className='mt-7 flex justify-end space-x-2'>
<Button onClick={onClose}>{t(`${i18nPrefix}.dismiss`)}</Button>
<Button
className='flex space-x-1'
variant='primary'
onClick={onGenerate}
disabled={isLoading}
>
<Generator className='h-4 w-4 text-white' />
<span className='text-xs font-semibold text-white'>{t('appDebug.codegen.generate')}</span>
<Generator className='h-4 w-4 ' />
<span className='text-xs font-semibold '>{t('appDebug.codegen.generate')}</span>
</Button>
</div>
</div>

@ -11,12 +11,14 @@ import type { CodeGenRes } from '@/service/debug'
import { GetCodeGeneratorResModal } from '@/app/components/app/configuration/config/code-generator/get-code-generator-res'
type Props = {
nodeId: string
className?: string
onGenerated?: (prompt: string) => void
codeLanguages: CodeLanguage
}
const CodeGenerateBtn: FC<Props> = ({
nodeId,
className,
codeLanguages,
onGenerated,
@ -40,6 +42,7 @@ const CodeGenerateBtn: FC<Props> = ({
codeLanguages={codeLanguages}
onClose={showAutomaticFalse}
onFinished={handleAutomaticRes}
nodeId={nodeId}
/>
)}
</div>

@ -16,8 +16,10 @@ import useToggleExpend from '@/app/components/workflow/nodes/_base/hooks/use-tog
import type { FileEntity } from '@/app/components/base/file-uploader/types'
import FileListInLog from '@/app/components/base/file-uploader/file-list-in-log'
import ActionButton from '@/app/components/base/action-button'
import type { Node, NodeOutPutVar } from '@/app/components/workflow/types'
type Props = {
nodeId?: string
className?: string
title: React.JSX.Element | string
headerRight?: React.JSX.Element
@ -35,9 +37,12 @@ type Props = {
showFileList?: boolean
showCodeGenerator?: boolean
tip?: React.JSX.Element
nodesOutputVars?: NodeOutPutVar[]
availableNodes?: Node[]
}
const Base: FC<Props> = ({
nodeId,
className,
title,
headerRight,
@ -86,7 +91,11 @@ const Base: FC<Props> = ({
{headerRight}
{showCodeGenerator && codeLanguages && (
<div className='ml-1'>
<CodeGeneratorButton onGenerated={onGenerated} codeLanguages={codeLanguages} />
<CodeGeneratorButton
onGenerated={onGenerated}
codeLanguages={codeLanguages}
nodeId={nodeId!}
/>
</div>
)}
<ActionButton className='ml-1' onClick={handleCopy}>

@ -20,6 +20,7 @@ loader.config({ paths: { vs: `${basePath}/vs` } })
const CODE_EDITOR_LINE_HEIGHT = 18
export type Props = {
nodeId?: string
value?: string | object
placeholder?: React.JSX.Element | string
onChange?: (value: string) => void
@ -47,6 +48,7 @@ export const languageMap = {
}
const CodeEditor: FC<Props> = ({
nodeId,
value = '',
placeholder = '',
onChange = noop,
@ -175,6 +177,7 @@ const CodeEditor: FC<Props> = ({
</div>
: (
<Base
nodeId={nodeId}
className='relative'
title={title}
value={outPutValue}

@ -166,8 +166,6 @@ const Editor: FC<Props> = ({
className='ml-[5px]'
onGenerated={onGenerated}
modelConfig={modelConfig}
nodesOutputVars={nodesOutputVars}
availableNodes={availableNodes}
currentPrompt={value}
/>
)}

@ -356,7 +356,7 @@ const VarReferenceVars: FC<Props> = ({
{
!hideSearch && (
<>
<div className={cn('var-search-input-wrapper mx-2 mb-1 mt-2', searchBoxClassName)} onClick={e => e.stopPropagation()}>
<div className={cn('var-search-input-wrapper mx-2 mb-2 mt-2', searchBoxClassName)} onClick={e => e.stopPropagation()}>
<Input
className='var-search-input'
showLeftIcon
@ -406,7 +406,7 @@ const VarReferenceVars: FC<Props> = ({
zIndex={zIndex}
/>
))}
{item.isFlat && !filteredVars[i + 1]?.isFlat && (
{item.isFlat && !filteredVars[i + 1]?.isFlat && !!filteredVars.find(item => !item.isFlat) && (
<div className='relative mt-[14px] flex items-center space-x-1'>
<div className='h-0 w-3 shrink-0 border border-divider-subtle'></div>
<div className='system-2xs-semibold-uppercase text-text-tertiary'>{t('workflow.debug.lastOutput')}</div>

@ -1,18 +1,19 @@
import { useEffect, useState } from 'react'
type Params = {
ref: React.RefObject<HTMLDivElement>
ref?: React.RefObject<HTMLDivElement | null>
hasFooter?: boolean
isInNode?: boolean
}
const useToggleExpend = ({ ref, hasFooter = true, isInNode }: Params) => {
const [isExpand, setIsExpand] = useState(false)
const [wrapHeight, setWrapHeight] = useState(ref.current?.clientHeight)
const [wrapHeight, setWrapHeight] = useState(ref?.current?.clientHeight)
const editorExpandHeight = isExpand ? wrapHeight! - (hasFooter ? 56 : 29) : 0
useEffect(() => {
if (!ref?.current) return
setWrapHeight(ref.current?.clientHeight)
// eslint-disable-next-line react-hooks/exhaustive-deps
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isExpand])
const wrapClassName = (() => {

@ -89,6 +89,7 @@ const Panel: FC<NodePanelProps<CodeNodeType>> = ({
</Field>
<Split />
<CodeEditor
nodeId={id}
isInNode
readOnly={readOnly}
title={

@ -8,8 +8,7 @@ import { ActionButton } from '@/app/components/base/action-button'
import GetAutomaticResModal from '@/app/components/app/configuration/config/automatic/get-automatic-res'
import { AppType } from '@/types/app'
import type { GenRes } from '@/service/debug'
import type { ModelConfig, Node, NodeOutPutVar } from '@/app/components/workflow/types'
import { GeneratorType } from '@/app/components/app/configuration/config/automatic/types'
import type { ModelConfig } from '@/app/components/workflow/types'
import { useHooksStore } from '../../../hooks-store'
type Props = {
@ -17,8 +16,6 @@ type Props = {
onGenerated?: (prompt: string) => void
modelConfig?: ModelConfig
nodeId: string
nodesOutputVars?: NodeOutPutVar[]
availableNodes?: Node[]
currentPrompt?: string
}
@ -26,8 +23,6 @@ const PromptGeneratorBtn: FC<Props> = ({
className,
onGenerated,
nodeId,
nodesOutputVars,
availableNodes,
currentPrompt,
}) => {
const [showAutomatic, { setTrue: showAutomaticTrue, setFalse: showAutomaticFalse }] = useBoolean(false)
@ -49,9 +44,6 @@ const PromptGeneratorBtn: FC<Props> = ({
isShow={showAutomatic}
onClose={showAutomaticFalse}
onFinished={handleAutomaticRes}
generatorType={GeneratorType.prompt}
nodesOutputVars={nodesOutputVars}
availableNodes={availableNodes}
flowId={configsMap?.flowId || ''}
nodeId={nodeId}
currentPrompt={currentPrompt}

Loading…
Cancel
Save