| 'use client' | 'use client' | ||||
| import React from 'react' | |||||
| import { useRef, useState } from 'react' | |||||
| import { t } from 'i18next' | import { t } from 'i18next' | ||||
| import copy from 'copy-to-clipboard' | import copy from 'copy-to-clipboard' | ||||
| import s from './style.module.css' | import s from './style.module.css' | ||||
| import Tooltip from '@/app/components/base/tooltip' | import Tooltip from '@/app/components/base/tooltip' | ||||
| import { randomString } from '@/utils' | |||||
| type ICopyBtnProps = { | type ICopyBtnProps = { | ||||
| value: string | value: string | ||||
| className, | className, | ||||
| isPlain, | isPlain, | ||||
| }: ICopyBtnProps) => { | }: ICopyBtnProps) => { | ||||
| const [isCopied, setIsCopied] = React.useState(false) | |||||
| const [isCopied, setIsCopied] = useState(false) | |||||
| const selector = useRef(`copy-tooltip-${randomString(4)}`) | |||||
| return ( | return ( | ||||
| <div className={`${className}`}> | <div className={`${className}`}> | ||||
| <Tooltip | <Tooltip | ||||
| selector={`copy-btn-tooltip-${value}`} | |||||
| selector={selector.current} | |||||
| content={(isCopied ? t('appApi.copied') : t('appApi.copy')) as string} | content={(isCopied ? t('appApi.copied') : t('appApi.copy')) as string} | ||||
| className='z-10' | className='z-10' | ||||
| > | > |
| import GroupName from '@/app/components/app/configuration/base/group-name' | import GroupName from '@/app/components/app/configuration/base/group-name' | ||||
| import Loading from '@/app/components/base/loading' | import Loading from '@/app/components/base/loading' | ||||
| import Confirm from '@/app/components/base/confirm' | import Confirm from '@/app/components/base/confirm' | ||||
| // type | |||||
| import type { AutomaticRes } from '@/service/debug' | |||||
| const noDataIcon = ( | const noDataIcon = ( | ||||
| <svg width="56" height="56" viewBox="0 0 56 56" fill="none" xmlns="http://www.w3.org/2000/svg"> | <svg width="56" height="56" viewBox="0 0 56 56" fill="none" xmlns="http://www.w3.org/2000/svg"> | ||||
| </svg> | </svg> | ||||
| ) | ) | ||||
| export type AutomaticRes = { | |||||
| prompt: string | |||||
| variables: string[] | |||||
| opening_statement: string | |||||
| } | |||||
| export type IGetAutomaticResProps = { | export type IGetAutomaticResProps = { | ||||
| mode: AppType | mode: AppType | ||||
| isShow: boolean | isShow: boolean | ||||
| audiences, | audiences, | ||||
| hoping_to_solve: hopingToSolve, | hoping_to_solve: hopingToSolve, | ||||
| }) | }) | ||||
| setRes(res as AutomaticRes) | |||||
| setRes(res) | |||||
| } | } | ||||
| finally { | finally { | ||||
| setLoadingFalse() | setLoadingFalse() | ||||
| onClose={() => setShowConfirmOverwrite(false)} | onClose={() => setShowConfirmOverwrite(false)} | ||||
| onConfirm={() => { | onConfirm={() => { | ||||
| setShowConfirmOverwrite(false) | setShowConfirmOverwrite(false) | ||||
| onFinished(res as AutomaticRes) | |||||
| onFinished(res!) | |||||
| }} | }} | ||||
| onCancel={() => setShowConfirmOverwrite(false)} | onCancel={() => setShowConfirmOverwrite(false)} | ||||
| /> | /> |
| return res.replaceAll('\n', '<br/>').replaceAll('```', '') | return res.replaceAll('\n', '<br/>').replaceAll('```', '') | ||||
| } | } | ||||
| const handleStream = (response: any, onData: IOnData, onCompleted?: IOnCompleted, onThought?: IOnThought, onMessageEnd?: IOnMessageEnd) => { | |||||
| const handleStream = (response: Response, onData: IOnData, onCompleted?: IOnCompleted, onThought?: IOnThought, onMessageEnd?: IOnMessageEnd) => { | |||||
| if (!response.ok) | if (!response.ok) | ||||
| throw new Error('Network response was not ok') | throw new Error('Network response was not ok') | ||||
| const reader = response.body.getReader() | |||||
| const reader = response.body?.getReader() | |||||
| const decoder = new TextDecoder('utf-8') | const decoder = new TextDecoder('utf-8') | ||||
| let buffer = '' | let buffer = '' | ||||
| let bufferObj: any | |||||
| let bufferObj: Record<string, any> | |||||
| let isFirstMessage = true | let isFirstMessage = true | ||||
| function read() { | function read() { | ||||
| let hasError = false | let hasError = false | ||||
| reader.read().then((result: any) => { | |||||
| reader?.read().then((result: any) => { | |||||
| if (result.done) { | if (result.done) { | ||||
| onCompleted && onCompleted() | onCompleted && onCompleted() | ||||
| return | return | ||||
| lines.forEach((message) => { | lines.forEach((message) => { | ||||
| if (message.startsWith('data: ')) { // check if it starts with data: | if (message.startsWith('data: ')) { // check if it starts with data: | ||||
| try { | try { | ||||
| bufferObj = JSON.parse(message.substring(6)) // remove data: and parse as json | |||||
| bufferObj = JSON.parse(message.substring(6)) as Record<string, any>// remove data: and parse as json | |||||
| } | } | ||||
| catch (e) { | catch (e) { | ||||
| // mute handle message cut off | // mute handle message cut off | ||||
| onData('', false, { | onData('', false, { | ||||
| conversationId: undefined, | conversationId: undefined, | ||||
| messageId: '', | messageId: '', | ||||
| errorMessage: bufferObj.message, | |||||
| errorCode: bufferObj.code, | |||||
| errorMessage: bufferObj?.message, | |||||
| errorCode: bufferObj?.code, | |||||
| }) | }) | ||||
| hasError = true | hasError = true | ||||
| onCompleted && onCompleted(true) | |||||
| onCompleted?.(true) | |||||
| return | return | ||||
| } | } | ||||
| if (bufferObj.event === 'message') { | if (bufferObj.event === 'message') { | ||||
| isFirstMessage = false | isFirstMessage = false | ||||
| } | } | ||||
| else if (bufferObj.event === 'agent_thought') { | else if (bufferObj.event === 'agent_thought') { | ||||
| onThought?.(bufferObj as any) | |||||
| onThought?.(bufferObj as ThoughtItem) | |||||
| } | } | ||||
| else if (bufferObj.event === 'message_end') { | else if (bufferObj.event === 'message_end') { | ||||
| onMessageEnd?.(bufferObj as any) | |||||
| onMessageEnd?.(bufferObj as MessageEnd) | |||||
| } | } | ||||
| } | } | ||||
| }) | }) | ||||
| errorMessage: `${e}`, | errorMessage: `${e}`, | ||||
| }) | }) | ||||
| hasError = true | hasError = true | ||||
| onCompleted && onCompleted(true) | |||||
| onCompleted?.(true) | |||||
| return | return | ||||
| } | } | ||||
| if (!hasError) | if (!hasError) |
| import type { IOnCompleted, IOnData, IOnError, IOnMessageEnd } from './base' | import type { IOnCompleted, IOnData, IOnError, IOnMessageEnd } from './base' | ||||
| import { get, post, ssePost } from './base' | import { get, post, ssePost } from './base' | ||||
| export type AutomaticRes = { | |||||
| prompt: string | |||||
| variables: string[] | |||||
| opening_statement: string | |||||
| } | |||||
| export const sendChatMessage = async (appId: string, body: Record<string, any>, { onData, onCompleted, onError, getAbortController, onMessageEnd }: { | export const sendChatMessage = async (appId: string, body: Record<string, any>, { onData, onCompleted, onError, getAbortController, onMessageEnd }: { | ||||
| onData: IOnData | onData: IOnData | ||||
| onCompleted: IOnCompleted | onCompleted: IOnCompleted | ||||
| } | } | ||||
| export const generateRule = (body: Record<string, any>) => { | export const generateRule = (body: Record<string, any>) => { | ||||
| return post('/rule-generate', { | |||||
| return post<AutomaticRes>('/rule-generate', { | |||||
| body, | body, | ||||
| }) | }) | ||||
| } | } |