iT邦幫忙

2023 iThome 鐵人賽

DAY 22
0
Mobile Development

Ionic結合ChatGPT - 30天打造AI英語口說導師APP系列 第 22

【Day - 22】Function Calling實戰4 - 判斷文法的正確性

  • 分享至 

  • xImage
  •  

在【Day - 19】時,我們探討了GPT-3.5模型的Function Calling,發現它難以在回覆對話的同時進行文法檢查。另外,我也認為若在和AI的對話中參雜解析和即時指出語法錯誤,可能會打斷原本對話的流暢性。因此,我選擇將文法檢查功能獨立出來,以提示的方式形式呈現,避免影響到對話的進行。在今天的Function Calling實戰第四天中,我們將繼續探索不同的Function Calling實作。Let's Go!

建立文法檢查

首先,在chatgpt.model.ts檔案中,新增兩個文法檢查的Model,其中,GrammerCheckDataModel用於定義Function Calling的輸出格式,而GrammerDataModel則用於狀態管理:

export interface GrammerCheckDataModel {
  hasGrammerMistake: boolean;
}

export interface GrammerDataModel extends GrammerCheckDataModel {
  mistakeSentence: string;
}

openai.service.ts檔案中,建立一個getGrammerCheckRequestData()的方法,該方法為文法檢查的Function Calling結構。其中,parameters的JSON Schema是根據上方定義的GrammerCheckDataModel來配置的:

private getGrammerCheckRequestData(contentData: string): ChatRequestModel {
  return {
    model: 'gpt-4',
    messages: [
      {
        role: 'system',
        content: '請檢查是否有文法或使用上的任何錯誤。'
      },
      {
        role: 'user',
        content: contentData
      }
    ],
    temperature: 0.7,
    top_p: 1,
    functions: [
      {
        name: 'grammerChecker',
        description: '',
        parameters: {
          type: 'object',
          properties: {
            hasGrammerMistake: {
              type: 'boolean',
              description: ''
            }
          },
          required: [
            'hasGrammerMistake'
          ]
        }
      }
    ],
    function_call: {
      name: 'grammerChecker'
    }
  }
}

接下來在相同的檔案中,建立了一個checkGrammerHasMistake()的方法。這個方法的結構與chatAPI相似。利用map Operator,將文法的錯誤和相關內容一併回傳:

.
.
.
public chatAPI(contentData: string) {
  .
  .
  .
}

public checkGrammerHasMistake(contentData: string) {
  return this.http.post<ChatResponseModel>('https://api.openai.com/v1/chat/completions', this.getGrammerCheckRequestData(contentData), { headers: this.headers }).pipe(
    map(chatAPIResult => {
      //取得function_call.arguments的字串並轉成物件
	  const grammerCheckData = JSON.parse(chatAPIResult.choices[0].message.function_call?.arguments!) as GrammerCheckDataModel;
      return {
        hasGrammerMistake: grammerCheckData.hasGrammerMistake,
        mistakeSentence: contentData
      } as GrammerDataModel;
    }),
  );
}

 

文法狀態管理

與【Day - 21】的做法相同,在status.service.ts檔案中,建立一個grammerStatusSubject$來追踪和管理文法檢查的狀態。此外,新增了一個setGrammerStatus()方法,讓外部能夠通過這個方法來修改狀態:

.
.
.
//語氣狀態
private styleStatusSubject$ = new BehaviorSubject<AIStyle>('friendly');
//文法檢查狀態
private grammerStatusSubject$ = new BehaviorSubject<GrammerDataModel>({
  hasGrammerMistake: false,
  mistakeSentence: ''
});
.
.
.
get grammerStatus$(): Observable<GrammerDataModel> {
  return this.grammerStatusSubject$.asObservable();
}
.
.
.
public setGrammerStatus(grammerData: GrammerDataModel) {
  this.grammerStatusSubject$.next({
    hasGrammerMistake: grammerData.hasGrammerMistake,
    mistakeSentence: grammerData.mistakeSentence
  });
}

public resetGrammerStatus() {
  this.grammerStatusSubject$.next({
    hasGrammerMistake: false,
    mistakeSentence: ''
  });
}

OnGetRecordingBase64Text()方法中,我組合了chatAPI()checkGrammerHasMistake()兩個功能,利用forkJoin Operator確保它們同時執行。當它們都完成時,我們可以從每個功能中獲得最後的結果。然後,將GrammerDataModel加入到textToSpeech()方法中:

OnGetRecordingBase64Text(recordingBase64Data: RecordingData) {
  const requestData: AudioConvertRequestModel = {
    aacBase64Data: recordingBase64Data.value.recordDataBase64
  };
  //重設文法狀態
  this.statusService.resetGrammerStatus();
  //啟動讀取
  this.statusService.startLoading();
  //Audio Convert API
  this.http.post<AudioConvertResponseModel>('你的Web APP URL/AudioConvert/aac2m4a', requestData).pipe(
    //Whisper API
    switchMap(audioAPIResult => this.openaiService.whisperAPI(audioAPIResult.m4aBase64Data)),
    //Chat API
    switchMap(whisperAPIResult => forkJoin([this.openaiService.chatAPI(whisperAPIResult.text), this.openaiService.checkGrammerHasMistake(whisperAPIResult.text)])),
    //Speech Service API
    switchMap(chatAndGrammerResult => this.textToSpeech(chatAndGrammerResult[0], chatAndGrammerResult[1])),
    finalize(() => {
      //停止讀取
      this.statusService.stopLoading();
    })
  ).subscribe(result => {
    //當前GPT回覆的語氣狀態
    this.statusService.setStyleStatus(result.gptStyle);
    //當前文法的對錯狀態
    this.statusService.setGrammerStatus({
      hasGrammerMistake: result.hasGrammerMistake,
      mistakeSentence: result.mistakeSentence
    });
    //播放音訊
    this.statusService.playAudio(result.audioFile);
  });
}

private textToSpeech(conversationData: ConversationDataModel, grammerData: GrammerDataModel) {
  return this.speechService.textToSpeech(conversationData).pipe(
    map(audioFileResult => ({
      audioFile: audioFileResult,
      gptStyle: conversationData.gptResponseTextStyle,
      hasGrammerMistake: grammerData.hasGrammerMistake,
      mistakeSentence: grammerData.mistakeSentence
    }))
  );
}

 

測試文法檢查功能

最後,我們來觀察GrammerDataModel物件的返回值。在測試過程中,我故意說了一句錯誤文法的英文句子:「How do you are?」。而Function Calling也確實成功的捕捉到了這個文法錯誤。
https://ithelp.ithome.com.tw/upload/images/20230922/20161663Zd0nwEVMNK.png

結語

今天是Function Calling實戰的尾聲了,在研究和實作的過程中不僅讓人覺得它充滿趣味和創造力,更是一個非常強大和實用的工具。透過這個功能,我們能夠更精確的操控GPT模型的輸出,定製特定的答案格式,甚至結合其他技術或服務,實現前所未有的應用場景。這不僅為開發者提供了更大的彈性,也為使用者帶來了更為個性化和高質量的互動體驗。隨著技術的進步和模型的演進,期待未來能有更多不同的Function Calling實踐哦!



Github專案程式碼:Ionic結合ChatGPT - Day22


上一篇
【Day - 21】Function Calling實戰3 - 結合GPT和3D圖像動畫
下一篇
【Day - 23】Sheet Modal - 設計與實現文法錯誤提示功能
系列文
Ionic結合ChatGPT - 30天打造AI英語口說導師APP30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言