如何使用React和OpenAI API構建和部署ChatGPT克隆應用程式

如何使用React和OpenAI API構建和部署ChatGPT克隆應用程式

隨著聊天機器人和虛擬助手的使用不斷增加,許多企業和開發人員正在尋找建立自己的人工智慧驅動的聊天機器人的方法。ChatGPT就是這樣一個聊天機器人,它由OpenAI建立,能夠進行類似人類的對話,並回答各種問題。

你要建造什麼?

在本教程中,你將學習如何使用React和OpenAI API構建一個ChatGPT克隆應用程式。如果你想在週末嘗試做一個有趣的、有吸引力的專案,這是一個深入瞭解React和OpenAI的好機會。

你還將學習如何從你的GitHub倉庫直接部署到應用託管平臺。下面是ChatGPT克隆應用程式的Demo演示。

ChatGPT克隆應用

ChatGPT克隆應用

如果你想更仔細地檢查這個專案,你可以訪問其GitHub倉庫

另外,你也可以克隆React應用啟動專案,它帶有基本元素,如樣式、Font Awesome CDN連結、OpenAI包和基本結構,以幫助你開始工作。

要求/前提條件如下:

本教程被設計成一種 “跟隨” 的體驗。因此,建議你具備以下條件,以便輕鬆地進行編碼:

本文將從OpenAI API簡述,及為何選取React進行開發及具體的開發實踐、伺服器部署等多個方面,進行非常詳盡的ChatGPT克隆開發說明。

  1. 什麼是OpenAI API?
  2. 為什麼是React?
  3. 如何用React和OpenAI API建立ChatGPT克隆版
  4. 如何將React應用部署到伺服器上

什麼是OpenAI API?

OpenAI API是一個基於雲的平臺,授予開發者通過API訪問OpenAI的語言模型,如GPT-3。它允許開發者將自然語言處理功能,如文字補全、情感分析、總結和翻譯新增到他們的應用程式中,而無需開發和訓練他們的模型。

要使用OpenAI的API,開發者必須在OpenAI網站上建立一個賬戶並獲得一個API金鑰。API金鑰用於驗證API請求和跟蹤使用情況。

一旦獲得了API金鑰,開發者就可以使用API向語言模型提交文字並接收響應。

為什麼是React?

React是一個用於構建使用者介面的流行JavaScript庫。根據2022年Stack Overflow的開發者調查,它是第二大最常用的網路技術,擁有42.62%的市場份額。

React允許開發者建立代表使用者介面不同部分的宣告性元件。這些元件是用一種叫做JSX的語法定義的,它是JavaScript和HTML的結合。

由於其龐大的元件庫和工具包的生態系統,開發人員可以輕鬆地與OpenAI API等API合作和整合,以建立複雜的聊天介面,這也是它成為構建ChatGPT克隆應用程式的最佳選擇。

那麼,我們應如何設定你的React開發環境?具體如下:

安裝React或建立React專案的最好方法是用create-react-app來安裝它。一個先決條件是在你的機器上安裝Node.js。為了確認你已經安裝了Node,在終端執行以下命令。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
node -v
node -v
node -v

如果它帶出了一個版本,那麼它就存在。要使用npx,你需要確保你的Node版本不低於v14.0.0,你的NPM版本不低於v5.6;否則,你可能需要通過執行 npm update -g 來更新它。一旦你瞭解了npm,你現在可以通過執行下面的命令來建立一個React專案:

npx create-react-app chatgpt-clone

注意:”chatgpt-clone” 是我們正在建立的應用程式名稱,但你可以把它改成你選擇的任何名稱。

安裝過程可能需要幾分鐘的時間。一旦成功,你可以導航到該目錄並安裝Node.js OpenAI包,它提供了從Node.js訪問OpenAI API的便利,使用下面的命令:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
npm install openai
npm install openai
npm install openai

現在你可以執行 npm start,看到你的應用程式在localhost:3000上執行。

當使用 create-react-app 命令建立一個React專案時,它會自動構建一個資料夾結構。與你有關的主要資料夾是 src 資料夾,它是進行開發的地方。這個資料夾預設包含許多檔案,但你應該只關注App.jsindex.jsindex.css檔案。

  1. App.jsApp.js檔案是React應用程式的主要元件。它通常代表頂層元件,渲染應用程式中的所有其他元件。
  2. index.js:這個檔案是你的React應用程式的入口點。它是應用程式開啟時載入的第一個檔案,負責將App.js元件渲染到瀏覽器上。
  3. index.css:這個檔案負責定義你的React應用程式的整體風格和佈局。

如何用React和OpenAI API建立ChatGPT克隆版

ChatGPT克隆應用程式將由兩個元件組成,使應用程式更容易理解和維護。這兩個元件是:

  1. 表單部分:這個元件包括一個文字區域欄位和一個按鈕,供使用者與聊天機器人互動。
  2. 回答部分:問題和相應的答案將被儲存在一個陣列中,並顯示在這個部分。你將按時間順序迴圈瀏覽該陣列,先顯示最新的。

設定ChatGPT克隆應用程式

在本教程中,讓我們首先建立應用程式的介面,然後你可以實現功能,使你的應用程式與OpenAI API進行互動。首先建立你將在本教程中使用的兩個元件。為了適當的組織,你將在src資料夾中建立一個components資料夾,所有的元件都將存放在這裡。

表單部分元件

這是一個簡單的表單,由一個 textarea 和一個提交 button 組成。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// components/FormSection.jsx
const FormSection = () => {
return (
<div className="form-section">
<textarea
rows="5"
className="form-control"
placeholder="Ask me anything..."
></textarea>
<button className="btn">
Generate Response 🤖
</button>
</div>
)
}
export default FormSection;
// components/FormSection.jsx const FormSection = () => { return ( <div className="form-section"> <textarea rows="5" className="form-control" placeholder="Ask me anything..." ></textarea> <button className="btn"> Generate Response 🤖 </button> </div> ) } export default FormSection;
// components/FormSection.jsx
const FormSection = () => {
return (
<div className="form-section">
<textarea
rows="5"
className="form-control"
placeholder="Ask me anything..."
></textarea>
<button className="btn">
Generate Response 🤖
</button>
</div>
)
}
export default FormSection;

當你把它匯入你的App.js檔案時,這個表單應該是這個樣子的:

表單部分元件

表單部分元件

Info:本教程的重點在於構建和部署你的應用程式。所以你可以將src/index.css檔案中的樣式複製到你自己的專案中,以獲得相同的結果/應用。

回答部分元件

這個部分是顯示所有問題和答案的地方。當你把它匯入你的App.js檔案時,這個部分將是這樣的。

回答部分元件

回答部分元件

你將從一個陣列和迴圈中獲取這些問題和答案,使你的程式碼更容易閱讀和維護。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// components/AnswerSection.jsx
const AnswerSection = () => {
return (
<>
<hr className="hr-line" />
<div className="answer-container">
<div className="answer-section">
<p className="question">Who is the founder of OpenAi?</p>
<p className="answer">OpenAI was founded in December 2015 by Elon Musk, Sam Altman, Greg Brockman, Ilya Sutskever, Wojciech Zaremba, and John Schulman.</p>
<div className="copy-icon">
<i className="fa-solid fa-copy"></i>
</div>
</div>
</div>
</>
)
}
export default AnswerSection;
// components/AnswerSection.jsx const AnswerSection = () => { return ( <> <hr className="hr-line" /> <div className="answer-container"> <div className="answer-section"> <p className="question">Who is the founder of OpenAi?</p> <p className="answer">OpenAI was founded in December 2015 by Elon Musk, Sam Altman, Greg Brockman, Ilya Sutskever, Wojciech Zaremba, and John Schulman.</p> <div className="copy-icon"> <i className="fa-solid fa-copy"></i> </div> </div> </div> </> ) } export default AnswerSection;
// components/AnswerSection.jsx
const AnswerSection = () => {
return (
<>
<hr className="hr-line" />
<div className="answer-container">
<div className="answer-section">
<p className="question">Who is the founder of OpenAi?</p>
<p className="answer">OpenAI was founded in December 2015 by Elon Musk, Sam Altman, Greg Brockman, Ilya Sutskever, Wojciech Zaremba, and John Schulman.</p>
<div className="copy-icon">
<i className="fa-solid fa-copy"></i>
</div>
</div>
</div>
</>
)
}
export default AnswerSection;

主頁

現在你已經建立了這兩個元件,但當你執行你的應用程式時,什麼也不會出現,因為你需要將它們匯入你的App.js檔案。對於這個應用程式,你將不實現任何形式的路由,這意味著App.js檔案將作為你的應用程式的主頁元件/頁面。

你可以在匯入元件之前新增一些內容,比如你的應用程式的標題和描述。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// App.js
import FormSection from './components/FormSection';
import AnswerSection from './components/AnswerSection';
const App = () => {
return (
<div>
<div className="header-section">
<h1>ChatGPT CLONE 🤖</h1>
<p>
I am an automated question and answer system, designed to assist you
in finding relevant information. You are welcome to ask me any queries
you may have, and I will do my utmost to offer you a reliable
response. Kindly keep in mind that I am a machine and operate solely
based on programmed algorithms.
</p>
</div>
<FormSection />
<AnswerSection />
</div>
);
};
export default App;
// App.js import FormSection from './components/FormSection'; import AnswerSection from './components/AnswerSection'; const App = () => { return ( <div> <div className="header-section"> <h1>ChatGPT CLONE 🤖</h1> <p> I am an automated question and answer system, designed to assist you in finding relevant information. You are welcome to ask me any queries you may have, and I will do my utmost to offer you a reliable response. Kindly keep in mind that I am a machine and operate solely based on programmed algorithms. </p> </div> <FormSection /> <AnswerSection /> </div> ); }; export default App;
// App.js
import FormSection from './components/FormSection';
import AnswerSection from './components/AnswerSection';
const App = () => {
return (
<div>
<div className="header-section">
<h1>ChatGPT CLONE 🤖</h1>
<p>
I am an automated question and answer system, designed to assist you
in finding relevant information. You are welcome to ask me any queries
you may have, and I will do my utmost to offer you a reliable
response. Kindly keep in mind that I am a machine and operate solely
based on programmed algorithms.
</p>
</div>
<FormSection />
<AnswerSection />
</div>
);
};
export default App;

在上面的程式碼中,這兩個元件被匯入並新增到應用程式中。當你執行你的應用程式時,你的應用程式將是這個樣子:

完整的ChatGPT克隆應用

完整的ChatGPT克隆應用

新增功能和整合OpenAI API

你現在有了你的應用程式的使用者介面。下一步是使應用程式發揮作用,以便它能與OpenAI API互動並獲得響應。首先,你需要從你的表單中獲取提交時的值,因為它將被用來查詢OpenAI API。

從表單中獲取資料

在React中,儲存和更新資料的最佳方式是使用狀態。在功能元件中,useState() 鉤子是用來處理狀態的。你可以建立一個狀態,將表單中的值分配給該狀態,並在其值發生變化時更新它。讓我們先把 useState() 鉤子匯入FormSection.jsx元件,然後建立一個狀態來儲存和更新 newQuestions

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// components/FormSection.jsx
import { useState } from 'react';
const FormSection = ({ generateResponse }) => {
const [newQuestion, setNewQuestion] = useState('');
return (
// Form to submit a new question
)
}
export default FormSection;
// components/FormSection.jsx import { useState } from 'react'; const FormSection = ({ generateResponse }) => { const [newQuestion, setNewQuestion] = useState(''); return ( // Form to submit a new question ) } export default FormSection;
// components/FormSection.jsx
import { useState } from 'react';
const FormSection = ({ generateResponse }) => {
const [newQuestion, setNewQuestion] = useState('');
return (
// Form to submit a new question
)
}
export default FormSection;

接下來,你可以把 textarea 的值分配給狀態,並建立一個 onChange() 事件,在輸入值發生變化時更新狀態:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<textarea
rows="5"
className="form-control"
placeholder="Ask me anything..."
value={newQuestion}
onChange={(e) => setNewQuestion(e.target.value)}
></textarea>
<textarea rows="5" className="form-control" placeholder="Ask me anything..." value={newQuestion} onChange={(e) => setNewQuestion(e.target.value)} ></textarea>
<textarea
rows="5"
className="form-control"
placeholder="Ask me anything..."
value={newQuestion}
onChange={(e) => setNewQuestion(e.target.value)}
></textarea>

最後,你可以建立一個 onClick() 事件,在提交按鈕被點選時載入一個函式。這個方法將在App.js檔案中建立,並作為props傳入FormSection.jsx元件中,其引數為 newQuestion 和 setNewQuestion 值。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<button className="btn" onClick={() => generateResponse(newQuestion, setNewQuestion)}>
Generate Response 🤖
</button>
<button className="btn" onClick={() => generateResponse(newQuestion, setNewQuestion)}> Generate Response 🤖 </button>
<button className="btn" onClick={() => generateResponse(newQuestion, setNewQuestion)}>
Generate Response 🤖
</button>

你現在已經建立了一個狀態來儲存和更新表單的值,新增了一個方法,該方法作為道具從App.js檔案中傳遞,並處理了點選事件。這就是最終程式碼的模樣:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// components/FormSection.jsx
import { useState } from 'react';
const FormSection = ({ generateResponse }) => {
const [newQuestion, setNewQuestion] = useState('');
return (
<div className="form-section">
<textarea
rows="5"
className="form-control"
placeholder="Ask me anything..."
value={newQuestion}
onChange={(e) => setNewQuestion(e.target.value)}
></textarea>
<button className="btn" onClick={() => generateResponse(newQuestion, setNewQuestion)}>
Generate Response 🤖
</button>
</div>
)
}
export default FormSection;
// components/FormSection.jsx import { useState } from 'react'; const FormSection = ({ generateResponse }) => { const [newQuestion, setNewQuestion] = useState(''); return ( <div className="form-section"> <textarea rows="5" className="form-control" placeholder="Ask me anything..." value={newQuestion} onChange={(e) => setNewQuestion(e.target.value)} ></textarea> <button className="btn" onClick={() => generateResponse(newQuestion, setNewQuestion)}> Generate Response 🤖 </button> </div> ) } export default FormSection;
// components/FormSection.jsx
import { useState } from 'react';
const FormSection = ({ generateResponse }) => {
const [newQuestion, setNewQuestion] = useState('');
return (
<div className="form-section">
<textarea
rows="5"
className="form-control"
placeholder="Ask me anything..."
value={newQuestion}
onChange={(e) => setNewQuestion(e.target.value)}
></textarea>
<button className="btn" onClick={() => generateResponse(newQuestion, setNewQuestion)}>
Generate Response 🤖
</button>
</div>
)
}
export default FormSection;

下一步將是在App.js檔案中建立一個方法來處理與OpenAI API互動的整個過程。

與OpenAI API互動

要與OpenAI API互動並在React應用程式中獲得API金鑰,你必須建立一個OpenAI API賬戶。你可以使用你的谷歌賬戶或電子郵件在OpenAI網站上註冊一個賬戶。要生成API金鑰,點選網站右上角的Personal;會出現一些選項;點選View API keys

訪問OpenAI的API金鑰

訪問OpenAI的API金鑰

點選Create new secret key按鈕,將密匙複製到某個地方,因為你會在這個應用程式中使用它來與OpenAI進行互動。現在你可以通過匯入openai包(你已經安裝了)和配置方法來初始化OpenAI。然後用你生成的金鑰建立一個配置,用它來初始化OpenAI。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// src/App.js
import { Configuration, OpenAIApi } from 'openai';
import FormSection from './components/FormSection';
import AnswerSection from './components/AnswerSection';
const App = () => {
const configuration = new Configuration({
apiKey: process.env.REACT_APP_OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);
return (
// Render FormSection and AnswerSection
);
};
export default App;
// src/App.js import { Configuration, OpenAIApi } from 'openai'; import FormSection from './components/FormSection'; import AnswerSection from './components/AnswerSection'; const App = () => { const configuration = new Configuration({ apiKey: process.env.REACT_APP_OPENAI_API_KEY, }); const openai = new OpenAIApi(configuration); return ( // Render FormSection and AnswerSection ); }; export default App;
// src/App.js
import { Configuration, OpenAIApi } from 'openai';
import FormSection from './components/FormSection';
import AnswerSection from './components/AnswerSection';
const App = () => {
const configuration = new Configuration({
apiKey: process.env.REACT_APP_OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);
return (
// Render FormSection and AnswerSection
);
};
export default App;

在上面的程式碼中,OpenAI的API金鑰被儲存為.env檔案中的一個環境變數。你可以在你的應用程式的根目錄下建立一個.env檔案,並將金鑰儲存到變數 REACT_APP_OPENAI_API_KEY

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// .env
REACT_APP_OPENAI_API_KEY = sk-xxxxxxxxxx…
// .env REACT_APP_OPENAI_API_KEY = sk-xxxxxxxxxx…
// .env
REACT_APP_OPENAI_API_KEY = sk-xxxxxxxxxx…

現在你可以繼續在App.js檔案中建立 generateResponse 方法,並傳入你已經建立的表單中預期的兩個引數,以處理請求並從API獲得響應。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// src/App.js
import FormSection from './components/FormSection';
import AnswerSection from './components/AnswerSection';
const App = () => {
const generateResponse = (newQuestion, setNewQuestion) => {
// Set up OpenAI API and handle response
};
return (
// Render FormSection and AnswerSection
);
};
export default App;
// src/App.js import FormSection from './components/FormSection'; import AnswerSection from './components/AnswerSection'; const App = () => { const generateResponse = (newQuestion, setNewQuestion) => { // Set up OpenAI API and handle response }; return ( // Render FormSection and AnswerSection ); }; export default App;
// src/App.js
import FormSection from './components/FormSection';
import AnswerSection from './components/AnswerSection';
const App = () => {
const generateResponse = (newQuestion, setNewQuestion) => {
// Set up OpenAI API and handle response
};
return (
// Render FormSection and AnswerSection
);
};
export default App;

你現在可以向OpenAI API傳送請求。OpenAI API可以執行許多操作,如問答(Q&A)、語法糾正、翻譯等等。對於這些操作中的每一項,其選項都是不同的。例如,問答的引擎值是 text-davinci-00,而SQL翻譯的引擎值是 code-davinci-002。請隨時檢視OpenAI的例子文件,瞭解各種例子和它們的選項。

在本教程中,我們只使用Q&A,這是選項的樣子:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
{
model: "text-davinci-003",
prompt: "Who is Obama?",
temperature: 0,
max_tokens: 100,
top_p: 1,
frequency_penalty: 0.0,
presence_penalty: 0.0,
stop: ["\"],
}
{ model: "text-davinci-003", prompt: "Who is Obama?", temperature: 0, max_tokens: 100, top_p: 1, frequency_penalty: 0.0, presence_penalty: 0.0, stop: ["\"], }
{
model: "text-davinci-003",
prompt: "Who is Obama?",
temperature: 0,
max_tokens: 100,
top_p: 1,
frequency_penalty: 0.0,
presence_penalty: 0.0,
stop: ["\"],
}

Note: 上面程式碼改變了prompt值。

Prompt是由表單傳送的問題。這意味著你需要從你作為引數傳入 generateResponse 方法的表單輸入中接收它。要做到這一點,你將定義選項,然後使用傳播操作符來建立一個完整的選項,其中包括prompt:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// src/App.js
import { Configuration, OpenAIApi } from 'openai';
import FormSection from './components/FormSection';
import AnswerSection from './components/AnswerSection';
const App = () => {
const configuration = new Configuration({
apiKey: process.env.REACT_APP_OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);
const generateResponse = async (newQuestion, setNewQuestion) => {
let options = {
model: 'text-davinci-003',
temperature: 0,
max_tokens: 100,
top_p: 1,
frequency_penalty: 0.0,
presence_penalty: 0.0,
stop: ['/'],
};
let completeOptions = {
...options,
prompt: newQuestion,
};
};
return (
// Render FormSection and AnswerSection
);
};
export default App;
// src/App.js import { Configuration, OpenAIApi } from 'openai'; import FormSection from './components/FormSection'; import AnswerSection from './components/AnswerSection'; const App = () => { const configuration = new Configuration({ apiKey: process.env.REACT_APP_OPENAI_API_KEY, }); const openai = new OpenAIApi(configuration); const generateResponse = async (newQuestion, setNewQuestion) => { let options = { model: 'text-davinci-003', temperature: 0, max_tokens: 100, top_p: 1, frequency_penalty: 0.0, presence_penalty: 0.0, stop: ['/'], }; let completeOptions = { ...options, prompt: newQuestion, }; }; return ( // Render FormSection and AnswerSection ); }; export default App;
// src/App.js
import { Configuration, OpenAIApi } from 'openai';
import FormSection from './components/FormSection';
import AnswerSection from './components/AnswerSection';
const App = () => {
const configuration = new Configuration({
apiKey: process.env.REACT_APP_OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);
const generateResponse = async (newQuestion, setNewQuestion) => {
let options = {
model: 'text-davinci-003',
temperature: 0,
max_tokens: 100,
top_p: 1,
frequency_penalty: 0.0,
presence_penalty: 0.0,
stop: ['/'],
};
let completeOptions = {
...options,
prompt: newQuestion,
};
};
return (
// Render FormSection and AnswerSection
);
};
export default App;

在這一點上,剩下的就是通過 createCompletion 方法向OpenAI傳送一個請求,以獲得響應。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// src/App.js
import { Configuration, OpenAIApi } from 'openai';
import FormSection from './components/FormSection';
import AnswerSection from './components/AnswerSection';
import { useState } from 'react';
const App = () => {
const configuration = new Configuration({
apiKey: process.env.REACT_APP_OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);
const [storedValues, setStoredValues] = useState([]);
const generateResponse = async (newQuestion, setNewQuestion) => {
let options = {
model: 'text-davinci-003',
temperature: 0,
max_tokens: 100,
top_p: 1,
frequency_penalty: 0.0,
presence_penalty: 0.0,
stop: ['/'],
};
let completeOptions = {
...options,
prompt: newQuestion,
};
const response = await openai.createCompletion(completeOptions);
console.log(response.data.choices[0].text);
};
return (
// Render FormSection and AnswerSection
);
};
export default App;
// src/App.js import { Configuration, OpenAIApi } from 'openai'; import FormSection from './components/FormSection'; import AnswerSection from './components/AnswerSection'; import { useState } from 'react'; const App = () => { const configuration = new Configuration({ apiKey: process.env.REACT_APP_OPENAI_API_KEY, }); const openai = new OpenAIApi(configuration); const [storedValues, setStoredValues] = useState([]); const generateResponse = async (newQuestion, setNewQuestion) => { let options = { model: 'text-davinci-003', temperature: 0, max_tokens: 100, top_p: 1, frequency_penalty: 0.0, presence_penalty: 0.0, stop: ['/'], }; let completeOptions = { ...options, prompt: newQuestion, }; const response = await openai.createCompletion(completeOptions); console.log(response.data.choices[0].text); }; return ( // Render FormSection and AnswerSection ); }; export default App;
// src/App.js
import { Configuration, OpenAIApi } from 'openai';
import FormSection from './components/FormSection';
import AnswerSection from './components/AnswerSection';
import { useState } from 'react';
const App = () => {
const configuration = new Configuration({
apiKey: process.env.REACT_APP_OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);
const [storedValues, setStoredValues] = useState([]);
const generateResponse = async (newQuestion, setNewQuestion) => {
let options = {
model: 'text-davinci-003',
temperature: 0,
max_tokens: 100,
top_p: 1,
frequency_penalty: 0.0,
presence_penalty: 0.0,
stop: ['/'],
};
let completeOptions = {
...options,
prompt: newQuestion,
};
const response = await openai.createCompletion(completeOptions);
console.log(response.data.choices[0].text);
};
return (
// Render FormSection and AnswerSection
);
};
export default App;

在上面的程式碼中,答案的文字將顯示在你的控制檯。請自由地通過提出任何問題來測試你的應用程式。最後一步是建立一個儲存問題和答案陣列的狀態,然後將這個陣列作為一個道具傳送到AnswerSection元件。這就是App.js的最終程式碼的樣子:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// src/App.js
import { Configuration, OpenAIApi } from 'openai';
import FormSection from './components/FormSection';
import AnswerSection from './components/AnswerSection';
import { useState } from 'react';
const App = () => {
const configuration = new Configuration({
apiKey: process.env.REACT_APP_OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);
const [storedValues, setStoredValues] = useState([]);
const generateResponse = async (newQuestion, setNewQuestion) => {
let options = {
model: 'text-davinci-003',
temperature: 0,
max_tokens: 100,
top_p: 1,
frequency_penalty: 0.0,
presence_penalty: 0.0,
stop: ['/'],
};
let completeOptions = {
...options,
prompt: newQuestion,
};
const response = await openai.createCompletion(completeOptions);
if (response.data.choices) {
setStoredValues([
{
question: newQuestion,
answer: response.data.choices[0].text,
},
...storedValues,
]);
setNewQuestion('');
}
};
return (
<div>
<div className="header-section">
<h1>ChatGPT CLONE 🤖</h1>
<p>
I am an automated question and answer system, designed to assist you
in finding relevant information. You are welcome to ask me any
queries you may have, and I will do my utmost to offer you a
reliable response. Kindly keep in mind that I am a machine and
operate solely based on programmed algorithms.
</p>
</div>
<FormSection generateResponse={generateResponse} />
<AnswerSection storedValues={storedValues} />
</div>
);
};
export default App;
// src/App.js import { Configuration, OpenAIApi } from 'openai'; import FormSection from './components/FormSection'; import AnswerSection from './components/AnswerSection'; import { useState } from 'react'; const App = () => { const configuration = new Configuration({ apiKey: process.env.REACT_APP_OPENAI_API_KEY, }); const openai = new OpenAIApi(configuration); const [storedValues, setStoredValues] = useState([]); const generateResponse = async (newQuestion, setNewQuestion) => { let options = { model: 'text-davinci-003', temperature: 0, max_tokens: 100, top_p: 1, frequency_penalty: 0.0, presence_penalty: 0.0, stop: ['/'], }; let completeOptions = { ...options, prompt: newQuestion, }; const response = await openai.createCompletion(completeOptions); if (response.data.choices) { setStoredValues([ { question: newQuestion, answer: response.data.choices[0].text, }, ...storedValues, ]); setNewQuestion(''); } }; return ( <div> <div className="header-section"> <h1>ChatGPT CLONE 🤖</h1> <p> I am an automated question and answer system, designed to assist you in finding relevant information. You are welcome to ask me any queries you may have, and I will do my utmost to offer you a reliable response. Kindly keep in mind that I am a machine and operate solely based on programmed algorithms. </p> </div> <FormSection generateResponse={generateResponse} /> <AnswerSection storedValues={storedValues} /> </div> ); }; export default App;
// src/App.js
import { Configuration, OpenAIApi } from 'openai';
import FormSection from './components/FormSection';
import AnswerSection from './components/AnswerSection';
import { useState } from 'react';
const App = () => {
const configuration = new Configuration({
apiKey: process.env.REACT_APP_OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);
const [storedValues, setStoredValues] = useState([]);
const generateResponse = async (newQuestion, setNewQuestion) => {
let options = {
model: 'text-davinci-003',
temperature: 0,
max_tokens: 100,
top_p: 1,
frequency_penalty: 0.0,
presence_penalty: 0.0,
stop: ['/'],
};
let completeOptions = {
...options,
prompt: newQuestion,
};
const response = await openai.createCompletion(completeOptions);
if (response.data.choices) {
setStoredValues([
{
question: newQuestion,
answer: response.data.choices[0].text,
},
...storedValues,
]);
setNewQuestion('');
}
};
return (
<div>
<div className="header-section">
<h1>ChatGPT CLONE 🤖</h1>
<p>
I am an automated question and answer system, designed to assist you
in finding relevant information. You are welcome to ask me any
queries you may have, and I will do my utmost to offer you a
reliable response. Kindly keep in mind that I am a machine and
operate solely based on programmed algorithms.
</p>
</div>
<FormSection generateResponse={generateResponse} />
<AnswerSection storedValues={storedValues} />
</div>
);
};
export default App;

現在你可以編輯AnswerSection元件,讓它從App.js接收props值,並使用JavaScript  Map() 方法檢視 storedValues 陣列:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// components/AnswerSection.jsx
const AnswerSection = ({ storedValues }) => {
return (
<>
<hr className="hr-line" />
<div className="answer-container">
{storedValues.map((value, index) => {
return (
<div className="answer-section" key={index}>
<p className="question">{value.question}</p>
<p className="answer">{value.answer}</p>
<div className="copy-icon">
<i className="fa-solid fa-copy"></i>
</div>
</div>
);
})}
</div>
</>
)
}
export default AnswerSection;
// components/AnswerSection.jsx const AnswerSection = ({ storedValues }) => { return ( <> <hr className="hr-line" /> <div className="answer-container"> {storedValues.map((value, index) => { return ( <div className="answer-section" key={index}> <p className="question">{value.question}</p> <p className="answer">{value.answer}</p> <div className="copy-icon"> <i className="fa-solid fa-copy"></i> </div> </div> ); })} </div> </> ) } export default AnswerSection;
// components/AnswerSection.jsx
const AnswerSection = ({ storedValues }) => {
return (
<>
<hr className="hr-line" />
<div className="answer-container">
{storedValues.map((value, index) => {
return (
<div className="answer-section" key={index}>
<p className="question">{value.question}</p>
<p className="answer">{value.answer}</p>
<div className="copy-icon">
<i className="fa-solid fa-copy"></i>
</div>
</div>
);
})}
</div>
</>
)
}
export default AnswerSection;

當你執行你的應用程式並通過提問來測試它時,答案會顯示在下面。但是你會注意到複製按鈕沒有工作。你需要給按鈕新增一個 onClick() 事件,這樣它就會觸發一個方法來處理這個功能。你可以使用 navigator.clipboard.writeText() 方法來處理這個功能。這就是AnswerSection元件現在的樣子:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// components/AnswerSection.jsx
const AnswerSection = ({ storedValues }) => {
const copyText = (text) => {
navigator.clipboard.writeText(text);
};
return (
<>
<hr className="hr-line" />
<div className="answer-container">
{storedValues.map((value, index) => {
return (
<div className="answer-section" key={index}>
<p className="question">{value.question}</p>
<p className="answer">{value.answer}</p>
<div
className="copy-icon"
onClick={() => copyText(value.answer)}
>
<i className="fa-solid fa-copy"></i>
</div>
</div>
);
})}
</div>
</>
)
}
export default AnswerSection;
// components/AnswerSection.jsx const AnswerSection = ({ storedValues }) => { const copyText = (text) => { navigator.clipboard.writeText(text); }; return ( <> <hr className="hr-line" /> <div className="answer-container"> {storedValues.map((value, index) => { return ( <div className="answer-section" key={index}> <p className="question">{value.question}</p> <p className="answer">{value.answer}</p> <div className="copy-icon" onClick={() => copyText(value.answer)} > <i className="fa-solid fa-copy"></i> </div> </div> ); })} </div> </> ) } export default AnswerSection;
// components/AnswerSection.jsx
const AnswerSection = ({ storedValues }) => {
const copyText = (text) => {
navigator.clipboard.writeText(text);
};
return (
<>
<hr className="hr-line" />
<div className="answer-container">
{storedValues.map((value, index) => {
return (
<div className="answer-section" key={index}>
<p className="question">{value.question}</p>
<p className="answer">{value.answer}</p>
<div
className="copy-icon"
onClick={() => copyText(value.answer)}
>
<i className="fa-solid fa-copy"></i>
</div>
</div>
);
})}
</div>
</>
)
}
export default AnswerSection;

當你執行你的應用程式時,你的ChatGPT克隆應用程式將完美執行。你現在可以部署你的應用程式,線上訪問它,並與朋友分享。

如何將你的React應用程式部署到伺服器上

僅僅建立這個應用程式並把它留在你的本地計算機上是不夠的。你要在網上分享它,這樣別人就可以訪問它。讓我們看看如何使用GitHub和Kinsta來做這件事。

推送你的程式碼到GitHub

要推送程式碼到GitHub,可以使用Git命令,這是一種可靠而有效的方式來管理程式碼變更,進行專案協作,並維護版本歷史。

推送程式碼的第一步是建立一個新的倉庫,登入你的GitHub賬戶,點選螢幕右上角的+按鈕,從下拉選單中選擇New repository

在GitHub上建立一個新的倉庫

在GitHub上建立一個新的倉庫

給你的資源庫起個名字,新增描述(可選),並選擇你希望它是公開的還是私有的。點選Create repository來建立它。

一旦你的倉庫被建立,確保你從倉庫的主頁上獲得倉庫的 URL,你將需要它來推送你的程式碼到 GitHub。

訪問你的倉庫的URL

訪問你的倉庫的URL

開啟你的終端或命令提示符,導航到包含你的專案的目錄。逐一執行下面的命令,將你的程式碼推送到GitHub倉庫:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
git init
git add .
git commit -m "my first commit"
git remote add origin [repository URL]
git push -u origin master
git init git add . git commit -m "my first commit" git remote add origin [repository URL] git push -u origin master
git init
git add .
git commit -m "my first commit"
git remote add origin [repository URL]
git push -u origin master

git init 初始化本地的 Git 倉庫,git add . 將當前目錄及其子目錄下的所有檔案新增到新的 Git 倉庫。git commit -m "my first commit" 將修改提交到倉庫,並附上簡短的資訊。git remote add origin [repository URL] 將倉庫的 URL 設定為遠端倉庫, git push -u origin master 將程式碼推送到遠端倉庫(origin)的主分支。

提示:你可以把 “my first commit” 換成你自己的簡簡訊息,描述你所做的修改,把”[repository URL]”換成你的 GitHub 倉庫的 URL。一旦你的程式碼被推送到GitHub,你就可以把你的倉庫部署到伺服器了。

將你的ChatGPT克隆應用部署到伺服器上

要將你的版本庫部署到伺服器(以Kinsta為例),請遵循以下步驟:

  1. 在 “My Kinsta” 儀表板上登入或建立您的Kinsta賬戶。
  2. 點選左側邊欄的Applications,然後點選Add service
  3. 從下拉選單中選擇Application,將React應用部署到Kinsta。
  4. 在出現的模式中選擇你想部署的倉庫。如果你有多個分支,你可以選擇一個你想部署的分支,併為應用程式指定一個名稱。在25個可用的data center location中選擇一個,Kinsta會自動檢測一個啟動命令。
  5. 最後,向GitHub這樣的公共主機推送API金鑰並不安全,它是作為environment variable新增到本地的。在託管時,你也可以使用相同的變數名和金鑰作為其值將其新增為環境變數。

將ChatGPT克隆部署到伺服器

將ChatGPT克隆部署到伺服器

你的應用程式將開始部署,在幾分鐘內,將提供一個連結來訪問你的應用程式的部署版本。在這種情況下,這是https://chatgpt-clone-g9q10.kinsta.app/

Note:你可以啟用自動部署,這樣Kinsta會在你改變程式碼庫並推送到GitHub時重新部署你的應用程式。

小結

OpenAI API可用於構建廣泛的潛在應用,從客戶支援和個人助理到語言翻譯和內容建立。

在本教程中,你已經學會了如何用React和OpenAI構建一個ChatGPT克隆應用。你可以將這個應用/功能整合到其他應用中,為使用者提供類似人類的對話體驗。

用OpenAI API可以做的事情還有很多,以及如何改進這個克隆應用。例如,你可以實現本地儲存,這樣即使你重新整理瀏覽器,以前的問題和答案也不會消失。

有了Kinsta的免費試用和興趣層,你可以很容易地開始使用我們的應用託管,而不需要任何費用。那麼為什麼不試一試,看看你能創造什麼呢?

在下面的評論中分享你的專案和經驗。

評論留言