feat(gpt-runner-web): optimize css styles
This commit is contained in:
@@ -48,13 +48,13 @@
|
||||
"dependencies": {
|
||||
"@nicepkg/gpt-runner-shared": "workspace:*",
|
||||
"ignore": "^5.2.4",
|
||||
"langchain": "^0.0.118",
|
||||
"unconfig": "^0.3.9",
|
||||
"langchain": "^0.0.122",
|
||||
"unconfig": "^0.3.10",
|
||||
"uuid": "^9.0.0",
|
||||
"zod": "^3.21.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@anthropic-ai/sdk": "^0.5.8",
|
||||
"@anthropic-ai/sdk": "^0.5.10",
|
||||
"openai": "^3.3.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,8 +106,8 @@
|
||||
"launch-editor": "^2.6.0",
|
||||
"minimatch": "^9.0.3",
|
||||
"open": "^8.4.2",
|
||||
"socket.io": "^4.7.1",
|
||||
"socket.io-client": "^4.7.1",
|
||||
"socket.io": "^4.7.2",
|
||||
"socket.io-client": "^4.7.2",
|
||||
"zod": "^3.21.4",
|
||||
"zod-to-json-schema": "^3.21.4"
|
||||
},
|
||||
@@ -116,4 +116,4 @@
|
||||
"@types/ip": "^1.1.0",
|
||||
"express": "^4.18.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"common": {
|
||||
"notificationConfig": {
|
||||
"createAt": "2023-07-24 23:31:22",
|
||||
"createAt": "2023-08-06 18:37:10",
|
||||
"title": "GPT Runner Notification",
|
||||
"message": "v1.2.0 is release"
|
||||
"message": "v1.2.2 is release"
|
||||
},
|
||||
"releaseConfig": {
|
||||
"createAt": "2023-07-24 23:41:04",
|
||||
@@ -23,18 +23,18 @@
|
||||
},
|
||||
"zh_CN": {
|
||||
"notificationConfig": {
|
||||
"createAt": "2023-07-24 23:31:26",
|
||||
"createAt": "2023-08-06 18:37:06",
|
||||
"title": "GPT Runner 通知",
|
||||
"message": "\n### 版本更新到了 v1.2.0\n1. 重启 vscode 即可去扩展处更新\n2. cli 的执行 `npm i -g gptr` 即可更新\n\n### 本次功能更新\n1. 针对语言为简体中文的用户提供 OpenAI API key 供应商,也就是你可以白嫖了。\n2. 点击左上角设置,切换供应商即可。\n3. 本次 API Key 由慷慨大方的 `剑廿三` 提供,让我们把掌声送给他。\n\n### 交流\n1. 想进群交流的加 wechat: `qq2214962083`\n "
|
||||
"message": "\n### 🚀 新版 v1.2.2 (2023-08-06)\n\n> vscode 用户重启 vscode 后即可在扩展处更新。\n>\n> cli 用户执行 `npm i -g gptr` 即可更新。\n\n1. 针对语言为简体中文的用户提供 OpenAI API key 第三方供应商,也就是你可以白嫖了。\n2. 点击左上角设置,切换供应商即可。\n3. 本次 API Key 由慷慨大方的 `朝云云` 提供,让我们把掌声送给他。\n\n### 💬 交流\n\n1. 想进群交流的加 wechat: `qq2214962083`\n2. 所有捐赠 API Key 的朋友,都可以在这里免费展示 50 字以内的广告直到 API Key 失效,如果你也想捐赠 API Key,可以联系我。\n3. 此处广告仅供展示,与 GPT-Runner 无关,**若有财产交易,请自行承担风险**\n\n### 📢 YunAI - AI驱动的WEB对话应用 (朝云云供应商广告)\n\n🔵 [**点击进入**](https://faschat.zyai.online/)注册即送大量3.5使用次数\n\n如需适配 GPT-Runner 的 4.0-32k 或 Claude 接口服务,可 VX 联系:`YunAi0101`\n\n "
|
||||
},
|
||||
"vendorsConfig": {
|
||||
"createAt": "2023-07-24 23:40:49",
|
||||
"createAt": "2023-08-06 18:37:22",
|
||||
"openai": [
|
||||
{
|
||||
"vendorName": "xabcai",
|
||||
"vendorName": "朝云云供应商",
|
||||
"vendorSecrets": {
|
||||
"basePath": "https://api.xabcai.com/v1",
|
||||
"apiKey": "c2stWHZQeGJQMVBySFduZDJFZ0xpa0lKTlQzOTNoc3pZdDdmN0NNZUozSE1pdkw2QVdx"
|
||||
"basePath": "http://8.130.89.91:3000/v1",
|
||||
"apiKey": "c2stQUlBc2NTUGk2RVR0cXVSVThmMmYzODU1NTk4NzQ4M2U4YjE1QWU4MzEwMjMxZTRi"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
"settings_tab_settings": "Einstellungen",
|
||||
"settings_tab_config_info": "Konfigurationsinformationen",
|
||||
"settings_tab_about": "Über",
|
||||
"settings_tab_notifications": "Benachrichtigungen",
|
||||
"override_model_type": "Modelltyp überschreiben",
|
||||
"default": "Standard",
|
||||
"override_settings": "Einstellungen überschreiben",
|
||||
@@ -101,4 +102,4 @@
|
||||
"file_editor_forgot_save_tips_title": "Möchten Sie die Änderungen an {{fileName}} speichern?",
|
||||
"file_editor_forgot_save_tips_content": "Ihre Änderungen gehen verloren, wenn Sie sie nicht speichern."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,6 +51,7 @@
|
||||
"settings_tab_settings": "Settings",
|
||||
"settings_tab_config_info": "Config Info",
|
||||
"settings_tab_about": "About",
|
||||
"settings_tab_notifications": "Notifications",
|
||||
"override_model_type": "Override Model Type",
|
||||
"default": "Default",
|
||||
"override_settings": "Override Settings",
|
||||
@@ -101,4 +102,4 @@
|
||||
"file_editor_forgot_save_tips_title": "Do you want to save changes to {{fileName}}?",
|
||||
"file_editor_forgot_save_tips_content": "Your changes will be lost if you don't save them."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,6 +51,7 @@
|
||||
"settings_tab_settings": "設定",
|
||||
"settings_tab_config_info": "設定情報",
|
||||
"settings_tab_about": "情報",
|
||||
"settings_tab_notifications": "通知",
|
||||
"override_model_type": "モデルタイプを上書き",
|
||||
"default": "デフォルト",
|
||||
"override_settings": "設定を上書き",
|
||||
@@ -101,4 +102,4 @@
|
||||
"file_editor_forgot_save_tips_title": "変更を{{fileName}}に保存しますか?",
|
||||
"file_editor_forgot_save_tips_content": "保存しない場合、変更は失われます。"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,6 +51,7 @@
|
||||
"settings_tab_settings": "设置",
|
||||
"settings_tab_config_info": "配置信息",
|
||||
"settings_tab_about": "关于",
|
||||
"settings_tab_notifications": "通知",
|
||||
"override_model_type": "覆盖模型类型",
|
||||
"default": "默认",
|
||||
"override_settings": "覆盖设置",
|
||||
@@ -101,4 +102,4 @@
|
||||
"file_editor_forgot_save_tips_title": "你想要保存对{{fileName}}的更改吗?",
|
||||
"file_editor_forgot_save_tips_content": "如果你不保存,你的改动将会丢失."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,6 +51,7 @@
|
||||
"settings_tab_settings": "設定",
|
||||
"settings_tab_config_info": "配置信息",
|
||||
"settings_tab_about": "關於",
|
||||
"settings_tab_notifications": "通知",
|
||||
"override_model_type": "覆蓋模型類型",
|
||||
"default": "默認",
|
||||
"override_settings": "覆寫設置",
|
||||
@@ -101,4 +102,4 @@
|
||||
"file_editor_forgot_save_tips_title": "你想要保存對{{fileName}}的更改嗎?",
|
||||
"file_editor_forgot_save_tips_content": "如果你不保存,你的改動將會丟失."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||
import { type ComponentType, type FC, type PropsWithChildren, Suspense, memo, useEffect } from 'react'
|
||||
import { type ComponentType, type FC, type PropsWithChildren, Suspense, memo, useEffect, useMemo } from 'react'
|
||||
import type { FallbackProps } from 'react-error-boundary'
|
||||
import { ErrorBoundary } from 'react-error-boundary'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
@@ -16,6 +16,7 @@ import { Toast } from './components/toast'
|
||||
import { LoadingView } from './components/loading-view'
|
||||
import { ConfettiProvider } from './store/context/confetti-context'
|
||||
import { ModalProvider } from './store/context/modal-context'
|
||||
import { useCssVarColor } from './hooks/use-css-var-color.hook'
|
||||
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
@@ -86,10 +87,38 @@ export const AppProviders: FC<PropsWithChildren> = memo(({ children }) => {
|
||||
})
|
||||
|
||||
export const App: FC = memo(() => {
|
||||
const { rgba: backgroundRgba, isDark } = useCssVarColor({
|
||||
cssVarName: '--panel-view-background',
|
||||
})
|
||||
|
||||
const { rgba: borderRgba } = useCssVarColor({
|
||||
cssVarName: '--panel-view-border',
|
||||
})
|
||||
|
||||
const myBackdropBg = useMemo(() => {
|
||||
if (!backgroundRgba)
|
||||
return 'transparent'
|
||||
|
||||
return `rgba(${backgroundRgba.r}, ${backgroundRgba.g}, ${backgroundRgba.b}, ${isDark ? '0.6' : '0.8'})`
|
||||
}, [backgroundRgba, isDark])
|
||||
|
||||
const [myScrollbarBg, myScrollbarHoverBg] = useMemo(() => {
|
||||
if (!borderRgba)
|
||||
return ['var(--panel-view-border)', 'var(--panel-view-border)'] as const
|
||||
|
||||
return [`rgba(${borderRgba.r}, ${borderRgba.g}, ${borderRgba.b}, 0.2)`, `rgba(${borderRgba.r}, ${borderRgba.g}, ${borderRgba.b}, 0.8)`] as const
|
||||
}, [borderRgba, isDark])
|
||||
|
||||
return (
|
||||
<Suspense fallback={<LoadingView absolute />}>
|
||||
<AppProviders>
|
||||
<GlobalStyle />
|
||||
<GlobalStyle appendCss={`
|
||||
body {
|
||||
--my-backdrop-bg: ${myBackdropBg};
|
||||
--my-scrollbar-bg: ${myScrollbarBg};
|
||||
--my-scrollbar-hover-bg: ${myScrollbarHoverBg};
|
||||
}
|
||||
`} />
|
||||
<GlobalThemeStyle />
|
||||
<MarkdownStyle />
|
||||
<AppRouter />
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { styled } from 'styled-components'
|
||||
import { Logo } from '../logo'
|
||||
import { backDropBg } from '../../styles/utils'
|
||||
|
||||
export const Wrapper = styled.div`
|
||||
display: flex;
|
||||
@@ -9,6 +10,7 @@ export const Wrapper = styled.div`
|
||||
flex-shrink: 0;
|
||||
padding: 0.5rem;
|
||||
border-top: 1px solid var(--panel-view-border);
|
||||
${backDropBg}
|
||||
`
|
||||
|
||||
export const ToolbarWrapper = styled.div`
|
||||
@@ -34,6 +36,18 @@ export const TextAreaWrapper = styled.div`
|
||||
&:hover {
|
||||
border-color: var(--focus-border);
|
||||
}
|
||||
|
||||
.monaco-editor {
|
||||
background-color: transparent !important;
|
||||
|
||||
.margin {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
}
|
||||
|
||||
.monaco-editor-background {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
|
||||
@@ -138,7 +138,7 @@ export const ChatMessageInput: FC<ChatMessageInputProps> = memo((props) => {
|
||||
{toolbarSlot}
|
||||
|
||||
{showTopLogo && <LogoWrapper>
|
||||
<StyledLogo color={'var(--panel-tab-foreground)'} {...logoProps} ></StyledLogo>
|
||||
<StyledLogo color={'var(--focus-border)'} {...logoProps} ></StyledLogo>
|
||||
</LogoWrapper>}
|
||||
</ToolbarWrapper>
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { styled } from 'styled-components'
|
||||
import type { MessageItemProps } from '.'
|
||||
|
||||
export const MsgWrapper = styled.div<{ $isMe: boolean }>`
|
||||
display: flex;
|
||||
@@ -26,7 +25,7 @@ export const MsgContentWrapper = styled.div<{ $isMe: boolean }>`
|
||||
position: relative;
|
||||
`
|
||||
|
||||
export const MsgContent = styled.div<{ $showToolbar: MessageItemProps['showToolbar']; $isMe: boolean }>`
|
||||
export const MsgContent = styled.div<{ $isMe: boolean }>`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-radius: 0.5rem;
|
||||
@@ -43,34 +42,6 @@ export const MsgContent = styled.div<{ $showToolbar: MessageItemProps['showToolb
|
||||
& .msg-content-footer {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
${({ $showToolbar, $isMe }) => ($showToolbar === 'hover'
|
||||
? `
|
||||
position: absolute;
|
||||
top: 0;
|
||||
${$isMe ? 'right' : 'left'}: 0;
|
||||
z-index: 1;
|
||||
min-height: 100%;
|
||||
|
||||
& .msg-content-footer {
|
||||
opacity: 0;
|
||||
margin-top: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
&:hover .msg-content-footer {
|
||||
opacity: 1;
|
||||
margin-top: 0.5rem;
|
||||
height: auto;
|
||||
}
|
||||
`
|
||||
: $showToolbar === 'never'
|
||||
? `
|
||||
& .msg-content-footer {
|
||||
display: none;
|
||||
}
|
||||
`
|
||||
: '')}
|
||||
`
|
||||
|
||||
export const MsgContentFooterWrapper = styled.div`
|
||||
|
||||
@@ -5,7 +5,6 @@ import { ChatMessageStatus, ChatRole } from '@nicepkg/gpt-runner-shared/common'
|
||||
import type { MessageTextViewProps } from '../chat-message-text-view'
|
||||
import { MessageTextView } from '../chat-message-text-view'
|
||||
import { Icon } from '../icon'
|
||||
import { useHover } from '../../hooks/use-hover.hook'
|
||||
import { MsgAvatarWrapper, MsgContent, MsgContentFooterWrapper, MsgContentWrapper, MsgWrapper } from './chat-message-item.styles'
|
||||
|
||||
export interface BuildMessageToolbarState extends SingleChatMessage {
|
||||
@@ -13,7 +12,6 @@ export interface BuildMessageToolbarState extends SingleChatMessage {
|
||||
}
|
||||
export interface MessageItemProps extends SingleChatMessage, Partial<MessageTextViewProps> {
|
||||
status: ChatMessageStatus
|
||||
showToolbar?: 'always' | 'hover' | 'never'
|
||||
showAvatar?: boolean
|
||||
style?: React.CSSProperties
|
||||
buildMessageToolbar?: (state: BuildMessageToolbarState) => React.ReactNode
|
||||
@@ -26,34 +24,12 @@ export const MessageItem: FC<MessageItemProps> = memo((props) => {
|
||||
status,
|
||||
style,
|
||||
showAvatar = false,
|
||||
showToolbar = 'hover',
|
||||
buildCodeToolbar,
|
||||
buildMessageToolbar,
|
||||
...messageTextViewProps
|
||||
} = props
|
||||
|
||||
const [hoverContentRef, isContentHover] = useHover()
|
||||
const contents = status === ChatMessageStatus.Pending ? `${text}\u{258A}` : text
|
||||
const renderContent = ({ showToolbar }: Pick<MessageItemProps, 'showToolbar'>) => {
|
||||
return <MsgContent
|
||||
$showToolbar={showToolbar}
|
||||
$isMe={name === ChatRole.User}>
|
||||
|
||||
<MessageTextView
|
||||
contents={contents}
|
||||
buildCodeToolbar={buildCodeToolbar}
|
||||
{...messageTextViewProps}
|
||||
/>
|
||||
|
||||
<MsgContentFooterWrapper className='msg-content-footer'>
|
||||
{buildMessageToolbar?.({
|
||||
name,
|
||||
text,
|
||||
status,
|
||||
})}
|
||||
</MsgContentFooterWrapper>
|
||||
</MsgContent>
|
||||
}
|
||||
|
||||
return (
|
||||
<MsgWrapper style={style} $isMe={name === ChatRole.User}>
|
||||
@@ -61,29 +37,26 @@ export const MessageItem: FC<MessageItemProps> = memo((props) => {
|
||||
<Icon className={clsx(name === ChatRole.User ? 'codicon-account' : 'codicon-github')} />
|
||||
</MsgAvatarWrapper>
|
||||
<MsgContentWrapper
|
||||
ref={hoverContentRef}
|
||||
$isMe={name === ChatRole.User}
|
||||
style={{
|
||||
maxWidth: showAvatar ? 'calc(100% - 6rem)' : '100%',
|
||||
}}
|
||||
>
|
||||
{
|
||||
showToolbar === 'hover'
|
||||
? (
|
||||
<>
|
||||
{/* use absolute position to render a same content with toolbar
|
||||
this is helpful to not change height */}
|
||||
{renderContent({
|
||||
showToolbar: 'never',
|
||||
})}
|
||||
{isContentHover && renderContent({
|
||||
showToolbar: 'hover',
|
||||
})}
|
||||
</>)
|
||||
: renderContent({
|
||||
showToolbar,
|
||||
})
|
||||
}
|
||||
<MsgContent $isMe={name === ChatRole.User}>
|
||||
<MessageTextView
|
||||
contents={contents}
|
||||
buildCodeToolbar={buildCodeToolbar}
|
||||
{...messageTextViewProps}
|
||||
/>
|
||||
|
||||
<MsgContentFooterWrapper className='msg-content-footer'>
|
||||
{buildMessageToolbar?.({
|
||||
name,
|
||||
text,
|
||||
status,
|
||||
})}
|
||||
</MsgContentFooterWrapper>
|
||||
</MsgContent>
|
||||
</MsgContentWrapper>
|
||||
</MsgWrapper>
|
||||
)
|
||||
|
||||
@@ -4,7 +4,10 @@ import { MessageItem } from '../chat-message-item'
|
||||
import { Panel } from './chat-message-panel.styles'
|
||||
|
||||
export interface ChatMessagePanelProps {
|
||||
style?: React.CSSProperties
|
||||
topSlot?: React.ReactNode
|
||||
messageItems: MessageItemProps[]
|
||||
bottomSlot?: React.ReactNode
|
||||
}
|
||||
|
||||
// Define the ref type for the component
|
||||
@@ -12,13 +15,15 @@ export type ChatMessagePanelRef = HTMLDivElement
|
||||
|
||||
// Use ForwardRefRenderFunction to define the component with an explicit ref parameter
|
||||
export const ChatMessagePanel = memo(forwardRef<ChatMessagePanelRef, ChatMessagePanelProps>((props, ref) => {
|
||||
const { messageItems } = props
|
||||
const { messageItems, style, topSlot, bottomSlot } = props
|
||||
|
||||
return (
|
||||
<Panel ref={ref}>
|
||||
<Panel style={style} ref={ref}>
|
||||
{topSlot}
|
||||
{messageItems.map((item, index) => {
|
||||
return <MessageItem key={index} {...item}></MessageItem>
|
||||
})}
|
||||
{bottomSlot}
|
||||
</Panel>
|
||||
)
|
||||
}))
|
||||
|
||||
@@ -5,6 +5,7 @@ const lineWeight = '8px'
|
||||
|
||||
export const DragLine = styled.div<{ $dragLineColor: string; $dragLineActiveColor: string; $dragLineWidth: string }>`
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
/* background: ${({ $dragLineColor }) => $dragLineColor}; */
|
||||
border-color: ${({ $dragLineColor }) => $dragLineColor};
|
||||
border-style: solid;
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import type { FC } from 'react'
|
||||
import { memo, useEffect, useMemo, useRef } from 'react'
|
||||
import { forwardRef, memo, useEffect, useImperativeHandle, useMemo, useRef } from 'react'
|
||||
import type { UserDragConfig } from '@use-gesture/react'
|
||||
import { useDrag } from '@use-gesture/react'
|
||||
import type { SpringOptions } from 'framer-motion'
|
||||
import { motion, useMotionValue, useSpring } from 'framer-motion'
|
||||
import type { MotionValue, SpringOptions } from 'framer-motion'
|
||||
import { AnimatePresence, motion, useMotionValue, useSpring } from 'framer-motion'
|
||||
import { isDomHidden } from '../../helpers/utils'
|
||||
import { DragLine } from './drag-resize-view.styles'
|
||||
|
||||
@@ -16,6 +15,12 @@ export interface DragDirectionConfig {
|
||||
*/
|
||||
boundary: number[]
|
||||
}
|
||||
|
||||
export interface DragResizeViewRef {
|
||||
motionDragWidth: MotionValue<number> | undefined
|
||||
motionDragHeight: MotionValue<number> | undefined
|
||||
}
|
||||
|
||||
export interface DragResizeViewProps {
|
||||
initWidth?: number
|
||||
initHeight?: number
|
||||
@@ -29,14 +34,10 @@ export interface DragResizeViewProps {
|
||||
dragLineActiveColor?: string
|
||||
dragLineWidth?: string
|
||||
children: React.ReactNode
|
||||
|
||||
// drawer
|
||||
drawerClassName?: string
|
||||
drawerStyle?: React.CSSProperties
|
||||
open?: boolean
|
||||
}
|
||||
|
||||
export const DragResizeView: FC<DragResizeViewProps> = memo((props) => {
|
||||
export const DragResizeView = memo(forwardRef<DragResizeViewRef, DragResizeViewProps>((props, ref) => {
|
||||
const {
|
||||
initWidth,
|
||||
initHeight,
|
||||
@@ -51,13 +52,11 @@ export const DragResizeView: FC<DragResizeViewProps> = memo((props) => {
|
||||
dragLineWidth = '1px',
|
||||
children,
|
||||
|
||||
// drawer
|
||||
drawerClassName,
|
||||
drawerStyle,
|
||||
// drag
|
||||
open = true,
|
||||
} = props
|
||||
|
||||
const ref = useRef<HTMLDivElement>(null)
|
||||
const dragRef = useRef<HTMLDivElement>(null)
|
||||
const finalWidth = useMotionValue(initWidth)
|
||||
const finalHeight = useMotionValue(initHeight)
|
||||
|
||||
@@ -83,9 +82,9 @@ export const DragResizeView: FC<DragResizeViewProps> = memo((props) => {
|
||||
|
||||
useEffect(() => {
|
||||
const handleWindowResize = () => {
|
||||
if (ref.current && !isDomHidden(ref.current)) {
|
||||
finalWidth.set(ref.current.offsetWidth)
|
||||
finalHeight.set(ref.current.offsetHeight)
|
||||
if (dragRef.current && !isDomHidden(dragRef.current)) {
|
||||
finalWidth.set(dragRef.current.offsetWidth)
|
||||
finalHeight.set(dragRef.current.offsetHeight)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,39 +197,33 @@ export const DragResizeView: FC<DragResizeViewProps> = memo((props) => {
|
||||
const dragWidth = useSpring(finalWidth, springConfig)
|
||||
const dragHeight = useSpring(finalHeight, springConfig)
|
||||
|
||||
// drawer
|
||||
const drawerWidth = useSpring(finalWidth, springConfig)
|
||||
const drawerHeight = useSpring(finalHeight, springConfig)
|
||||
|
||||
useEffect(() => {
|
||||
drawerWidth.set(!open && isX ? 0 : finalWidth.get())
|
||||
// drawer
|
||||
dragWidth.set(!open && isX ? 0 : finalWidth.get())
|
||||
}, [open, isX])
|
||||
|
||||
useEffect(() => {
|
||||
drawerHeight.set(!open && isY ? 0 : finalHeight.get())
|
||||
// drawer
|
||||
dragHeight.set(!open && isY ? 0 : finalHeight.get())
|
||||
}, [open, isY])
|
||||
|
||||
// drawer
|
||||
return <motion.div
|
||||
className={drawerClassName}
|
||||
style={{
|
||||
...drawerStyle,
|
||||
width: initWidth !== undefined ? drawerWidth : '',
|
||||
height: initHeight !== undefined ? drawerHeight : '',
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
>
|
||||
useImperativeHandle(ref, () => ({
|
||||
motionDragWidth: initWidth !== undefined ? dragWidth : undefined,
|
||||
motionDragHeight: initHeight !== undefined ? dragHeight : undefined,
|
||||
}), [initWidth, initHeight])
|
||||
|
||||
{/* drag */}
|
||||
// drag & drag
|
||||
return <AnimatePresence>
|
||||
<motion.div
|
||||
ref={dragRef}
|
||||
className={dragClassName}
|
||||
style={{
|
||||
...dragStyle,
|
||||
width: initWidth !== undefined ? dragWidth : '',
|
||||
height: initHeight !== undefined ? dragHeight : '',
|
||||
position: 'relative',
|
||||
overflow: 'hidden',
|
||||
...dragStyle,
|
||||
}}
|
||||
ref={ref}
|
||||
>
|
||||
{children}
|
||||
|
||||
@@ -250,7 +243,7 @@ export const DragResizeView: FC<DragResizeViewProps> = memo((props) => {
|
||||
: null
|
||||
})}
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
})
|
||||
</AnimatePresence>
|
||||
}))
|
||||
|
||||
DragResizeView.displayName = 'DragResizeView'
|
||||
|
||||
@@ -4,8 +4,7 @@ import type { FC } from 'react'
|
||||
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import * as monaco from 'monaco-editor'
|
||||
import type { MonacoEditorInstance } from '../../types/monaco-editor'
|
||||
import { useGlobalStore } from '../../store/zustand/global'
|
||||
import { isDarkTheme } from '../../styles/themes'
|
||||
import { useDarkTheme } from '../../hooks/use-css-var-color.hook'
|
||||
import { initLanguageSettings } from './monaco/init-languages-settings'
|
||||
import { createSwitchLanguageCommand } from './monaco/commands/switch-language'
|
||||
import { createCtrlSToSaveAction } from './monaco/actions/ctrls-to-save'
|
||||
@@ -67,10 +66,7 @@ export const Editor: FC<EditorProps> = memo((props) => {
|
||||
const defaultLanguage = defaultLanguageFromProps || DEFAULT_LANGUAGE
|
||||
const language = languageFromProps || currentExtLanguage || defaultLanguage
|
||||
|
||||
const {
|
||||
themeName,
|
||||
} = useGlobalStore()
|
||||
const isDark = isDarkTheme(themeName)
|
||||
const isDark = useDarkTheme()
|
||||
|
||||
const handleEditorWillMount = useCallback((monaco: Monaco) => {
|
||||
// here is the monaco instance
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { css, styled } from 'styled-components'
|
||||
|
||||
export const ButtonWrapper = styled.div<{ $hoverShowText?: boolean }>`
|
||||
export const ButtonWrapper = styled.div<{ $transparentBgWhenNotHover: boolean; $hoverShowText?: boolean }>`
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
overflow: hidden;
|
||||
|
||||
vscode-button {
|
||||
&:not(:hover) {
|
||||
background: transparent;
|
||||
background: ${({ $transparentBgWhenNotHover }) => ($transparentBgWhenNotHover ? 'transparent' : '')};
|
||||
}
|
||||
|
||||
/* &::part(control) {
|
||||
|
||||
@@ -17,6 +17,7 @@ export interface IconButtonProps extends GetComponentProps<InstanceType<typeof V
|
||||
radius?: string
|
||||
showText?: boolean
|
||||
hoverShowText?: boolean
|
||||
transparentBgWhenNotHover?: boolean
|
||||
isAnimating?: boolean
|
||||
animateDuration?: number
|
||||
animateEase?: Tween['ease']
|
||||
@@ -35,6 +36,7 @@ export const IconButton: FC<IconButtonProps> = memo((props) => {
|
||||
iconClassName,
|
||||
showText = true,
|
||||
hoverShowText = true,
|
||||
transparentBgWhenNotHover = false,
|
||||
radius = '0.25rem',
|
||||
className, style,
|
||||
buttonStyle,
|
||||
@@ -95,7 +97,7 @@ export const IconButton: FC<IconButtonProps> = memo((props) => {
|
||||
},
|
||||
}
|
||||
|
||||
return <ButtonWrapper className={clsx('icon-button', className)} style={style} $hoverShowText={hoverShowText}>
|
||||
return <ButtonWrapper $transparentBgWhenNotHover={transparentBgWhenNotHover} className={clsx('icon-button', className)} style={style} $hoverShowText={hoverShowText}>
|
||||
<VSCodeButton
|
||||
onClick={handleClick}
|
||||
appearance="secondary"
|
||||
|
||||
@@ -22,7 +22,8 @@ export const ModalContentWrapper = styled.div`
|
||||
flex-direction: column;
|
||||
max-width: 100%;
|
||||
max-height: 80vh;
|
||||
width: min(500px, calc(100vw - 1rem));
|
||||
width: 100%;
|
||||
max-width: min(800px, calc(100vw - 1rem));
|
||||
overflow: hidden;
|
||||
background: var(--panel-view-background);
|
||||
border-radius: 0.5rem;
|
||||
|
||||
@@ -154,7 +154,7 @@ export const PopoverMenu: React.FC<PopoverMenuProps> = memo((props) => {
|
||||
},
|
||||
menu: {
|
||||
maxHeight: Math.min(childrenY, windowHeight) - minusHeightSpace,
|
||||
height: childrenInMenuWhenOpen ? 'unset' : '100vh',
|
||||
height: childrenInMenuWhenOpen ? 'unset' : 'auto',
|
||||
},
|
||||
},
|
||||
bottom: {
|
||||
@@ -164,7 +164,7 @@ export const PopoverMenu: React.FC<PopoverMenuProps> = memo((props) => {
|
||||
},
|
||||
menu: {
|
||||
maxHeight: Math.min(windowHeight - childrenY - childrenHeight, windowHeight) - minusHeightSpace,
|
||||
height: childrenInMenuWhenOpen ? 'unset' : '100vh',
|
||||
height: childrenInMenuWhenOpen ? 'unset' : 'auto',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -234,7 +234,9 @@ export const PopoverMenu: React.FC<PopoverMenuProps> = memo((props) => {
|
||||
>
|
||||
{yPosition === 'bottom' && renderToolbar()}
|
||||
|
||||
<MenuChildrenWrapper>
|
||||
<MenuChildrenWrapper style={{
|
||||
display: childrenInMenuWhenOpen ? '' : 'flex',
|
||||
}}>
|
||||
{yPosition === 'top' && buildMenuSlot()}
|
||||
|
||||
{childrenInMenuWhenOpen
|
||||
@@ -250,6 +252,7 @@ export const PopoverMenu: React.FC<PopoverMenuProps> = memo((props) => {
|
||||
</MenuChildrenWrapper>
|
||||
|
||||
{yPosition === 'top' && renderToolbar()}
|
||||
|
||||
</Menu>
|
||||
</MenuMask>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import styled from 'styled-components'
|
||||
import { backDropBg } from '../../styles/utils'
|
||||
|
||||
export const MenuMask = styled.div`
|
||||
overflow: hidden;
|
||||
@@ -16,12 +17,13 @@ export const Toolbar = styled.div`
|
||||
`
|
||||
|
||||
export const Menu = styled.div`
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: var(--panel-view-background);
|
||||
border: 1px solid var(--panel-view-border);
|
||||
border-radius: 0.5rem;
|
||||
overflow: hidden;
|
||||
${backDropBg}
|
||||
`
|
||||
|
||||
export const MenuChildrenWrapper = styled.div`
|
||||
@@ -29,7 +31,6 @@ export const MenuChildrenWrapper = styled.div`
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
|
||||
|
||||
& > .icon-button {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
|
||||
@@ -5,7 +5,8 @@ import type { TreeProps } from '../tree'
|
||||
import { Tree } from '../tree'
|
||||
import type { TreeItemBaseStateOtherInfo, TreeItemProps } from '../tree-item'
|
||||
import { LoadingView } from '../loading-view'
|
||||
import { SidebarHeader, SidebarSearch, SidebarSearchRightWrapper, SidebarSearchWrapper, SidebarTreeWrapper, SidebarUnderSearchWrapper, SidebarWrapper } from './sidebar.styles'
|
||||
import { useElementSizeRealTime } from '../../hooks/use-element-size-real-time.hook'
|
||||
import { SidebarHeader, SidebarSearch, SidebarSearchRightWrapper, SidebarSearchWrapper, SidebarTopBlurContainer, SidebarTreeWrapper, SidebarUnderSearchWrapper, SidebarWrapper } from './sidebar.styles'
|
||||
|
||||
export interface SidebarProps<OtherInfo extends TreeItemBaseStateOtherInfo = TreeItemBaseStateOtherInfo> {
|
||||
defaultSearchKeyword?: string
|
||||
@@ -37,6 +38,7 @@ function Sidebar_<OtherInfo extends TreeItemBaseStateOtherInfo = TreeItemBaseSta
|
||||
const [searchKeyword, setSearchKeyword] = useState(defaultSearchKeyword)
|
||||
const [debouncedSearchKeyword, setDebouncedSearchKeyword] = useState(defaultSearchKeyword)
|
||||
const [finalItems, setFinalItems] = useState<TreeItemProps<OtherInfo>[]>([])
|
||||
const [SidebarTopBlurContainerRef, { height: SidebarTopBlurContainerHeight }] = useElementSizeRealTime<HTMLDivElement>()
|
||||
|
||||
useDebounce(() => {
|
||||
setDebouncedSearchKeyword(searchKeyword)
|
||||
@@ -78,26 +80,38 @@ function Sidebar_<OtherInfo extends TreeItemBaseStateOtherInfo = TreeItemBaseSta
|
||||
return <SidebarWrapper style={{
|
||||
flexDirection: reverseTreeUi ? 'column-reverse' : 'column',
|
||||
}}>
|
||||
<SidebarHeader>
|
||||
{buildTopToolbarSlot?.()}
|
||||
</SidebarHeader>
|
||||
<SidebarSearchWrapper>
|
||||
<SidebarSearch
|
||||
placeholder={placeholder}
|
||||
value={searchKeyword}
|
||||
onInput={(e: any) => {
|
||||
setSearchKeyword(e.target?.value)
|
||||
}}>
|
||||
</SidebarSearch>
|
||||
<SidebarSearchRightWrapper>
|
||||
{buildSearchRightSlot?.()}
|
||||
</SidebarSearchRightWrapper>
|
||||
</SidebarSearchWrapper>
|
||||
<SidebarUnderSearchWrapper>
|
||||
{buildUnderSearchSlot?.()}
|
||||
</SidebarUnderSearchWrapper>
|
||||
<SidebarTopBlurContainer ref={SidebarTopBlurContainerRef}>
|
||||
<SidebarHeader>
|
||||
{buildTopToolbarSlot?.()}
|
||||
</SidebarHeader>
|
||||
<SidebarSearchWrapper>
|
||||
<SidebarSearch
|
||||
placeholder={placeholder}
|
||||
value={searchKeyword}
|
||||
onInput={(e: any) => {
|
||||
setSearchKeyword(e.target?.value)
|
||||
}}>
|
||||
</SidebarSearch>
|
||||
<SidebarSearchRightWrapper>
|
||||
{buildSearchRightSlot?.()}
|
||||
</SidebarSearchRightWrapper>
|
||||
</SidebarSearchWrapper>
|
||||
<SidebarUnderSearchWrapper>
|
||||
{buildUnderSearchSlot?.()}
|
||||
</SidebarUnderSearchWrapper>
|
||||
</SidebarTopBlurContainer>
|
||||
|
||||
<SidebarTreeWrapper>
|
||||
{loading && <LoadingView absolute></LoadingView>}
|
||||
|
||||
<div style={{
|
||||
flexShrink: '0',
|
||||
width: '100%',
|
||||
height: SidebarTopBlurContainerHeight,
|
||||
}}>
|
||||
|
||||
</div>
|
||||
|
||||
<Tree
|
||||
{...tree}
|
||||
items={finalItems}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { VSCodeTextField } from '@vscode/webview-ui-toolkit/react'
|
||||
import { styled } from 'styled-components'
|
||||
import { backDropBg } from '../../styles/utils'
|
||||
|
||||
export const SidebarWrapper = styled.div`
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
@@ -10,6 +12,19 @@ export const SidebarWrapper = styled.div`
|
||||
overflow: hidden;
|
||||
`
|
||||
|
||||
export const SidebarTopBlurContainer = styled.div`
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
padding: 0 0.5rem;
|
||||
${backDropBg}
|
||||
`
|
||||
|
||||
export const SidebarHeader = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -1,17 +1,26 @@
|
||||
import { motion } from 'framer-motion'
|
||||
import styled from 'styled-components'
|
||||
import { Icon } from '../icon'
|
||||
import { backDropBg } from '../../styles/utils'
|
||||
|
||||
export const TabContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
padding-top: calc(var(--design-unit) * 7px + var(--border-width) * 3px);
|
||||
`
|
||||
|
||||
export const TabListHeader = styled.div`
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
padding: calc(var(--border-width) * 3px) 1rem;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
${backDropBg}
|
||||
|
||||
&[data-show-more=true] {
|
||||
padding-right: 2rem;
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
import { useCallback, useLayoutEffect, useRef, useState } from 'react'
|
||||
import { useGlobalStore } from '../store/zustand/global'
|
||||
|
||||
interface RgbaColor {
|
||||
r: number
|
||||
g: number
|
||||
b: number
|
||||
a: number
|
||||
}
|
||||
|
||||
// A helper function to convert RGB to boolean indicating if color is dark
|
||||
function isColorDark(rgba: RgbaColor | null): boolean {
|
||||
if (!rgba)
|
||||
return false
|
||||
|
||||
// https://stackoverflow.com/questions/11867545/change-text-color-based-on-brightness-of-the-covered-background-area
|
||||
const brightness = Math.round(((rgba.r * 299) + (rgba.g * 587) + (rgba.b * 114)) / 1000)
|
||||
return brightness <= 125
|
||||
}
|
||||
|
||||
// Helper function to convert hex color to RGB
|
||||
function hexToRGBA(hex: string): RgbaColor | null {
|
||||
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i.exec(hex)
|
||||
return result
|
||||
? {
|
||||
r: parseInt(result[1], 16),
|
||||
g: parseInt(result[2], 16),
|
||||
b: parseInt(result[3], 16),
|
||||
a: parseInt(result[4], 16) || 1,
|
||||
}
|
||||
: null
|
||||
}
|
||||
|
||||
export interface GetCssVarColorInfoProps {
|
||||
element: HTMLElement | null
|
||||
cssVarName: string
|
||||
}
|
||||
|
||||
interface GetCssVarColorInfoResult {
|
||||
rgba: RgbaColor | null
|
||||
isDark: boolean
|
||||
}
|
||||
|
||||
export function getCssVarColorInfo(props: GetCssVarColorInfoProps): GetCssVarColorInfoResult {
|
||||
const { element, cssVarName } = props
|
||||
|
||||
let rgba: RgbaColor | null = null
|
||||
let isDark = false
|
||||
|
||||
if (element) {
|
||||
const colorValue = getComputedStyle(element).getPropertyValue(cssVarName).trim()
|
||||
|
||||
if (colorValue.startsWith('#')) {
|
||||
const result = hexToRGBA(colorValue)
|
||||
rgba = result
|
||||
}
|
||||
else {
|
||||
const rgbaArr = colorValue.match(/\d+/g)?.map(Number)
|
||||
if (rgbaArr && rgbaArr.length >= 3) {
|
||||
const [r, g, b, a = 1] = rgbaArr
|
||||
rgba = { r, g, b, a }
|
||||
}
|
||||
}
|
||||
isDark = isColorDark(rgba)
|
||||
}
|
||||
|
||||
return { rgba, isDark }
|
||||
}
|
||||
|
||||
export function isDarkTheme() {
|
||||
const { isDark } = getCssVarColorInfo({ element: document.body, cssVarName: '--panel-view-background' })
|
||||
return isDark
|
||||
}
|
||||
|
||||
export type UseCssVarColorProps = Omit<GetCssVarColorInfoProps, 'element'> & {
|
||||
elementRef?: React.RefObject<HTMLElement>
|
||||
}
|
||||
|
||||
export type UseCssVarColorResult = GetCssVarColorInfoResult & {
|
||||
updateColor: () => void
|
||||
}
|
||||
|
||||
export function useCssVarColor(props: UseCssVarColorProps): UseCssVarColorResult {
|
||||
const { elementRef: elementRefFromProps, cssVarName } = props
|
||||
|
||||
const elementRefFromPrivate = useRef<HTMLElement>(document.body)
|
||||
const elementRef = elementRefFromProps || elementRefFromPrivate
|
||||
const hasElement = (elementRefFromProps ? elementRefFromProps.current : elementRefFromPrivate.current) instanceof HTMLElement
|
||||
|
||||
const [rgba, setRgbColor] = useState<RgbaColor | null>(null)
|
||||
const [isDark, setIsDark] = useState(false)
|
||||
const { themeName } = useGlobalStore()
|
||||
|
||||
const updateColor = useCallback(() => {
|
||||
const app = document.querySelector<HTMLElement>('#root')
|
||||
if (app)
|
||||
elementRefFromPrivate.current = app
|
||||
|
||||
if (!hasElement)
|
||||
return
|
||||
|
||||
const { rgba, isDark } = getCssVarColorInfo({ element: elementRef.current, cssVarName })
|
||||
setRgbColor(rgba)
|
||||
setIsDark(isDark)
|
||||
}, [cssVarName, hasElement, elementRef.current])
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (!hasElement)
|
||||
return
|
||||
|
||||
updateColor()
|
||||
const observer = new MutationObserver((mutationsList) => {
|
||||
for (const mutation of mutationsList) {
|
||||
if (mutation.type === 'attributes')
|
||||
updateColor()
|
||||
}
|
||||
})
|
||||
|
||||
observer.observe(document.body, { attributes: true })
|
||||
|
||||
return () => observer.disconnect()
|
||||
}, [updateColor, hasElement, themeName])
|
||||
|
||||
return { rgba, isDark, updateColor }
|
||||
}
|
||||
|
||||
export function useDarkTheme(): boolean {
|
||||
const { isDark } = useCssVarColor({ cssVarName: '--panel-view-background' })
|
||||
|
||||
return isDark
|
||||
}
|
||||
@@ -15,7 +15,6 @@ export const ContentWrapper = styled.div<{ $isPopoverContent?: boolean; $isTopTo
|
||||
${props => props.$isPopoverContent && css`
|
||||
width: calc(100vw - 1rem);
|
||||
height: 100%;
|
||||
background: var(--panel-view-background);
|
||||
max-width: 500px;
|
||||
|
||||
${withBreakpoint('sm', css`
|
||||
|
||||
@@ -2,6 +2,7 @@ import { css, styled } from 'styled-components'
|
||||
import { withBreakpoint } from '../../../../helpers/with-breakpoint'
|
||||
|
||||
export const ChatPanelWrapper = styled.div`
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
@@ -15,5 +16,4 @@ export const ChatPanelWrapper = styled.div`
|
||||
`
|
||||
|
||||
export const ChatPanelPopoverTreeWrapper = styled.div`
|
||||
height: 100%;
|
||||
`
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import type { FC, RefObject } from 'react'
|
||||
import { memo, useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { ChatMessageStatus, ChatRole, ClientEventName, getErrorMsg } from '@nicepkg/gpt-runner-shared/common'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { toast } from 'react-hot-toast'
|
||||
import { copyToClipboard } from '@nicepkg/gpt-runner-shared/browser'
|
||||
import { motion } from 'framer-motion'
|
||||
import type { ChatMessagePanelProps } from '../../../../components/chat-message-panel'
|
||||
import { FormTitle } from '../../../../components/form-title'
|
||||
import { ChatMessagePanel } from '../../../../components/chat-message-panel'
|
||||
@@ -16,16 +17,17 @@ import { useGlobalStore } from '../../../../store/zustand/global'
|
||||
import type { GptFileTreeItem } from '../../../../store/zustand/global/sidebar-tree.slice'
|
||||
import { getGlobalConfig } from '../../../../helpers/global-config'
|
||||
import { PopoverMenu } from '../../../../components/popover-menu'
|
||||
import type { DragResizeViewRef } from '../../../../components/drag-resize-view'
|
||||
import { DragResizeView } from '../../../../components/drag-resize-view'
|
||||
import { useElementSizeRealTime } from '../../../../hooks/use-element-size-real-time.hook'
|
||||
import { useTempStore } from '../../../../store/zustand/temp'
|
||||
import type { MessageCodeBlockTheme } from '../../../../components/chat-message-code-block'
|
||||
import { isDarkTheme } from '../../../../styles/themes'
|
||||
import { emitter } from '../../../../helpers/emitter'
|
||||
import { ModelSettings } from '../settings/components/model-settings'
|
||||
import { ContentWrapper } from '../../chat.styles'
|
||||
import { ContextSettings } from '../settings/components/context-settings'
|
||||
import { OverrideModelTypeSettings } from '../settings/components/model-settings/override-model-type'
|
||||
import { useDarkTheme } from '../../../../hooks/use-css-var-color.hook'
|
||||
import { ChatPanelPopoverTreeWrapper, ChatPanelWrapper } from './chat-panel.styles'
|
||||
import { createRemarkOpenEditorPlugin } from './remark-plugin'
|
||||
|
||||
@@ -68,6 +70,7 @@ export const ChatPanel: FC<ChatPanelProps> = memo((props) => {
|
||||
const [gptFileTreeItem, setGptFileTreeItem] = useState<GptFileTreeItem>()
|
||||
const [chatPanelRef, { width: chatPanelWidth, height: chatPanelHeight }] = useElementSizeRealTime<HTMLDivElement>()
|
||||
const { filesRelativePaths } = useTempStore()
|
||||
const dargChatInputRef = useRef<DragResizeViewRef>(null)
|
||||
|
||||
const defaultInitChatInputHeight = useMemo(() => {
|
||||
const DEFAULT_CHAT_INPUT_HEIGHT = 250
|
||||
@@ -251,13 +254,13 @@ export const ChatPanel: FC<ChatPanelProps> = memo((props) => {
|
||||
</>
|
||||
}, [handleCopy, handleInsertCodes, handleDiffCodes])
|
||||
|
||||
const codeBlockTheme: MessageCodeBlockTheme = isDarkTheme(themeName) ? 'dark' : 'light'
|
||||
const isDark = useDarkTheme()
|
||||
const codeBlockTheme: MessageCodeBlockTheme = isDark ? 'dark' : 'light'
|
||||
|
||||
const messagePanelProps: ChatMessagePanelProps = useMemo(() => {
|
||||
return {
|
||||
messageItems: chatInstance?.messages.map((message, i) => {
|
||||
const isLast = i === chatInstance.messages.length - 1
|
||||
const isLastTwo = i >= chatInstance.messages.length - 2
|
||||
const isAi = message.name === ChatRole.Assistant
|
||||
|
||||
const handleRegenerateMessage = () => {
|
||||
@@ -320,7 +323,6 @@ export const ChatPanel: FC<ChatPanelProps> = memo((props) => {
|
||||
...message,
|
||||
remarkPlugins,
|
||||
status: isLast ? status : ChatMessageStatus.Success,
|
||||
showToolbar: isLastTwo ? 'always' : 'hover',
|
||||
showAvatar: chatPanelWidth > 600,
|
||||
theme: codeBlockTheme,
|
||||
buildCodeToolbar: status === ChatMessageStatus.Pending ? undefined : buildCodeToolbar,
|
||||
@@ -482,6 +484,9 @@ export const ChatPanel: FC<ChatPanelProps> = memo((props) => {
|
||||
childrenInMenuWhenOpen={true}
|
||||
buildChildrenSlot={({ isHovering }) => {
|
||||
return <IconButton
|
||||
style={{
|
||||
paddingLeft: isHovering ? '0' : '0.5rem',
|
||||
}}
|
||||
text={t('chat_page.clear_history_btn')}
|
||||
iconClassName='codicon-clear-all'
|
||||
hoverShowText={!isHovering}
|
||||
@@ -523,30 +528,53 @@ export const ChatPanel: FC<ChatPanelProps> = memo((props) => {
|
||||
}
|
||||
|
||||
return <ChatPanelWrapper ref={chatPanelRef}>
|
||||
<ChatMessagePanel ref={scrollDownRef} {...messagePanelProps}></ChatMessagePanel>
|
||||
<ChatMessagePanel
|
||||
ref={scrollDownRef}
|
||||
{...messagePanelProps}
|
||||
bottomSlot={
|
||||
<motion.div
|
||||
style={{
|
||||
flexShrink: '0',
|
||||
width: '100%',
|
||||
height: dargChatInputRef.current?.motionDragHeight,
|
||||
}}
|
||||
></motion.div>
|
||||
}
|
||||
></ChatMessagePanel>
|
||||
|
||||
{initChatInputHeight && <DragResizeView
|
||||
initHeight={initChatInputHeight}
|
||||
dragDirectionConfigs={[
|
||||
{
|
||||
direction: 'top',
|
||||
boundary: [-(maxInitChatInputHeight - initChatInputHeight), 100],
|
||||
},
|
||||
]}>
|
||||
<ChatMessageInput
|
||||
showTopLogo={chatPanelWidth > 600}
|
||||
showBottomLogo={chatPanelWidth <= 600}
|
||||
value={chatInstance?.inputtingPrompt || ''}
|
||||
onChange={handleInputChange}
|
||||
toolbarSlot={renderInputToolbar()}
|
||||
onSendMessage={handleGenerateAnswer}
|
||||
logoProps={{
|
||||
onClick() {
|
||||
setInitChatInputHeight(initChatInputHeight === defaultInitChatInputHeight ? maxInitChatInputHeight : defaultInitChatInputHeight)
|
||||
{initChatInputHeight
|
||||
&& <DragResizeView
|
||||
ref={dargChatInputRef}
|
||||
initHeight={initChatInputHeight}
|
||||
dragDirectionConfigs={[
|
||||
{
|
||||
direction: 'top',
|
||||
boundary: [-(maxInitChatInputHeight - initChatInputHeight), 100],
|
||||
},
|
||||
]}
|
||||
dragStyle={{
|
||||
position: 'absolute',
|
||||
bottom: '0',
|
||||
left: '0',
|
||||
zIndex: '9',
|
||||
width: '100%',
|
||||
}}
|
||||
></ChatMessageInput>
|
||||
</DragResizeView>}
|
||||
>
|
||||
<ChatMessageInput
|
||||
showTopLogo={chatPanelWidth > 600}
|
||||
showBottomLogo={chatPanelWidth <= 600}
|
||||
value={chatInstance?.inputtingPrompt || ''}
|
||||
onChange={handleInputChange}
|
||||
toolbarSlot={renderInputToolbar()}
|
||||
onSendMessage={handleGenerateAnswer}
|
||||
logoProps={{
|
||||
onClick() {
|
||||
setInitChatInputHeight(initChatInputHeight === defaultInitChatInputHeight ? maxInitChatInputHeight : defaultInitChatInputHeight)
|
||||
},
|
||||
}}
|
||||
></ChatMessageInput>
|
||||
</DragResizeView>
|
||||
}
|
||||
</ChatPanelWrapper>
|
||||
})
|
||||
|
||||
|
||||
@@ -3,12 +3,12 @@ import type { SingleFileConfig, UserConfig } from '@nicepkg/gpt-runner-shared/co
|
||||
import { useGlobalStore } from '../../../../../../store/zustand/global'
|
||||
import type { MessageCodeBlockTheme } from '../../../../../../components/chat-message-code-block'
|
||||
import { MessageCodeBlock } from '../../../../../../components/chat-message-code-block'
|
||||
import { isDarkTheme } from '../../../../../../styles/themes'
|
||||
import { useUserConfig } from '../../../../../../hooks/use-user-config.hook'
|
||||
import { ConfigInfoWrapper } from '../../settings.styles'
|
||||
import { FormTitle } from '../../../../../../components/form-title'
|
||||
import { FlexColumn } from '../../../../../../styles/global.styles'
|
||||
import { LoadingView } from '../../../../../../components/loading-view'
|
||||
import { useDarkTheme } from '../../../../../../hooks/use-css-var-color.hook'
|
||||
|
||||
export interface ConfigInfoProps {
|
||||
rootPath?: string
|
||||
@@ -19,11 +19,12 @@ export interface ConfigInfoProps {
|
||||
|
||||
export const ConfigInfo: FC<ConfigInfoProps> = memo((props) => {
|
||||
const { rootPath, chatId, singleFileConfig: singleFileConfigFromProps, userConfig: userConfigFromProps } = props
|
||||
const { themeName, getGptFileTreeItemFromChatId } = useGlobalStore()
|
||||
const { getGptFileTreeItemFromChatId } = useGlobalStore()
|
||||
|
||||
const isDark = useDarkTheme()
|
||||
const codeBlockTheme: MessageCodeBlockTheme = useMemo(() => {
|
||||
return isDarkTheme(themeName) ? 'dark' : 'light'
|
||||
}, [themeName])
|
||||
return isDark ? 'dark' : 'light'
|
||||
}, [isDark])
|
||||
|
||||
const gptFileTreeItem = useMemo(() => {
|
||||
if (!chatId)
|
||||
|
||||
@@ -8,6 +8,7 @@ import { useIsMobile } from '../../../../hooks/use-is-mobile.hook'
|
||||
import type { UseTokenNumProps } from '../../../../hooks/use-token-num.hook'
|
||||
import { useTokenNum } from '../../../../hooks/use-token-num.hook'
|
||||
import { formatNumWithK } from '../../../../helpers/utils'
|
||||
import { useTempStore } from '../../../../store/zustand/temp'
|
||||
import { TopToolbarBlank, TopToolbarLeft, TopToolbarRight, TopToolbarWrapper } from './top-toolbar.styles'
|
||||
|
||||
export interface TopToolbarProps extends UseTokenNumProps {
|
||||
@@ -23,13 +24,15 @@ export const TopToolbar = memo(forwardRef<HTMLDivElement, TopToolbarProps>((prop
|
||||
const { t } = useTranslation()
|
||||
const isMobile = useIsMobile()
|
||||
const { totalTokenNum } = useTokenNum(useTokenNumProps)
|
||||
const { updateCurrentAppConfig } = useTempStore()
|
||||
|
||||
const popMenus: {
|
||||
const menus: {
|
||||
text: string
|
||||
alwaysShowText?: boolean
|
||||
iconClassName: string
|
||||
menuView?: React.ReactNode
|
||||
menuProps?: PopoverMenuProps
|
||||
onClick?: () => void
|
||||
}[] = [{
|
||||
text: t('chat_page.settings_btn'),
|
||||
alwaysShowText: true,
|
||||
@@ -45,12 +48,21 @@ export const TopToolbar = memo(forwardRef<HTMLDivElement, TopToolbarProps>((prop
|
||||
alwaysShowText: !isMobile,
|
||||
iconClassName: 'codicon-info',
|
||||
menuView: aboutView,
|
||||
}, {
|
||||
text: t('chat_page.settings_tab_notifications'),
|
||||
alwaysShowText: !isMobile,
|
||||
iconClassName: 'codicon-bell',
|
||||
onClick() {
|
||||
updateCurrentAppConfig({
|
||||
showNotificationModal: true,
|
||||
})
|
||||
},
|
||||
}]
|
||||
|
||||
return <>
|
||||
<TopToolbarWrapper ref={ref}>
|
||||
<TopToolbarLeft>
|
||||
{popMenus.map((popMenu, index) => {
|
||||
{menus.map((popMenu, index) => {
|
||||
const { text, alwaysShowText, iconClassName, menuView, menuProps } = popMenu
|
||||
|
||||
return <PopoverMenu
|
||||
@@ -73,9 +85,16 @@ export const TopToolbar = memo(forwardRef<HTMLDivElement, TopToolbarProps>((prop
|
||||
text={text}
|
||||
iconClassName={iconClassName}
|
||||
hoverShowText={!alwaysShowText && !isHovering}
|
||||
transparentBgWhenNotHover
|
||||
style={{
|
||||
paddingLeft: '0.5rem',
|
||||
}}
|
||||
onClick={(e: any) => {
|
||||
if (popMenu.onClick) {
|
||||
e.stopPropagation()
|
||||
popMenu.onClick?.()
|
||||
}
|
||||
}}
|
||||
></IconButton>
|
||||
}}
|
||||
buildMenuSlot={() => {
|
||||
|
||||
@@ -1,32 +1,54 @@
|
||||
import { createGlobalStyle, styled } from 'styled-components'
|
||||
|
||||
export const GlobalStyle = createGlobalStyle`
|
||||
export const GlobalStyle = createGlobalStyle<{ appendCss?: string }>`
|
||||
#root {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-webkit-user-drag: none;
|
||||
background: var(--background);
|
||||
color: var(--foreground);
|
||||
font-family: var(--font-family);
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-webkit-user-drag: none;
|
||||
background: var(--background);
|
||||
color: var(--foreground);
|
||||
font-family: var(--font-family);
|
||||
|
||||
--my-button-height: calc(var(--border-width) * 1px * 2 + var(--button-padding-vertical) * 2 + var(--type-ramp-base-font-size));
|
||||
--my-input-height: calc(var(--border-width) * 1px * 2 + var(--input-height) * 1px);
|
||||
--my-button-height: calc(var(--border-width) * 1px * 2 + var(--button-padding-vertical) * 2 + var(--type-ramp-base-font-size));
|
||||
--my-input-height: calc(var(--border-width) * 1px * 2 + var(--input-height) * 1px);
|
||||
--my-backdrop-filter: saturate(180%) blur(20px);
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: var(--my-scrollbar-bg);
|
||||
border-radius: 5px;
|
||||
transition: all 0.3s ease-in-out;
|
||||
|
||||
&:hover {
|
||||
background: var(--my-scrollbar-hover-bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
${props => props.appendCss}
|
||||
`
|
||||
|
||||
export const FlexRow = styled.div`
|
||||
|
||||
@@ -173,6 +173,7 @@ export const MarkdownStyle = createGlobalStyle`
|
||||
blockquote {
|
||||
border-left: 4px solid var(--panel-view-border);
|
||||
padding: 0 15px;
|
||||
margin-left: 15px;
|
||||
}
|
||||
blockquote > :first-child {
|
||||
margin-top: 0;
|
||||
|
||||
@@ -23,9 +23,4 @@ if (getGlobalConfig().defaultTheme !== 'default') {
|
||||
;(themeMap as any).default = defaultTheme
|
||||
}
|
||||
|
||||
export function isDarkTheme(themeName: ThemeName) {
|
||||
const darkThemes: ThemeName[] = ['default', 'gptrDark', 'vscodeDynamic', 'vscodeDark', 'jetbrainsDark']
|
||||
return darkThemes.includes(themeName)
|
||||
}
|
||||
|
||||
export type ThemeName = keyof typeof themeMap
|
||||
|
||||
@@ -5,3 +5,18 @@ export const textEllipsis = css`
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
`
|
||||
|
||||
export const backDropBg = css`
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
z-index: -1;
|
||||
backdrop-filter: var(--my-backdrop-filter);
|
||||
-webkit-backdrop-filter: var(--my-backdrop-filter);
|
||||
background: var(--my-backdrop-bg);
|
||||
}
|
||||
`
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { useMutation, useQuery } from '@tanstack/react-query'
|
||||
import type { ReactNode } from 'react'
|
||||
import { memo, useMemo } from 'react'
|
||||
import { memo } from 'react'
|
||||
import type { MarkAsVisitedAppConfigReqParams } from '@nicepkg/gpt-runner-shared/common'
|
||||
import { useTempStore } from '../../store/zustand/temp'
|
||||
import { useGlobalStore } from '../../store/zustand/global'
|
||||
import { fetchAppConfig, markAsVisitedAppConfig } from '../../networks/config'
|
||||
import { Modal } from '../../components/modal'
|
||||
import { MessageTextView } from '../../components/chat-message-text-view'
|
||||
import { Wrapper } from './layout.styles'
|
||||
|
||||
export interface LayoutProps {
|
||||
children?: ReactNode
|
||||
@@ -37,18 +38,18 @@ export const Layout = memo((props: LayoutProps) => {
|
||||
})
|
||||
|
||||
const notificationConfig = currentAppConfig?.currentConfig?.notificationConfig
|
||||
const releaseConfig = currentAppConfig?.currentConfig?.releaseConfig
|
||||
// const releaseConfig = currentAppConfig?.currentConfig?.releaseConfig
|
||||
|
||||
const releaseLog = useMemo(() => {
|
||||
let content = ''
|
||||
releaseConfig?.changeLogs.forEach((log) => {
|
||||
content += `## ${log.version}\n`
|
||||
content += `${log.changes}\n\n`
|
||||
})
|
||||
return content
|
||||
}, [releaseConfig?.changeLogs])
|
||||
// const releaseLog = useMemo(() => {
|
||||
// let content = ''
|
||||
// releaseConfig?.changeLogs.forEach((log) => {
|
||||
// content += `## ${log.version}\n`
|
||||
// content += `${log.changes}\n\n`
|
||||
// })
|
||||
// return content
|
||||
// }, [releaseConfig?.changeLogs])
|
||||
|
||||
return <>
|
||||
return <Wrapper>
|
||||
{/* notification modal */}
|
||||
<Modal
|
||||
zIndex={99}
|
||||
@@ -73,7 +74,7 @@ export const Layout = memo((props: LayoutProps) => {
|
||||
</Modal>
|
||||
|
||||
{/* release log modal */}
|
||||
<Modal
|
||||
{/* <Modal
|
||||
zIndex={100}
|
||||
open={Boolean(currentAppConfig?.showReleaseModal)}
|
||||
title={'Release Log'}
|
||||
@@ -93,10 +94,10 @@ export const Layout = memo((props: LayoutProps) => {
|
||||
>
|
||||
<MessageTextView
|
||||
contents={releaseLog} />
|
||||
</Modal>
|
||||
</Modal> */}
|
||||
|
||||
{children}
|
||||
</>
|
||||
</Wrapper>
|
||||
})
|
||||
|
||||
Layout.displayName = 'Layout'
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import { styled } from 'styled-components'
|
||||
|
||||
export const Wrapper = styled.div`
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
`
|
||||
@@ -80,19 +80,19 @@
|
||||
"@monaco-editor/react": "^4.5.1",
|
||||
"@nicepkg/gpt-runner-core": "workspace:*",
|
||||
"@nicepkg/gpt-runner-shared": "workspace:*",
|
||||
"@tanstack/react-query": "^4.32.0",
|
||||
"@tanstack/react-query": "^4.32.5",
|
||||
"@types/connect-history-api-fallback": "^1.5.0",
|
||||
"@types/cors": "^2.8.13",
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/global-agent": "^2.1.1",
|
||||
"@types/keyboardjs": "^2.5.1",
|
||||
"@types/lodash-es": "^4.17.8",
|
||||
"@types/react": "^18.2.17",
|
||||
"@types/react": "^18.2.18",
|
||||
"@types/react-dom": "^18.2.7",
|
||||
"@types/react-syntax-highlighter": "^15.5.7",
|
||||
"@types/uuid": "^9.0.2",
|
||||
"@use-gesture/react": "^10.2.27",
|
||||
"@vitejs/plugin-react": "^4.0.3",
|
||||
"@vitejs/plugin-react": "^4.0.4",
|
||||
"@vscode/webview-ui-toolkit": "^1.2.2",
|
||||
"clsx": "^2.0.0",
|
||||
"commander": "^10.0.1",
|
||||
@@ -104,32 +104,33 @@
|
||||
"framer-motion": "^10.15.0",
|
||||
"fs-extra": "^11.1.1",
|
||||
"global-agent": "^3.0.0",
|
||||
"i18next": "^23.3.0",
|
||||
"i18next": "^23.4.1",
|
||||
"i18next-browser-languagedetector": "^7.1.0",
|
||||
"i18next-http-backend": "^2.2.1",
|
||||
"js-base64": "^3.7.5",
|
||||
"keyboardjs": "^2.7.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"monaco-editor": "^0.40.0",
|
||||
"monaco-editor": "^0.41.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-error-boundary": "^4.0.10",
|
||||
"react-hook-form": "^7.45.2",
|
||||
"react-hot-toast": "^2.4.1",
|
||||
"react-i18next": "^13.0.2",
|
||||
"react-i18next": "^13.0.3",
|
||||
"react-markdown": "^8.0.7",
|
||||
"react-router-dom": "^6.14.2",
|
||||
"react-syntax-highlighter": "^15.5.0",
|
||||
"react-tiny-popover": "^7.2.4",
|
||||
"react-use": "^17.4.0",
|
||||
"remark-gfm": "^3.0.1",
|
||||
"styled-components": "^6.0.5",
|
||||
"undici": "^5.22.1",
|
||||
"styled-components": "^6.0.7",
|
||||
"undici": "^5.23.0",
|
||||
"unist-util-visit": "^5.0.0",
|
||||
"uuid": "^9.0.0",
|
||||
"vite": "^4.4.7",
|
||||
"vite": "^4.4.8",
|
||||
"vite-plugin-monaco-editor": "^1.1.0",
|
||||
"vite-plugin-svgr": "^3.2.0",
|
||||
"zustand": "^4.3.9"
|
||||
"web-streams-polyfill": "^3.2.1",
|
||||
"zustand": "^4.4.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,36 @@
|
||||
import type { NotificationConfig } from '@nicepkg/gpt-runner-shared/common'
|
||||
|
||||
export const notificationConfig: NotificationConfig = {
|
||||
createAt: '2023-07-24 23:31:22',
|
||||
createAt: '2023-08-06 18:37:10',
|
||||
title: 'GPT Runner Notification',
|
||||
message: 'v1.2.0 is release',
|
||||
message: 'v1.2.2 is release',
|
||||
}
|
||||
|
||||
export const cnNotificationConfig: NotificationConfig = {
|
||||
createAt: '2023-07-24 23:31:26',
|
||||
createAt: '2023-08-06 18:37:06',
|
||||
title: 'GPT Runner 通知',
|
||||
message: `
|
||||
### 版本更新到了 v1.2.0
|
||||
1. 重启 vscode 即可去扩展处更新
|
||||
2. cli 的执行 \`npm i -g gptr\` 即可更新
|
||||
### 🚀 新版 v1.2.2 (2023-08-06)
|
||||
|
||||
### 本次功能更新
|
||||
1. 针对语言为简体中文的用户提供 OpenAI API key 供应商,也就是你可以白嫖了。
|
||||
> vscode 用户重启 vscode 后即可在扩展处更新。
|
||||
>
|
||||
> cli 用户执行 \`npm i -g gptr\` 即可更新。
|
||||
|
||||
1. 针对语言为简体中文的用户提供 OpenAI API key 第三方供应商,也就是你可以白嫖了。
|
||||
2. 点击左上角设置,切换供应商即可。
|
||||
3. 本次 API Key 由慷慨大方的 \`剑廿三\` 提供,让我们把掌声送给他。
|
||||
3. 本次 API Key 由慷慨大方的 \`朝云云\` 提供,让我们把掌声送给他。
|
||||
|
||||
### 💬 交流
|
||||
|
||||
### 交流
|
||||
1. 想进群交流的加 wechat: \`qq2214962083\`
|
||||
2. 所有捐赠 API Key 的朋友,都可以在这里免费展示 50 字以内的广告直到 API Key 失效,如果你也想捐赠 API Key,可以联系我。
|
||||
3. 此处广告仅供展示,与 GPT-Runner 无关,**若有财产交易,请自行承担风险**
|
||||
|
||||
### 📢 YunAI - AI驱动的WEB对话应用 (朝云云供应商广告)
|
||||
|
||||
🔵 [**点击进入**](https://faschat.zyai.online/)注册即送大量3.5使用次数
|
||||
|
||||
如需适配 GPT-Runner 的 4.0-32k 或 Claude 接口服务,可 VX 联系:\`YunAi0101\`
|
||||
|
||||
`,
|
||||
}
|
||||
|
||||
@@ -8,13 +8,13 @@ export const vendorsConfig: VendorsConfig = {
|
||||
}
|
||||
|
||||
export const cnVendorsConfig: VendorsConfig = {
|
||||
createAt: '2023-07-24 23:40:49',
|
||||
createAt: '2023-08-06 18:37:22',
|
||||
[ChatModelType.Openai]: [{
|
||||
vendorName: 'xabcai',
|
||||
vendorName: '朝云云供应商',
|
||||
vendorSecrets: {
|
||||
basePath: 'https://api.xabcai.com/v1',
|
||||
basePath: 'http://8.130.89.91:3000/v1',
|
||||
// don't forgot it should be base64
|
||||
apiKey: 'c2stWHZQeGJQMVBySFduZDJFZ0xpa0lKTlQzOTNoc3pZdDdmN0NNZUozSE1pdkw2QVdx',
|
||||
apiKey: 'c2stQUlBc2NTUGk2RVR0cXVSVThmMmYzODU1NTk4NzQ4M2U4YjE1QWU4MzEwMjMxZTRi',
|
||||
},
|
||||
}],
|
||||
[ChatModelType.Anthropic]: [],
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { canUseNodeFetchWithoutCliFlag, getDefaultProxyUrl } from '@nicepkg/gpt-runner-shared/node'
|
||||
import { bootstrap } from 'global-agent'
|
||||
import { Headers, ProxyAgent, Request, Response, fetch, setGlobalDispatcher } from 'undici'
|
||||
import { ReadableStream } from 'web-streams-polyfill/ponyfill'
|
||||
|
||||
if (!canUseNodeFetchWithoutCliFlag()) {
|
||||
console.log('GPT Runner: add polyfill for fetch', process.version)
|
||||
@@ -9,6 +10,7 @@ if (!canUseNodeFetchWithoutCliFlag()) {
|
||||
globalThis.Headers = Headers as any
|
||||
globalThis.Request = Request as any
|
||||
globalThis.Response = Response as any
|
||||
globalThis.ReadableStream = ReadableStream as any
|
||||
}
|
||||
|
||||
// global proxy
|
||||
|
||||
650
pnpm-lock.yaml
generated
650
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user