iT邦幫忙

2024 iThome 鐵人賽

DAY 15
0
生成式 AI

生成式 AI 時代下的 Azure Machine Learning系列 第 15

Day15-用 Tkinter 來寫個 Fine Tune 資料用的小工具

  • 分享至 

  • xImage
  •  

今天我們用 tkinter 來寫一個輸入資料可以產生 JSONL 的小工具。

Tkinter 是 Python 的 GUI 套件,它提供了一個簡單易用的方式來建立視覺化應用程式。通過 Tkinter,開發者可以使用各種介面元件,如按鈕、標籤、文本框和選單,來設計互動式應用程式,而不需要額外安裝第三方套件。Tkinter 使用的是 Tk ,這個庫是多平台的,意即你所寫的程式碼可以在 Windows、macOS 和 Linux 等多個操作系統上運行。

我們使用指令 poetry add tk 就可以安裝起來了。

我們今天的目標是做一個 GUI,讓用戶輸入「user prompt」和「assistant prompt」,並配合一個「system prompt」,將這些資料輸出為 fine tune 所需要的格式,然後導出為 JSONL 文件。

主程式架構

1. 應用程式初始化

class QnAExporter:
def __init__(self, root):
    self.root = root
    self.root.title("Q&A JSONL Exporter")
    self.messages = []

這部分定義了一個 QnAExporter 類,它是應用程式的核心。__init__ 函數初始化介面,並將主視窗標題設置為「Q&A JSONL Exporter」。self.messages 則是一個列表,用來儲存所有的 Q&A 及系統訊息,這些訊息最終會被導出為 JSONL 文件。

2. 系統訊息框

system_frame = tk.LabelFrame(root, text="System Message", padx=10, pady=10)
system_frame.pack(fill="both", padx=10, pady=5)

self.system_text = tk.Text(system_frame, height=4, wrap=tk.WORD)
self.system_text.pack(fill="both", expand=True)

這裡創建了一個用來輸入系統訊息的區域。LabelFrame 是一個帶有標籤的框架,讓用戶知道這個區域是用來輸入「系統訊息」的。self.system_text 是一個 Text 文本框,允許用戶輸入多行文本,這裡的 wrap=tk.WORD 設置文本自動換行。

3. User prompt 和 assistant prompt 輸入區

qa_frame = tk.LabelFrame(root, text="Add Q&A Pair", padx=10, pady=10)
qa_frame.pack(fill="both", padx=10, pady=5)

tk.Label(qa_frame, text="User Question:").grid(row=0, column=0, sticky="e")
self.question_entry = tk.Entry(qa_frame, width=50)
self.question_entry.grid(row=0, column=1, padx=5, pady=2)

tk.Label(qa_frame, text="Assistant Answer:").grid(row=1, column=0, sticky="e")
self.answer_entry = tk.Entry(qa_frame, width=50)
self.answer_entry.grid(row=1, column=1, padx=5, pady=2)

add_button = tk.Button(qa_frame, text="Add Q&A Pair", command=self.add_pair)
add_button.grid(row=2, column=0, columnspan=2, pady=5)

這一段程式碼創建了一個輸入區域,讓用戶輸入 User prompt 和 assistant prompt。使用網格(grid)來排列每個元素。當按下「Add Q&A Pair」按鈕時,會調用 add_pair() 函數,將 Q&A 加入到列表中。

4. 已加入的 Q&A 顯示區

listbox_frame = tk.LabelFrame(root, text="Added Q&A Pairs", padx=10, pady=10)
listbox_frame.pack(fill="both", padx=10, pady=5, expand=True)

self.qa_text = tk.Text(listbox_frame, width=80, height=15, wrap=tk.WORD)
self.qa_text.pack(side="left", fill="both", expand=True)

scrollbar = tk.Scrollbar(listbox_frame, orient="vertical", command=self.qa_text.yview)
scrollbar.pack(side="right", fill="y")
self.qa_text.config(yscrollcommand=scrollbar.set)

這段程式碼用來顯示所有已加入的 Q&A 和系統訊息。這裡使用了 Text 元件代替 Listbox,因為 Text 更適合顯示多行內容,這裡可以顯示每個 Q&A 對話中的 user prompt,assistant prompt 和 system prompt。滾動條(Scrollbar)與文本框連接,當內容超出視窗大小時,允許用戶滾動查看。

5. 新增 Q&A 到列表並顯示

def add_pair(self):
question = self.question_entry.get().strip()
answer = self.answer_entry.get().strip()
system_message = self.system_text.get("1.0", tk.END).strip()

if not system_message:
    messagebox.showwarning("Input Error", "System message must be provided.")
    return

if not question or not answer:
    messagebox.showwarning("Input Error", "Both question and answer must be provided.")
    return

pair = {
    "messages": [
        {
            "role": "system",
            "content": system_message
        },
        {
            "role": "user",
            "content": question
        },
        {
            "role": "assistant",
            "content": answer
        }
    ]
}

self.messages.append(pair)

display_text = f"--- Q&A Pair {len(self.messages)} ---\nSystem Message:\n{system_message}\nQ: {question}\nA: {answer}\n\n"
self.qa_text.insert(tk.END, display_text)
self.qa_text.see(tk.END)

self.question_entry.delete(0, tk.END)
self.answer_entry.delete(0, tk.END)

這個函數處理當用戶點擊「Add Q&A Pair」按鈕時的邏輯:

從文本框中提取 user prompt,assistant prompt 和 system prompt。如果其中任一欄位未填寫,會顯示錯誤提示(messagebox.showwarning)。

將這些資料封裝成一個 dict,並將其加入到 self.messages 列表中。在 Text 框中顯示加入的 Q&A 對話,並且會自動滾動到最新的內容。同時會清空輸入框,方便下一次輸入。

6. 導出資料為 JSONL 格式

def export_jsonl(self):
if not self.messages:
    messagebox.showwarning("No Data", "No Q&A pairs to export.")
    return

file_path = filedialog.asksaveasfilename(defaultextension=".jsonl",
                                         filetypes=[("JSON Lines", "*.jsonl")])
if not file_path:
    return

try:
    with open(file_path, 'w', encoding='utf-8') as f:
        for msg in self.messages:
            json_line = json.dumps(msg, ensure_ascii=False)
            f.write(json_line + '\n')
    messagebox.showinfo("Success", f"Data successfully exported to {file_path}")
except Exception as e:
    messagebox.showerror("Error", f"An error occurred while exporting:\n{e}")

這個函數處理將已經加入的 Q&A 導出為 JSONL 文件的過程:

檢查是否有已添加的 Q&A,若無則顯示警告。使用 filedialog.asksaveasfilename 彈出保存文件對話框,讓用戶選擇保存路徑和文件名。還將所有 Q&A 資料逐行轉換為 JSONL 格式,並儲存到文件中。如果導出成功,顯示成功;如果發生錯誤,則顯示錯誤。

明天我們開始用這個工具來準備 Fine Tune 用的資料吧!


上一篇
Day14-Fine Tune 模型的資料準備
下一篇
Day16-產生 Fine Tune 用的資料
系列文
生成式 AI 時代下的 Azure Machine Learning30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言