index.tsx 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. 'use client'
  2. import type { FC } from 'react'
  3. import React from 'react'
  4. import { useContext } from 'use-context-selector'
  5. import produce from 'immer'
  6. import {
  7. RiAddLine,
  8. } from '@remixicon/react'
  9. import { useTranslation } from 'react-i18next'
  10. import SimplePromptInput from './simple-prompt-input'
  11. import Button from '@/app/components/base/button'
  12. import AdvancedMessageInput from '@/app/components/app/configuration/config-prompt/advanced-prompt-input'
  13. import { PromptRole } from '@/models/debug'
  14. import type { PromptItem, PromptVariable } from '@/models/debug'
  15. import { type AppType, ModelModeType } from '@/types/app'
  16. import ConfigContext from '@/context/debug-configuration'
  17. import { MAX_PROMPT_MESSAGE_LENGTH } from '@/config'
  18. export type IPromptProps = {
  19. mode: AppType
  20. promptTemplate: string
  21. promptVariables: PromptVariable[]
  22. readonly?: boolean
  23. noTitle?: boolean
  24. gradientBorder?: boolean
  25. editorHeight?: number
  26. noResize?: boolean
  27. onChange?: (prompt: string, promptVariables: PromptVariable[]) => void
  28. }
  29. const Prompt: FC<IPromptProps> = ({
  30. mode,
  31. promptTemplate,
  32. promptVariables,
  33. noTitle,
  34. gradientBorder,
  35. readonly = false,
  36. editorHeight,
  37. noResize,
  38. onChange,
  39. }) => {
  40. const { t } = useTranslation()
  41. const {
  42. isAdvancedMode,
  43. currentAdvancedPrompt,
  44. setCurrentAdvancedPrompt,
  45. modelModeType,
  46. dataSets,
  47. hasSetBlockStatus,
  48. } = useContext(ConfigContext)
  49. const handleMessageTypeChange = (index: number, role: PromptRole) => {
  50. const newPrompt = produce(currentAdvancedPrompt as PromptItem[], (draft) => {
  51. draft[index].role = role
  52. })
  53. setCurrentAdvancedPrompt(newPrompt)
  54. }
  55. const handleValueChange = (value: string, index?: number) => {
  56. if (modelModeType === ModelModeType.chat) {
  57. const newPrompt = produce(currentAdvancedPrompt as PromptItem[], (draft) => {
  58. draft[index as number].text = value
  59. })
  60. setCurrentAdvancedPrompt(newPrompt, true)
  61. }
  62. else {
  63. const prompt = currentAdvancedPrompt as PromptItem
  64. setCurrentAdvancedPrompt({
  65. ...prompt,
  66. text: value,
  67. }, true)
  68. }
  69. }
  70. const handleAddMessage = () => {
  71. const currentAdvancedPromptList = currentAdvancedPrompt as PromptItem[]
  72. if (currentAdvancedPromptList.length === 0) {
  73. setCurrentAdvancedPrompt([{
  74. role: PromptRole.system,
  75. text: '',
  76. }])
  77. return
  78. }
  79. const lastMessageType = currentAdvancedPromptList[currentAdvancedPromptList.length - 1]?.role
  80. const appendMessage = {
  81. role: lastMessageType === PromptRole.user ? PromptRole.assistant : PromptRole.user,
  82. text: '',
  83. }
  84. setCurrentAdvancedPrompt([...currentAdvancedPromptList, appendMessage])
  85. }
  86. const handlePromptDelete = (index: number) => {
  87. const currentAdvancedPromptList = currentAdvancedPrompt as PromptItem[]
  88. const newPrompt = produce(currentAdvancedPromptList, (draft) => {
  89. draft.splice(index, 1)
  90. })
  91. setCurrentAdvancedPrompt(newPrompt)
  92. }
  93. const isContextMissing = dataSets.length > 0 && !hasSetBlockStatus.context
  94. const [isHideContextMissTip, setIsHideContextMissTip] = React.useState(false)
  95. if (!isAdvancedMode) {
  96. return (
  97. <SimplePromptInput
  98. mode={mode}
  99. promptTemplate={promptTemplate}
  100. promptVariables={promptVariables}
  101. readonly={readonly}
  102. onChange={onChange}
  103. noTitle={noTitle}
  104. gradientBorder={gradientBorder}
  105. editorHeight={editorHeight}
  106. noResize={noResize}
  107. />
  108. )
  109. }
  110. return (
  111. <div>
  112. <div className='space-y-3'>
  113. {modelModeType === ModelModeType.chat
  114. ? (
  115. (currentAdvancedPrompt as PromptItem[]).map((item, index) => (
  116. <AdvancedMessageInput
  117. key={index}
  118. isChatMode
  119. type={item.role as PromptRole}
  120. value={item.text}
  121. onTypeChange={type => handleMessageTypeChange(index, type)}
  122. canDelete={(currentAdvancedPrompt as PromptItem[]).length > 1}
  123. onDelete={() => handlePromptDelete(index)}
  124. onChange={value => handleValueChange(value, index)}
  125. promptVariables={promptVariables}
  126. isContextMissing={isContextMissing && !isHideContextMissTip}
  127. onHideContextMissingTip={() => setIsHideContextMissTip(true)}
  128. noResize={noResize}
  129. />
  130. ))
  131. )
  132. : (
  133. <AdvancedMessageInput
  134. type={(currentAdvancedPrompt as PromptItem).role as PromptRole}
  135. isChatMode={false}
  136. value={(currentAdvancedPrompt as PromptItem).text}
  137. onTypeChange={type => handleMessageTypeChange(0, type)}
  138. canDelete={false}
  139. onDelete={() => handlePromptDelete(0)}
  140. onChange={value => handleValueChange(value)}
  141. promptVariables={promptVariables}
  142. isContextMissing={isContextMissing && !isHideContextMissTip}
  143. onHideContextMissingTip={() => setIsHideContextMissTip(true)}
  144. noResize={noResize}
  145. />
  146. )
  147. }
  148. </div>
  149. {(modelModeType === ModelModeType.chat && (currentAdvancedPrompt as PromptItem[]).length < MAX_PROMPT_MESSAGE_LENGTH) && (
  150. <Button
  151. onClick={handleAddMessage}
  152. className='mt-3 w-full'>
  153. <RiAddLine className='w-4 h-4 mr-2' />
  154. <div>{t('appDebug.promptMode.operation.addMessage')}</div>
  155. </Button>
  156. )}
  157. </div>
  158. )
  159. }
  160. export default React.memo(Prompt)