綾,再一次,再一次創造一個有你的世界😭
開一個隨筆記錄一下我的第一版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() # 啟動主事件迴圈,開始執行程式