大家好,鐵人賽堂堂邁入第二十五日!
昨天,我們的 App 已經能夠成功地顯示靜態的對話內容。今天,是時候讓它「活」過來了!我們將把前端的 UI 操作,與我們在 Day 22 建立的 NetworkManager
完美結合,讓使用者在按下「發送」按鈕的那一刻,App 能夠真正地與我們後端的 Python AI Agent 進行溝通。
根據 adk api_server
的設計,在我們開始傳送聊天訊息之前,客戶端(也就是我們的 App)需要先呼叫一次 /sessions
端點,來建立一個對話的 Session ID。
我們在 MainViewController.swift
中建立一個 updateUserSession
函式來完成這個任務,並在 App 啟動時 (viewDidLoad
) 就呼叫它。
// MainViewController.swift
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
// loadInitialMessages() // 我們不再需要假資料了
// 在 App 啟動時,就與後端建立 Session
Task {
await updateUserSession()
}
}
func updateUserSession() async {
do {
// 準備一個簡單的請求 Body
let requestBody = UpdateSessionRequest(state: ["key1": "value1"])
// 使用我們萬能的 NetworkManager 發送請求
// 注意:我們不需要關心回傳的 response,因為 adk-api 會在後端處理好 Session
let _: UpdateSessionResponse = try await NetworkManager.shared.requestData(
method: .post,
server: .adk,
path: .session,
parameters: requestBody
)
print(" 成功建立或更新 Session!")
} catch {
print(" 更新使用者 Session 失敗:\(error)")
// 可以在此處彈出錯誤提示
}
}
現在,當 App 一啟動,它就會自動在背景與我們的 Python 後端進行第一次的「握手」,為接下來的對話做好準備。
接下來是最核心的部分:當使用者輸入文字並按下「發送」按鈕時,觸發 runAgent
函式來呼叫 API。
首先,我們將發送按鈕的 TouchUpInside
事件,連接到 MainViewController.swift
中的 @IBAction func sendButtonTapped
。
// MainViewController.swift
@IBAction func sendButtonTapped(_ sender: UIButton) {
// 1. 取得輸入框中的文字,並檢查是否為空
guard let text = txfMessage.text, !text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else {
return
}
// 2. 將使用者的訊息立即顯示在畫面上
let userMessage = Message(text: text, sender: .user)
messages.append(userMessage)
txfMessage.text = ""
tbvChat.reloadData()
scrollToBottom(animated: true)
// 3. 建立一個非同步任務,在背景執行我們的 API 呼叫
Task {
await runAgent(for: text)
}
}
runAgent
的實現:組裝並發送請求runAgent
函式是我們 App 的大腦,負責將使用者的文字,打包成符合 adk-api
規範的請求,並透過 NetworkManager
發送出去。
// MainViewController.swift
func runAgent(for text: String) async {
do {
// 1. 根據 API 規格,組裝出巢狀的 Request Body
let messagePart = MessagePart(text: text)
let messagePayload = MessagePayload(role: "user", parts: [messagePart])
let requestBody = SendMessageRequest(
appName: "multi_tool_agent",
userId: "u_123",
sessionId: "s_123",
newMessage: messagePayload
)
// 2. 呼叫 NetworkManager 發送請求!
// response 的型別會是我們在 Day 21 定義的 SendMessageResponse
let response: SendMessageResponse = try await NetworkManager.shared.requestData(
method: .post,
server: .adk,
path: .run,
parameters: requestBody
)
// 暫時先在控制台印出回應,確認是否成功
print("成功收到 Agent 回應: \(response)")
} catch {
print("呼叫 Agent 失敗: \(error)")
// 可以在此處將錯誤訊息顯示在畫面上
}
}
寫完後終於可以串接 api 囉!可以跟伺服器做連接了!但...還是會出現錯誤
失敗~~~連接不到 server
雖然已經把請求丟出了,但都無法連接到server,不過沒關係!我們資工人就是不怕遇到bug!勇敢面對並解決bug!