ChatGPT最近很火爆大家都知道吧,今天废话不多说 直接给大家带来一个ChatGPT中文版的源码
先对整体进行一个介绍,这套源码界面很有科技感,其次是功能方面有专门的指令输入框,让你可以舒舒服服的玩转你手中的prompts
其次有黑夜和白天两个模式以及回到顶部功能
下面废话不多说 直接上代码
由于代码太多 我直接放前端页面的代码
代码是基于nodejs写的
下面是header文件
---
import Logo from './Logo.astro'
import Themetoggle from './Themetoggle.astro'
---
<header>
<div class="flex justify-between">
<Logo />
<Themetoggle />
</div>
<div class="flex items-center mt-2">
<span class="text-2xl text-slate font-extrabold mr-1">CTGPT.</span>
<span class="text-2xl text-transparent font-extrabold bg-clip-text bg-gradient-to-r from-sky-400 to-emerald-600">CN</span>
</div>
<p mt-1 text-slate op-60>基于 OpenAI API (gpt-3.5-turbo)开发.</p>
</header>
下面是footer文件
<footer>
<p mt-8 text-xs op-30>
<br>
<a
border-b border-slate border-none hover:border-dashed
href="https://wwji.lanzouf.com/iVoeB0o7wrxe" target="_blank"
>
安卓端下载
<span px-1>|</span>
</a>
<a
border-b border-slate border-none hover:border-dashed
href="https://wwji.lanzouf.com/iYlRb0o7wryf" target="_blank"
>
苹果端下载(safari打开安装需要去设置描述文件安装)
</a>
</p>
<script charset="UTF-8" id="LA_COLLECT" src="//sdk.51.la/js-sdk-pro.min.js"></script>
<script>LA.init({id:"Jzntbyt4gmLpmsXz",ck:"Jzntbyt4gmLpmsXz"})</script>
<script>
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?5aff25b20308b19618d1ea0a4797216b";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</p>
</footer>
下面是问题框代码
import type { ChatMessage } from '@/types'
import { createSignal, Index, Show } from 'solid-js'
import IconClear from './icons/Clear'
import MessageItem from './MessageItem'
import SystemRoleSettings from './SystemRoleSettings'
import _ from 'lodash'
import { generateSignature } from '@/utils/auth'
export default () => {
let inputRef: HTMLTextAreaElement
const [currentSystemRoleSettings, setCurrentSystemRoleSettings] = createSignal('')
const [systemRoleEditing, setSystemRoleEditing] = createSignal(false)
const [messageList, setMessageList] = createSignal<ChatMessage[]>([])
const [currentAssistantMessage, setCurrentAssistantMessage] = createSignal('')
const [loading, setLoading] = createSignal(false)
const [controller, setController] = createSignal<AbortController>(null)
const handleButtonClick = async () => {
const inputValue = inputRef.value
if (!inputValue) {
return
}
// @ts-ignore
if (window?.umami) umami.trackEvent('chat_generate')
inputRef.value = ''
setMessageList([
...messageList(),
{
role: 'user',
content: inputValue,
},
])
requestWithLatestMessage()
}
const throttle =_.throttle(function(){
window.scrollTo({top: document.body.scrollHeight, behavior: 'smooth'})
}, 300, {
leading: true,
trailing: false
})
const requestWithLatestMessage = async () => {
setLoading(true)
setCurrentAssistantMessage('')
const storagePassword = localStorage.getItem('pass')
try {
const controller = new AbortController()
setController(controller)
const requestMessageList = [...messageList()]
if (currentSystemRoleSettings()) {
requestMessageList.unshift({
role: 'system',
content: currentSystemRoleSettings(),
})
}
const timestamp = Date.now()
const response = await fetch('/api/generate', {
method: 'POST',
body: JSON.stringify({
messages: requestMessageList,
time: timestamp,
pass: storagePassword,
sign: await generateSignature({
t: timestamp,
m: requestMessageList?.[requestMessageList.length - 1]?.content || '',
}),
}),
signal: controller.signal,
})
if (!response.ok) {
throw new Error(response.statusText)
}
const data = response.body
if (!data) {
throw new Error('No data')
}
const reader = data.getReader()
const decoder = new TextDecoder('utf-8')
let done = false
while (!done) {
const { value, done: readerDone } = await reader.read()
if (value) {
let char = decoder.decode(value)
if (char === '\n' && currentAssistantMessage().endsWith('\n')) {
continue
}
if (char) {
setCurrentAssistantMessage(currentAssistantMessage() + char)
}
throttle()
}
done = readerDone
}
} catch (e) {
console.error(e)
setLoading(false)
setController(null)
return
}
archiveCurrentMessage()
}
const archiveCurrentMessage = () => {
if (currentAssistantMessage()) {
setMessageList([
...messageList(),
{
role: 'assistant',
content: currentAssistantMessage(),
},
])
setCurrentAssistantMessage('')
setLoading(false)
setController(null)
inputRef.focus()
}
}
const clear = () => {
inputRef.value = ''
inputRef.style.height = 'auto';
setMessageList([])
setCurrentAssistantMessage('')
setCurrentSystemRoleSettings('')
}
const stopStreamFetch = () => {
if (controller()) {
controller().abort()
archiveCurrentMessage()
}
}
const retryLastFetch = () => {
if (messageList().length > 0) {
const lastMessage = messageList()[messageList().length - 1]
console.log(lastMessage)
if (lastMessage.role === 'assistant') {
setMessageList(messageList().slice(0, -1))
requestWithLatestMessage()
}
}
}
const handleKeydown = (e: KeyboardEvent) => {
if (e.isComposing || e.shiftKey) {
return
}
if (e.key === 'Enter') {
handleButtonClick()
}
}
return (
<div my-6>
<SystemRoleSettings
canEdit={() => messageList().length === 0}
systemRoleEditing={systemRoleEditing}
setSystemRoleEditing={setSystemRoleEditing}
currentSystemRoleSettings={currentSystemRoleSettings}
setCurrentSystemRoleSettings={setCurrentSystemRoleSettings}
/>
<Index each={messageList()}>
{(message, index) => (
<MessageItem
role={message().role}
message={message().content}
showRetry={() => (message().role === 'assistant' && index === messageList().length - 1)}
onRetry={retryLastFetch}
/>
)}
</Index>
{currentAssistantMessage() && (
<MessageItem
role="assistant"
message={currentAssistantMessage}
/>
)}
<Show
when={!loading()}
fallback={() => (
<div class="h-12 my-4 flex gap-4 items-center justify-center bg-slate bg-op-15 rounded-sm">
<span>AI正在思考中...</span>
<div class="px-2 py-0.5 border border-slate rounded-md text-sm op-70 cursor-pointer hover:bg-slate/10" onClick={stopStreamFetch}>停止</div>
</div>
)}
>
<div class="my-4 flex items-center gap-2 transition-opacity" class:op-50={systemRoleEditing()}>
<textarea
ref={inputRef!}
disabled={systemRoleEditing()}
onKeyDown={handleKeydown}
placeholder="问些问题吧..."
autocomplete="off"
autofocus
onInput={() => {
inputRef.style.height = 'auto';
inputRef.style.height = inputRef.scrollHeight + 'px';
}}
rows="1"
w-full
px-3 py-3
min-h-12
max-h-36
rounded-sm
bg-slate
bg-op-15
resize-none
focus:bg-op-20
focus:ring-0
focus:outline-none
placeholder:op-50
dark="placeholder:op-30"
scroll-pa-8px
/>
<button onClick={handleButtonClick} disabled={systemRoleEditing()} h-12 px-4 py-2 bg-slate bg-op-15 hover:bg-op-20 rounded-sm>
Send
</button>
<button title="Clear" onClick={clear} disabled={systemRoleEditing()} h-12 px-4 py-2 bg-slate bg-op-15 hover:bg-op-20 rounded-sm>
<IconClear />
</button>
</div>
</Show>
</div>
)
}
本文含有隐藏内容,请 开通VIP 后查看