mirror of
https://git.mirrors.martin98.com/https://github.com/langgenius/dify.git
synced 2025-08-14 06:45:58 +08:00
feat: conversation app support pin and delete conversation (#467)
This commit is contained in:
parent
accc5faae3
commit
ec261aea54
@ -24,7 +24,7 @@ const ConfirmUI: FC<IConfirmUIProps> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
return (
|
return (
|
||||||
<div className="w-[420px] rounded-lg p-7 bg-white">
|
<div className="w-[420px] max-w-full rounded-lg p-7 bg-white">
|
||||||
<div className='flex items-center'>
|
<div className='flex items-center'>
|
||||||
{type === 'info' && (<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
{type === 'info' && (<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path d="M17.3333 21.3333H16V16H14.6667M16 10.6667H16.0133M28 16C28 17.5759 27.6896 19.1363 27.0866 20.5922C26.4835 22.0481 25.5996 23.371 24.4853 24.4853C23.371 25.5996 22.0481 26.4835 20.5922 27.0866C19.1363 27.6896 17.5759 28 16 28C14.4241 28 12.8637 27.6896 11.4078 27.0866C9.95189 26.4835 8.62902 25.5996 7.51472 24.4853C6.40042 23.371 5.5165 22.0481 4.91345 20.5922C4.31039 19.1363 4 17.5759 4 16C4 12.8174 5.26428 9.76516 7.51472 7.51472C9.76516 5.26428 12.8174 4 16 4C19.1826 4 22.2348 5.26428 24.4853 7.51472C26.7357 9.76516 28 12.8174 28 16Z" stroke="#9CA3AF" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
|
<path d="M17.3333 21.3333H16V16H14.6667M16 10.6667H16.0133M28 16C28 17.5759 27.6896 19.1363 27.0866 20.5922C26.4835 22.0481 25.5996 23.371 24.4853 24.4853C23.371 25.5996 22.0481 26.4835 20.5922 27.0866C19.1363 27.6896 17.5759 28 16 28C14.4241 28 12.8637 27.6896 11.4078 27.0866C9.95189 26.4835 8.62902 25.5996 7.51472 24.4853C6.40042 23.371 5.5165 22.0481 4.91345 20.5922C4.31039 19.1363 4 17.5759 4 16C4 12.8174 5.26428 9.76516 7.51472 7.51472C9.76516 5.26428 12.8174 4 16 4C19.1826 4 22.2348 5.26428 24.4853 7.51472C26.7357 9.76516 28 12.8174 28 16Z" stroke="#9CA3AF" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
|
||||||
|
@ -9,7 +9,7 @@ import s from './style.module.css'
|
|||||||
import Popover from '@/app/components/base/popover'
|
import Popover from '@/app/components/base/popover'
|
||||||
|
|
||||||
const PinIcon = (
|
const PinIcon = (
|
||||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg className="shrink-0" width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path d="M8.00012 9.99967L8.00012 14.6663M5.33346 4.87176V6.29217C5.33346 6.43085 5.33346 6.50019 5.31985 6.56652C5.30777 6.62536 5.2878 6.6823 5.26047 6.73579C5.22966 6.79608 5.18635 6.85023 5.09972 6.95852L4.0532 8.26667C3.60937 8.82145 3.38746 9.09884 3.38721 9.33229C3.38699 9.53532 3.4793 9.72738 3.63797 9.85404C3.82042 9.99967 4.17566 9.99967 4.88612 9.99967H11.1141C11.8246 9.99967 12.1798 9.99967 12.3623 9.85404C12.5209 9.72738 12.6133 9.53532 12.613 9.33229C12.6128 9.09884 12.3909 8.82145 11.947 8.26667L10.9005 6.95852C10.8139 6.85023 10.7706 6.79608 10.7398 6.73579C10.7125 6.6823 10.6925 6.62536 10.6804 6.56652C10.6668 6.50019 10.6668 6.43085 10.6668 6.29217V4.87176C10.6668 4.79501 10.6668 4.75664 10.6711 4.71879C10.675 4.68517 10.6814 4.6519 10.6903 4.61925C10.7003 4.5825 10.7146 4.54687 10.7431 4.47561L11.415 2.79582C11.611 2.30577 11.709 2.06074 11.6682 1.86404C11.6324 1.69203 11.5302 1.54108 11.3838 1.44401C11.2163 1.33301 10.9524 1.33301 10.4246 1.33301H5.57563C5.04782 1.33301 4.78391 1.33301 4.61646 1.44401C4.47003 1.54108 4.36783 1.69203 4.33209 1.86404C4.29122 2.06074 4.38923 2.30577 4.58525 2.79583L5.25717 4.47561C5.28567 4.54687 5.29992 4.5825 5.30995 4.61925C5.31886 4.6519 5.32526 4.68517 5.32912 4.71879C5.33346 4.75664 5.33346 4.79501 5.33346 4.87176Z" stroke="#667085" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>
|
<path d="M8.00012 9.99967L8.00012 14.6663M5.33346 4.87176V6.29217C5.33346 6.43085 5.33346 6.50019 5.31985 6.56652C5.30777 6.62536 5.2878 6.6823 5.26047 6.73579C5.22966 6.79608 5.18635 6.85023 5.09972 6.95852L4.0532 8.26667C3.60937 8.82145 3.38746 9.09884 3.38721 9.33229C3.38699 9.53532 3.4793 9.72738 3.63797 9.85404C3.82042 9.99967 4.17566 9.99967 4.88612 9.99967H11.1141C11.8246 9.99967 12.1798 9.99967 12.3623 9.85404C12.5209 9.72738 12.6133 9.53532 12.613 9.33229C12.6128 9.09884 12.3909 8.82145 11.947 8.26667L10.9005 6.95852C10.8139 6.85023 10.7706 6.79608 10.7398 6.73579C10.7125 6.6823 10.6925 6.62536 10.6804 6.56652C10.6668 6.50019 10.6668 6.43085 10.6668 6.29217V4.87176C10.6668 4.79501 10.6668 4.75664 10.6711 4.71879C10.675 4.68517 10.6814 4.6519 10.6903 4.61925C10.7003 4.5825 10.7146 4.54687 10.7431 4.47561L11.415 2.79582C11.611 2.30577 11.709 2.06074 11.6682 1.86404C11.6324 1.69203 11.5302 1.54108 11.3838 1.44401C11.2163 1.33301 10.9524 1.33301 10.4246 1.33301H5.57563C5.04782 1.33301 4.78391 1.33301 4.61646 1.44401C4.47003 1.54108 4.36783 1.69203 4.33209 1.86404C4.29122 2.06074 4.38923 2.30577 4.58525 2.79583L5.25717 4.47561C5.28567 4.54687 5.29992 4.5825 5.30995 4.61925C5.31886 4.6519 5.32526 4.68517 5.32912 4.71879C5.33346 4.75664 5.33346 4.79501 5.33346 4.87176Z" stroke="#667085" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>
|
||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
@ -43,7 +43,7 @@ const ItemOperation: FC<IItemOperationProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
{isShowDelete && (
|
{isShowDelete && (
|
||||||
<div className={cn(s.actionItem, s.deleteActionItem, 'hover:bg-gray-50 group')} onClick={onDelete} >
|
<div className={cn(s.actionItem, s.deleteActionItem, 'hover:bg-gray-50 group')} onClick={onDelete} >
|
||||||
<TrashIcon className={'w-4 h-4 stroke-current text-gray-500 stroke-2 group-hover:text-red-500'} />
|
<TrashIcon className={'shrink-0 w-4 h-4 stroke-current text-gray-500 stroke-2 group-hover:text-red-500'} />
|
||||||
<span className={cn(s.actionName, 'group-hover:text-red-500')}>{t('explore.sidebar.action.delete')}</span>
|
<span className={cn(s.actionName, 'group-hover:text-red-500')}>{t('explore.sidebar.action.delete')}</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import type { ConversationItem } from '@/models/share'
|
|
||||||
import produce from 'immer'
|
import produce from 'immer'
|
||||||
|
import type { ConversationItem } from '@/models/share'
|
||||||
|
|
||||||
const storageConversationIdKey = 'conversationIdInfo'
|
const storageConversationIdKey = 'conversationIdInfo'
|
||||||
|
|
||||||
type ConversationInfoType = Omit<ConversationItem, 'inputs' | 'id'>
|
type ConversationInfoType = Omit<ConversationItem, 'inputs' | 'id'>
|
||||||
function useConversation() {
|
function useConversation() {
|
||||||
const [conversationList, setConversationList] = useState<ConversationItem[]>([])
|
const [conversationList, setConversationList] = useState<ConversationItem[]>([])
|
||||||
|
const [pinnedConversationList, setPinnedConversationList] = useState<ConversationItem[]>([])
|
||||||
const [currConversationId, doSetCurrConversationId] = useState<string>('-1')
|
const [currConversationId, doSetCurrConversationId] = useState<string>('-1')
|
||||||
// when set conversation id, we do not have set appId
|
// when set conversation id, we do not have set appId
|
||||||
const setCurrConversationId = (id: string, appId: string, isSetToLocalStroge = true, newConversationName = '') => {
|
const setCurrConversationId = (id: string, appId: string, isSetToLocalStroge = true, newConversationName = '') => {
|
||||||
@ -29,9 +30,10 @@ function useConversation() {
|
|||||||
// input can be updated by user
|
// input can be updated by user
|
||||||
const [newConversationInputs, setNewConversationInputs] = useState<Record<string, any> | null>(null)
|
const [newConversationInputs, setNewConversationInputs] = useState<Record<string, any> | null>(null)
|
||||||
const resetNewConversationInputs = () => {
|
const resetNewConversationInputs = () => {
|
||||||
if (!newConversationInputs) return
|
if (!newConversationInputs)
|
||||||
setNewConversationInputs(produce(newConversationInputs, draft => {
|
return
|
||||||
Object.keys(draft).forEach(key => {
|
setNewConversationInputs(produce(newConversationInputs, (draft) => {
|
||||||
|
Object.keys(draft).forEach((key) => {
|
||||||
draft[key] = ''
|
draft[key] = ''
|
||||||
})
|
})
|
||||||
}))
|
}))
|
||||||
@ -48,6 +50,8 @@ function useConversation() {
|
|||||||
return {
|
return {
|
||||||
conversationList,
|
conversationList,
|
||||||
setConversationList,
|
setConversationList,
|
||||||
|
pinnedConversationList,
|
||||||
|
setPinnedConversationList,
|
||||||
currConversationId,
|
currConversationId,
|
||||||
setCurrConversationId,
|
setCurrConversationId,
|
||||||
getConversationIdFromStorage,
|
getConversationIdFromStorage,
|
||||||
@ -59,8 +63,8 @@ function useConversation() {
|
|||||||
setCurrInputs,
|
setCurrInputs,
|
||||||
currConversationInfo,
|
currConversationInfo,
|
||||||
setNewConversationInfo,
|
setNewConversationInfo,
|
||||||
setExistConversationInfo
|
setExistConversationInfo,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default useConversation;
|
export default useConversation
|
||||||
|
@ -14,7 +14,7 @@ import { ToastContext } from '@/app/components/base/toast'
|
|||||||
import Sidebar from '@/app/components/share/chat/sidebar'
|
import Sidebar from '@/app/components/share/chat/sidebar'
|
||||||
import ConfigSence from '@/app/components/share/chat/config-scence'
|
import ConfigSence from '@/app/components/share/chat/config-scence'
|
||||||
import Header from '@/app/components/share/header'
|
import Header from '@/app/components/share/header'
|
||||||
import { fetchAppInfo, fetchAppParams, fetchChatList, fetchConversations, fetchSuggestedQuestions, sendChatMessage, stopChatMessageResponding, updateFeedback } from '@/service/share'
|
import { delConversation, fetchAppInfo, fetchAppParams, fetchChatList, fetchConversations, fetchSuggestedQuestions, pinConversation, sendChatMessage, stopChatMessageResponding, unpinConversation, updateFeedback } from '@/service/share'
|
||||||
import type { ConversationItem, SiteInfo } from '@/models/share'
|
import type { ConversationItem, SiteInfo } from '@/models/share'
|
||||||
import type { PromptConfig, SuggestedQuestionsAfterAnswerConfig } from '@/models/debug'
|
import type { PromptConfig, SuggestedQuestionsAfterAnswerConfig } from '@/models/debug'
|
||||||
import type { Feedbacktype, IChatItem } from '@/app/components/app/chat'
|
import type { Feedbacktype, IChatItem } from '@/app/components/app/chat'
|
||||||
@ -25,6 +25,7 @@ import Loading from '@/app/components/base/loading'
|
|||||||
import { replaceStringWithValues } from '@/app/components/app/configuration/prompt-value-panel'
|
import { replaceStringWithValues } from '@/app/components/app/configuration/prompt-value-panel'
|
||||||
import { userInputsFormToPromptVariables } from '@/utils/model-config'
|
import { userInputsFormToPromptVariables } from '@/utils/model-config'
|
||||||
import type { InstalledApp } from '@/models/explore'
|
import type { InstalledApp } from '@/models/explore'
|
||||||
|
import Confirm from '@/app/components/base/confirm'
|
||||||
|
|
||||||
export type IMainProps = {
|
export type IMainProps = {
|
||||||
isInstalledApp?: boolean
|
isInstalledApp?: boolean
|
||||||
@ -65,9 +66,12 @@ const Main: FC<IMainProps> = ({
|
|||||||
/*
|
/*
|
||||||
* conversation info
|
* conversation info
|
||||||
*/
|
*/
|
||||||
|
const [allConversationList, setAllConversationList] = useState<ConversationItem[]>([])
|
||||||
const {
|
const {
|
||||||
conversationList,
|
conversationList,
|
||||||
setConversationList,
|
setConversationList,
|
||||||
|
pinnedConversationList,
|
||||||
|
setPinnedConversationList,
|
||||||
currConversationId,
|
currConversationId,
|
||||||
setCurrConversationId,
|
setCurrConversationId,
|
||||||
getConversationIdFromStorage,
|
getConversationIdFromStorage,
|
||||||
@ -81,11 +85,50 @@ const Main: FC<IMainProps> = ({
|
|||||||
setNewConversationInfo,
|
setNewConversationInfo,
|
||||||
setExistConversationInfo,
|
setExistConversationInfo,
|
||||||
} = useConversation()
|
} = useConversation()
|
||||||
const [hasMore, setHasMore] = useState<boolean>(false)
|
const [hasMore, setHasMore] = useState<boolean>(true)
|
||||||
|
const [hasPinnedMore, setHasPinnedMore] = useState<boolean>(true)
|
||||||
const onMoreLoaded = ({ data: conversations, has_more }: any) => {
|
const onMoreLoaded = ({ data: conversations, has_more }: any) => {
|
||||||
setHasMore(has_more)
|
setHasMore(has_more)
|
||||||
setConversationList([...conversationList, ...conversations])
|
setConversationList([...conversationList, ...conversations])
|
||||||
}
|
}
|
||||||
|
const onPinnedMoreLoaded = ({ data: conversations, has_more }: any) => {
|
||||||
|
setHasPinnedMore(has_more)
|
||||||
|
setPinnedConversationList([...pinnedConversationList, ...conversations])
|
||||||
|
}
|
||||||
|
const [controlUpdateConversationList, setControlUpdateConversationList] = useState(0)
|
||||||
|
const noticeUpdateList = () => {
|
||||||
|
setConversationList([])
|
||||||
|
setHasMore(true)
|
||||||
|
setPinnedConversationList([])
|
||||||
|
setHasPinnedMore(true)
|
||||||
|
setControlUpdateConversationList(Date.now())
|
||||||
|
}
|
||||||
|
const handlePin = async (id: string) => {
|
||||||
|
await pinConversation(isInstalledApp, installedAppInfo?.id, id)
|
||||||
|
notify({ type: 'success', message: t('common.api.success') })
|
||||||
|
noticeUpdateList()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleUnpin = async (id: string) => {
|
||||||
|
await unpinConversation(isInstalledApp, installedAppInfo?.id, id)
|
||||||
|
notify({ type: 'success', message: t('common.api.success') })
|
||||||
|
noticeUpdateList()
|
||||||
|
}
|
||||||
|
const [isShowConfirm, { setTrue: showConfirm, setFalse: hideConfirm }] = useBoolean(false)
|
||||||
|
const [toDeleteConversationId, setToDeleteConversationId] = useState('')
|
||||||
|
const handleDelete = (id: string) => {
|
||||||
|
setToDeleteConversationId(id)
|
||||||
|
hideSidebar() // mobile
|
||||||
|
showConfirm()
|
||||||
|
}
|
||||||
|
|
||||||
|
const didDelete = async () => {
|
||||||
|
await delConversation(isInstalledApp, installedAppInfo?.id, toDeleteConversationId)
|
||||||
|
notify({ type: 'success', message: t('common.api.success') })
|
||||||
|
hideConfirm()
|
||||||
|
noticeUpdateList()
|
||||||
|
}
|
||||||
|
|
||||||
const [suggestedQuestionsAfterAnswerConfig, setSuggestedQuestionsAfterAnswerConfig] = useState<SuggestedQuestionsAfterAnswerConfig | null>(null)
|
const [suggestedQuestionsAfterAnswerConfig, setSuggestedQuestionsAfterAnswerConfig] = useState<SuggestedQuestionsAfterAnswerConfig | null>(null)
|
||||||
|
|
||||||
const [conversationIdChangeBecauseOfNew, setConversationIdChangeBecauseOfNew, getConversationIdChangeBecauseOfNew] = useGetState(false)
|
const [conversationIdChangeBecauseOfNew, setConversationIdChangeBecauseOfNew, getConversationIdChangeBecauseOfNew] = useGetState(false)
|
||||||
@ -121,7 +164,7 @@ const Main: FC<IMainProps> = ({
|
|||||||
let notSyncToStateIntroduction = ''
|
let notSyncToStateIntroduction = ''
|
||||||
let notSyncToStateInputs: Record<string, any> | undefined | null = {}
|
let notSyncToStateInputs: Record<string, any> | undefined | null = {}
|
||||||
if (!isNewConversation) {
|
if (!isNewConversation) {
|
||||||
const item = conversationList.find(item => item.id === currConversationId)
|
const item = allConversationList.find(item => item.id === currConversationId)
|
||||||
notSyncToStateInputs = item?.inputs || {}
|
notSyncToStateInputs = item?.inputs || {}
|
||||||
setCurrInputs(notSyncToStateInputs)
|
setCurrInputs(notSyncToStateInputs)
|
||||||
notSyncToStateIntroduction = item?.introduction || ''
|
notSyncToStateIntroduction = item?.introduction || ''
|
||||||
@ -229,6 +272,10 @@ const Main: FC<IMainProps> = ({
|
|||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fetchAllConversations = () => {
|
||||||
|
return fetchConversations(isInstalledApp, installedAppInfo?.id, undefined, undefined, 100)
|
||||||
|
}
|
||||||
|
|
||||||
const fetchInitData = () => {
|
const fetchInitData = () => {
|
||||||
return Promise.all([isInstalledApp
|
return Promise.all([isInstalledApp
|
||||||
? {
|
? {
|
||||||
@ -240,7 +287,7 @@ const Main: FC<IMainProps> = ({
|
|||||||
},
|
},
|
||||||
plan: 'basic',
|
plan: 'basic',
|
||||||
}
|
}
|
||||||
: fetchAppInfo(), fetchConversations(isInstalledApp, installedAppInfo?.id), fetchAppParams(isInstalledApp, installedAppInfo?.id)])
|
: fetchAppInfo(), fetchAllConversations(), fetchAppParams(isInstalledApp, installedAppInfo?.id)])
|
||||||
}
|
}
|
||||||
|
|
||||||
// init
|
// init
|
||||||
@ -255,10 +302,10 @@ const Main: FC<IMainProps> = ({
|
|||||||
setIsPublicVersion(tempIsPublicVersion)
|
setIsPublicVersion(tempIsPublicVersion)
|
||||||
const prompt_template = ''
|
const prompt_template = ''
|
||||||
// handle current conversation id
|
// handle current conversation id
|
||||||
const { data: conversations, has_more } = conversationData as { data: ConversationItem[]; has_more: boolean }
|
const { data: allConversations } = conversationData as { data: ConversationItem[]; has_more: boolean }
|
||||||
const _conversationId = getConversationIdFromStorage(appId)
|
const _conversationId = getConversationIdFromStorage(appId)
|
||||||
const isNotNewConversation = conversations.some(item => item.id === _conversationId)
|
const isNotNewConversation = allConversations.some(item => item.id === _conversationId)
|
||||||
setHasMore(has_more)
|
setAllConversationList(allConversations)
|
||||||
// fetch new conversation info
|
// fetch new conversation info
|
||||||
const { user_input_form, opening_statement: introduction, suggested_questions_after_answer }: any = appParams
|
const { user_input_form, opening_statement: introduction, suggested_questions_after_answer }: any = appParams
|
||||||
const prompt_variables = userInputsFormToPromptVariables(user_input_form)
|
const prompt_variables = userInputsFormToPromptVariables(user_input_form)
|
||||||
@ -276,7 +323,7 @@ const Main: FC<IMainProps> = ({
|
|||||||
} as PromptConfig)
|
} as PromptConfig)
|
||||||
setSuggestedQuestionsAfterAnswerConfig(suggested_questions_after_answer)
|
setSuggestedQuestionsAfterAnswerConfig(suggested_questions_after_answer)
|
||||||
|
|
||||||
setConversationList(conversations as ConversationItem[])
|
// setConversationList(conversations as ConversationItem[])
|
||||||
|
|
||||||
if (isNotNewConversation)
|
if (isNotNewConversation)
|
||||||
setCurrConversationId(_conversationId, appId, false)
|
setCurrConversationId(_conversationId, appId, false)
|
||||||
@ -403,12 +450,10 @@ const Main: FC<IMainProps> = ({
|
|||||||
if (hasError)
|
if (hasError)
|
||||||
return
|
return
|
||||||
|
|
||||||
let currChatList = conversationList
|
|
||||||
if (getConversationIdChangeBecauseOfNew()) {
|
if (getConversationIdChangeBecauseOfNew()) {
|
||||||
const { data: conversations, has_more }: any = await fetchConversations(isInstalledApp, installedAppInfo?.id)
|
const { data: allConversations }: any = await fetchAllConversations()
|
||||||
setHasMore(has_more)
|
setAllConversationList(allConversations)
|
||||||
setConversationList(conversations as ConversationItem[])
|
noticeUpdateList()
|
||||||
currChatList = conversations
|
|
||||||
}
|
}
|
||||||
setConversationIdChangeBecauseOfNew(false)
|
setConversationIdChangeBecauseOfNew(false)
|
||||||
resetNewConversationInputs()
|
resetNewConversationInputs()
|
||||||
@ -451,14 +496,21 @@ const Main: FC<IMainProps> = ({
|
|||||||
return (
|
return (
|
||||||
<Sidebar
|
<Sidebar
|
||||||
list={conversationList}
|
list={conversationList}
|
||||||
|
pinnedList={pinnedConversationList}
|
||||||
onMoreLoaded={onMoreLoaded}
|
onMoreLoaded={onMoreLoaded}
|
||||||
|
onPinnedMoreLoaded={onPinnedMoreLoaded}
|
||||||
isNoMore={!hasMore}
|
isNoMore={!hasMore}
|
||||||
|
isPinnedNoMore={!hasPinnedMore}
|
||||||
onCurrentIdChange={handleConversationIdChange}
|
onCurrentIdChange={handleConversationIdChange}
|
||||||
currentId={currConversationId}
|
currentId={currConversationId}
|
||||||
copyRight={siteInfo.copyright || siteInfo.title}
|
copyRight={siteInfo.copyright || siteInfo.title}
|
||||||
isInstalledApp={isInstalledApp}
|
isInstalledApp={isInstalledApp}
|
||||||
installedAppId={installedAppInfo?.id}
|
installedAppId={installedAppInfo?.id}
|
||||||
siteInfo={siteInfo}
|
siteInfo={siteInfo}
|
||||||
|
onPin={handlePin}
|
||||||
|
onUnpin={handleUnpin}
|
||||||
|
controlUpdateList={controlUpdateConversationList}
|
||||||
|
onDelete={handleDelete}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -482,9 +534,6 @@ const Main: FC<IMainProps> = ({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* {isNewConversation ? 'new' : 'exist'}
|
|
||||||
{JSON.stringify(newConversationInputs ? newConversationInputs : {})}
|
|
||||||
{JSON.stringify(existConversationInputs ? existConversationInputs : {})} */}
|
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex rounded-t-2xl bg-white overflow-hidden',
|
'flex rounded-t-2xl bg-white overflow-hidden',
|
||||||
@ -551,6 +600,17 @@ const Main: FC<IMainProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>)
|
</div>)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{isShowConfirm && (
|
||||||
|
<Confirm
|
||||||
|
title={t('share.chat.deleteConversation.title')}
|
||||||
|
content={t('share.chat.deleteConversation.content')}
|
||||||
|
isShow={isShowConfirm}
|
||||||
|
onClose={hideConfirm}
|
||||||
|
onConfirm={didDelete}
|
||||||
|
onCancel={hideConfirm}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,32 +1,34 @@
|
|||||||
import React, { useRef } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import {
|
import {
|
||||||
ChatBubbleOvalLeftEllipsisIcon,
|
|
||||||
PencilSquareIcon,
|
PencilSquareIcon,
|
||||||
} from '@heroicons/react/24/outline'
|
} from '@heroicons/react/24/outline'
|
||||||
import { ChatBubbleOvalLeftEllipsisIcon as ChatBubbleOvalLeftEllipsisSolidIcon } from '@heroicons/react/24/solid'
|
import cn from 'classnames'
|
||||||
import { useInfiniteScroll } from 'ahooks'
|
|
||||||
import Button from '../../../base/button'
|
import Button from '../../../base/button'
|
||||||
|
import List from './list'
|
||||||
import AppInfo from '@/app/components/share/chat/sidebar/app-info'
|
import AppInfo from '@/app/components/share/chat/sidebar/app-info'
|
||||||
// import Card from './card'
|
// import Card from './card'
|
||||||
import type { ConversationItem, SiteInfo } from '@/models/share'
|
import type { ConversationItem, SiteInfo } from '@/models/share'
|
||||||
import { fetchConversations } from '@/service/share'
|
import { fetchConversations } from '@/service/share'
|
||||||
|
|
||||||
function classNames(...classes: any[]) {
|
|
||||||
return classes.filter(Boolean).join(' ')
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ISidebarProps = {
|
export type ISidebarProps = {
|
||||||
copyRight: string
|
copyRight: string
|
||||||
currentId: string
|
currentId: string
|
||||||
onCurrentIdChange: (id: string) => void
|
onCurrentIdChange: (id: string) => void
|
||||||
list: ConversationItem[]
|
list: ConversationItem[]
|
||||||
|
pinnedList: ConversationItem[]
|
||||||
isInstalledApp: boolean
|
isInstalledApp: boolean
|
||||||
installedAppId?: string
|
installedAppId?: string
|
||||||
siteInfo: SiteInfo
|
siteInfo: SiteInfo
|
||||||
onMoreLoaded: (res: { data: ConversationItem[]; has_more: boolean }) => void
|
onMoreLoaded: (res: { data: ConversationItem[]; has_more: boolean }) => void
|
||||||
|
onPinnedMoreLoaded: (res: { data: ConversationItem[]; has_more: boolean }) => void
|
||||||
isNoMore: boolean
|
isNoMore: boolean
|
||||||
|
isPinnedNoMore: boolean
|
||||||
|
onPin: (id: string) => void
|
||||||
|
onUnpin: (id: string) => void
|
||||||
|
controlUpdateList: number
|
||||||
|
onDelete: (id: string) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const Sidebar: FC<ISidebarProps> = ({
|
const Sidebar: FC<ISidebarProps> = ({
|
||||||
@ -34,37 +36,42 @@ const Sidebar: FC<ISidebarProps> = ({
|
|||||||
currentId,
|
currentId,
|
||||||
onCurrentIdChange,
|
onCurrentIdChange,
|
||||||
list,
|
list,
|
||||||
|
pinnedList,
|
||||||
isInstalledApp,
|
isInstalledApp,
|
||||||
installedAppId,
|
installedAppId,
|
||||||
siteInfo,
|
siteInfo,
|
||||||
onMoreLoaded,
|
onMoreLoaded,
|
||||||
|
onPinnedMoreLoaded,
|
||||||
isNoMore,
|
isNoMore,
|
||||||
|
isPinnedNoMore,
|
||||||
|
onPin,
|
||||||
|
onUnpin,
|
||||||
|
controlUpdateList,
|
||||||
|
onDelete,
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const listRef = useRef<HTMLDivElement>(null)
|
const [hasPinned, setHasPinned] = useState(false)
|
||||||
|
|
||||||
useInfiniteScroll(
|
const checkHasPinned = async () => {
|
||||||
async () => {
|
const { data }: any = await fetchConversations(isInstalledApp, installedAppId, undefined, true)
|
||||||
if (!isNoMore) {
|
setHasPinned(data.length > 0)
|
||||||
const lastId = list[list.length - 1].id
|
}
|
||||||
const { data: conversations, has_more }: any = await fetchConversations(isInstalledApp, installedAppId, lastId)
|
|
||||||
onMoreLoaded({ data: conversations, has_more })
|
useEffect(() => {
|
||||||
}
|
checkHasPinned()
|
||||||
return { list: [] }
|
}, [])
|
||||||
},
|
|
||||||
{
|
useEffect(() => {
|
||||||
target: listRef,
|
if (controlUpdateList !== 0)
|
||||||
isNoMore: () => {
|
checkHasPinned()
|
||||||
return isNoMore
|
}, [controlUpdateList])
|
||||||
},
|
|
||||||
reloadDeps: [isNoMore],
|
const maxListHeight = isInstalledApp ? 'max-h-[30vh]' : 'max-h-[40vh]'
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
classNames(
|
cn(
|
||||||
isInstalledApp ? 'tablet:h-[calc(100vh_-_74px)]' : 'tablet:h-[calc(100vh_-_3rem)]',
|
isInstalledApp ? 'tablet:h-[calc(100vh_-_74px)]' : 'tablet:h-[calc(100vh_-_3rem)]',
|
||||||
'shrink-0 flex flex-col bg-white pc:w-[244px] tablet:w-[192px] mobile:w-[240px] border-r border-gray-200 mobile:h-screen',
|
'shrink-0 flex flex-col bg-white pc:w-[244px] tablet:w-[192px] mobile:w-[240px] border-r border-gray-200 mobile:h-screen',
|
||||||
)
|
)
|
||||||
@ -85,40 +92,48 @@ const Sidebar: FC<ISidebarProps> = ({
|
|||||||
<PencilSquareIcon className="mr-2 h-4 w-4" /> {t('share.chat.newChat')}
|
<PencilSquareIcon className="mr-2 h-4 w-4" /> {t('share.chat.newChat')}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
<div className='flex-grow h-0 overflow-y-auto overflow-x-hidden'>
|
||||||
<nav
|
{/* pinned list */}
|
||||||
ref={listRef}
|
{hasPinned && (
|
||||||
className="mt-4 flex-1 space-y-1 bg-white p-4 !pt-0 overflow-y-auto"
|
<div className='mt-4 px-4'>
|
||||||
>
|
<div className='mb-1.5 leading-[18px] text-xs text-gray-500 font-medium uppercase'>{t('share.chat.pinnedTitle')}</div>
|
||||||
{list.map((item) => {
|
<List
|
||||||
const isCurrent = item.id === currentId
|
className={maxListHeight}
|
||||||
const ItemIcon
|
currentId={currentId}
|
||||||
= isCurrent ? ChatBubbleOvalLeftEllipsisSolidIcon : ChatBubbleOvalLeftEllipsisIcon
|
onCurrentIdChange={onCurrentIdChange}
|
||||||
return (
|
list={pinnedList}
|
||||||
<div
|
isInstalledApp={isInstalledApp}
|
||||||
onClick={() => onCurrentIdChange(item.id)}
|
installedAppId={installedAppId}
|
||||||
key={item.id}
|
onMoreLoaded={onPinnedMoreLoaded}
|
||||||
className={classNames(
|
isNoMore={isPinnedNoMore}
|
||||||
isCurrent
|
isPinned={true}
|
||||||
? 'bg-primary-50 text-primary-600'
|
onPinChanged={id => onUnpin(id)}
|
||||||
: 'text-gray-700 hover:bg-gray-100 hover:text-gray-700',
|
controlUpdate={controlUpdateList + 1}
|
||||||
'group flex items-center rounded-md px-2 py-2 text-sm font-medium cursor-pointer',
|
onDelete={onDelete}
|
||||||
)}
|
/>
|
||||||
>
|
</div>
|
||||||
<ItemIcon
|
)}
|
||||||
className={classNames(
|
{/* unpinned list */}
|
||||||
isCurrent
|
<div className='mt-4 px-4'>
|
||||||
? 'text-primary-600'
|
{hasPinned && (
|
||||||
: 'text-gray-400 group-hover:text-gray-500',
|
<div className='mb-1.5 leading-[18px] text-xs text-gray-500 font-medium uppercase'>{t('share.chat.unpinnedTitle')}</div>
|
||||||
'mr-3 h-5 w-5 flex-shrink-0',
|
)}
|
||||||
)}
|
<List
|
||||||
aria-hidden="true"
|
className={cn(hasPinned ? maxListHeight : 'flex-grow')}
|
||||||
/>
|
currentId={currentId}
|
||||||
{item.name}
|
onCurrentIdChange={onCurrentIdChange}
|
||||||
</div>
|
list={list}
|
||||||
)
|
isInstalledApp={isInstalledApp}
|
||||||
})}
|
installedAppId={installedAppId}
|
||||||
</nav>
|
onMoreLoaded={onMoreLoaded}
|
||||||
|
isNoMore={isNoMore}
|
||||||
|
isPinned={false}
|
||||||
|
onPinChanged={id => onPin(id)}
|
||||||
|
controlUpdate={controlUpdateList + 1}
|
||||||
|
onDelete={onDelete}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div className="flex flex-shrink-0 pr-4 pb-4 pl-4">
|
<div className="flex flex-shrink-0 pr-4 pb-4 pl-4">
|
||||||
<div className="text-gray-400 font-normal text-xs">© {copyRight} {(new Date()).getFullYear()}</div>
|
<div className="text-gray-400 font-normal text-xs">© {copyRight} {(new Date()).getFullYear()}</div>
|
||||||
</div>
|
</div>
|
||||||
|
115
web/app/components/share/chat/sidebar/list/index.tsx
Normal file
115
web/app/components/share/chat/sidebar/list/index.tsx
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
'use client'
|
||||||
|
import type { FC } from 'react'
|
||||||
|
import React, { useRef } from 'react'
|
||||||
|
import {
|
||||||
|
ChatBubbleOvalLeftEllipsisIcon,
|
||||||
|
} from '@heroicons/react/24/outline'
|
||||||
|
import { useInfiniteScroll } from 'ahooks'
|
||||||
|
import { ChatBubbleOvalLeftEllipsisIcon as ChatBubbleOvalLeftEllipsisSolidIcon } from '@heroicons/react/24/solid'
|
||||||
|
import cn from 'classnames'
|
||||||
|
import s from './style.module.css'
|
||||||
|
import type { ConversationItem } from '@/models/share'
|
||||||
|
import { fetchConversations } from '@/service/share'
|
||||||
|
import ItemOperation from '@/app/components/explore/item-operation'
|
||||||
|
|
||||||
|
export type IListProps = {
|
||||||
|
className: string
|
||||||
|
currentId: string
|
||||||
|
onCurrentIdChange: (id: string) => void
|
||||||
|
list: ConversationItem[]
|
||||||
|
isInstalledApp: boolean
|
||||||
|
installedAppId?: string
|
||||||
|
onMoreLoaded: (res: { data: ConversationItem[]; has_more: boolean }) => void
|
||||||
|
isNoMore: boolean
|
||||||
|
isPinned: boolean
|
||||||
|
onPinChanged: (id: string) => void
|
||||||
|
controlUpdate: number
|
||||||
|
onDelete: (id: string) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const List: FC<IListProps> = ({
|
||||||
|
className,
|
||||||
|
currentId,
|
||||||
|
onCurrentIdChange,
|
||||||
|
list,
|
||||||
|
isInstalledApp,
|
||||||
|
installedAppId,
|
||||||
|
onMoreLoaded,
|
||||||
|
isNoMore,
|
||||||
|
isPinned,
|
||||||
|
onPinChanged,
|
||||||
|
controlUpdate,
|
||||||
|
onDelete,
|
||||||
|
}) => {
|
||||||
|
const listRef = useRef<HTMLDivElement>(null)
|
||||||
|
|
||||||
|
useInfiniteScroll(
|
||||||
|
async () => {
|
||||||
|
if (!isNoMore) {
|
||||||
|
const lastId = list[list.length - 1]?.id
|
||||||
|
const { data: conversations, has_more }: any = await fetchConversations(isInstalledApp, installedAppId, lastId, isPinned)
|
||||||
|
onMoreLoaded({ data: conversations, has_more })
|
||||||
|
}
|
||||||
|
return { list: [] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
target: listRef,
|
||||||
|
isNoMore: () => {
|
||||||
|
return isNoMore
|
||||||
|
},
|
||||||
|
reloadDeps: [isNoMore, controlUpdate],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return (
|
||||||
|
<nav
|
||||||
|
ref={listRef}
|
||||||
|
className={cn(className, 'shrink-0 space-y-1 bg-white pb-[60px] overflow-y-auto')}
|
||||||
|
>
|
||||||
|
{list.map((item) => {
|
||||||
|
const isCurrent = item.id === currentId
|
||||||
|
const ItemIcon
|
||||||
|
= isCurrent ? ChatBubbleOvalLeftEllipsisSolidIcon : ChatBubbleOvalLeftEllipsisIcon
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
onClick={() => onCurrentIdChange(item.id)}
|
||||||
|
key={item.id}
|
||||||
|
className={cn(s.item,
|
||||||
|
isCurrent
|
||||||
|
? 'bg-primary-50 text-primary-600'
|
||||||
|
: 'text-gray-700 hover:bg-gray-200 hover:text-gray-700',
|
||||||
|
'group flex justify-between items-center rounded-md px-2 py-2 text-sm font-medium cursor-pointer',
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className='flex items-center w-0 grow'>
|
||||||
|
<ItemIcon
|
||||||
|
className={cn(
|
||||||
|
isCurrent
|
||||||
|
? 'text-primary-600'
|
||||||
|
: 'text-gray-400 group-hover:text-gray-500',
|
||||||
|
'mr-3 h-5 w-5 flex-shrink-0',
|
||||||
|
)}
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
|
<span>{item.name}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{
|
||||||
|
!isCurrent && (
|
||||||
|
<div className={cn(s.opBtn, 'shrink-0')} onClick={e => e.stopPropagation()}>
|
||||||
|
<ItemOperation
|
||||||
|
isPinned={isPinned}
|
||||||
|
togglePin={() => onPinChanged(item.id)}
|
||||||
|
isShowDelete
|
||||||
|
onDelete={() => onDelete(item.id)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</nav>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default React.memo(List)
|
@ -0,0 +1,7 @@
|
|||||||
|
.opBtn {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item:hover .opBtn {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
@ -1,45 +1,51 @@
|
|||||||
const translation = {
|
const translation = {
|
||||||
common: {
|
common: {
|
||||||
welcome: "Welcome to use",
|
welcome: 'Welcome to use',
|
||||||
appUnavailable: "App is unavailable",
|
appUnavailable: 'App is unavailable',
|
||||||
appUnkonwError: "App is unavailable"
|
appUnkonwError: 'App is unavailable',
|
||||||
},
|
},
|
||||||
chat: {
|
chat: {
|
||||||
newChat: "New chat",
|
newChat: 'New chat',
|
||||||
newChatDefaultName: "New conversation",
|
pinnedTitle: 'Pinned',
|
||||||
powerBy: "Powered by",
|
unpinnedTitle: 'Chats',
|
||||||
prompt: "Prompt",
|
newChatDefaultName: 'New conversation',
|
||||||
privatePromptConfigTitle: "Conversation settings",
|
powerBy: 'Powered by',
|
||||||
publicPromptConfigTitle: "Initial Prompt",
|
prompt: 'Prompt',
|
||||||
configStatusDes: "Before start, you can modify conversation settings",
|
privatePromptConfigTitle: 'Conversation settings',
|
||||||
|
publicPromptConfigTitle: 'Initial Prompt',
|
||||||
|
configStatusDes: 'Before start, you can modify conversation settings',
|
||||||
configDisabled:
|
configDisabled:
|
||||||
"Previous session settings have been used for this session.",
|
'Previous session settings have been used for this session.',
|
||||||
startChat: "Start Chat",
|
startChat: 'Start Chat',
|
||||||
privacyPolicyLeft:
|
privacyPolicyLeft:
|
||||||
"Please read the ",
|
'Please read the ',
|
||||||
privacyPolicyMiddle:
|
privacyPolicyMiddle:
|
||||||
"privacy policy",
|
'privacy policy',
|
||||||
privacyPolicyRight:
|
privacyPolicyRight:
|
||||||
" provided by the app developer.",
|
' provided by the app developer.',
|
||||||
|
deleteConversation: {
|
||||||
|
title: 'Delete conversation',
|
||||||
|
content: 'Are you sure you want to delete this conversation?',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
generation: {
|
generation: {
|
||||||
tabs: {
|
tabs: {
|
||||||
create: "Create",
|
create: 'Create',
|
||||||
saved: "Saved",
|
saved: 'Saved',
|
||||||
},
|
},
|
||||||
savedNoData: {
|
savedNoData: {
|
||||||
title: "You haven't saved a result yet!",
|
title: 'You haven\'t saved a result yet!',
|
||||||
description: 'Start generating content, and find your saved results here.',
|
description: 'Start generating content, and find your saved results here.',
|
||||||
startCreateContent: 'Start create content'
|
startCreateContent: 'Start create content',
|
||||||
},
|
},
|
||||||
title: "AI Completion",
|
title: 'AI Completion',
|
||||||
queryTitle: "Query content",
|
queryTitle: 'Query content',
|
||||||
queryPlaceholder: "Write your query content...",
|
queryPlaceholder: 'Write your query content...',
|
||||||
run: "RUN",
|
run: 'RUN',
|
||||||
copy: "Copy",
|
copy: 'Copy',
|
||||||
resultTitle: "AI Completion",
|
resultTitle: 'AI Completion',
|
||||||
noData: "AI will give you what you want here.",
|
noData: 'AI will give you what you want here.',
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
|
|
||||||
export default translation;
|
export default translation
|
||||||
|
@ -1,41 +1,47 @@
|
|||||||
const translation = {
|
const translation = {
|
||||||
common: {
|
common: {
|
||||||
welcome: "欢迎使用",
|
welcome: '欢迎使用',
|
||||||
appUnavailable: "应用不可用",
|
appUnavailable: '应用不可用',
|
||||||
appUnkonwError: "应用不可用",
|
appUnkonwError: '应用不可用',
|
||||||
},
|
},
|
||||||
chat: {
|
chat: {
|
||||||
newChat: "新对话",
|
newChat: '新对话',
|
||||||
newChatDefaultName: "新的对话",
|
pinnedTitle: '已置顶',
|
||||||
powerBy: "Powered by",
|
unpinnedTitle: '对话列表',
|
||||||
prompt: "提示词",
|
newChatDefaultName: '新的对话',
|
||||||
privatePromptConfigTitle: "对话设置",
|
powerBy: 'Powered by',
|
||||||
publicPromptConfigTitle: "对话前提示词",
|
prompt: '提示词',
|
||||||
configStatusDes: "开始前,您可以修改对话设置",
|
privatePromptConfigTitle: '对话设置',
|
||||||
configDisabled: "此次会话已使用上次会话表单",
|
publicPromptConfigTitle: '对话前提示词',
|
||||||
startChat: "开始对话",
|
configStatusDes: '开始前,您可以修改对话设置',
|
||||||
privacyPolicyLeft: "请阅读由该应用开发者提供的",
|
configDisabled: '此次会话已使用上次会话表单',
|
||||||
privacyPolicyMiddle: "隐私政策",
|
startChat: '开始对话',
|
||||||
privacyPolicyRight: "。",
|
privacyPolicyLeft: '请阅读由该应用开发者提供的',
|
||||||
|
privacyPolicyMiddle: '隐私政策',
|
||||||
|
privacyPolicyRight: '。',
|
||||||
|
deleteConversation: {
|
||||||
|
title: '删除对话',
|
||||||
|
content: '您确定要删除此对话吗?',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
generation: {
|
generation: {
|
||||||
tabs: {
|
tabs: {
|
||||||
create: "创建",
|
create: '创建',
|
||||||
saved: "已保存",
|
saved: '已保存',
|
||||||
},
|
},
|
||||||
savedNoData: {
|
savedNoData: {
|
||||||
title: "您还没有保存结果!",
|
title: '您还没有保存结果!',
|
||||||
description: '开始生成内容,您可以在这里找到保存的结果。',
|
description: '开始生成内容,您可以在这里找到保存的结果。',
|
||||||
startCreateContent: '开始生成内容'
|
startCreateContent: '开始生成内容',
|
||||||
},
|
},
|
||||||
title: "AI 智能书写",
|
title: 'AI 智能书写',
|
||||||
queryTitle: "查询内容",
|
queryTitle: '查询内容',
|
||||||
queryPlaceholder: "请输入文本内容",
|
queryPlaceholder: '请输入文本内容',
|
||||||
run: "运行",
|
run: '运行',
|
||||||
copy: "拷贝",
|
copy: '拷贝',
|
||||||
resultTitle: "AI 书写",
|
resultTitle: 'AI 书写',
|
||||||
noData: "AI 会在这里给你惊喜。",
|
noData: 'AI 会在这里给你惊喜。',
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
|
|
||||||
export default translation;
|
export default translation
|
||||||
|
@ -1,16 +1,18 @@
|
|||||||
import type { IOnCompleted, IOnData, IOnError } from './base'
|
import type { IOnCompleted, IOnData, IOnError } from './base'
|
||||||
import {
|
import {
|
||||||
del as consoleDel, get as consoleGet, post as consolePost,
|
del as consoleDel, get as consoleGet, patch as consolePatch, post as consolePost,
|
||||||
delPublic as del, getPublic as get, postPublic as post, ssePost,
|
delPublic as del, getPublic as get, patchPublic as patch, postPublic as post, ssePost,
|
||||||
} from './base'
|
} from './base'
|
||||||
import type { Feedbacktype } from '@/app/components/app/chat'
|
import type { Feedbacktype } from '@/app/components/app/chat'
|
||||||
|
|
||||||
function getAction(action: 'get' | 'post' | 'del', isInstalledApp: boolean) {
|
function getAction(action: 'get' | 'post' | 'del' | 'patch', isInstalledApp: boolean) {
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case 'get':
|
case 'get':
|
||||||
return isInstalledApp ? consoleGet : get
|
return isInstalledApp ? consoleGet : get
|
||||||
case 'post':
|
case 'post':
|
||||||
return isInstalledApp ? consolePost : post
|
return isInstalledApp ? consolePost : post
|
||||||
|
case 'patch':
|
||||||
|
return isInstalledApp ? consolePatch : patch
|
||||||
case 'del':
|
case 'del':
|
||||||
return isInstalledApp ? consoleDel : del
|
return isInstalledApp ? consoleDel : del
|
||||||
}
|
}
|
||||||
@ -55,8 +57,20 @@ export const fetchAppInfo = async () => {
|
|||||||
return get('/site')
|
return get('/site')
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fetchConversations = async (isInstalledApp: boolean, installedAppId = '', last_id?: string) => {
|
export const fetchConversations = async (isInstalledApp: boolean, installedAppId = '', last_id?: string, pinned?: boolean, limit?: number) => {
|
||||||
return getAction('get', isInstalledApp)(getUrl('conversations', isInstalledApp, installedAppId), { params: { ...{ limit: 20 }, ...(last_id ? { last_id } : {}) } })
|
return getAction('get', isInstalledApp)(getUrl('conversations', isInstalledApp, installedAppId), { params: { ...{ limit: limit || 20 }, ...(last_id ? { last_id } : {}), ...(pinned !== undefined ? { pinned } : {}) } })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const pinConversation = async (isInstalledApp: boolean, installedAppId = '', id: string) => {
|
||||||
|
return getAction('patch', isInstalledApp)(getUrl(`conversations/${id}/pin`, isInstalledApp, installedAppId))
|
||||||
|
}
|
||||||
|
|
||||||
|
export const unpinConversation = async (isInstalledApp: boolean, installedAppId = '', id: string) => {
|
||||||
|
return getAction('patch', isInstalledApp)(getUrl(`conversations/${id}/unpin`, isInstalledApp, installedAppId))
|
||||||
|
}
|
||||||
|
|
||||||
|
export const delConversation = async (isInstalledApp: boolean, installedAppId = '', id: string) => {
|
||||||
|
return getAction('del', isInstalledApp)(getUrl(`conversations/${id}`, isInstalledApp, installedAppId))
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fetchChatList = async (conversationId: string, isInstalledApp: boolean, installedAppId = '') => {
|
export const fetchChatList = async (conversationId: string, isInstalledApp: boolean, installedAppId = '') => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user