mirror of
https://github.com/Minidoracat/mcp-feedback-enhanced.git
synced 2025-07-27 10:42:25 +08:00
测试
This commit is contained in:
parent
9c412a1321
commit
2cd8d91bb9
@ -156,6 +156,10 @@
|
|||||||
"submitted": {
|
"submitted": {
|
||||||
"title": "Submitted",
|
"title": "Submitted",
|
||||||
"message": "Waiting for next MCP call"
|
"message": "Waiting for next MCP call"
|
||||||
|
},
|
||||||
|
"completed": {
|
||||||
|
"title": "Completed",
|
||||||
|
"message": "Session completed"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
|
@ -156,6 +156,10 @@
|
|||||||
"submitted": {
|
"submitted": {
|
||||||
"title": "反馈已提交",
|
"title": "反馈已提交",
|
||||||
"message": "等待下次 MCP 调用"
|
"message": "等待下次 MCP 调用"
|
||||||
|
},
|
||||||
|
"completed": {
|
||||||
|
"title": "已完成",
|
||||||
|
"message": "会话已完成"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
|
@ -161,6 +161,10 @@
|
|||||||
"submitted": {
|
"submitted": {
|
||||||
"title": "回饋已提交",
|
"title": "回饋已提交",
|
||||||
"message": "等待下次 MCP 調用"
|
"message": "等待下次 MCP 調用"
|
||||||
|
},
|
||||||
|
"completed": {
|
||||||
|
"title": "已完成",
|
||||||
|
"message": "會話已完成"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
|
@ -318,25 +318,46 @@ class WebUIManager:
|
|||||||
|
|
||||||
def create_session(self, project_directory: str, summary: str) -> str:
|
def create_session(self, project_directory: str, summary: str) -> str:
|
||||||
"""創建新的回饋會話 - 重構為單一活躍會話模式,保留標籤頁狀態"""
|
"""創建新的回饋會話 - 重構為單一活躍會話模式,保留標籤頁狀態"""
|
||||||
# 保存舊會話的 WebSocket 連接以便發送更新通知
|
# 保存舊會話的引用和 WebSocket 連接
|
||||||
|
old_session = self.current_session
|
||||||
old_websocket = None
|
old_websocket = None
|
||||||
if self.current_session and self.current_session.websocket:
|
if old_session and old_session.websocket:
|
||||||
old_websocket = self.current_session.websocket
|
old_websocket = old_session.websocket
|
||||||
debug_log("保存舊會話的 WebSocket 連接以發送更新通知")
|
debug_log("保存舊會話的 WebSocket 連接以發送更新通知")
|
||||||
|
|
||||||
# 如果已有活躍會話,先保存其標籤頁狀態到全局狀態
|
# 創建新會話
|
||||||
if self.current_session:
|
|
||||||
debug_log("保存現有會話的標籤頁狀態並清理會話")
|
|
||||||
# 保存標籤頁狀態到全局
|
|
||||||
if hasattr(self.current_session, "active_tabs"):
|
|
||||||
self._merge_tabs_to_global(self.current_session.active_tabs)
|
|
||||||
|
|
||||||
# 同步清理會話資源(但保留 WebSocket 連接)
|
|
||||||
self.current_session._cleanup_sync()
|
|
||||||
|
|
||||||
session_id = str(uuid.uuid4())
|
session_id = str(uuid.uuid4())
|
||||||
session = WebFeedbackSession(session_id, project_directory, summary)
|
session = WebFeedbackSession(session_id, project_directory, summary)
|
||||||
|
|
||||||
|
# 如果有舊會話,處理狀態轉換和清理
|
||||||
|
if old_session:
|
||||||
|
debug_log(f"處理舊會話 {old_session.session_id} 的狀態轉換,當前狀態: {old_session.status.value}")
|
||||||
|
|
||||||
|
# 保存標籤頁狀態到全局
|
||||||
|
if hasattr(old_session, "active_tabs"):
|
||||||
|
self._merge_tabs_to_global(old_session.active_tabs)
|
||||||
|
|
||||||
|
# 如果舊會話是已提交狀態,進入下一步(已完成)
|
||||||
|
if old_session.status == SessionStatus.FEEDBACK_SUBMITTED:
|
||||||
|
debug_log(f"舊會話 {old_session.session_id} 進入下一步:已提交 → 已完成")
|
||||||
|
success = old_session.next_step("反饋已處理,會話完成")
|
||||||
|
if success:
|
||||||
|
debug_log(f"✅ 舊會話 {old_session.session_id} 成功進入已完成狀態")
|
||||||
|
else:
|
||||||
|
debug_log(f"❌ 舊會話 {old_session.session_id} 無法進入下一步")
|
||||||
|
else:
|
||||||
|
debug_log(f"舊會話 {old_session.session_id} 狀態為 {old_session.status.value},無需轉換")
|
||||||
|
|
||||||
|
# 確保舊會話仍在字典中(用於API獲取)
|
||||||
|
if old_session.session_id in self.sessions:
|
||||||
|
debug_log(f"舊會話 {old_session.session_id} 仍在會話字典中")
|
||||||
|
else:
|
||||||
|
debug_log(f"⚠️ 舊會話 {old_session.session_id} 不在會話字典中,重新添加")
|
||||||
|
self.sessions[old_session.session_id] = old_session
|
||||||
|
|
||||||
|
# 同步清理會話資源(但保留 WebSocket 連接)
|
||||||
|
old_session._cleanup_sync()
|
||||||
|
|
||||||
# 將全局標籤頁狀態繼承到新會話
|
# 將全局標籤頁狀態繼承到新會話
|
||||||
session.active_tabs = self.global_active_tabs.copy()
|
session.active_tabs = self.global_active_tabs.copy()
|
||||||
|
|
||||||
@ -348,25 +369,11 @@ class WebUIManager:
|
|||||||
debug_log(f"創建新的活躍會話: {session_id}")
|
debug_log(f"創建新的活躍會話: {session_id}")
|
||||||
debug_log(f"繼承 {len(session.active_tabs)} 個活躍標籤頁")
|
debug_log(f"繼承 {len(session.active_tabs)} 個活躍標籤頁")
|
||||||
|
|
||||||
# 處理會話更新通知
|
# 處理WebSocket連接轉移
|
||||||
if old_websocket:
|
if old_websocket:
|
||||||
# 有舊連接,立即發送會話更新通知並轉移連接
|
# 直接轉移連接到新會話,消息發送由 smart_open_browser 統一處理
|
||||||
self._old_websocket_for_update = old_websocket
|
session.websocket = old_websocket
|
||||||
self._new_session_for_update = session
|
debug_log("已將舊 WebSocket 連接轉移到新會話")
|
||||||
debug_log("已保存舊 WebSocket 連接,準備發送會話更新通知")
|
|
||||||
|
|
||||||
# 立即發送會話更新通知
|
|
||||||
import asyncio
|
|
||||||
|
|
||||||
try:
|
|
||||||
# 在後台任務中發送通知並轉移連接
|
|
||||||
asyncio.create_task(self._send_immediate_session_update())
|
|
||||||
except Exception as e:
|
|
||||||
debug_log(f"創建會話更新任務失敗: {e}")
|
|
||||||
# 即使任務創建失敗,也要嘗試直接轉移連接
|
|
||||||
session.websocket = old_websocket
|
|
||||||
debug_log("任務創建失敗,直接轉移 WebSocket 連接到新會話")
|
|
||||||
self._pending_session_update = True
|
|
||||||
else:
|
else:
|
||||||
# 沒有舊連接,標記需要發送會話更新通知(當新 WebSocket 連接建立時)
|
# 沒有舊連接,標記需要發送會話更新通知(當新 WebSocket 連接建立時)
|
||||||
self._pending_session_update = True
|
self._pending_session_update = True
|
||||||
@ -682,107 +689,9 @@ class WebUIManager:
|
|||||||
else:
|
else:
|
||||||
debug_log("沒有活躍的桌面應用程式實例")
|
debug_log("沒有活躍的桌面應用程式實例")
|
||||||
|
|
||||||
async def notify_session_update(self, session):
|
|
||||||
"""向活躍標籤頁發送會話更新通知"""
|
|
||||||
try:
|
|
||||||
# 檢查是否有活躍的 WebSocket 連接
|
|
||||||
if session.websocket:
|
|
||||||
# 直接通過當前會話的 WebSocket 發送
|
|
||||||
await session.websocket.send_json(
|
|
||||||
{
|
|
||||||
"type": "session_updated",
|
|
||||||
"action": "new_session_created",
|
|
||||||
"message": "新會話已創建,正在更新頁面內容",
|
|
||||||
"session_info": {
|
|
||||||
"project_directory": session.project_directory,
|
|
||||||
"summary": session.summary,
|
|
||||||
"session_id": session.session_id,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
debug_log("會話更新通知已通過 WebSocket 發送")
|
|
||||||
else:
|
|
||||||
# 沒有活躍連接,設置待更新標記
|
|
||||||
self._pending_session_update = True
|
|
||||||
debug_log("沒有活躍 WebSocket 連接,設置待更新標記")
|
|
||||||
except Exception as e:
|
|
||||||
debug_log(f"發送會話更新通知失敗: {e}")
|
|
||||||
# 設置待更新標記作為備用方案
|
|
||||||
self._pending_session_update = True
|
|
||||||
|
|
||||||
async def _send_immediate_session_update(self):
|
|
||||||
"""立即發送會話更新通知(使用舊的 WebSocket 連接)"""
|
|
||||||
try:
|
|
||||||
# 檢查是否有保存的舊 WebSocket 連接
|
|
||||||
if hasattr(self, "_old_websocket_for_update") and hasattr(
|
|
||||||
self, "_new_session_for_update"
|
|
||||||
):
|
|
||||||
old_websocket = self._old_websocket_for_update
|
|
||||||
new_session = self._new_session_for_update
|
|
||||||
|
|
||||||
# 改進的連接有效性檢查
|
|
||||||
websocket_valid = False
|
|
||||||
if old_websocket:
|
|
||||||
try:
|
|
||||||
# 檢查 WebSocket 連接狀態
|
|
||||||
if hasattr(old_websocket, "client_state"):
|
|
||||||
websocket_valid = (
|
|
||||||
old_websocket.client_state
|
|
||||||
!= old_websocket.client_state.DISCONNECTED
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
# 如果沒有 client_state 屬性,嘗試發送測試消息來檢查連接
|
|
||||||
websocket_valid = True
|
|
||||||
except Exception as check_error:
|
|
||||||
debug_log(f"檢查 WebSocket 連接狀態失敗: {check_error}")
|
|
||||||
websocket_valid = False
|
|
||||||
|
|
||||||
if websocket_valid:
|
|
||||||
try:
|
|
||||||
# 發送會話更新通知
|
|
||||||
await old_websocket.send_json(
|
|
||||||
{
|
|
||||||
"type": "session_updated",
|
|
||||||
"action": "new_session_created",
|
|
||||||
"message": "新會話已創建,正在更新頁面內容",
|
|
||||||
"session_info": {
|
|
||||||
"project_directory": new_session.project_directory,
|
|
||||||
"summary": new_session.summary,
|
|
||||||
"session_id": new_session.session_id,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
debug_log("已通過舊 WebSocket 連接發送會話更新通知")
|
|
||||||
|
|
||||||
# 延遲一小段時間讓前端處理消息
|
|
||||||
await asyncio.sleep(0.2)
|
|
||||||
|
|
||||||
# 將 WebSocket 連接轉移到新會話
|
|
||||||
new_session.websocket = old_websocket
|
|
||||||
debug_log("已將 WebSocket 連接轉移到新會話")
|
|
||||||
|
|
||||||
except Exception as send_error:
|
|
||||||
debug_log(f"發送會話更新通知失敗: {send_error}")
|
|
||||||
# 如果發送失敗,仍然嘗試轉移連接
|
|
||||||
new_session.websocket = old_websocket
|
|
||||||
debug_log("發送失敗但仍轉移 WebSocket 連接到新會話")
|
|
||||||
else:
|
|
||||||
debug_log("舊 WebSocket 連接無效,設置待更新標記")
|
|
||||||
self._pending_session_update = True
|
|
||||||
|
|
||||||
# 清理臨時變數
|
|
||||||
delattr(self, "_old_websocket_for_update")
|
|
||||||
delattr(self, "_new_session_for_update")
|
|
||||||
|
|
||||||
else:
|
|
||||||
# 沒有舊連接,設置待更新標記
|
|
||||||
self._pending_session_update = True
|
|
||||||
debug_log("沒有舊 WebSocket 連接,設置待更新標記")
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
debug_log(f"立即發送會話更新通知失敗: {e}")
|
|
||||||
# 回退到待更新標記
|
|
||||||
self._pending_session_update = True
|
|
||||||
|
|
||||||
async def _safe_close_websocket(self, websocket):
|
async def _safe_close_websocket(self, websocket):
|
||||||
"""安全關閉 WebSocket 連接,避免事件循環衝突 - 僅在連接已轉移後調用"""
|
"""安全關閉 WebSocket 連接,避免事件循環衝突 - 僅在連接已轉移後調用"""
|
||||||
@ -1127,7 +1036,7 @@ async def launch_web_feedback_ui(
|
|||||||
"""
|
"""
|
||||||
manager = get_web_ui_manager()
|
manager = get_web_ui_manager()
|
||||||
|
|
||||||
# 創建或更新當前活躍會話
|
# 創建新會話(每次AI調用都應該創建新會話)
|
||||||
manager.create_session(project_directory, summary)
|
manager.create_session(project_directory, summary)
|
||||||
session = manager.get_current_session()
|
session = manager.get_current_session()
|
||||||
|
|
||||||
@ -1154,9 +1063,9 @@ async def launch_web_feedback_ui(
|
|||||||
|
|
||||||
debug_log(f"[DEBUG] 服務器地址: {feedback_url}")
|
debug_log(f"[DEBUG] 服務器地址: {feedback_url}")
|
||||||
|
|
||||||
# 如果檢測到活躍標籤頁但沒有開啟新視窗,立即發送會話更新通知
|
# 如果檢測到活躍標籤頁,消息已在 smart_open_browser 中發送,無需額外處理
|
||||||
if has_active_tabs:
|
if has_active_tabs:
|
||||||
debug_log("檢測到活躍標籤頁,跳過額外的會話更新通知(已在 smart_open_browser 中發送)")
|
debug_log("檢測到活躍標籤頁,會話更新通知已發送")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# 等待用戶回饋,傳遞 timeout 參數
|
# 等待用戶回饋,傳遞 timeout 參數
|
||||||
|
@ -29,15 +29,13 @@ from ...utils.resource_manager import get_resource_manager, register_process
|
|||||||
|
|
||||||
|
|
||||||
class SessionStatus(Enum):
|
class SessionStatus(Enum):
|
||||||
"""會話狀態枚舉"""
|
"""會話狀態枚舉 - 單向流轉設計"""
|
||||||
|
|
||||||
WAITING = "waiting" # 等待中
|
WAITING = "waiting" # 等待中
|
||||||
ACTIVE = "active" # 活躍中
|
|
||||||
FEEDBACK_SUBMITTED = "feedback_submitted" # 已提交反饋
|
FEEDBACK_SUBMITTED = "feedback_submitted" # 已提交反饋
|
||||||
COMPLETED = "completed" # 已完成
|
COMPLETED = "completed" # 已完成
|
||||||
TIMEOUT = "timeout" # 超時
|
ERROR = "error" # 錯誤(終態)
|
||||||
ERROR = "error" # 錯誤
|
EXPIRED = "expired" # 已過期(終態)
|
||||||
EXPIRED = "expired" # 已過期
|
|
||||||
|
|
||||||
|
|
||||||
class CleanupReason(Enum):
|
class CleanupReason(Enum):
|
||||||
@ -174,21 +172,79 @@ class WebFeedbackSession:
|
|||||||
f"會話 {self.session_id} 初始化完成,自動清理延遲: {auto_cleanup_delay}秒,最大空閒: {max_idle_time}秒"
|
f"會話 {self.session_id} 初始化完成,自動清理延遲: {auto_cleanup_delay}秒,最大空閒: {max_idle_time}秒"
|
||||||
)
|
)
|
||||||
|
|
||||||
def update_status(self, status: SessionStatus, message: str | None = None):
|
def next_step(self, message: str | None = None) -> bool:
|
||||||
"""更新會話狀態"""
|
"""進入下一個狀態 - 單向流轉,不可倒退"""
|
||||||
self.status = status
|
old_status = self.status
|
||||||
|
|
||||||
|
# 定義狀態流轉路徑
|
||||||
|
next_status_map = {
|
||||||
|
SessionStatus.WAITING: SessionStatus.FEEDBACK_SUBMITTED,
|
||||||
|
SessionStatus.FEEDBACK_SUBMITTED: SessionStatus.COMPLETED,
|
||||||
|
SessionStatus.COMPLETED: None, # 終態
|
||||||
|
SessionStatus.ERROR: None, # 終態
|
||||||
|
SessionStatus.EXPIRED: None # 終態
|
||||||
|
}
|
||||||
|
|
||||||
|
next_status = next_status_map.get(self.status)
|
||||||
|
|
||||||
|
if next_status is None:
|
||||||
|
debug_log(f"⚠️ 會話 {self.session_id} 已處於終態 {self.status.value},無法進入下一步")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 執行狀態轉換
|
||||||
|
self.status = next_status
|
||||||
if message:
|
if message:
|
||||||
self.status_message = message
|
self.status_message = message
|
||||||
# 統一使用 time.time()
|
else:
|
||||||
|
# 默認消息
|
||||||
|
default_messages = {
|
||||||
|
SessionStatus.FEEDBACK_SUBMITTED: "用戶已提交反饋",
|
||||||
|
SessionStatus.COMPLETED: "會話已完成"
|
||||||
|
}
|
||||||
|
self.status_message = default_messages.get(next_status, "狀態已更新")
|
||||||
|
|
||||||
self.last_activity = time.time()
|
self.last_activity = time.time()
|
||||||
|
|
||||||
# 如果會話變為活躍狀態,重置清理定時器
|
# 如果會話變為已提交狀態,重置清理定時器
|
||||||
if status in [SessionStatus.ACTIVE, SessionStatus.FEEDBACK_SUBMITTED]:
|
if next_status == SessionStatus.FEEDBACK_SUBMITTED:
|
||||||
self._schedule_auto_cleanup()
|
self._schedule_auto_cleanup()
|
||||||
|
|
||||||
debug_log(
|
debug_log(
|
||||||
f"會話 {self.session_id} 狀態更新: {status.value} - {self.status_message}"
|
f"✅ 會話 {self.session_id} 狀態流轉: {old_status.value} → {next_status.value} - {self.status_message}"
|
||||||
)
|
)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def set_error(self, message: str = "會話發生錯誤") -> bool:
|
||||||
|
"""設置錯誤狀態(特殊方法,可從任何狀態進入)"""
|
||||||
|
old_status = self.status
|
||||||
|
self.status = SessionStatus.ERROR
|
||||||
|
self.status_message = message
|
||||||
|
self.last_activity = time.time()
|
||||||
|
|
||||||
|
debug_log(
|
||||||
|
f"❌ 會話 {self.session_id} 設置為錯誤狀態: {old_status.value} → {self.status.value} - {message}"
|
||||||
|
)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def set_expired(self, message: str = "會話已過期") -> bool:
|
||||||
|
"""設置過期狀態(特殊方法,可從任何狀態進入)"""
|
||||||
|
old_status = self.status
|
||||||
|
self.status = SessionStatus.EXPIRED
|
||||||
|
self.status_message = message
|
||||||
|
self.last_activity = time.time()
|
||||||
|
|
||||||
|
debug_log(
|
||||||
|
f"⏰ 會話 {self.session_id} 設置為過期狀態: {old_status.value} → {self.status.value} - {message}"
|
||||||
|
)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def can_proceed(self) -> bool:
|
||||||
|
"""檢查是否可以進入下一步"""
|
||||||
|
return self.status in [SessionStatus.WAITING, SessionStatus.FEEDBACK_SUBMITTED]
|
||||||
|
|
||||||
|
def is_terminal(self) -> bool:
|
||||||
|
"""檢查是否處於終態"""
|
||||||
|
return self.status in [SessionStatus.COMPLETED, SessionStatus.ERROR, SessionStatus.EXPIRED]
|
||||||
|
|
||||||
def get_status_info(self) -> dict[str, Any]:
|
def get_status_info(self) -> dict[str, Any]:
|
||||||
"""獲取會話狀態信息"""
|
"""獲取會話狀態信息"""
|
||||||
@ -404,10 +460,8 @@ class WebFeedbackSession:
|
|||||||
self.settings = settings or {}
|
self.settings = settings or {}
|
||||||
self.images = self._process_images(images)
|
self.images = self._process_images(images)
|
||||||
|
|
||||||
# 更新狀態為已提交反饋
|
# 進入下一步:等待中 → 已提交反饋
|
||||||
self.update_status(
|
self.next_step("已送出反饋,等待下次 MCP 調用")
|
||||||
SessionStatus.FEEDBACK_SUBMITTED, "已送出反饋,等待下次 MCP 調用"
|
|
||||||
)
|
|
||||||
|
|
||||||
self.feedback_completed.set()
|
self.feedback_completed.set()
|
||||||
|
|
||||||
|
@ -157,6 +157,41 @@ def setup_routes(manager: "WebUIManager"):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@manager.app.get("/api/all-sessions")
|
||||||
|
async def get_all_sessions():
|
||||||
|
"""獲取所有會話的實時狀態"""
|
||||||
|
try:
|
||||||
|
sessions_data = []
|
||||||
|
|
||||||
|
# 獲取所有會話的實時狀態
|
||||||
|
for session_id, session in manager.sessions.items():
|
||||||
|
session_info = {
|
||||||
|
"session_id": session.session_id,
|
||||||
|
"project_directory": session.project_directory,
|
||||||
|
"summary": session.summary,
|
||||||
|
"status": session.status.value,
|
||||||
|
"status_message": session.status_message,
|
||||||
|
"created_at": int(session.created_at * 1000), # 轉換為毫秒
|
||||||
|
"last_activity": int(session.last_activity * 1000),
|
||||||
|
"feedback_completed": session.feedback_completed.is_set(),
|
||||||
|
"has_websocket": session.websocket is not None,
|
||||||
|
"is_current": session == manager.current_session
|
||||||
|
}
|
||||||
|
sessions_data.append(session_info)
|
||||||
|
|
||||||
|
# 按創建時間排序(最新的在前)
|
||||||
|
sessions_data.sort(key=lambda x: x["created_at"], reverse=True)
|
||||||
|
|
||||||
|
debug_log(f"返回 {len(sessions_data)} 個會話的實時狀態")
|
||||||
|
return JSONResponse(content={"sessions": sessions_data})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
debug_log(f"獲取所有會話狀態失敗: {e}")
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=500,
|
||||||
|
content={"error": f"獲取會話狀態失敗: {e!s}"}
|
||||||
|
)
|
||||||
|
|
||||||
@manager.app.websocket("/ws")
|
@manager.app.websocket("/ws")
|
||||||
async def websocket_endpoint(websocket: WebSocket):
|
async def websocket_endpoint(websocket: WebSocket):
|
||||||
"""WebSocket 端點 - 重構後移除 session_id 依賴"""
|
"""WebSocket 端點 - 重構後移除 session_id 依賴"""
|
||||||
|
@ -686,7 +686,7 @@
|
|||||||
|
|
||||||
// 檢查是否是新會話創建的通知
|
// 檢查是否是新會話創建的通知
|
||||||
if (data.action === 'new_session_created') {
|
if (data.action === 'new_session_created') {
|
||||||
console.log('🆕 檢測到新會話創建,準備刷新頁面顯示新內容');
|
console.log('🆕 檢測到新會話創建,完全刷新頁面以確保狀態同步');
|
||||||
|
|
||||||
// 播放音效通知
|
// 播放音效通知
|
||||||
if (this.audioManager) {
|
if (this.audioManager) {
|
||||||
@ -699,9 +699,9 @@
|
|||||||
window.MCPFeedback.Utils.CONSTANTS.MESSAGE_SUCCESS
|
window.MCPFeedback.Utils.CONSTANTS.MESSAGE_SUCCESS
|
||||||
);
|
);
|
||||||
|
|
||||||
// 延遲一小段時間讓用戶看到通知,然後刷新頁面
|
// 延遲一小段時間讓用戶看到通知,然後完全刷新頁面
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
console.log('🔄 刷新頁面以顯示新會話內容');
|
console.log('🔄 完全刷新頁面以顯示新會話內容');
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
}, 1500);
|
}, 1500);
|
||||||
|
|
||||||
@ -831,7 +831,16 @@
|
|||||||
* 處理狀態更新(原始版本,供防抖使用)
|
* 處理狀態更新(原始版本,供防抖使用)
|
||||||
*/
|
*/
|
||||||
FeedbackApp.prototype._originalHandleStatusUpdate = function(statusInfo) {
|
FeedbackApp.prototype._originalHandleStatusUpdate = function(statusInfo) {
|
||||||
console.log('處理狀態更新:', statusInfo);
|
console.log('📊 處理狀態更新:', statusInfo);
|
||||||
|
|
||||||
|
const sessionId = statusInfo.session_id;
|
||||||
|
console.log('🔍 狀態更新詳情:', {
|
||||||
|
currentSessionId: this.currentSessionId,
|
||||||
|
newSessionId: sessionId,
|
||||||
|
status: statusInfo.status,
|
||||||
|
message: statusInfo.message,
|
||||||
|
isNewSession: sessionId !== this.currentSessionId
|
||||||
|
});
|
||||||
|
|
||||||
// 更新 SessionManager 的狀態資訊
|
// 更新 SessionManager 的狀態資訊
|
||||||
if (this.sessionManager && this.sessionManager.updateStatusInfo) {
|
if (this.sessionManager && this.sessionManager.updateStatusInfo) {
|
||||||
@ -844,43 +853,36 @@
|
|||||||
document.title = 'MCP Feedback - ' + projectName;
|
document.title = 'MCP Feedback - ' + projectName;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 提取會話 ID
|
// 使用之前已聲明的 sessionId
|
||||||
const sessionId = statusInfo.session_id || this.currentSessionId;
|
|
||||||
|
|
||||||
// 根據狀態更新 UI
|
// 前端只管理會話ID,所有狀態都從服務器獲取
|
||||||
|
console.log('📊 收到服務器狀態更新:', statusInfo.status, '會話ID:', sessionId);
|
||||||
|
|
||||||
|
// 更新當前會話ID
|
||||||
|
if (sessionId) {
|
||||||
|
this.currentSessionId = sessionId;
|
||||||
|
console.log('🔄 更新當前會話ID:', sessionId.substring(0, 8) + '...');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根據服務器狀態更新消息顯示(不修改前端狀態)
|
||||||
switch (statusInfo.status) {
|
switch (statusInfo.status) {
|
||||||
case 'feedback_submitted':
|
case 'feedback_submitted':
|
||||||
this.uiManager.setFeedbackState(window.MCPFeedback.Utils.CONSTANTS.FEEDBACK_SUBMITTED, sessionId);
|
|
||||||
const submittedMessage = window.i18nManager ? window.i18nManager.t('feedback.submittedWaiting') : '已送出反饋,等待下次 MCP 調用...';
|
const submittedMessage = window.i18nManager ? window.i18nManager.t('feedback.submittedWaiting') : '已送出反饋,等待下次 MCP 調用...';
|
||||||
this.updateSummaryStatus(submittedMessage);
|
this.updateSummaryStatus(submittedMessage);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'active':
|
|
||||||
case 'waiting':
|
case 'waiting':
|
||||||
// 檢查是否是新會話
|
const waitingMessage = window.i18nManager ? window.i18nManager.t('feedback.waitingForUser') : '等待用戶回饋...';
|
||||||
if (sessionId && sessionId !== this.currentSessionId) {
|
this.updateSummaryStatus(waitingMessage);
|
||||||
// 新會話:重置為等待狀態
|
|
||||||
this.uiManager.setFeedbackState(window.MCPFeedback.Utils.CONSTANTS.FEEDBACK_WAITING, sessionId);
|
|
||||||
} else {
|
|
||||||
// 同一會話:保護已提交狀態,避免被覆蓋
|
|
||||||
const currentState = this.uiManager.getFeedbackState();
|
|
||||||
if (currentState !== window.MCPFeedback.Utils.CONSTANTS.FEEDBACK_SUBMITTED) {
|
|
||||||
this.uiManager.setFeedbackState(window.MCPFeedback.Utils.CONSTANTS.FEEDBACK_WAITING, sessionId);
|
|
||||||
} else {
|
|
||||||
console.log('🔒 保護已提交狀態,不重置為等待狀態');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (statusInfo.status === 'waiting') {
|
// 檢查並啟動自動提交(如果條件滿足)
|
||||||
const waitingMessage = window.i18nManager ? window.i18nManager.t('feedback.waitingForUser') : '等待用戶回饋...';
|
const self = this;
|
||||||
this.updateSummaryStatus(waitingMessage);
|
setTimeout(function() {
|
||||||
|
self.checkAndStartAutoSubmit();
|
||||||
// 檢查並啟動自動提交(如果條件滿足)
|
}, 100);
|
||||||
const self = this;
|
break;
|
||||||
setTimeout(function() {
|
case 'completed':
|
||||||
self.checkAndStartAutoSubmit();
|
const completedMessage = window.i18nManager ? window.i18nManager.t('feedback.completed') : '會話已完成';
|
||||||
}, 100); // 短暫延遲確保狀態更新完成
|
this.updateSummaryStatus(completedMessage);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -923,10 +925,15 @@
|
|||||||
* 檢查是否可以提交回饋
|
* 檢查是否可以提交回饋
|
||||||
*/
|
*/
|
||||||
FeedbackApp.prototype.canSubmitFeedback = function() {
|
FeedbackApp.prototype.canSubmitFeedback = function() {
|
||||||
return this.webSocketManager &&
|
// 簡化檢查:只檢查WebSocket連接,狀態由服務器端驗證
|
||||||
this.webSocketManager.isReady() &&
|
const wsReady = this.webSocketManager && this.webSocketManager.isReady();
|
||||||
this.uiManager &&
|
|
||||||
this.uiManager.getFeedbackState() === window.MCPFeedback.Utils.CONSTANTS.FEEDBACK_WAITING;
|
console.log('🔍 提交檢查:', {
|
||||||
|
wsReady: wsReady,
|
||||||
|
sessionId: this.currentSessionId
|
||||||
|
});
|
||||||
|
|
||||||
|
return wsReady;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1203,14 +1210,9 @@
|
|||||||
FeedbackApp.prototype.handleSessionUpdate = function(sessionData) {
|
FeedbackApp.prototype.handleSessionUpdate = function(sessionData) {
|
||||||
console.log('🔄 處理自動檢測到的會話更新:', sessionData);
|
console.log('🔄 處理自動檢測到的會話更新:', sessionData);
|
||||||
|
|
||||||
// 更新當前會話 ID
|
// 只更新當前會話 ID,不管理狀態
|
||||||
this.currentSessionId = sessionData.session_id;
|
this.currentSessionId = sessionData.session_id;
|
||||||
|
|
||||||
// 重置回饋狀態
|
|
||||||
if (this.uiManager) {
|
|
||||||
this.uiManager.setFeedbackState(window.MCPFeedback.Utils.CONSTANTS.FEEDBACK_WAITING, sessionData.session_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 局部更新頁面內容
|
// 局部更新頁面內容
|
||||||
this.refreshPageContent();
|
this.refreshPageContent();
|
||||||
};
|
};
|
||||||
@ -1233,9 +1235,17 @@
|
|||||||
.then(function(sessionData) {
|
.then(function(sessionData) {
|
||||||
console.log('📥 獲取到最新會話資料:', sessionData);
|
console.log('📥 獲取到最新會話資料:', sessionData);
|
||||||
|
|
||||||
// 重置回饋狀態
|
// 檢查並保護已提交狀態
|
||||||
if (sessionData.session_id && self.uiManager) {
|
if (sessionData.session_id && self.uiManager) {
|
||||||
self.uiManager.setFeedbackState(window.MCPFeedback.Utils.CONSTANTS.FEEDBACK_WAITING, sessionData.session_id);
|
const currentState = self.uiManager.getFeedbackState();
|
||||||
|
if (currentState !== window.MCPFeedback.Utils.CONSTANTS.FEEDBACK_SUBMITTED) {
|
||||||
|
self.uiManager.setFeedbackState(window.MCPFeedback.Utils.CONSTANTS.FEEDBACK_WAITING, sessionData.session_id);
|
||||||
|
console.log('🔄 局部更新:重置回饋狀態為等待中');
|
||||||
|
} else {
|
||||||
|
console.log('🔒 局部更新:保護已提交狀態,不重置');
|
||||||
|
// 只更新會話ID,保持已提交狀態
|
||||||
|
self.uiManager.setFeedbackState(window.MCPFeedback.Utils.CONSTANTS.FEEDBACK_SUBMITTED, sessionData.session_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新 AI 摘要內容
|
// 更新 AI 摘要內容
|
||||||
|
@ -62,9 +62,13 @@
|
|||||||
if (this.currentSession && this.currentSession.session_id) {
|
if (this.currentSession && this.currentSession.session_id) {
|
||||||
console.log('📊 檢測到會話 ID 變更,處理舊會話:', this.currentSession.session_id, '->', sessionData.session_id);
|
console.log('📊 檢測到會話 ID 變更,處理舊會話:', this.currentSession.session_id, '->', sessionData.session_id);
|
||||||
|
|
||||||
// 將舊會話標記為完成並加入歷史記錄
|
// 將舊會話加入歷史記錄,保持其原有狀態
|
||||||
const oldSession = Object.assign({}, this.currentSession);
|
const oldSession = Object.assign({}, this.currentSession);
|
||||||
oldSession.status = 'completed';
|
|
||||||
|
// 完全保持舊會話的原有狀態,不做任何修改
|
||||||
|
// 讓服務器端負責狀態轉換,前端只負責顯示
|
||||||
|
console.log('📊 保持舊會話的原有狀態:', oldSession.status);
|
||||||
|
|
||||||
oldSession.completed_at = TimeUtils.getCurrentTimestamp();
|
oldSession.completed_at = TimeUtils.getCurrentTimestamp();
|
||||||
|
|
||||||
// 計算持續時間
|
// 計算持續時間
|
||||||
@ -589,23 +593,25 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 從伺服器載入會話歷史
|
* 從伺服器載入會話歷史(包含實時狀態)
|
||||||
*/
|
*/
|
||||||
SessionDataManager.prototype.loadFromServer = function() {
|
SessionDataManager.prototype.loadFromServer = function() {
|
||||||
const self = this;
|
const self = this;
|
||||||
|
|
||||||
fetch('/api/load-session-history')
|
// 首先嘗試獲取實時會話狀態
|
||||||
|
fetch('/api/all-sessions')
|
||||||
.then(function(response) {
|
.then(function(response) {
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
return response.json();
|
return response.json();
|
||||||
} else {
|
} else {
|
||||||
throw new Error('伺服器回應錯誤: ' + response.status);
|
throw new Error('獲取實時會話狀態失敗: ' + response.status);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then(function(data) {
|
.then(function(data) {
|
||||||
if (data && Array.isArray(data.sessions)) {
|
if (data && Array.isArray(data.sessions)) {
|
||||||
|
// 使用實時會話狀態
|
||||||
self.sessionHistory = data.sessions;
|
self.sessionHistory = data.sessions;
|
||||||
console.log('📊 從伺服器載入', self.sessionHistory.length, '個會話');
|
console.log('📊 從伺服器載入', self.sessionHistory.length, '個實時會話狀態');
|
||||||
|
|
||||||
// 載入完成後進行清理和統計更新
|
// 載入完成後進行清理和統計更新
|
||||||
self.cleanupExpiredSessions();
|
self.cleanupExpiredSessions();
|
||||||
@ -621,13 +627,53 @@
|
|||||||
self.onDataChanged();
|
self.onDataChanged();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.warn('📊 伺服器回應格式錯誤:', data);
|
console.warn('📊 實時會話狀態回應格式錯誤,回退到歷史文件');
|
||||||
self.sessionHistory = [];
|
self.loadFromHistoryFile();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function(error) {
|
||||||
|
console.warn('📊 獲取實時會話狀態失敗,回退到歷史文件:', error);
|
||||||
|
self.loadFromHistoryFile();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// 即使沒有資料也要更新統計
|
/**
|
||||||
|
* 從歷史文件載入會話數據(備用方案)
|
||||||
|
*/
|
||||||
|
SessionDataManager.prototype.loadFromHistoryFile = function() {
|
||||||
|
const self = this;
|
||||||
|
|
||||||
|
fetch('/api/load-session-history')
|
||||||
|
.then(function(response) {
|
||||||
|
if (response.ok) {
|
||||||
|
return response.json();
|
||||||
|
} else {
|
||||||
|
throw new Error('伺服器回應錯誤: ' + response.status);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(function(data) {
|
||||||
|
if (data && Array.isArray(data.sessions)) {
|
||||||
|
self.sessionHistory = data.sessions;
|
||||||
|
console.log('📊 從歷史文件載入', self.sessionHistory.length, '個會話');
|
||||||
|
|
||||||
|
// 載入完成後進行清理和統計更新
|
||||||
|
self.cleanupExpiredSessions();
|
||||||
|
self.updateStats();
|
||||||
|
|
||||||
|
// 觸發歷史記錄變更回調
|
||||||
|
if (self.onHistoryChange) {
|
||||||
|
self.onHistoryChange(self.sessionHistory);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 觸發資料變更回調
|
||||||
|
if (self.onDataChanged) {
|
||||||
|
self.onDataChanged();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.warn('📊 歷史文件回應格式錯誤:', data);
|
||||||
|
self.sessionHistory = [];
|
||||||
self.updateStats();
|
self.updateStats();
|
||||||
|
|
||||||
// 觸發歷史記錄變更回調(空列表)
|
|
||||||
if (self.onHistoryChange) {
|
if (self.onHistoryChange) {
|
||||||
self.onHistoryChange(self.sessionHistory);
|
self.onHistoryChange(self.sessionHistory);
|
||||||
}
|
}
|
||||||
@ -638,13 +684,10 @@
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(function(error) {
|
.catch(function(error) {
|
||||||
console.warn('📊 從伺服器載入會話歷史失敗:', error);
|
console.warn('📊 從歷史文件載入失敗:', error);
|
||||||
self.sessionHistory = [];
|
self.sessionHistory = [];
|
||||||
|
|
||||||
// 載入失敗時也要更新統計
|
|
||||||
self.updateStats();
|
self.updateStats();
|
||||||
|
|
||||||
// 觸發歷史記錄變更回調(空列表)
|
|
||||||
if (self.onHistoryChange) {
|
if (self.onHistoryChange) {
|
||||||
self.onHistoryChange(self.sessionHistory);
|
self.onHistoryChange(self.sessionHistory);
|
||||||
}
|
}
|
||||||
|
@ -486,9 +486,18 @@
|
|||||||
|
|
||||||
// 狀態徽章
|
// 狀態徽章
|
||||||
const statusContainer = DOMUtils.createElement('div', { className: 'session-status' });
|
const statusContainer = DOMUtils.createElement('div', { className: 'session-status' });
|
||||||
|
const statusText = StatusUtils.getStatusText(sessionData.status);
|
||||||
|
|
||||||
|
// 添加調試信息
|
||||||
|
console.log('🎨 會話狀態調試:', {
|
||||||
|
sessionId: sessionData.session_id ? sessionData.session_id.substring(0, 8) + '...' : 'unknown',
|
||||||
|
rawStatus: sessionData.status,
|
||||||
|
displayText: statusText
|
||||||
|
});
|
||||||
|
|
||||||
const statusBadge = DOMUtils.createElement('span', {
|
const statusBadge = DOMUtils.createElement('span', {
|
||||||
className: 'status-badge ' + (sessionData.status || 'waiting'),
|
className: 'status-badge ' + (sessionData.status || 'waiting'),
|
||||||
textContent: StatusUtils.getStatusText(sessionData.status)
|
textContent: statusText
|
||||||
});
|
});
|
||||||
|
|
||||||
statusContainer.appendChild(statusBadge);
|
statusContainer.appendChild(statusBadge);
|
||||||
|
@ -47,7 +47,7 @@
|
|||||||
'waiting_for_feedback': 'connectionMonitor.waiting',
|
'waiting_for_feedback': 'connectionMonitor.waiting',
|
||||||
'active': 'status.processing.title',
|
'active': 'status.processing.title',
|
||||||
'feedback_submitted': 'status.submitted.title',
|
'feedback_submitted': 'status.submitted.title',
|
||||||
'completed': 'status.submitted.title',
|
'completed': 'status.completed.title',
|
||||||
'timeout': 'session.timeout',
|
'timeout': 'session.timeout',
|
||||||
'error': 'status.error',
|
'error': 'status.error',
|
||||||
'expired': 'session.timeout',
|
'expired': 'session.timeout',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user