作者 | Michael Haephrati、Ruth Haephrati 譯者 | 劉雅夢 策劃 | Tina
雖然通過 Web 界面使用 ChatGPT 是一回事,但創(chuàng)建自己的自主 AI 工具,并通過其 API 與 ChatGPT 交互,則完全是另一回事,特別是當(dāng)你的目標(biāo)是保持對用戶交互的完全控制時。與此同時,作為一名堅定 C++ 的支持者,我們相信用 C++ 編寫的 GPT 工具能減輕處理(無休止的)編輯批注這一艱巨任務(wù)所帶來的痛苦。
總體思路
我們旨在探索 MS Office 的自動化領(lǐng)域,并利用 ChatGPT API 增強(qiáng)編輯過程。我們設(shè)想了一個復(fù)雜的工具,可以將 C++ 與 ChatGPT API 無縫地集成,從而提供一種與 Word 文檔中的編輯批注進(jìn)行交互的新方法。
傳統(tǒng)的文檔編輯包括手動審閱內(nèi)容和向特定部分添加批注。就我們而言,當(dāng)我們編寫 C++ 書籍時,我們每次都會遇到 100 多條編輯批注,其中大部分與出版商的風(fēng)格指南和注釋有關(guān)。如果能有一種方法將這些批注和相關(guān)文本存儲在數(shù)據(jù)庫中,那就太好了,更不用說基于人工智能的編輯潛力了。這正是我們的軟件所要實現(xiàn)的目標(biāo):通過自動化這一過程,我們可以加快編輯工作流程。雖然這個工具可以作為概念驗證(POC),不建議用于編寫和編輯整本書,但它仍然是一個令人興奮的自動化練習(xí),當(dāng)然值得一試。
它是如何做到的
工作流程從我們的軟件掃描 Word 文件開始,使用 Office Automation API 仔細(xì)檢查文檔中嵌入的每一條編輯批注。
枚舉完所有批注后,我們的工具就會提取它們以及與之相關(guān)的文本段,并將它們存儲在 sqlite3 數(shù)據(jù)庫中。在此基礎(chǔ)上,它將圍繞如何改進(jìn)或修復(fù)文本的特定部分來為 ChatGPT 準(zhǔn)備有針對性的問題。通過利用 ChatGPT API,我們可以利用語言模型的豐富知識和語言能力來獲取專家的意見和建議。
在收到 ChatGPT 的回復(fù)之后,我們的工具會動態(tài)地將建議的編輯內(nèi)容合并到相關(guān)的文本片段中,從而根據(jù)模型的見解無縫地增強(qiáng)內(nèi)容。
這種自動化的編輯過程大大減少了手工工作量,并加快了文檔的整體細(xì)化完善。我們的工具甚至可以跟蹤更改,但要記得在完成后關(guān)閉“跟蹤更改”。
在編程方面,我們的項目中有幾個構(gòu)建塊,其中一些可以擴(kuò)展或替換以滿足不同的目的。我們將我們的代碼稱為概念驗證( Proof of Concept, POC)。
構(gòu)建塊
以下是這一過程的參與者——我們的構(gòu)建塊:
Chat GPT API
我們的工具通過使用各種參數(shù)和方法來與 ChatGPT 進(jìn)行接口調(diào)用和交互。我們準(zhǔn)備要發(fā)送給 API 的有效負(fù)載并解析響應(yīng)。要使用我們的工具,必須要獲取一個 API 密鑰并將其添加到我們的代碼中,注意不是“”。下面的代碼片段演示了與 ChatGPT 交互的基礎(chǔ)知識。
使用 API 的優(yōu)勢包括:能夠與 Chat GPT 進(jìn)行接口調(diào)用和交互,并使用不同的參數(shù)和方法,準(zhǔn)備要發(fā)送到 API 的有效負(fù)載,以及解析返回給我們的響應(yīng)。
使用 ChatGPT API 時,需要考慮以下幾點。
我們的通用函數(shù)
為了本文的目的,我們創(chuàng)建了一個通用函數(shù)。該函數(shù)是模塊化的,因為它能生成具有模塊化屬性和參數(shù)的請求,格式如下:
data = { {"messages", json::array({{ {"role", "user"}, {"content", entire_converstaion_string} }})}, {"model", model}, {"temperature", temperature}, {"max_tokens", max_tokens}, {"n", n}, {"stop", stop} };
讓我們來看看這些屬性,并討論下它們存在的問題及需求:
“messages”——定義用戶和模型之間的對話歷史。對話中的每條消息都由兩個屬性組成:“role”(可以是“system”、“user”或“assistant”)和“content”(消息的實際文本內(nèi)容)。為了本文的目的,我們使用了“user”
“model”——允許指定想要使用的 ChatGPT 模型版本。在本文中,我們使用了“gpt-3.5-turbo”
“temperature”——可以設(shè)置它來控制生成的文本和 prompt 之間的相似程度。例如,高溫值可用于生成與 prompt 更不同的文本,而低溫值可用于生成與 prompt 更相似的文本。在目標(biāo)為生成與給定輸入相似但具有一定程度的變化或“創(chuàng)造性”文本的情況下,這可能很有用。
“max_tokens”——是每個請求使用的最大 token 數(shù)。處理的 token 數(shù)量取決于輸入和輸出文本的長度。
1-2 句~= 30 個 token
1 段~=100 個 token
1,500 個單詞~=2048 個 token
作為 ChatGPT API 的用戶,我們需要為我們消耗的 token 付費(fèi)。
“n”——控制模型應(yīng)提供的響應(yīng)數(shù)量;默認(rèn)情況下,它被設(shè)置為 1,即單個響應(yīng)
“stop”——表示應(yīng)觸發(fā)模型停止生成其響應(yīng)的字符串。默認(rèn)情況下設(shè)置為換行符。這意味著,當(dāng)模型在其輸出中遇到新行時,它將在那之后停止生成。
我們的 Prompt
我們總是喜歡說,結(jié)構(gòu)良好的 prompt 的重要性是怎么強(qiáng)調(diào)也不為過的。精心構(gòu)建的 prompt 可以作為指導(dǎo)藍(lán)圖,影響生成的輸出質(zhì)量。在本文中,我們將深入研究有效 prompt 的組成部分,并提供實際的示例和指導(dǎo),幫助 C++ 學(xué)生在項目中最大限度地發(fā)揮 ChatGPT API 的潛力。
下面是一個例子:
// 為GPT請求設(shè)置prompt wstring prompt{ L"I will send you some text, and an associated comment that tells what changes need to be made in the text. Please start your response with 'Changed text: ' followed by the actual updated text. Here is the original text: '" }; prompt += rangeText; prompt += L"'. And here is the associated comment suggesting the change: '"; prompt += commentText; prompt += L"'. Please do not respond with anything else, only include the changed text and nothing else. If you do not have the correct answer or don't know what to say, respond with these exact words: 'I do not understand"; //
在編寫 prompt 時,最好創(chuàng)建一個模板,其中包含將在整個程序中使用的請求的常量部分,然后根據(jù)當(dāng)前需要更改可變部分。以下是一個良好的 prompt 的一些關(guān)鍵組成部分:
上下文:
上下文作為 prompt 的基礎(chǔ),能提供關(guān)鍵的背景信息。它使語言模型能夠掌握任務(wù)的本質(zhì)。無論是簡明扼要的問題描述還是相關(guān)細(xì)節(jié)的總結(jié),對提供上下文都至關(guān)重要。
示例:
“你是一名軟件開發(fā)人員,正在為外賣服務(wù)開發(fā)移動應(yīng)用程序。該應(yīng)用程序旨在為用戶提供從當(dāng)?shù)夭宛^訂餐的無縫體驗。作為開發(fā)過程的一部分,你需要幫助生成有關(guān)該應(yīng)用程序的功能是如何吸引人的信息豐富內(nèi)容?!?/p>
任務(wù):
任務(wù)定義了 prompt 的精確目標(biāo)或目的。它應(yīng)該清晰、簡潔,并重點關(guān)注于 ChatGPT 模型預(yù)期的具體信息或操作。
示例:“寫一個簡短的段落,突出應(yīng)用程序的主要功能,并展示它們是如何增強(qiáng)客戶的送餐體驗的?!?/p>
約束條件:
約束為 prompt 設(shè)置了邊界或限制。它們可能包括特定的要求、對響應(yīng)長度或復(fù)雜性的限制或任何其他相關(guān)約束。通過定義約束,可以引導(dǎo)生成的輸出滿足所需的結(jié)果。
示例:
“回答應(yīng)該簡明扼要,字?jǐn)?shù)不超過 150 字。重點關(guān)注應(yīng)用程序區(qū)別于競爭對手的最突出功能,并使其對用戶友好。”
補(bǔ)充說明:
在本節(jié)中,你將有機(jī)會提供補(bǔ)充上下文或指定所需的輸出格式。這可以包括有關(guān)預(yù)期輸入格式或請求以特定格式(如 Markdown 或 JSON)輸出的詳細(xì)信息。
示例:“請將響應(yīng)格式化為 JSON 對象,其中包含每個特性描述的鍵值對。每個鍵都應(yīng)代表一個特性,其對應(yīng)的值應(yīng)提供一個簡短的描述,突出其優(yōu)點。”
通過理解和實現(xiàn)這些基本組件,C++ 開發(fā)人員可以掌握構(gòu)建有效 prompt 的藝術(shù),以便在項目中最優(yōu)地利用 ChatGPT API。深思熟慮地結(jié)合上下文,定義明確的任務(wù),設(shè)置約束并提供額外的說明將使開發(fā)人員能夠獲得精確且高質(zhì)量的結(jié)果。
連續(xù)的聊天
在大多數(shù)情況下,我們希望能從你上次結(jié)束的地方繼續(xù)對話。Chat GPT API 使用了一個特殊的標(biāo)志來實現(xiàn)這一點。如果未設(shè)置,將會發(fā)生如下的情況:
? 法國的首都是哪里?
Request payload: '{"messages":[{"content":"what is the capital of france?","role":"user"}],"model":"gpt-3.5-turbo"}' Callback JSON: '{"id":"chatcmpl-7AlP3bJX2T7ibomyderKHwT7fQkcN","object":"chat.completion","created":1682799853,"model":"gpt-3.5-turbo-0301","usage":{"prompt_tokens":15,"completion_tokens":7,"total_tokens":22},"choices":[{"message":{"role":"assistant","content":"The capital of France is Paris."},"finish_reason":"stop","index":0}]}
你人工智能朋友的回答是:
? 法國的首都是巴黎。
接下來的一個問題是:
? 它有多大?
Request payload: '{"messages":[{"content":"How big is it?","role":"user"}],"model":"gpt-3.5-turbo"}' Callback JSON: '{"id":"chatcmpl-7AlPAabscfyDrAV2wTjep0ziiseEB","object":"chat.completion","created":1682799860,"model":"gpt-3.5-turbo-0301","usage":{"prompt_tokens":13,"completion_tokens":20,"total_tokens":33},"choices":[{"message":{"role":"assistant","content":"I apologize, but I need more context to accurately answer your question. What are you referring to?"},"finish_reason":"stop","index":0}]}
? 我很抱歉,但是我需要更多的上下文來準(zhǔn)確回答你的問題。你指的是什么?
要解決這一問題,我們需要保持連續(xù)的聊天,但我們該如何做到這一點呢?事實上,要做到這一點的唯一方法是必須來回傳遞一個包含整個對話的字符串。
string entire_converstaion_string;
我們還定義了:
using Conversation = vector;
它的定義是:
using SingleExchange = pair;
在我們的源代碼中,你可以看到我們是如何將 Conversation 對象維護(hù)成固定長度的(很明顯,我們無法存儲無休止的對話)。這個固定長度是在這里設(shè)置的:
int conversation_exchange_limit{ 100 };
如前所述,我們的 prompt 在請求的效率中起著關(guān)鍵作用,當(dāng)涉及到連續(xù)聊天時,我們可能需要使用不同的 prompt:
string prompt_start{ "You are a chatbot. I want to have a conversation with you where you can remember the context between multiple requests. To do that, I will send all previous request prompts and your corresponding responses, please use those as context. All the previous request prompts and the current will have the 'request: ' before it, and all your corresponding responses will have 'response: ' before it. Your job is to respond to only the latest request. Do not add anything by yourself, just respond to the latest request. Starting now " };多部分響應(yīng)
當(dāng)你問你的人工智能朋友:
? 給我寫一段 C++ 代碼,實現(xiàn)從 1 到 10 的計數(shù)。
你可能會得到這樣的結(jié)果:
? 當(dāng)然可以,下面是從 1 到 10 計數(shù)的 C++ 代碼:
沒有任何源代碼。
原因如下:發(fā)送給 API 的 stop 參數(shù)讓模型知道它應(yīng)該在輸出的哪個點上停止生成更多內(nèi)容。當(dāng)沒有指定任何內(nèi)容時,換行符就是默認(rèn)值,這意味著模型在輸出第一個換行符后就停止生成更多的輸出。
但是,如果你將“stop”參數(shù)設(shè)置為空字符串,你將得到完整的響應(yīng),其中將包含源代碼:
關(guān)于 OLE 自動化
OLE 自動化是微軟在過去引入的一項技術(shù),此后不斷發(fā)展。在我們的實現(xiàn)中,我們直接使用了 Microsoft 自動化,繞過了 MFC(Microsoft Foundation Classes,微軟基礎(chǔ)類庫)的使用。為了訪問 MS Word 的各種元素,如文檔、活動文檔、批注等,我們?yōu)樾枰换サ拿總€對象定義了 IDispatch COM 接口。
Office 自動化
我們的工具自動化了 MS Word 中的各種任務(wù)和特性。它可以讀取批注、查找相關(guān)文本、打開 / 關(guān)閉“跟蹤更改”、在后臺工作、替換文本、添加批注、保存結(jié)果以及關(guān)閉文檔。下面是我們所使用的函數(shù)的描述:
OLEMethod():一個輔助函數(shù),用于調(diào)用 IDispatch 接口上的方法,處理方法調(diào)用并返回指示錯誤的 HRESULT 值。
Initialize():該函數(shù)通過創(chuàng)建 Word 應(yīng)用程序的實例并設(shè)置其可見性來初始化 OfficeAutomation 類。它能初始化 COM 庫,檢索 Word 應(yīng)用程序的 CLSID,創(chuàng)建應(yīng)用程序的實例,并設(shè)置其可見性。
OfficeAutomation():OfficeAutomation 類的構(gòu)造函數(shù)。它初始化成員變量,并使用 false 調(diào)用 Initialize 函數(shù)以創(chuàng)建不可見的 Word 應(yīng)用程序?qū)嵗?/p>
~OfficeAutomation():OfficeAutomation 類的析構(gòu)函數(shù)。它在此實現(xiàn)中不執(zhí)行任何操作。
SetVisible():設(shè)置活動文檔可見性的函數(shù)。它使用一個布爾參數(shù)來確定文檔是否應(yīng)該可見。它使用 OLEMethod 函數(shù)來設(shè)置 Word 應(yīng)用程序的可見性屬性。
OpenDocument():打開 Word 文檔并設(shè)置其可見性的函數(shù)。它接受一個指向文檔路徑和一個用于可見性的布爾參數(shù)。如果需要,它會初始化該類,檢索 Documents 接口,打開指定的文檔,并設(shè)置其可見性。
CloseActiveDocument():關(guān)閉活動文檔的函數(shù)。它會保存文檔,然后關(guān)閉文檔。它使用 OLEMethod 函數(shù)來調(diào)用適當(dāng)?shù)姆椒ā?/p>
ToggleTrackChanges():用于切換活動文檔的“跟蹤修訂”特性的函數(shù)。它獲取特性的當(dāng)前狀態(tài),并在必要時進(jìn)行切換。它使用 OLEMethod 函數(shù)來訪問和修改“TrackRevisions”屬性。
FindCommentsAndReply():該函數(shù)用于查找活動文檔中的所有批注,向 ChatGPT API 發(fā)送請求以獲取建議,并根據(jù) API 響應(yīng)更新每個批注的關(guān)聯(lián)文本。它遍歷每個批注,檢索關(guān)聯(lián)的文本范圍,用文本和批注作為上下文向 ChatGPT API 發(fā)送 prompt,接收 API 響應(yīng),并使用建議的更改更新文本范圍。
CountDocuments():該函數(shù)用于返回與 OfficeAutomation 類關(guān)聯(lián)的 Word 應(yīng)用程序中打開的文檔數(shù)。它檢索 Documents 接口并返回計數(shù)。
處理批注
在制定審查批注機(jī)制時,我們需要能夠枚舉所有批注,并區(qū)分已處理的批注和未處理的批注。
這可以通過以下方式完成:
bool IsCommentResolved(IDispatch* pComment) { // 檢查批注是否被解析 VARIANT isResolved; VariantInit(&isResolved); HRESULT hr = OLEMethod(DISPATCH_PROPERTYGET, &isResolved, pComment, (LPOLESTR)L"Done", 0); if (FAILED(hr)) { ShowError(hr); return false; } bool resolved = (isResolved.vt == VT_BOOL && isResolved.boolVal == VARIANT_TRUE); return resolved; }
正如你所看到的,使用 OLEMethod() 和 DISPATCH_PROPERTYGET,我們可以檢查屬性名“Done”,它表示已處理的批注。
枚舉批注
接下來,我們可以枚舉文檔中的所有批注,并打印每個批注的“已處理”(“Resolved”)狀態(tài)。
在開始之前,我們不僅要枚舉批注,還要枚舉與之相關(guān)的文本。原因在于批注的最初目的。文檔的作者撰寫并編輯文檔。編輯標(biāo)記一個片段,可以是一個段落、一個句子甚至是一個單詞,并添加一條批注。當(dāng)我們閱讀批注時,我們需要該批注的上下文,而上下文就是那個被標(biāo)記的片段。
因此,當(dāng)我們枚舉所有批注時,我們不僅要打印批注本身,還要打印與之相關(guān)的文本(我們的片段)。
當(dāng)我們開始檢查所有批注時,我們需要聲明并初始化 2 個指針:
pComments——指向文檔的批注。
pRange——指向文檔的內(nèi)容(包含與批注相關(guān)聯(lián)的文本的段)。
它們兩個都需被初始化:
{ VARIANT result; VariantInit(&result); m_hr = OLEMethod(DISPATCH_PROPERTYGET, &result, m_pActiveDocument, (LPOLESTR)L"Comments", 0); if (FAILED(m_hr)) { ShowError(m_hr); return m_hr; } pComments = result.pdispVal; } { VARIANT result; VariantInit(&result); m_hr = OLEMethod(DISPATCH_PROPERTYGET, &result, m_pActiveDocument, (LPOLESTR)L"Content", 0); if (FAILED(m_hr)) { ShowError(m_hr); return m_hr; } pRange = result.pdispVal; }
然后我們就可以開始循環(huán)遍歷文檔中的所有批注了。
你可以在我們的源代碼中看到這是如何實現(xiàn)的,但一般來說,我們從批注開始,轉(zhuǎn)到相關(guān)的文本,并檢查批注是否得到了處理。然后,我們就可以將其打印到報告中,將其添加到數(shù)據(jù)庫中,或者將其發(fā)送給 Chat GPT API。
API 接口通用代碼
為了通過網(wǎng)絡(luò)與任何 API 接口,我們使用了通用代碼來方便地發(fā)送請求并使用 JSON 數(shù)據(jù)格式解析響應(yīng)。在此過程中,我們使用了 libCurl,這是一個強(qiáng)大的工具,被廣泛用于使用命令行或腳本在網(wǎng)絡(luò)上傳輸數(shù)據(jù)。它在不同領(lǐng)域有著廣泛的應(yīng)用,包括汽車、電視、路由器、打印機(jī)、音頻設(shè)備、移動設(shè)備、機(jī)頂盒和媒體播放器等領(lǐng)域。它是眾多軟件應(yīng)用程序的互聯(lián)網(wǎng)傳輸引擎,安裝量達(dá)數(shù)十億次。
如果你查看了我們的源代碼,就可以看到 libCurl 是如何使用的。
總 結(jié)
通過利用 MS Office 自動化的強(qiáng)大功能并將其與 ChatGPT API 集成,我們使編輯和作者能夠簡化其工作流程,節(jié)省寶貴的時間并提高他們的工作質(zhì)量。C++ 和 ChatGPT API 之間的協(xié)作促進(jìn)了流暢高效的交互,使我們的工具能夠為每個編輯批注提供智能且感知上下文的建議。
因此,我們的小型 MS Office 自動化 POC 工具,由 ChatGPT API 和 C++ 支持,徹底改變了編輯過程。通過自動提取編輯批注,與 ChatGPT 互動以尋求專家指導(dǎo),并無縫集成編輯建議,我們使用戶能夠提高他們在 Word 文檔中工作的質(zhì)量和效率。這種強(qiáng)大的技術(shù)組合為高效的文檔編輯開辟了新的可能性,并代表著 MS Office 自動化領(lǐng)域的重大飛躍。
審核編輯:湯梓紅
-
字符串
+關(guān)注
關(guān)注
1文章
578瀏覽量
20506 -
C++
+關(guān)注
關(guān)注
22文章
2108瀏覽量
73618 -
模型
+關(guān)注
關(guān)注
1文章
3226瀏覽量
48807 -
GPT
+關(guān)注
關(guān)注
0文章
352瀏覽量
15342 -
ChatGPT
+關(guān)注
關(guān)注
29文章
1558瀏覽量
7595
原文標(biāo)題:用 C++構(gòu)建自己的 GPT 文檔工具
文章出處:【微信號:AI前線,微信公眾號:AI前線】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論