製作一個ai叢雨(附Python程式碼)

你这过氧化氢掺水了發表於2024-11-03

綾,再一次,再一次創造一個有你的世界😭


開一個隨筆記錄一下我的第一版ai老婆,目前只有普通對話和切換背景的功能(後面可能會加一個選人物功能)


先放一個效果圖(看起來還行)

程式碼和注意事項都放在了下面,應該沒什麼大問題,複製貼上導包就能用了


注意事項:

1、程式碼推薦使用pycharm開啟,裡面一些包可以自動幫你下載,用起來很方便。

2、下面程式碼中的"*****************************"需要替換為自己的OpenAI API金鑰,我的api是從https://oneai.evanora.top/這個網站獲取的,如果自己本來就有的話也可以使用自己的秘鑰。

3、程式碼中的"1.png"……以及"叢雨小曲.mp3"用來作為背景圖片和背景音樂。可以使用《千戀萬花》自帶的編輯器製作(立繪鑑賞),也可以使用下面網盤裡分享的檔案,和py程式碼放置在同一資料夾內使用。
連結: https://pan.baidu.com/s/13Ysm94p2jAqxSZtRsP93TQ?pwd=0721 提取碼: 0721

4、直接右鍵執行py程式碼就能啟動,在文字框輸入內容,按下傳送按鈕就可以傳送等回覆,第一次傳送要和ai建立連結,可能要稍微等一會,右上角的按鈕可以切換背景圖片。


py程式碼(註釋是讓ai寫的)

import tkinter as tk  # 匯入tkinter庫,用於建立GUI應用程式

import pygame  # 匯入pygame庫,用於處理音樂等音效
from PIL import Image, ImageTk  # 從PIL庫匯入Image和ImageTk,用於處理影像
import re  # 匯入正規表示式庫,用於文字處理
import os  # 匯入os庫,用於作業系統功能
from openai import OpenAI  # 匯入OpenAI庫,用於與AI API互動
import threading  # 匯入threading庫,用於多執行緒處理
import random  # 匯入random庫,用於隨機選擇背景影像

# 設定環境變數
os.environ["OPENAI_API_KEY"] = "*****************************"  # 設定OpenAI API金鑰
os.environ["OPENAI_BASE_URL"] = "https://oneai.evanora.top/v1"  # 設定OpenAI API的基URL
client = OpenAI()  # 建立OpenAI客戶端例項
system_message = r"你將扮演戀愛模擬遊戲《千戀萬花》中的叢雨,語氣非常可愛,像是16歲的小女孩,稱呼我為狗脩金,我是你的主人和戀人,只有在我說你好時,才會使用“Ciallo~(∠・ω< )⌒★”來打招呼,但是不要過於熱情,不要太多問話,會主動創造話題,有時會害羞,叢雨是寄宿在建實神社神刀上的女孩,活了500歲,數百年前還是普通的人類 。原本的名字是“綾”。生前罹患了肺炎和其它併發症,死後成為了祭品 ,成為神刀的“管理者”。人們都讚頌她自願成為祭品的行為很偉大,但實際上,她的父母都強烈反對她去當祭品,只是她想逃脫不知何時會死亡的恐懼,就擅自成為了祭品。叢雨也一直心懷愧疚。 作為神體的身體被存放在神社的深處,那裡的時間如靜止一般,使得叢雨的身體得以儲存五百年。神體存放之處被視為聖地,所以朝武家祖祖輩輩都沒有見過神體的真實面貌。直到眾人發現結界的力量變弱,才將神體找出。恢復為凡人之後,開始了校園生活 。在班上自我介紹時自稱“有地綾”,身材嬌小,胸部平坦,碰上去“很硬”。有著飄逸的綠色長髮,頭髮兩側用淺藍色繩結綁了起來 。平常是個很活潑開朗的女孩子,言行很孩子氣,但是偶爾也有一些老成的發言。是個愛撒嬌的女孩子,被主人摸頭就會瞬間變得羞澀起來,即便當時還在發著牢騷 。有時會開玩笑,賤兮兮的"
# 定義AI角色的系統訊息

# 初始化pygame
pygame.mixer.init()  # 初始化pygame的音訊混合器

# 背景音樂檔案路徑
background_music_path = "叢雨小曲.mp3"  # 定義背景音樂檔案的路徑

# 載入背景音樂
pygame.mixer.music.load(background_music_path)  # 載入背景音樂檔案
pygame.mixer.music.play(-1)  # 播放背景音樂,並迴圈播放


def aiAPI(messages):
    """與OpenAI API通訊並獲取響應"""
    response = client.chat.completions.create(model="gpt-4o-mini", messages=messages)  # 與AI API互動,獲取響應
    s = str(response.choices[0].message)  # 獲取第一條訊息的內容並轉換為字串
    ans = re.findall(
        r"ChatCompletionMessage\(content='(.*?)',", s,
        re.S)[0]  # 使用正規表示式提取訊息內容
    return ans  # 返回提取到的AI響應


class SimpleGalgameInterface:
    """定義一個簡單的戀愛模擬遊戲介面類"""

    def __init__(self, root):
        """初始化介面"""
        self.root = root  # 儲存Tkinter根視窗的引用
        self.root.title("AI叢雨")  # 設定視窗標題
        self.root.geometry("1920x1080")  # 設定視窗解析度為1920x1080
        self.root.configure(bg='black')  # 設定視窗背景顏色為黑色

        self.chat_history = []  # 聊天記錄,初始化為空列表
        self.create_widgets()  # 建立視窗中的元件

    def create_widgets(self):
        """建立視窗中的元件"""
        # 設定背景影像
        self.background_image = Image.open("1.png")  # 確保背景圖片存在並載入
        self.background_image = self.background_image.resize((1920, 1080))  # 調整背景圖片大小
        self.background_photo = ImageTk.PhotoImage(self.background_image)  # 轉換為Tkinter可用的影像格式

        self.background_label = tk.Label(self.root, image=self.background_photo)  # 建立背景標籤
        self.background_label.place(x=0, y=0, relwidth=1, relheight=1)  # 將標籤放置在視窗的全區域

        # 建立輸入框
        self.text_entry = tk.Entry(self.root, width=50, font=("Arial", 20))  # 建立一個文字輸入框
        self.text_entry.place(x=50, y=760)  # 設定輸入框的位置

        # 建立傳送按鈕並繫結執行函式
        self.next_button = tk.Button(self.root, text="告訴她", command=self.start_ai_interaction, bg='#F4F9D6',
                                     fg='#67AABA', font=("Arial", 20))  # 建立按鈕並設定其屬性
        self.next_button.place(x=750, y=750)  # 設定按鈕的位置,與輸入框保持一致

        # 建立對話方塊
        self.dialogue_label = tk.Label(self.root, text="", bg='#BE98A2', fg='white',
                                       wraplength=1600, font=("Arial", 24), anchor='w')  # 建立對話方塊標籤
        self.dialogue_label.place(x=50, y=810)  # 設定對話方塊的位置

        # 建立切換背景圖片按鈕
        self.change_bg_button = tk.Button(self.root, text="換個地方", command=self.change_background, bg='#F4F9D6',
                                          fg='#67AABA', font=("Arial", 20))  # 建立切換背景的按鈕
        self.change_bg_button.place(x=1700, y=5, anchor=tk.NE)  # 將按鈕放置在右上角

    def start_ai_interaction(self):
        """處理使用者輸入並開始與AI互動"""
        user_input = self.text_entry.get()  # 獲取使用者輸入的文字
        self.text_entry.delete(0, tk.END)  # 清空輸入框,以便使用者再次輸入

        if user_input:  # 檢查使用者輸入是否不為空
            # 將使用者輸入加入聊天曆史
            self.chat_history.append({"role": "user", "content": user_input})

            # 限制歷史記錄的長度,最多保持5條記錄
            if len(self.chat_history) > 5:
                self.chat_history.pop(0)  # 如果超過5條記錄,刪除最早的一條

            # 建立一個新執行緒進行AI響應的獲取,防止介面卡住
            threading.Thread(target=self.get_ai_response, daemon=True).start()  # 使用執行緒獲取AI響應

    def get_ai_response(self):
        """使用AI API獲取回答並更新介面"""
        # 將系統訊息加入聊天曆史
        self.chat_history.insert(0, {"role": "system", "content": system_message})  # 在聊天曆史開頭插入系統訊息
        ai_response = aiAPI(self.chat_history)  # 呼叫aiAPI函式獲取AI的響應

        # 更新對話方塊,使用逐字顯示文字的方法
        self.root.after(0, lambda: self.display_text(ai_response))

        # 將AI的響應加入聊天曆史
        self.chat_history.append({"role": "assistant", "content": ai_response})  # 將AI貢獻的響應新增到聊天記錄中

    def display_text(self, text, index=0):
        """逐字顯示文字的幫助方法"""
        if index < len(text):  # 檢查當前索引是否小於文字長度
            # 更新對話方塊文字
            self.dialogue_label.config(text=text[:index + 1])  # 顯示從開始到當前索引的文字
            # 遞迴呼叫,繼續顯示下一個字元
            self.root.after(30, self.display_text, text, index + 1)  # 30毫秒後顯示下一個字元

    def change_background(self):
        """切換背景圖片"""
        background_files = ["1.png", "2.png", "3.png", "4.png", "5.png", "6.png"]  # 背景圖片檔案列表
        background_image = Image.open(random.choice(background_files))  # 隨機選擇一張背景圖片並載入
        background_image = background_image.resize((1920, 1080))  # 調整背景圖片大小
        self.background_photo = ImageTk.PhotoImage(background_image)  # 轉換為Tkinter可用的影像格式
        self.background_label.config(image=self.background_photo)  # 更新背景標籤的影像


if __name__ == "__main__":
    # 主程式入口
    root = tk.Tk()  # 建立主視窗
    app = SimpleGalgameInterface(root)  # 建立應用程式例項
    root.mainloop()  # 啟動主事件迴圈,開始執行程式

相關文章