Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6216d84ecd | ||
|
|
ea887ad755 | ||
|
|
c98a2a3cb8 | ||
|
|
06f41c3758 |
@@ -1,3 +1,11 @@
|
|||||||
|
## v2.4.1
|
||||||
|
|
||||||
|
`2023-02-18`
|
||||||
|
|
||||||
|
### Enhancement
|
||||||
|
- 调整部份移动端上的样式
|
||||||
|
- 输入框支持换行
|
||||||
|
|
||||||
## v2.4.0
|
## v2.4.0
|
||||||
|
|
||||||
`2023-02-17`
|
`2023-02-17`
|
||||||
@@ -6,6 +14,7 @@
|
|||||||
- 响应式支持移动端
|
- 响应式支持移动端
|
||||||
### Enhancement
|
### Enhancement
|
||||||
- 修改部份描述错误
|
- 修改部份描述错误
|
||||||
|
|
||||||
## v2.3.3
|
## v2.3.3
|
||||||
|
|
||||||
`2023-02-16`
|
`2023-02-16`
|
||||||
|
|||||||
44
README.md
44
README.md
@@ -2,9 +2,7 @@
|
|||||||
|
|
||||||
使用 express 和 vue3 搭建的 ChartGPT 演示网页
|
使用 express 和 vue3 搭建的 ChartGPT 演示网页
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
> 提示:目前 `OpenAI` 开放的模型最高只有 `GPT-3`,和现在网页所使用的 `GPT-3.5` 或 `GPT-4` 有很大差距,需要等官方开放最新的模型接口。
|
> 提示:目前 `OpenAI` 开放的模型最高只有 `GPT-3`,和现在网页所使用的 `GPT-3.5` 或 `GPT-4` 有很大差距,需要等官方开放最新的模型接口。
|
||||||
|
|
||||||
@@ -80,26 +78,7 @@ pnpm dev
|
|||||||
```
|
```
|
||||||
|
|
||||||
## 打包
|
## 打包
|
||||||
|
## Docker build
|
||||||
### 后端服务
|
|
||||||
> 如果你不需要本项目的 `node` 接口,可以省略如下操作
|
|
||||||
|
|
||||||
复制 `service` 文件夹到你有 `node` 服务环境的服务器上。(搜索关键字:`express部署`)
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# 安装
|
|
||||||
pnpm install
|
|
||||||
|
|
||||||
# 打包
|
|
||||||
pnpm build
|
|
||||||
|
|
||||||
# 运行
|
|
||||||
pnpm prod
|
|
||||||
```
|
|
||||||
|
|
||||||
PS: 不进行打包,直接在服务器上运行 `pnpm start` 也可
|
|
||||||
|
|
||||||
## Docker build & run
|
|
||||||
|
|
||||||
[参考信息](https://github.com/Chanzhaoyu/chatgpt-web/pull/42)
|
[参考信息](https://github.com/Chanzhaoyu/chatgpt-web/pull/42)
|
||||||
|
|
||||||
@@ -123,8 +102,25 @@ services:
|
|||||||
OPENAI_API_KEY: xxxxxx
|
OPENAI_API_KEY: xxxxxx
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### 后端服务
|
||||||
|
> 如果你不需要本项目的 `node` 接口,可以省略如下操作
|
||||||
|
|
||||||
### 网页
|
复制 `service` 文件夹到你有 `node` 服务环境的服务器上。(搜索关键字:`express部署`)
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# 安装
|
||||||
|
pnpm install
|
||||||
|
|
||||||
|
# 打包
|
||||||
|
pnpm build
|
||||||
|
|
||||||
|
# 运行
|
||||||
|
pnpm prod
|
||||||
|
```
|
||||||
|
|
||||||
|
PS: 不进行打包,直接在服务器上运行 `pnpm start` 也可
|
||||||
|
|
||||||
|
### 前端打包
|
||||||
|
|
||||||
根目录下运行以下命令,然后将 `dist` 文件夹复制到你的托管服务器上
|
根目录下运行以下命令,然后将 `dist` 文件夹复制到你的托管服务器上
|
||||||
|
|
||||||
|
|||||||
BIN
docs/c1.png
BIN
docs/c1.png
Binary file not shown.
|
Before Width: | Height: | Size: 188 KiB |
BIN
docs/c2.png
BIN
docs/c2.png
Binary file not shown.
|
Before Width: | Height: | Size: 136 KiB |
BIN
docs/cover-2.png
BIN
docs/cover-2.png
Binary file not shown.
|
Before Width: | Height: | Size: 200 KiB |
BIN
docs/cover.png
Normal file
BIN
docs/cover.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "chatgpt-web",
|
"name": "chatgpt-web",
|
||||||
"version": "2.4.0",
|
"version": "2.4.1",
|
||||||
"private": false,
|
"private": false,
|
||||||
"description": "ChatGPT Web",
|
"description": "ChatGPT Web",
|
||||||
"author": "ChenZhaoYu <chenzhaoyu1994@gmail.com>",
|
"author": "ChenZhaoYu <chenzhaoyu1994@gmail.com>",
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { useChat } from './hooks/useChat'
|
|||||||
import { fetchChatAPI } from '@/api'
|
import { fetchChatAPI } from '@/api'
|
||||||
import { HoverButton, SvgIcon } from '@/components/common'
|
import { HoverButton, SvgIcon } from '@/components/common'
|
||||||
import { useHistoryStore } from '@/store'
|
import { useHistoryStore } from '@/store'
|
||||||
|
import { useBasicLayout } from '@/hooks/useBasicLayout'
|
||||||
|
|
||||||
let controller = new AbortController()
|
let controller = new AbortController()
|
||||||
|
|
||||||
@@ -15,6 +16,8 @@ const ms = useMessage()
|
|||||||
|
|
||||||
const historyStore = useHistoryStore()
|
const historyStore = useHistoryStore()
|
||||||
|
|
||||||
|
const { isMobile } = useBasicLayout()
|
||||||
|
|
||||||
let messageReactive: MessageReactive | null = null
|
let messageReactive: MessageReactive | null = null
|
||||||
|
|
||||||
const scrollRef = ref<HTMLDivElement>()
|
const scrollRef = ref<HTMLDivElement>()
|
||||||
@@ -30,6 +33,12 @@ const heartbeat = computed(() => historyStore.heartbeat)
|
|||||||
const list = computed<Chat.Chat[]>(() => historyStore.getCurrentChat)
|
const list = computed<Chat.Chat[]>(() => historyStore.getCurrentChat)
|
||||||
const chatList = computed<Chat.Chat[]>(() => list.value.filter(item => (!item.reversal && !item.error)))
|
const chatList = computed<Chat.Chat[]>(() => list.value.filter(item => (!item.reversal && !item.error)))
|
||||||
|
|
||||||
|
const footerMobileStyle = computed(() => {
|
||||||
|
if (isMobile.value)
|
||||||
|
return ['pl-2', 'pt-2', 'pb-6', 'fixed', 'bottom-0', 'left-0', 'right-0', 'z-30']
|
||||||
|
return []
|
||||||
|
})
|
||||||
|
|
||||||
async function handleSubmit() {
|
async function handleSubmit() {
|
||||||
if (loading.value)
|
if (loading.value)
|
||||||
return
|
return
|
||||||
@@ -69,8 +78,10 @@ async function handleSubmit() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleEnter(event: KeyboardEvent) {
|
function handleEnter(event: KeyboardEvent) {
|
||||||
if (event.key === 'Enter')
|
if (event.key === 'Enter' && !event.shiftKey) {
|
||||||
|
event.preventDefault()
|
||||||
handleSubmit()
|
handleSubmit()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function addMessage(
|
function addMessage(
|
||||||
@@ -143,7 +154,11 @@ watch(
|
|||||||
<Layout>
|
<Layout>
|
||||||
<div class="flex flex-col h-full">
|
<div class="flex flex-col h-full">
|
||||||
<main class="flex-1 overflow-hidden">
|
<main class="flex-1 overflow-hidden">
|
||||||
<div ref="scrollRef" class="h-full p-4 overflow-hidden overflow-y-auto">
|
<div
|
||||||
|
ref="scrollRef"
|
||||||
|
class="h-full p-4 overflow-hidden overflow-y-auto"
|
||||||
|
:class="[{ 'p-2': isMobile }]"
|
||||||
|
>
|
||||||
<template v-if="!list.length">
|
<template v-if="!list.length">
|
||||||
<div class="flex items-center justify-center mt-4 text-center text-neutral-300">
|
<div class="flex items-center justify-center mt-4 text-center text-neutral-300">
|
||||||
<SvgIcon icon="ri:bubble-chart-fill" class="mr-2 text-3xl" />
|
<SvgIcon icon="ri:bubble-chart-fill" class="mr-2 text-3xl" />
|
||||||
@@ -153,21 +168,34 @@ watch(
|
|||||||
<template v-else>
|
<template v-else>
|
||||||
<div>
|
<div>
|
||||||
<Message
|
<Message
|
||||||
v-for="(item, index) of list" :key="index" :date-time="item.dateTime" :message="item.message"
|
v-for="(item, index) of list"
|
||||||
:reversal="item.reversal" :error="item.error"
|
:key="index"
|
||||||
|
:date-time="item.dateTime"
|
||||||
|
:message="item.message"
|
||||||
|
:reversal="item.reversal"
|
||||||
|
:error="item.error"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
<footer class="p-4">
|
<footer
|
||||||
|
class="p-4"
|
||||||
|
:class="footerMobileStyle"
|
||||||
|
>
|
||||||
<div class="flex items-center justify-between space-x-2">
|
<div class="flex items-center justify-between space-x-2">
|
||||||
<HoverButton tooltip="Clear conversations">
|
<HoverButton tooltip="Clear conversations">
|
||||||
<span class="text-xl text-[#4f555e]" @click="handleClear">
|
<span class="text-xl text-[#4f555e]" @click="handleClear">
|
||||||
<SvgIcon icon="ri:delete-bin-line" />
|
<SvgIcon icon="ri:delete-bin-line" />
|
||||||
</span>
|
</span>
|
||||||
</HoverButton>
|
</HoverButton>
|
||||||
<NInput v-model:value="prompt" placeholder="Type a message..." @keypress="handleEnter" />
|
<NInput
|
||||||
|
v-model:value="prompt"
|
||||||
|
type="textarea"
|
||||||
|
:autosize="{ minRows: 1, maxRows: 2 }"
|
||||||
|
placeholder="Ask me anything..."
|
||||||
|
@keypress="handleEnter"
|
||||||
|
/>
|
||||||
<NButton type="primary" :disabled="loading" @click="handleSubmit">
|
<NButton type="primary" :disabled="loading" @click="handleSubmit">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<SvgIcon icon="ri:send-plane-fill" />
|
<SvgIcon icon="ri:send-plane-fill" />
|
||||||
|
|||||||
@@ -22,13 +22,14 @@ const getContainerClass = computed(() => {
|
|||||||
return [
|
return [
|
||||||
'h-full',
|
'h-full',
|
||||||
{ 'pt-14': isMobile.value },
|
{ 'pt-14': isMobile.value },
|
||||||
|
{ 'pb-[70px]': isMobile.value },
|
||||||
{ 'pl-[260px]': !isMobile.value && !collapsed.value },
|
{ 'pl-[260px]': !isMobile.value && !collapsed.value },
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="h-screen p-4" :class="[{ 'p-0': isMobile }]">
|
<div class="h-screen" :class="[isMobile ? 'p-0' : 'p-4']">
|
||||||
<div class="h-full overflow-hidden" :class="getMobileClass">
|
<div class="h-full overflow-hidden" :class="getMobileClass">
|
||||||
<NLayout class="z-40 transition" :class="getContainerClass" has-sider>
|
<NLayout class="z-40 transition" :class="getContainerClass" has-sider>
|
||||||
<Sider />
|
<Sider />
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ function handleUpdateCollapsed() {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<header class="fixed top-0 left-0 right-0 z-50 border-b bg-white/80 backdrop-blur">
|
<header class="fixed top-0 left-0 right-0 z-50 border-b bg-white/80 backdrop-blur">
|
||||||
<div class="relative flex items-center justify-between px-4 h-14">
|
<div class="relative flex items-center justify-between h-14">
|
||||||
<button class="flex items-center justify-center w-11 h-11" @click="handleUpdateCollapsed">
|
<button class="flex items-center justify-center w-11 h-11" @click="handleUpdateCollapsed">
|
||||||
<SvgIcon v-if="collapsed" class="text-2xl" icon="ri:align-justify" />
|
<SvgIcon v-if="collapsed" class="text-2xl" icon="ri:align-justify" />
|
||||||
<SvgIcon v-else class="text-2xl" icon="ri:align-right" />
|
<SvgIcon v-else class="text-2xl" icon="ri:align-right" />
|
||||||
|
|||||||
@@ -29,7 +29,10 @@ watch(
|
|||||||
(val) => {
|
(val) => {
|
||||||
appStore.setSiderCollapsed(val)
|
appStore.setSiderCollapsed(val)
|
||||||
},
|
},
|
||||||
{ flush: 'post' },
|
{
|
||||||
|
immediate: true,
|
||||||
|
flush: 'post',
|
||||||
|
},
|
||||||
)
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -42,6 +45,7 @@ watch(
|
|||||||
collapse-mode="transform"
|
collapse-mode="transform"
|
||||||
position="absolute"
|
position="absolute"
|
||||||
bordered
|
bordered
|
||||||
|
style="z-index: 50;"
|
||||||
@update-collapsed="handleUpdateCollapsed"
|
@update-collapsed="handleUpdateCollapsed"
|
||||||
>
|
>
|
||||||
<div class="flex flex-col h-full" :class="[{ 'pt-14': isMobile }]">
|
<div class="flex flex-col h-full" :class="[{ 'pt-14': isMobile }]">
|
||||||
@@ -63,4 +67,7 @@ watch(
|
|||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
</NLayoutSider>
|
</NLayoutSider>
|
||||||
|
<template v-if="isMobile">
|
||||||
|
<div v-show="!collapsed" class="absolute inset-0 z-40 bg-black/40" @click="handleUpdateCollapsed" />
|
||||||
|
</template>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Reference in New Issue
Block a user