| @@ -1,9 +1,10 @@ | |||
| 'use client' | |||
| import React from 'react' | |||
| import { useRef, useState } from 'react' | |||
| import { t } from 'i18next' | |||
| import copy from 'copy-to-clipboard' | |||
| import s from './style.module.css' | |||
| import Tooltip from '@/app/components/base/tooltip' | |||
| import { randomString } from '@/utils' | |||
| type ICopyBtnProps = { | |||
| value: string | |||
| @@ -16,12 +17,13 @@ const CopyBtn = ({ | |||
| className, | |||
| isPlain, | |||
| }: ICopyBtnProps) => { | |||
| const [isCopied, setIsCopied] = React.useState(false) | |||
| const [isCopied, setIsCopied] = useState(false) | |||
| const selector = useRef(`copy-tooltip-${randomString(4)}`) | |||
| return ( | |||
| <div className={`${className}`}> | |||
| <Tooltip | |||
| selector={`copy-btn-tooltip-${value}`} | |||
| selector={selector.current} | |||
| content={(isCopied ? t('appApi.copied') : t('appApi.copy')) as string} | |||
| className='z-10' | |||
| > | |||
| @@ -14,6 +14,8 @@ import OpeningStatement from '@/app/components/app/configuration/features/chat-g | |||
| import GroupName from '@/app/components/app/configuration/base/group-name' | |||
| import Loading from '@/app/components/base/loading' | |||
| import Confirm from '@/app/components/base/confirm' | |||
| // type | |||
| import type { AutomaticRes } from '@/service/debug' | |||
| const noDataIcon = ( | |||
| <svg width="56" height="56" viewBox="0 0 56 56" fill="none" xmlns="http://www.w3.org/2000/svg"> | |||
| @@ -21,12 +23,6 @@ const noDataIcon = ( | |||
| </svg> | |||
| ) | |||
| export type AutomaticRes = { | |||
| prompt: string | |||
| variables: string[] | |||
| opening_statement: string | |||
| } | |||
| export type IGetAutomaticResProps = { | |||
| mode: AppType | |||
| isShow: boolean | |||
| @@ -98,7 +94,7 @@ const GetAutomaticRes: FC<IGetAutomaticResProps> = ({ | |||
| audiences, | |||
| hoping_to_solve: hopingToSolve, | |||
| }) | |||
| setRes(res as AutomaticRes) | |||
| setRes(res) | |||
| } | |||
| finally { | |||
| setLoadingFalse() | |||
| @@ -193,7 +189,7 @@ const GetAutomaticRes: FC<IGetAutomaticResProps> = ({ | |||
| onClose={() => setShowConfirmOverwrite(false)} | |||
| onConfirm={() => { | |||
| setShowConfirmOverwrite(false) | |||
| onFinished(res as AutomaticRes) | |||
| onFinished(res!) | |||
| }} | |||
| onCancel={() => setShowConfirmOverwrite(false)} | |||
| /> | |||
| @@ -77,18 +77,18 @@ export function format(text: string) { | |||
| 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) | |||
| throw new Error('Network response was not ok') | |||
| const reader = response.body.getReader() | |||
| const reader = response.body?.getReader() | |||
| const decoder = new TextDecoder('utf-8') | |||
| let buffer = '' | |||
| let bufferObj: any | |||
| let bufferObj: Record<string, any> | |||
| let isFirstMessage = true | |||
| function read() { | |||
| let hasError = false | |||
| reader.read().then((result: any) => { | |||
| reader?.read().then((result: any) => { | |||
| if (result.done) { | |||
| onCompleted && onCompleted() | |||
| return | |||
| @@ -99,7 +99,7 @@ const handleStream = (response: any, onData: IOnData, onCompleted?: IOnCompleted | |||
| lines.forEach((message) => { | |||
| if (message.startsWith('data: ')) { // check if it starts with data: | |||
| 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) { | |||
| // mute handle message cut off | |||
| @@ -113,11 +113,11 @@ const handleStream = (response: any, onData: IOnData, onCompleted?: IOnCompleted | |||
| onData('', false, { | |||
| conversationId: undefined, | |||
| messageId: '', | |||
| errorMessage: bufferObj.message, | |||
| errorCode: bufferObj.code, | |||
| errorMessage: bufferObj?.message, | |||
| errorCode: bufferObj?.code, | |||
| }) | |||
| hasError = true | |||
| onCompleted && onCompleted(true) | |||
| onCompleted?.(true) | |||
| return | |||
| } | |||
| if (bufferObj.event === 'message') { | |||
| @@ -130,10 +130,10 @@ const handleStream = (response: any, onData: IOnData, onCompleted?: IOnCompleted | |||
| isFirstMessage = false | |||
| } | |||
| else if (bufferObj.event === 'agent_thought') { | |||
| onThought?.(bufferObj as any) | |||
| onThought?.(bufferObj as ThoughtItem) | |||
| } | |||
| else if (bufferObj.event === 'message_end') { | |||
| onMessageEnd?.(bufferObj as any) | |||
| onMessageEnd?.(bufferObj as MessageEnd) | |||
| } | |||
| } | |||
| }) | |||
| @@ -146,7 +146,7 @@ const handleStream = (response: any, onData: IOnData, onCompleted?: IOnCompleted | |||
| errorMessage: `${e}`, | |||
| }) | |||
| hasError = true | |||
| onCompleted && onCompleted(true) | |||
| onCompleted?.(true) | |||
| return | |||
| } | |||
| if (!hasError) | |||
| @@ -1,6 +1,12 @@ | |||
| import type { IOnCompleted, IOnData, IOnError, IOnMessageEnd } 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 }: { | |||
| onData: IOnData | |||
| onCompleted: IOnCompleted | |||
| @@ -46,7 +52,7 @@ export const fetchConvesationMessages = (appId: string, conversation_id: string) | |||
| } | |||
| export const generateRule = (body: Record<string, any>) => { | |||
| return post('/rule-generate', { | |||
| return post<AutomaticRes>('/rule-generate', { | |||
| body, | |||
| }) | |||
| } | |||