77"""
88
99# Standard imports
10+ import collections
1011import os
1112import time
12- from collections import defaultdict
13- from collections import deque
1413
1514# Third-party imports
16- from discord .ext import commands
17- from dotenv import load_dotenv
18- from google import genai
19- from google .genai import errors
20- from google .genai import types
15+ import discord .ext . commands
16+ import dotenv
17+ import google . genai
18+ import google .genai . errors
19+ import google .genai . types
2120import openai
2221
2322# Local imports
24- from cog .core .sql import end
25- from cog .core .sql import link_sql
23+ import cog .core .sql
2624
27- load_dotenv (f"{ os .getcwd ()} /.env" )
25+ dotenv . load_dotenv (f"{ os .getcwd ()} /.env" )
2826
2927# 免費額度內每日請求數最多、付費也最便宜的模型
3028# 額度與定價見 https://ai.google.dev/pricing
@@ -81,16 +79,16 @@ def load_knowledge():
8179if KNOWLEDGE :
8280 SYSTEM_PROMPT += "\n \n 以下是你知道的事實,回答相關問題時以此為準:\n " + KNOWLEDGE
8381
84- GENERATE_CONFIG = types .GenerateContentConfig (
82+ GENERATE_CONFIG = google . genai . types .GenerateContentConfig (
8583 system_instruction = SYSTEM_PROMPT ,
8684 max_output_tokens = MAX_REPLY_TOKENS ,
8785 # 關閉 thinking 以節省 token(flash 系列適用;
8886 # 若改用 gemini-2.5-pro 需移除這行)
89- thinking_config = types .ThinkingConfig (thinking_budget = 0 ),
87+ thinking_config = google . genai . types .ThinkingConfig (thinking_budget = 0 ),
9088)
9189
9290
93- class Chat (commands .Cog ):
91+ class Chat (discord . ext . commands .Cog ):
9492 """
9593 @中電喵 聊天功能。
9694
@@ -104,17 +102,21 @@ class Chat(commands.Cog):
104102
105103 def __init__ (self , bot ):
106104 self .bot = bot
107- self .client = genai .Client (api_key = GEMINI_API_KEY ) if GEMINI_API_KEY else None
105+ self .client = (
106+ google .genai .Client (api_key = GEMINI_API_KEY ) if GEMINI_API_KEY else None
107+ )
108108 self .groq = (
109109 openai .AsyncOpenAI (base_url = GROQ_BASE_URL , api_key = GROQ_API_KEY )
110110 if GROQ_API_KEY
111111 else None
112112 )
113113 # 每個頻道各自保留一小段對話歷史,超過上限自動丟棄最舊的
114- self .history = defaultdict (lambda : deque (maxlen = HISTORY_LIMIT ))
114+ self .history = collections .defaultdict (
115+ lambda : collections .deque (maxlen = HISTORY_LIMIT )
116+ )
115117 self .last_used = {}
116118
117- @commands .Cog .listener ()
119+ @discord . ext . commands .Cog .listener ()
118120 async def on_message (self , message ):
119121 # 機器人發言不可當成觸發條件,必須排除
120122 if message .author .bot :
@@ -204,10 +206,10 @@ def get_chat_nick(user_id):
204206 """
205207
206208 try :
207- connection , cursor = link_sql ()
209+ connection , cursor = cog . core . sql . link_sql ()
208210 cursor .execute ("SELECT nickname FROM chat_nick WHERE uid = %s" , (user_id ,))
209211 ret = cursor .fetchall ()
210- end (connection , cursor )
212+ cog . core . sql . end (connection , cursor )
211213 if ret and ret [0 ][0 ]:
212214 return ret [0 ][0 ]
213215 # 資料庫掛掉不該讓聊天功能跟著掛
@@ -291,7 +293,7 @@ async def generate(self, contents):
291293
292294 try :
293295 return await self ._generate_gemini (CHAT_MODEL , contents )
294- except errors .APIError as exception :
296+ except google . genai . errors .APIError as exception :
295297 if exception .code not in (429 , 500 , 503 ) or FALLBACK_MODEL == CHAT_MODEL :
296298 raise
297299 print (
@@ -301,7 +303,7 @@ async def generate(self, contents):
301303
302304 try :
303305 return await self ._generate_gemini (FALLBACK_MODEL , contents )
304- except errors .APIError as exception :
306+ except google . genai . errors .APIError as exception :
305307 if self .groq is None or exception .code not in (429 , 500 , 503 ):
306308 raise
307309 print (
@@ -330,10 +332,10 @@ async def chat(self, message, content):
330332 display_name = (
331333 self .get_chat_nick (message .author .id ) or message .author .display_name
332334 )
333- user_content = types .Content (
335+ user_content = google . genai . types .Content (
334336 role = "user" ,
335337 parts = [
336- types .Part (text = f"{ display_name } :{ content } " ),
338+ google . genai . types .Part (text = f"{ display_name } :{ content } " ),
337339 ],
338340 )
339341
@@ -342,7 +344,7 @@ async def chat(self, message, content):
342344 reply_text , model_used , tokens_in , tokens_out = await self .generate (
343345 list (channel_history ) + [user_content ]
344346 )
345- except errors .APIError as exception :
347+ except google . genai . errors .APIError as exception :
346348 if exception .code == 429 :
347349 # 免費額度的每分鐘上限滿了,約一分鐘後就會恢復
348350 await message .reply (
@@ -371,7 +373,9 @@ async def chat(self, message, content):
371373 # 對話成立才寫入歷史,讓後續對話有前後文
372374 channel_history .append (user_content )
373375 channel_history .append (
374- types .Content (role = "model" , parts = [types .Part (text = reply_text )])
376+ google .genai .types .Content (
377+ role = "model" , parts = [google .genai .types .Part (text = reply_text )]
378+ )
375379 )
376380
377381 # 紀錄 token 用量,方便追蹤免費額度
@@ -384,5 +388,5 @@ async def chat(self, message, content):
384388 await message .reply (reply_text [:2000 ], mention_author = False )
385389
386390
387- def setup (bot ):
391+ def setup (bot : discord . Bot ):
388392 bot .add_cog (Chat (bot ))
0 commit comments