mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-28 00:56:26 +00:00
feat: iframe embed
This commit is contained in:
@@ -2,9 +2,8 @@ import { GET, POST, DELETE, PUT } from './request';
|
||||
import type { ChatHistoryItemType } from '@/types/chat';
|
||||
import type { InitChatResponse, InitShareChatResponse } from './response/chat';
|
||||
import { RequestPaging } from '../types/index';
|
||||
import type { ShareChatSchema } from '@/types/mongoSchema';
|
||||
import type { OutLinkSchema } from '@/types/mongoSchema';
|
||||
import type { ShareChatEditType } from '@/types/app';
|
||||
import type { QuoteItemType } from '@/types/chat';
|
||||
import type { Props as UpdateHistoryProps } from '@/pages/api/chat/history/updateChatHistory';
|
||||
|
||||
/**
|
||||
@@ -50,6 +49,12 @@ export const delChatRecordByIndex = (data: { chatId: string; contentId: string }
|
||||
export const putChatHistory = (data: UpdateHistoryProps) =>
|
||||
PUT('/chat/history/updateChatHistory', data);
|
||||
|
||||
/**
|
||||
* 初始化分享聊天
|
||||
*/
|
||||
export const initShareChatInfo = (data: { shareId: string }) =>
|
||||
GET<InitShareChatResponse>(`/chat/shareChat/init`, data);
|
||||
|
||||
/**
|
||||
* create a shareChat
|
||||
*/
|
||||
@@ -63,15 +68,9 @@ export const createShareChat = (
|
||||
* get shareChat
|
||||
*/
|
||||
export const getShareChatList = (appId: string) =>
|
||||
GET<ShareChatSchema[]>(`/chat/shareChat/list`, { appId });
|
||||
GET<OutLinkSchema[]>(`/chat/shareChat/list`, { appId });
|
||||
|
||||
/**
|
||||
* delete a shareChat
|
||||
*/
|
||||
export const delShareChatById = (id: string) => DELETE(`/chat/shareChat/delete?id=${id}`);
|
||||
|
||||
/**
|
||||
* 初始化分享聊天
|
||||
*/
|
||||
export const initShareChatInfo = (data: { shareId: string }) =>
|
||||
GET<InitShareChatResponse>(`/chat/shareChat/init`, data);
|
||||
|
@@ -1,6 +1,7 @@
|
||||
export enum BillSourceEnum {
|
||||
fastgpt = 'fastgpt',
|
||||
api = 'api'
|
||||
api = 'api',
|
||||
shareLink = 'shareLink'
|
||||
}
|
||||
export enum PageTypeEnum {
|
||||
login = 'login',
|
||||
@@ -10,7 +11,8 @@ export enum PageTypeEnum {
|
||||
|
||||
export const BillSourceMap: Record<`${BillSourceEnum}`, string> = {
|
||||
[BillSourceEnum.fastgpt]: 'FastGpt 平台',
|
||||
[BillSourceEnum.api]: 'Api'
|
||||
[BillSourceEnum.api]: 'Api',
|
||||
[BillSourceEnum.shareLink]: '免登录链接'
|
||||
};
|
||||
|
||||
export enum PromotionEnum {
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { authUser, authApp, authShareChat } from '@/service/utils/auth';
|
||||
import { authUser, authApp, authShareChat, AuthUserTypeEnum } from '@/service/utils/auth';
|
||||
import { sseErrRes, jsonRes } from '@/service/response';
|
||||
import { withNextCors } from '@/service/utils/tools';
|
||||
import { ChatRoleEnum, ChatSourceEnum, sseResponseEventEnum } from '@/constants/chat';
|
||||
@@ -25,7 +25,6 @@ import { pushTaskBill } from '@/service/events/pushBill';
|
||||
import { BillSourceEnum } from '@/constants/user';
|
||||
import { ChatHistoryItemResType } from '@/types/chat';
|
||||
import { UserModelSchema } from '@/types/mongoSchema';
|
||||
import { getAIChatApi } from '@/service/ai/openai';
|
||||
|
||||
export type MessageItemType = ChatCompletionRequestMessage & { _id?: string };
|
||||
type FastGptWebChatProps = {
|
||||
@@ -84,7 +83,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
||||
if (!user) {
|
||||
throw new Error('Account is error');
|
||||
}
|
||||
if (authType !== 'token') {
|
||||
if (authType === AuthUserTypeEnum.apikey || shareId) {
|
||||
user.openaiAccount = undefined;
|
||||
}
|
||||
|
||||
@@ -208,7 +207,11 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
||||
appName: app.name,
|
||||
appId,
|
||||
userId,
|
||||
source: authType === 'apikey' ? BillSourceEnum.api : BillSourceEnum.fastgpt,
|
||||
source: (() => {
|
||||
if (authType === 'apikey') return BillSourceEnum.api;
|
||||
if (shareId) return BillSourceEnum.shareLink;
|
||||
return BillSourceEnum.fastgpt;
|
||||
})(),
|
||||
response: responseData,
|
||||
shareId
|
||||
});
|
||||
|
@@ -19,11 +19,10 @@ import {
|
||||
} from '@chakra-ui/react';
|
||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import { useToast } from '@/hooks/useToast';
|
||||
import { useLoading } from '@/hooks/useLoading';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { getShareChatList, delShareChatById, createShareChat } from '@/api/chat';
|
||||
import { formatTimeToChatTime, useCopyData, getErrText } from '@/utils/tools';
|
||||
import { formatTimeToChatTime, useCopyData } from '@/utils/tools';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { defaultShareChat } from '@/constants/model';
|
||||
import type { ShareChatEditType } from '@/types/app';
|
||||
@@ -67,8 +66,8 @@ const Share = ({ appId }: { appId: string }) => {
|
||||
onSuccess(id) {
|
||||
onCloseCreateShareChat();
|
||||
refetchShareChatList();
|
||||
const url = `对话地址为:${location.origin}/chat/share?shareId=${id}`;
|
||||
copyData(url, '已复制分享地址');
|
||||
const url = `${location.origin}/chat/share?shareId=${id}`;
|
||||
copyData(url, '创建成功。已复制分享地址,可直接分享使用');
|
||||
resetShareChat(defaultShareChat);
|
||||
}
|
||||
});
|
||||
@@ -116,40 +115,53 @@ const Share = ({ appId }: { appId: string }) => {
|
||||
<Td>{item.name}</Td>
|
||||
<Td>{formatPrice(item.total)}元</Td>
|
||||
<Td>{item.lastTime ? formatTimeToChatTime(item.lastTime) : '未使用'}</Td>
|
||||
<Td>
|
||||
<Flex>
|
||||
<MyTooltip label={'复制分享链接'}>
|
||||
<MyIcon
|
||||
mr={3}
|
||||
name="copy"
|
||||
w={'14px'}
|
||||
cursor={'pointer'}
|
||||
_hover={{ color: 'myBlue.600' }}
|
||||
onClick={() => {
|
||||
const url = `${location.origin}/chat/share?shareId=${item.shareId}`;
|
||||
copyData(url, '已复制分享链接');
|
||||
}}
|
||||
/>
|
||||
</MyTooltip>
|
||||
<MyTooltip label={'删除链接'}>
|
||||
<MyIcon
|
||||
name="delete"
|
||||
w={'14px'}
|
||||
cursor={'pointer'}
|
||||
_hover={{ color: 'red' }}
|
||||
onClick={async () => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
await delShareChatById(item._id);
|
||||
refetchShareChatList();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
setIsLoading(false);
|
||||
}}
|
||||
/>
|
||||
</MyTooltip>
|
||||
</Flex>
|
||||
<Td display={'flex'} alignItems={'center'}>
|
||||
<MyTooltip label={'嵌入网页'}>
|
||||
<MyIcon
|
||||
mr={4}
|
||||
name="apiLight"
|
||||
w={'14px'}
|
||||
cursor={'pointer'}
|
||||
_hover={{ color: 'myBlue.600' }}
|
||||
onClick={() => {
|
||||
const url = `${location.origin}/chat/share?shareId=${item.shareId}`;
|
||||
const src = `${location.origin}/js/iframe.js`;
|
||||
const script = `<script src="${src}" id="fastgpt-iframe" data-src="${url}" data-color="#4e83fd"></script>`;
|
||||
copyData(script, '已复制嵌入 Script,可在应用 HTML 底部嵌入', 3000);
|
||||
}}
|
||||
/>
|
||||
</MyTooltip>
|
||||
<MyTooltip label={'复制分享链接'}>
|
||||
<MyIcon
|
||||
mr={4}
|
||||
name="copy"
|
||||
w={'14px'}
|
||||
cursor={'pointer'}
|
||||
_hover={{ color: 'myBlue.600' }}
|
||||
onClick={() => {
|
||||
const url = `${location.origin}/chat/share?shareId=${item.shareId}`;
|
||||
copyData(url, '已复制分享链接,可直接分享使用');
|
||||
}}
|
||||
/>
|
||||
</MyTooltip>
|
||||
<MyTooltip label={'删除链接'}>
|
||||
<MyIcon
|
||||
name="delete"
|
||||
w={'14px'}
|
||||
cursor={'pointer'}
|
||||
_hover={{ color: 'red' }}
|
||||
onClick={async () => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
await delShareChatById(item._id);
|
||||
refetchShareChatList();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
setIsLoading(false);
|
||||
}}
|
||||
/>
|
||||
</MyTooltip>
|
||||
</Td>
|
||||
</Tr>
|
||||
))}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
import {
|
||||
Box,
|
||||
Grid,
|
||||
|
@@ -8,7 +8,7 @@ import { useRouter } from 'next/router';
|
||||
const ToolMenu = ({ history }: { history: ChatItemType[] }) => {
|
||||
const { onExportChat } = useChatBox();
|
||||
const router = useRouter();
|
||||
const { appId } = router.query;
|
||||
const { appId, shareId } = router.query;
|
||||
|
||||
const menuList = useMemo(
|
||||
() => [
|
||||
@@ -18,7 +18,8 @@ const ToolMenu = ({ history }: { history: ChatItemType[] }) => {
|
||||
onClick: () => {
|
||||
router.replace({
|
||||
query: {
|
||||
appId
|
||||
appId,
|
||||
shareId
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -35,7 +36,7 @@ const ToolMenu = ({ history }: { history: ChatItemType[] }) => {
|
||||
},
|
||||
{ icon: 'pdf', label: 'PDF导出', onClick: () => onExportChat({ type: 'pdf', history }) }
|
||||
],
|
||||
[appId, history, onExportChat, router]
|
||||
[appId, history, onExportChat, router, shareId]
|
||||
);
|
||||
|
||||
return history.length > 0 ? (
|
||||
@@ -59,7 +60,9 @@ const ToolMenu = ({ history }: { history: ChatItemType[] }) => {
|
||||
))}
|
||||
</MenuList>
|
||||
</Menu>
|
||||
) : null;
|
||||
) : (
|
||||
<Box w={'28px'} h={'28px'} />
|
||||
);
|
||||
};
|
||||
|
||||
export default ToolMenu;
|
||||
|
@@ -2,11 +2,14 @@ import type { NextApiRequest } from 'next';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import Cookie from 'cookie';
|
||||
import { App, OpenApi, User, OutLink, KB } from '../mongo';
|
||||
import type { AppSchema, UserModelSchema } from '@/types/mongoSchema';
|
||||
import { formatPrice } from '@/utils/user';
|
||||
import type { AppSchema } from '@/types/mongoSchema';
|
||||
import { ERROR_ENUM } from '../errorCode';
|
||||
|
||||
export type AuthType = 'token' | 'root' | 'apikey';
|
||||
export enum AuthUserTypeEnum {
|
||||
token = 'token',
|
||||
root = 'root',
|
||||
apikey = 'apikey'
|
||||
}
|
||||
|
||||
export const parseCookie = (cookie?: string): Promise<string> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -124,28 +127,28 @@ export const authUser = async ({
|
||||
|
||||
let uid = '';
|
||||
let appId = '';
|
||||
let authType: AuthType = 'token';
|
||||
let authType: `${AuthUserTypeEnum}` = AuthUserTypeEnum.token;
|
||||
|
||||
if (authToken) {
|
||||
uid = await parseCookie(cookie);
|
||||
authType = 'token';
|
||||
authType = AuthUserTypeEnum.token;
|
||||
} else if (authRoot) {
|
||||
uid = await parseRootKey(rootkey, userid);
|
||||
authType = 'root';
|
||||
authType = AuthUserTypeEnum.root;
|
||||
} else if (cookie) {
|
||||
uid = await parseCookie(cookie);
|
||||
authType = 'token';
|
||||
authType = AuthUserTypeEnum.token;
|
||||
} else if (apikey) {
|
||||
uid = await parseOpenApiKey(apikey);
|
||||
authType = 'apikey';
|
||||
authType = AuthUserTypeEnum.apikey;
|
||||
} else if (authorization) {
|
||||
const authResponse = await parseAuthorization(authorization);
|
||||
uid = authResponse.uid;
|
||||
appId = authResponse.appId;
|
||||
authType = 'apikey';
|
||||
authType = AuthUserTypeEnum.apikey;
|
||||
} else if (rootkey) {
|
||||
uid = await parseRootKey(rootkey, userid);
|
||||
authType = 'root';
|
||||
authType = AuthUserTypeEnum.root;
|
||||
} else {
|
||||
return Promise.reject(ERROR_ENUM.unAuthorization);
|
||||
}
|
||||
@@ -229,6 +232,6 @@ export const authShareChat = async ({ shareId }: { shareId: string }) => {
|
||||
user,
|
||||
userId: String(shareChat.userId),
|
||||
appId: String(shareChat.appId),
|
||||
authType: 'token' as AuthType
|
||||
authType: AuthUserTypeEnum.token
|
||||
};
|
||||
};
|
||||
|
3
client/src/types/mongoSchema.d.ts
vendored
3
client/src/types/mongoSchema.d.ts
vendored
@@ -4,7 +4,7 @@ import type { DataType } from './data';
|
||||
import { BillSourceEnum, InformTypeEnum } from '@/constants/user';
|
||||
import { TrainingModeEnum } from '@/constants/plugin';
|
||||
import type { AppModuleItemType } from './app';
|
||||
import { ChatSourceEnum } from '@/constants/chat';
|
||||
import { ChatSourceEnum, OutLinkTypeEnum } from '@/constants/chat';
|
||||
|
||||
export interface UserModelSchema {
|
||||
_id: string;
|
||||
@@ -144,6 +144,7 @@ export interface OutLinkSchema {
|
||||
name: string;
|
||||
total: number;
|
||||
lastTime: Date;
|
||||
type: `${OutLinkTypeEnum}`;
|
||||
}
|
||||
|
||||
export interface kbSchema {
|
||||
|
@@ -9,7 +9,7 @@ export const useCopyData = () => {
|
||||
const { toast } = useToast();
|
||||
|
||||
return {
|
||||
copyData: async (data: string, title: string = '复制成功') => {
|
||||
copyData: async (data: string, title: string = '复制成功', duration = 1000) => {
|
||||
try {
|
||||
if (navigator.clipboard) {
|
||||
await navigator.clipboard.writeText(data);
|
||||
@@ -28,7 +28,7 @@ export const useCopyData = () => {
|
||||
toast({
|
||||
title,
|
||||
status: 'success',
|
||||
duration: 1000
|
||||
duration
|
||||
});
|
||||
}
|
||||
};
|
||||
|
Reference in New Issue
Block a user