Feat: Adapt Gemini chat history and improve session cleanup
Browse filesUpdate `get_session_history` to retrieve chat history from `_chat_instance.history`
and convert `gemini_webapi.Part` objects to an OpenAI-compatible message format.
This aligns with recent changes in the `gemini_webapi` library's history structure.
Additionally, modify `reload_gemini_cookies` to clear `_chat_instance` for all
active sessions. This ensures that chat instances are re-initialized with the
newly loaded cookies, preventing issues with stale sessions.
- app/api/gemini_proxy.py +20 -4
- app/core/gemini_client_manager.py +9 -0
app/api/gemini_proxy.py
CHANGED
|
@@ -97,13 +97,29 @@ async def get_session_history(thread_id: str, auth_token: str = Depends(get_auth
|
|
| 97 |
logger.warning(f"认证令牌 {auth_token} 请求会话历史,会话 {thread_id} 存在但聊天实例未初始化。")
|
| 98 |
raise HTTPException(status_code=404, detail="会话聊天实例未初始化")
|
| 99 |
|
| 100 |
-
# 获取会话历史
|
| 101 |
history = []
|
| 102 |
-
if hasattr(session._chat_instance, '
|
| 103 |
-
history
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 104 |
logger.debug(f"认证令牌 {auth_token} 会话 {thread_id} 历史消息数量: {len(history)}")
|
| 105 |
else:
|
| 106 |
-
logger.warning(f"认证令牌 {auth_token} 会话 {thread_id} 的聊天实例没有 '
|
| 107 |
|
| 108 |
return JSONResponse({
|
| 109 |
"thread_id": thread_id,
|
|
|
|
| 97 |
logger.warning(f"认证令牌 {auth_token} 请求会话历史,会话 {thread_id} 存在但聊天实例未初始化。")
|
| 98 |
raise HTTPException(status_code=404, detail="会话聊天实例未初始化")
|
| 99 |
|
| 100 |
+
# 获取会话历史
|
| 101 |
history = []
|
| 102 |
+
if hasattr(session._chat_instance, 'history') and session._chat_instance.history:
|
| 103 |
+
# gemini_webapi 的 history 是一个包含 Part 对象的列表
|
| 104 |
+
# 需要将其转换为 OpenAI 兼容的 messages 格式
|
| 105 |
+
for i, part in enumerate(session._chat_instance.history):
|
| 106 |
+
role = "user" if i % 2 == 0 else "model" # 假设交替角色
|
| 107 |
+
content = ""
|
| 108 |
+
image_urls = []
|
| 109 |
+
|
| 110 |
+
if hasattr(part, 'text'):
|
| 111 |
+
content = part.text
|
| 112 |
+
|
| 113 |
+
# 如果有图片,这里需要更复杂的逻辑来处理,目前 gemini_webapi 的 history 不直接暴露图片 URL
|
| 114 |
+
# 对于图片,我们可能需要从原始请求中存储或重新生成,或者在前端处理
|
| 115 |
+
|
| 116 |
+
history.append({
|
| 117 |
+
"role": role,
|
| 118 |
+
"parts": [{"text": content}] # OpenAI 兼容的 parts 格式
|
| 119 |
+
})
|
| 120 |
logger.debug(f"认证令牌 {auth_token} 会话 {thread_id} 历史消息数量: {len(history)}")
|
| 121 |
else:
|
| 122 |
+
logger.warning(f"认证令牌 {auth_token} 会话 {thread_id} 的聊天实例没有 'history' 属性或历史为空。")
|
| 123 |
|
| 124 |
return JSONResponse({
|
| 125 |
"thread_id": thread_id,
|
app/core/gemini_client_manager.py
CHANGED
|
@@ -7,6 +7,7 @@ from typing import Dict, Any, List, Optional, Tuple
|
|
| 7 |
from gemini_webapi import GeminiClient
|
| 8 |
import gemini_webapi.exceptions # 导入 gemini_webapi 的异常模块
|
| 9 |
import asyncio # 导入 asyncio 模块用于异步操作
|
|
|
|
| 10 |
|
| 11 |
logger = logging.getLogger(__name__)
|
| 12 |
|
|
@@ -113,6 +114,14 @@ def reload_gemini_cookies():
|
|
| 113 |
# 清空所有现有的 GeminiClient 实例,强制下次请求时重新初始化
|
| 114 |
gemini_clients.clear()
|
| 115 |
logger.info("所有现有 GeminiClient 实例已清空,将在下次请求时重新初始化。")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 116 |
logger.info("Gemini Cookies 重新加载完成。")
|
| 117 |
|
| 118 |
def get_next_gemini_cookie_tuple() -> Optional[Tuple[str, str]]:
|
|
|
|
| 7 |
from gemini_webapi import GeminiClient
|
| 8 |
import gemini_webapi.exceptions # 导入 gemini_webapi 的异常模块
|
| 9 |
import asyncio # 导入 asyncio 模块用于异步操作
|
| 10 |
+
from app.core.session_manager import chat_sessions # 导入 chat_sessions
|
| 11 |
|
| 12 |
logger = logging.getLogger(__name__)
|
| 13 |
|
|
|
|
| 114 |
# 清空所有现有的 GeminiClient 实例,强制下次请求时重新初始化
|
| 115 |
gemini_clients.clear()
|
| 116 |
logger.info("所有现有 GeminiClient 实例已清空,将在下次请求时重新初始化。")
|
| 117 |
+
|
| 118 |
+
# 遍历所有会话,清空其 _chat_instance,强制重新初始化聊天实例
|
| 119 |
+
for auth_token in chat_sessions:
|
| 120 |
+
for session_id, session in chat_sessions[auth_token].items():
|
| 121 |
+
if session._chat_instance:
|
| 122 |
+
session._chat_instance = None
|
| 123 |
+
logger.info(f"会话 {session_id} 的聊天实例已清空。")
|
| 124 |
+
|
| 125 |
logger.info("Gemini Cookies 重新加载完成。")
|
| 126 |
|
| 127 |
def get_next_gemini_cookie_tuple() -> Optional[Tuple[str, str]]:
|