成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

花1塊錢讓你的網站支持 ChatGPT

人工智能
這是一個在這個星球上數以百萬計的服務中注冊帳戶的網站。 我們提供世界上大多數國家的虛擬號碼,以便您可以在線接收帶有確認代碼的短信。在我們的服務中,還有虛擬號碼的長期租賃,轉發連接,電話驗證等等。

本文轉載自微信公眾號「前端司南」,作者Tusi。轉載本文請聯系前端司南公眾號。

最近 ChatGPT 在技術圈子可太火了,票圈也被刷屏。我也決定來湊個熱鬧,給自己的博客加一個 ChatGPT 對話功能。

先附上體驗鏈接,源碼在底部也可以找到。

感謝大家的支持,我的 Open AI個人賬戶免費額度已經用盡,非常抱歉,請大家自行按照文章和源碼搭建體驗吧,或者自己注冊一個賬號去后臺體驗。

chatgpt_博客效果.gif

體驗 ChatGPT

ChatGPT 是 Open AI 訓練的一個 AI 對話模型,可以支持在多種場景下進行智能對話。

image.png

想體驗 ChatGPT,首先要注冊賬戶,但是這個產品在國內網絡并不能直接用,需要自行解決網絡問題。

image.png

搞定網絡問題后,注冊時會讓你提供郵箱驗證,

image.png

接著要驗證手機號,但是很遺憾國內手機號用不了。

image.png

你也可以選擇用 Google 賬號登錄,但是最終還是要驗證手機號。

所以我們需要先找一個國外的能接收短信驗證碼的手機號,此時可以上SMS-ACTIVATE。

這是一個在這個星球上數以百萬計的服務中注冊帳戶的網站。 我們提供世界上大多數國家的虛擬號碼,以便您可以在線接收帶有確認代碼的短信。 在我們的服務中,還有虛擬號碼的長期租賃,轉發連接,電話驗證等等。

SMS-ACTIVATE 上的價格是盧布,我們需要使用手機號碼做短信驗證,經過查詢可以發現,最便宜的是印度地區的手機號,零售價格是 10.5 盧布。

image.png

按照匯率算了一下,大概是1塊多RMB。

image.png

SMS-ACTIVATE 支持用某寶充值,我買了一個印度號,就可以收到來自 Open AI 的驗證碼了。

image.png

注意,這個號碼只是租用,是有期限的,所以我們要抓緊時間把注冊流程搞完,20分鐘過了,這個號碼就不是你的了。

注冊完 Open AI 的賬號后,就可以到 ChatGPT 的 Web工作臺體驗一把 AI 對話了。

chatgpt體驗.gif

通過 API 接入 Open AI 能力

體驗完 ChatGPT 之后,對于搞技術的我們來說,可能會想著怎么把這個能力接入到自己的產品中。

快速上手

ChatGPT 是 Open AI 訓練出來的模型,Open AI 也提供了 API 給開發者們調用,文檔和案例也比較全面。

機器學習很重要的一個步驟就是調參,但對于前端開發者來說,大部分人肯定是不知道怎么調參的,那我們就參考官方提供的最契合我們需求的案例就好了,這個 Chat 的案例就非常符合我們的場景需要。

image.png

官方有提供一個 nodejs 的 starter,我們可以基于此快速上手測試一把。

git clone https://github.com/openai/openai-quickstart-node.git

它的核心代碼是這么一部分,其中用到的openai是官方封裝好的 NodeJS Library。

const completion = await openai.createCompletion({
model: "text-davinci-003",
prompt: '提問內容',
temperature: 0.9,
max_tokens: 150,
top_p: 1,
frequency_penalty: 0,
presence_penalty: 0.6,
});

在調用 API 之前需要先在你的 Open AI 賬戶中生成一個 API Key。

目前官方給到的免費額度是 18 刀,超過的部分就需要自己付費了。計費是根據 Token 來算的,至于什么是 Token,可以參考Key concepts。

image.png

我們把上面那個 Chat 案例的參數拿過來直接用上,基本上也有個七八分 AI 回答問題的樣子了,這個可以自己去試一試效果,并不復雜。

接著就是研究一下怎么把這個 starter 的關鍵代碼集成到自己的產品中。

產品分析

我之前有在自己的博客中做過一個簡單的 WebSocket 聊天功能,而在 AI 對話這個需求中,前端 UI 部分基本上可以參考著WebSocket 聊天功能改改,工作量不是很大,主要工作量還是在前后端的邏輯和對接上面。

image.png

ChatGPT 的這個產品模式,它不是一個常規的 WebSocket 全雙工對話,而是像我們平常調接口一樣,發生用戶輸入后,客戶端發送請求到服務端,等待服務端響應,最后反饋給用戶,它僅僅是從界面上看起來像是聊天,實際上不是一個標準的聊天過程。所以前后端交互主要還是靠 HTTP 接口對接。

核心要素 Prompt

在openai.createCompletion調用時有一個很重要的參數prompt,它是對話的上下文信息,只有這個信息足夠完整,AI 才能正確地做出反饋。

舉個例子,假設在對話過程中有2個回合。

// 回合1
你:愛因斯坦是誰?
AI: 愛因斯坦(Albert Einstein)是20世紀最重要的物理學家,他被譽為“時空之父”。他發現了相對論,并獲得諾貝爾物理學獎。

第一個回合中,傳參prompt是愛因斯坦是誰?,機器人很好理解,馬上能給出符合實際的回復。

// 回合2
你:他做了什么貢獻?
AI: 他為社會做出了許多貢獻,例如改善公共衛生、建立教育基礎設施、提高農業生產能力、促進經濟發展等。

第二個回合傳參prompt是他做了什么貢獻?,看到機器人的答復,你可能會覺得有點離譜,因為這根本就是牛頭不對馬嘴。但是仔細想想,這是因為機器人不知道上下文信息,所以機器人不能理解他代表的含義,只能通過他做了什么貢獻?整句話去推測,所以從結果上看就是符合語言的邏輯,但是不符合我們給出的語境。

如果我們把第二個回合的傳參prompt改成你: 愛因斯坦是誰?\nAI: 愛因斯坦(Albert Einstein)是20世紀最重要的物理學家,他被譽為“時空之父”。他發現了相對論,并獲得諾貝爾物理學獎。\n你: 他做了什么貢獻?\nAI:,機器人就能夠理解上下文信息,給出接下來的符合邏輯的答復。

// 改進后的回合2
你:他做了什么貢獻?
AI: 愛因斯坦對科學有著重大的貢獻,他發明了相對論,改變了人們對世界、物理定律和宇宙的認識,并為量子力學奠定了基礎。他還發現了...

所以,我們的初步結論是:prompt參數應該包含此次對話主題的較完整內容,才能保證 AI 給出的下一次回答符合我們的基本認知。

前后端交互

對于前端來說,我們通常關注的是,我給后端發了什么數據,后端反饋給我什么數據。所以,前端關注點之一就是用戶的輸入,用上面的例子說,愛因斯坦是誰?和他做了什么貢獻?這兩個內容,應該分別作為前端兩次請求的參數。而且,對于前端來說,我們也不需要考慮后端傳給 Open AI 的prompt是不是完整,只要把用戶輸入的內容合理地傳給后端就夠了。

對于后端來說,我們要關注 session 問題,每個用戶應該有屬于自己和 AI 的私密對話空間,不能和其他的用戶對話串了數據,這個可以基于 session 實現。前端每次傳過來的信息只有簡單的用戶輸入,而后端要關注與 Open AI 的對接過程,結合用戶的輸入以及會話中保留的一些信息,合并成一個完整的prompt傳給 Open AI,這樣才能得到正常的對話過程。

所以基本的流程應該是這個樣子:

image.png

我們根據這個流程輸出第一版代碼。

后端V1版本代碼

router.get('/chat-v1', async function(req, res, next) {
// 取得用戶輸入
const wd = req.query.wd;
// 構造 prompt 參數
if (!req.session.chatgptSessionPrompt) {
req.session.chatgptSessionPrompt = ''
}
const prompt = req.session.chatgptSessionPrompt + `\n提問:` + wd + `\nAI:`
try {
const completion = await openai.createCompletion({
model: "text-davinci-003",
prompt,
temperature: 0.9,
max_tokens: 150,
top_p: 1,
frequency_penalty: 0,
presence_penalty: 0.6,
stop: ["\n提問:", "\nAI:"],
});
// 調用 Open AI 成功后,更新 session
req.session.chatgptSessionPrompt = prompt + completion.data
// 返回結果
res.status(200).json({
code: '0',
result: completion.data.choices[0].text
});
} catch (error) {
console.error(error)
res.status(500).json({
message: "Open AI 調用異常"
});
}
});

前端V1版本關鍵代碼

const sendChatContentV1 = async () => {
// 先顯示自己說的話
msgList.value.push({
time: format(new Date(), "HH:mm:ss"),
user: "我說",
content: chatForm.chatContent,
type: "mine",
customClass: "mine",
});
loading.value = true;
try {
// 調 chat-v1 接口,等結果
const { result } = await chatgptService.chatV1({ wd: chatForm.chatContent });
// 顯示 AI 的答復
msgList.value.push({
time: format(new Date(), "HH:mm:ss"),
user: "Chat AI",
content: result,
type: "others",
customClass: "others",
});
} finally {
loading.value = false;
}
};

chatgpt_v1.gif

基本的對話能力已經有了,但是最明顯的缺點就是一個回合等得太久了,我們希望他速度更快一點,至少在交互上看起來快一點。

流式輸出(服務器推 + EventSource)

還好 Open AI 也支持 stream 流式輸出,在前端可以配合 EventSource 一起用。

You can also set the stream parameter to true for the API to stream back text (as data-only server-sent events).

基本的數據流是這個樣子的:

image.png

后端改造如下:

router.get('/chat-v2', async function(req, res, next) {
// ...省略部分代碼
try {
const completion = await openai.createCompletion({
// ...省略部分代碼
// 增加了 stream 參數
stream: true
}, { responseType: 'stream' });
// 設置響應的 content-type 為 text/event-stream
res.setHeader("content-type", "text/event-stream")
// completion.data 是一個 ReadableStream,res 是一個 WritableStream,可以通過 pipe 打通管道,流式輸出給前端。
completion.data.pipe(res)
}
// ...省略部分代碼
});

前端放棄使用 axios 發起 HTTP 請求,而是改用 EventSource。

const sendChatContent = async () => {
// ...省略部分代碼
// 先顯示自己說的話
msgList.value.push({
time: format(new Date(), "HH:mm:ss"),
user: "我說",
content: chatForm.chatContent,
type: "mine",
customClass: "mine",
});

// 通過 EventSource 取數據
const es = new EventSource(`/api/chatgpt/chat?wd=${chatForm.chatContent}`);

// 記錄 AI 答復的內容
let content = "";

// ...省略部分代碼

es.onmessage = (e) => {
if (e.data === "[DONE]") {
// [DONE] 標志數據結束,調用 feedback 反饋給服務器
chatgptService.feedback(content);
es.close();
loading.value = false;
updateScrollTop();
return;
}
// 從數據中取出文本
const text = JSON.parse(e.data).choices[0].text;
if (text) {
if (!content) {
// 第一條數據來了,先顯示
msgList.value.push({
time: format(new Date(), "HH:mm:ss"),
user: "Chat AI",
content: text,
type: "others",
customClass: "others",
});
// 再拼接
content += text;
} else {
// 先拼接
content += text;
// 再更新內容,實現打字機效果
msgList.value[msgList.value.length - 1].content = content;
}
}
};
};

從代碼中可以發現前端在 EventSource message 接收結束時,還調用了一個 feedback 接口做反饋。這是因為在使用 Pipe 輸出時,后端沒有記錄 AI 答復的文本,考慮到前端已經處理了文本,這里就由前端做一次反饋,把本次 AI 答復的內容完整回傳給后端,后端再更新 session 中存儲的對話信息,保證對話上下文的完整性。

feedback 接口的實現比較簡單:

router.post('/feedback', function(req, res, next) {
if (req.body.result) {
req.session.chatgptSessionPrompt += req.body.result
res.status(200).json({
code: '0',
msg: "更新成功"
});
} else {
res.status(400).json({
msg: "參數錯誤"
});
}
});

我這里只是給出一種簡單的做法,實際產品中可能要考慮的會更多,或者應該在后端自行處理 session 內容,而不是依靠前端的反饋。

最終的效果大概是這個樣子:

chatgpt_博客效果.gif

限制訪問頻次

由于 Open AI 也是有免費額度的,所以在調用頻率和次數上也應該做個限制,防止被惡意調用,這個也可以通過 session 來處理。我這里也提供一種比較粗糙的處理方式,具體請往下看。實際產品中可能會寫 Redis,寫庫,加定時任務之類的,這方面我也不夠專業,就不多說了。

針對訪問頻率,我暫定的是 3 秒內最多調用一次,我們可以在調用 Open AI 成功之后,在 session 中記錄時間戳。

req.session.chatgptRequestTime = Date.now()

當一個新的請求過來時,可以用當前時間減去上次記錄的chatgptRequestTime,判斷一下是不是在 3 秒內,如果是,就返回 HTTP 狀態碼 429;如果不在 3 秒內,就可以繼續后面的邏輯。

if (req.session.chatgptRequestTime && Date.now() - req.session.chatgptRequestTime <= 3000) {
// 不允許在3s里重復調用
return res.status(429).json({
msg: "請降低請求頻次"
});
}

關于請求次數也是同樣的道理,我這里也寫得很簡單,實際上還應該有跨天清理等邏輯要做。我這里偷懶了,暫時沒做這些。

if (req.session.chatgptTimes && req.session.chatgptTimes >= 50) {
// 實際上還需要跨天清理,這里先偷懶了。
return res.status(403).json({
msg: "到達調用上限,歡迎明天再來哦"
});
}

同一個話題也不能聊太多,否則傳給 Open AI 的 prompt 參數會很大,這就可能會耗費很多 Token,也有可能超過 Open AI 參數的限制。

if (req.session.chatgptTopicCount && req.session.chatgptTopicCount >= 10) {
// 一個話題聊的次數超過限制時,需要強行重置 chatgptSessionPrompt,換個話題。
req.session.chatgptSessionPrompt = ''
req.session.chatgptTopicCount = 0
return res.status(403).json({
msg: "這個話題聊得有點深入了,不如換一個"
});
}

切換話題

客戶端應該也有切換話題的能力,否則 session 中記錄的信息可能會包含多個話題的內容,可能導致與用戶的預期不符。那我們做個接口就好了。

router.post('/changeTopic', function(req, res, next) {
req.session.chatgptSessionPrompt = ''
req.session.chatgptTopicCount = 0
res.status(200).json({
code: '0',
msg: "可以嘗試新的話題"
});
});

結語

總的來說,Open AI 開放出來的智能對話能力可以滿足基本需求,但是還有很大改進空間。我在文中給出的代碼僅供參考,不保證功能上的完美。

附上源碼地址,可以點個 star 嗎,球球了[認真臉]。

參考

?[1]體驗鏈接: https://blog.wbjiang.cn/chatgpt

[2]ChatGPT: https://openai.com/

[3]注冊: https://beta.openai.com/login/

[4]SMS-ACTIVATE: https://sms-activate.org/cn

[5]Web工作臺: https://chat.openai.com/chat

[6]文檔: https://beta.openai.com/

[7]案例: https://beta.openai.com/examples

[8]openai: https://www.npmjs.com/package/openai

[9]生成一個 API Key: https://beta.openai.com/account/api-keys

[10]Key concepts: https://beta.openai.com/docs/introduction/key-concepts

[11]WebSocket 聊天功能: https://blog.wbjiang.cn/chat

[12]data-only server-sent events: https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format

[13]源碼地址: https://github.com/cumt-robin/vue3-ts-blog-frontend

責任編輯:武曉燕 來源: 前端司南
相關推薦

2018-09-13 13:54:41

2014-12-28 09:05:28

2023-03-15 15:56:09

新華三

2023-09-07 16:18:50

網絡方案

2017-10-09 15:10:07

2015-10-21 14:53:24

微信賺錢用戶

2021-03-25 12:32:14

樹莓派Linux代碼

2017-08-15 16:45:14

鍵盤薄膜鍵盤機械鍵盤

2017-08-23 09:35:14

Intel酷睿內核

2024-05-21 11:35:48

阿里云通義千問

2020-07-08 09:27:01

公司短信平臺

2016-04-25 15:38:27

老司機VR看片

2015-03-30 00:56:48

2021-04-19 11:30:20

激活碼Window 10微軟

2021-03-06 07:15:07

微軟Windows 10Windows

2023-02-27 10:45:16

2017-10-31 16:06:51

大數據90后消費

2011-01-13 14:38:00

JavascriptCSSWeb

2019-12-25 14:15:02

開發技能代碼

2022-12-16 15:11:39

AI模型
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美三级久久久 | 在线看片网站 | av黄色免费在线观看 | 一区二区三区视频在线观看 | 麻豆视频在线免费观看 | 亚洲精品久久久久久久久久久 | 午夜视频在线观看视频 | 九九综合九九 | 久久久www成人免费无遮挡大片 | 亚洲a一区二区 | va在线 | 国产精品视频二区三区 | 久久夜视频 | 精品一区二区三区不卡 | www久久爱| 成年人网站免费视频 | 久久99精品视频 | 欧美日韩一卡二卡 | 黄色片视频网站 | 一区二区三区久久 | 99re在线播放 | 国产精品一区二区三区在线 | 国产精品久久久爽爽爽麻豆色哟哟 | 精品久| 欧美成人精品激情在线观看 | 国产精品国产精品国产专区不卡 | 国产精品国产精品国产专区不片 | 中文字幕成人 | 国产午夜久久久 | 成人三级在线播放 | 国产91久久精品一区二区 | 91久久| 欧美日韩精品综合 | 久草.com | 91视在线国内在线播放酒店 | av香蕉 | 亚洲第1页 | 亚洲欧美在线观看视频 | 久久国产精品一区二区三区 | 亚洲国产免费 | 国产午夜精品一区二区三区嫩草 |