diff --git a/docSite/content/zh-cn/docs/development/openapi/chat.md b/docSite/content/zh-cn/docs/development/openapi/chat.md index c7bcd2dea..5f9be13ce 100644 --- a/docSite/content/zh-cn/docs/development/openapi/chat.md +++ b/docSite/content/zh-cn/docs/development/openapi/chat.md @@ -959,10 +959,16 @@ curl --location --request POST 'http://localhost:3000/api/core/chat/getHistories {{< markdownify >}} {{% alert icon=" " context="success" %}} +目前仅能获取到当前 API key 的创建者的对话。 + - appId - 应用 Id - offset - 偏移量,即从第几条数据开始取 - pageSize - 记录数量 - source - 对话源。source=api,表示获取通过 API 创建的对话(不会获取到页面上的对话记录) +- startCreateTime - 开始创建时间(可选) +- endCreateTime - 结束创建时间(可选) +- startUpdateTime - 开始更新时间(可选) +- endUpdateTime - 结束更新时间(可选) {{% /alert %}} {{< /markdownify >}} diff --git a/packages/global/core/chat/type.d.ts b/packages/global/core/chat/type.d.ts index 3b1c9c3ce..76acc9916 100644 --- a/packages/global/core/chat/type.d.ts +++ b/packages/global/core/chat/type.d.ts @@ -26,6 +26,7 @@ export type ChatSchema = { teamId: string; tmbId: string; appId: string; + createTime: Date; updateTime: Date; title: string; customTitle: string; diff --git a/packages/service/core/chat/chatSchema.ts b/packages/service/core/chat/chatSchema.ts index 2209b84b9..a0c30d56d 100644 --- a/packages/service/core/chat/chatSchema.ts +++ b/packages/service/core/chat/chatSchema.ts @@ -34,6 +34,10 @@ const ChatSchema = new Schema({ ref: AppCollectionName, required: true }, + createTime: { + type: Date, + default: () => new Date() + }, updateTime: { type: Date, default: () => new Date() diff --git a/packages/service/core/dataset/search/controller.ts b/packages/service/core/dataset/search/controller.ts index 798350585..75e3105b5 100644 --- a/packages/service/core/dataset/search/controller.ts +++ b/packages/service/core/dataset/search/controller.ts @@ -27,6 +27,7 @@ import { type ChatItemType } from '@fastgpt/global/core/chat/type'; import type { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants'; import { datasetSearchQueryExtension } from './utils'; import type { RerankModelItemType } from '@fastgpt/global/core/ai/model.d'; +import { addLog } from '../../../common/system/log'; export type SearchDatasetDataProps = { histories: ChatItemType[]; @@ -544,117 +545,125 @@ export async function searchDatasetData( }; } - const searchResults = (await MongoDatasetDataText.aggregate( - [ - { - $match: { - teamId: new Types.ObjectId(teamId), - $text: { $search: await jiebaSplit({ text: query }) }, - datasetId: { $in: datasetIds.map((id) => new Types.ObjectId(id)) }, - ...(filterCollectionIdList - ? { - collectionId: { - $in: filterCollectionIdList.map((id) => new Types.ObjectId(id)) + try { + const searchResults = (await MongoDatasetDataText.aggregate( + [ + { + $match: { + teamId: new Types.ObjectId(teamId), + $text: { $search: await jiebaSplit({ text: query }) }, + datasetId: { $in: datasetIds.map((id) => new Types.ObjectId(id)) }, + ...(filterCollectionIdList + ? { + collectionId: { + $in: filterCollectionIdList.map((id) => new Types.ObjectId(id)) + } } - } - : {}), - ...(forbidCollectionIdList && forbidCollectionIdList.length > 0 - ? { - collectionId: { - $nin: forbidCollectionIdList.map((id) => new Types.ObjectId(id)) + : {}), + ...(forbidCollectionIdList && forbidCollectionIdList.length > 0 + ? { + collectionId: { + $nin: forbidCollectionIdList.map((id) => new Types.ObjectId(id)) + } } - } - : {}) + : {}) + } + }, + { + $sort: { + score: { $meta: 'textScore' } + } + }, + { + $limit: limit + }, + { + $project: { + _id: 1, + collectionId: 1, + dataId: 1, + score: { $meta: 'textScore' } + } } - }, + ], { - $sort: { - score: { $meta: 'textScore' } - } - }, - { - $limit: limit - }, - { - $project: { - _id: 1, - collectionId: 1, - dataId: 1, - score: { $meta: 'textScore' } - } + ...readFromSecondary } - ], - { - ...readFromSecondary - } - )) as (DatasetDataTextSchemaType & { score: number })[]; + )) as (DatasetDataTextSchemaType & { score: number })[]; - // Get data and collections - const [dataList, collections] = await Promise.all([ - MongoDatasetData.find( - { - _id: { $in: searchResults.map((item) => item.dataId) } - }, - '_id datasetId collectionId updateTime q a chunkIndex indexes', - { ...readFromSecondary } - ).lean(), - MongoDatasetCollection.find( - { - _id: { $in: searchResults.map((item) => item.collectionId) } - }, - '_id name fileId rawLink apiFileId externalFileId externalFileUrl', - { ...readFromSecondary } - ).lean() - ]); + // Get data and collections + const [dataList, collections] = await Promise.all([ + MongoDatasetData.find( + { + _id: { $in: searchResults.map((item) => item.dataId) } + }, + '_id datasetId collectionId updateTime q a chunkIndex indexes', + { ...readFromSecondary } + ).lean(), + MongoDatasetCollection.find( + { + _id: { $in: searchResults.map((item) => item.collectionId) } + }, + '_id name fileId rawLink apiFileId externalFileId externalFileUrl', + { ...readFromSecondary } + ).lean() + ]); - return { - fullTextRecallResults: searchResults - .map((item, index) => { - const collection = collections.find( - (col) => String(col._id) === String(item.collectionId) - ); - if (!collection) { - console.log('Collection is not found', item); - return; - } - const data = dataList.find((data) => String(data._id) === String(item.dataId)); - if (!data) { - console.log('Data is not found', item); - return; - } + return { + fullTextRecallResults: searchResults + .map((item, index) => { + const collection = collections.find( + (col) => String(col._id) === String(item.collectionId) + ); + if (!collection) { + console.log('Collection is not found', item); + return; + } + const data = dataList.find((data) => String(data._id) === String(item.dataId)); + if (!data) { + console.log('Data is not found', item); + return; + } - return { - id: String(data._id), - datasetId: String(data.datasetId), - collectionId: String(data.collectionId), - updateTime: data.updateTime, - q: data.q, - a: data.a, - chunkIndex: data.chunkIndex, - indexes: data.indexes, - ...getCollectionSourceData(collection), - score: [ - { - type: SearchScoreTypeEnum.fullText, - value: item.score || 0, - index - } - ] - }; - }) - .filter((item) => { - if (!item) return false; - return true; - }) - .map((item, index) => { - if (!item) return; - return { - ...item, - score: item.score.map((item) => ({ ...item, index })) - }; - }) as SearchDataResponseItemType[], - tokenLen: 0 - }; + return { + id: String(data._id), + datasetId: String(data.datasetId), + collectionId: String(data.collectionId), + updateTime: data.updateTime, + q: data.q, + a: data.a, + chunkIndex: data.chunkIndex, + indexes: data.indexes, + ...getCollectionSourceData(collection), + score: [ + { + type: SearchScoreTypeEnum.fullText, + value: item.score || 0, + index + } + ] + }; + }) + .filter((item) => { + if (!item) return false; + return true; + }) + .map((item, index) => { + if (!item) return; + return { + ...item, + score: item.score.map((item) => ({ ...item, index })) + }; + }) as SearchDataResponseItemType[], + tokenLen: 0 + }; + } catch (error) { + addLog.error('multiQueryRecall error', error); + return { + fullTextRecallResults: [], + tokenLen: 0 + }; + } }; const multiQueryRecall = async ({ embeddingLimit, diff --git a/packages/web/common/system/utils.ts b/packages/web/common/system/utils.ts index d51cf1aa1..63fceb55e 100644 --- a/packages/web/common/system/utils.ts +++ b/packages/web/common/system/utils.ts @@ -6,10 +6,6 @@ export const getUserFingerprint = async () => { console.log(result.visitorId); }; -export const hasHttps = () => { - return window.location.protocol === 'https:'; -}; - export const subRoute = process.env.NEXT_PUBLIC_BASE_URL; export const getWebReqUrl = (url: string = '') => { diff --git a/packages/web/hooks/useCopyData.tsx b/packages/web/hooks/useCopyData.tsx index 801c9ae4c..c671b151a 100644 --- a/packages/web/hooks/useCopyData.tsx +++ b/packages/web/hooks/useCopyData.tsx @@ -1,8 +1,6 @@ import { useTranslation } from 'next-i18next'; import { useToast } from './useToast'; import { useCallback } from 'react'; -import { hasHttps } from '../common/system/utils'; -import { isProduction } from '@fastgpt/global/common/system/constants'; import MyModal from '../components/common/MyModal'; import React from 'react'; import { Box, ModalBody } from '@chakra-ui/react'; @@ -26,7 +24,7 @@ export const useCopyData = () => { data = data.trim(); try { - if ((hasHttps() || !isProduction) && navigator.clipboard) { + if (navigator.clipboard && window.isSecureContext) { await navigator.clipboard.writeText(data); if (title) { toast({ @@ -36,13 +34,35 @@ export const useCopyData = () => { }); } } else { - throw new Error(''); + let textArea = document.createElement('textarea'); + textArea.value = data; + // 使text area不在viewport,同时设置不可见 + textArea.style.position = 'absolute'; + // @ts-ignore + textArea.style.opacity = 0; + textArea.style.left = '-999999px'; + textArea.style.top = '-999999px'; + document.body.appendChild(textArea); + textArea.focus(); + textArea.select(); + await new Promise((res, rej) => { + document.execCommand('copy') ? res('') : rej(); + textArea.remove(); + }).then(() => { + if (title) { + toast({ + title, + status: 'success', + duration + }); + } + }); } } catch (error) { setCopyContent(data); } }, - [t, toast] + [setCopyContent, t, toast] ); return { diff --git a/packages/web/i18n/en/common.json b/packages/web/i18n/en/common.json index c26f3bc59..b262c652a 100644 --- a/packages/web/i18n/en/common.json +++ b/packages/web/i18n/en/common.json @@ -941,6 +941,7 @@ "pay_corporate_payment": "Payment to the public", "pay_money": "Amount payable", "pay_success": "Payment successfully", + "pay_year_tip": "Pay 10 months, enjoy 1 year!", "permission.Collaborator": "Collaborator", "permission.Default permission": "Default Permission", "permission.Manage": "Manage", @@ -1144,7 +1145,7 @@ "support.wallet.subscription.Next plan": "Future Package", "support.wallet.subscription.Stand plan level": "Subscription Package", "support.wallet.subscription.Sub plan": "Subscription Package", - "support.wallet.subscription.Sub plan tip": "Free to use {{title}} or upgrade to a higher package", + "support.wallet.subscription.Sub plan tip": "Free to use [{{title}}] or upgrade to a higher package", "support.wallet.subscription.Team plan and usage": "Package and Usage", "support.wallet.subscription.Training weight": "Training Priority: {{weight}}", "support.wallet.subscription.Update extra ai points": "Extra AI Points", @@ -1159,7 +1160,6 @@ "support.wallet.subscription.function.Points": "{{amount}} AI Points", "support.wallet.subscription.mode.Month": "Month", "support.wallet.subscription.mode.Period": "Subscription Period", - "support.wallet.subscription.mode.Ten Year": "Pay 10 months, imagine 1 year!", "support.wallet.subscription.mode.Year": "Year", "support.wallet.subscription.mode.Year sale": "Two Months Free", "support.wallet.subscription.point": "Points", diff --git a/packages/web/i18n/zh-CN/common.json b/packages/web/i18n/zh-CN/common.json index 4c36a6d60..d76d7f262 100644 --- a/packages/web/i18n/zh-CN/common.json +++ b/packages/web/i18n/zh-CN/common.json @@ -940,6 +940,7 @@ "pay_corporate_payment": "对公支付", "pay_money": "应付金额", "pay_success": "支付成功", + "pay_year_tip": "支付 10 个月,畅享 1 年!", "permission.Collaborator": "协作者", "permission.Default permission": "默认权限", "permission.Manage": "管理", @@ -1143,7 +1144,7 @@ "support.wallet.subscription.Next plan": "未来套餐", "support.wallet.subscription.Stand plan level": "订阅套餐", "support.wallet.subscription.Sub plan": "订阅套餐", - "support.wallet.subscription.Sub plan tip": "免费使用 {{title}} 或升级更高的套餐", + "support.wallet.subscription.Sub plan tip": "免费使用【{{title}}】或升级更高的套餐", "support.wallet.subscription.Team plan and usage": "套餐与用量", "support.wallet.subscription.Training weight": "训练优先级:{{weight}}", "support.wallet.subscription.Update extra ai points": "额外 AI 积分", @@ -1158,7 +1159,6 @@ "support.wallet.subscription.function.Points": "{{amount}} AI 积分", "support.wallet.subscription.mode.Month": "按月", "support.wallet.subscription.mode.Period": "订阅周期", - "support.wallet.subscription.mode.Ten Year": "支付10个月,畅想1年!", "support.wallet.subscription.mode.Year": "按年", "support.wallet.subscription.mode.Year sale": "赠送两个月", "support.wallet.subscription.point": "积分", diff --git a/packages/web/i18n/zh-Hant/common.json b/packages/web/i18n/zh-Hant/common.json index ee5b51d51..f2d1eeefb 100644 --- a/packages/web/i18n/zh-Hant/common.json +++ b/packages/web/i18n/zh-Hant/common.json @@ -940,6 +940,7 @@ "pay_corporate_payment": "對公支付", "pay_money": "應付金額", "pay_success": "支付成功", + "pay_year_tip": "支付 10 個月,暢享 1 年!", "permission.Collaborator": "協作者", "permission.Default permission": "預設權限", "permission.Manage": "管理", @@ -1143,7 +1144,7 @@ "support.wallet.subscription.Next plan": "未來方案", "support.wallet.subscription.Stand plan level": "訂閱方案", "support.wallet.subscription.Sub plan": "訂閱方案", - "support.wallet.subscription.Sub plan tip": "免費使用 {{title}} 或升級更進階的方案", + "support.wallet.subscription.Sub plan tip": "免費使用【{{title}}】或升級更進階的方案", "support.wallet.subscription.Team plan and usage": "方案與使用量", "support.wallet.subscription.Training weight": "訓練優先權:{{weight}}", "support.wallet.subscription.Update extra ai points": "額外 AI 點數", @@ -1158,7 +1159,6 @@ "support.wallet.subscription.function.Points": "{{amount}} AI 點數", "support.wallet.subscription.mode.Month": "按月", "support.wallet.subscription.mode.Period": "訂閱週期", - "support.wallet.subscription.mode.Ten Year": "支付10個月,暢想1年!", "support.wallet.subscription.mode.Year": "按年", "support.wallet.subscription.mode.Year sale": "贈送兩個月", "support.wallet.subscription.point": "點數", diff --git a/projects/app/src/global/core/chat/api.d.ts b/projects/app/src/global/core/chat/api.d.ts index f0f7ac00d..533901888 100644 --- a/projects/app/src/global/core/chat/api.d.ts +++ b/projects/app/src/global/core/chat/api.d.ts @@ -60,6 +60,11 @@ export type InitChatResponse = { export type GetHistoriesProps = OutLinkChatAuthProps & { appId?: string; source?: `${ChatSourceEnum}`; + + startCreateTime?: string; + endCreateTime?: string; + startUpdateTime?: string; + endUpdateTime?: string; }; export type UpdateHistoryProps = OutLinkChatAuthProps & { diff --git a/projects/app/src/pageComponents/price/Standard.tsx b/projects/app/src/pageComponents/price/Standard.tsx index 831b44df7..d0de4fb07 100644 --- a/projects/app/src/pageComponents/price/Standard.tsx +++ b/projects/app/src/pageComponents/price/Standard.tsx @@ -89,7 +89,7 @@ const Standard = ({ mb={2} mr={'-2'} > - {t('common:support.wallet.subscription.mode.Ten Year')} + {t('common:pay_year_tip')} setSelectSubMode(e as `${SubModeEnum}`)} /> - + {/* card */} diff --git a/projects/app/src/pages/api/core/chat/getHistories.ts b/projects/app/src/pages/api/core/chat/getHistories.ts index 103a78b4e..486a78d29 100644 --- a/projects/app/src/pages/api/core/chat/getHistories.ts +++ b/projects/app/src/pages/api/core/chat/getHistories.ts @@ -20,7 +20,18 @@ async function handler( req: ApiRequestProps, _res: ApiResponseType ): Promise> { - const { appId, shareId, outLinkUid, teamId, teamToken, source } = req.body; + const { + appId, + shareId, + outLinkUid, + teamId, + teamToken, + source, + startCreateTime, + endCreateTime, + startUpdateTime, + endUpdateTime + } = req.body; const { offset, pageSize } = parsePaginationRequest(req); const match = await (async () => { @@ -49,7 +60,7 @@ async function handler( return { tmbId, appId, - source + ...(source && { source }) }; } })(); @@ -61,13 +72,29 @@ async function handler( }; } + const timeMatch: Record = {}; + if (startCreateTime || endCreateTime) { + timeMatch.createTime = { + ...(startCreateTime && { $gte: new Date(startCreateTime) }), + ...(endCreateTime && { $lte: new Date(endCreateTime) }) + }; + } + if (startUpdateTime || endUpdateTime) { + timeMatch.updateTime = { + ...(startUpdateTime && { $gte: new Date(startUpdateTime) }), + ...(endUpdateTime && { $lte: new Date(endUpdateTime) }) + }; + } + + const mergeMatch = { ...match, ...timeMatch }; + const [data, total] = await Promise.all([ - await MongoChat.find(match, 'chatId title top customTitle appId updateTime') + await MongoChat.find(mergeMatch, 'chatId title top customTitle appId updateTime') .sort({ top: -1, updateTime: -1 }) .skip(offset) .limit(pageSize) .lean(), - MongoChat.countDocuments(match) + MongoChat.countDocuments(mergeMatch) ]); return {