Skip to content

Commit 08fd84d

Browse files
CopilotHeDaas-Code
andcommitted
Fix UI freeze and integrate unified logging with LogCategory
1. Reduced API timeouts to prevent UI freeze: - chat_completion: 60s → 30s - stream: 60s → 30s - embedding: 30s → 20s - Separate timeout exception handling 2. Integrated copilot with unified logging system: - Added LogCategory.API for API requests - Added LogCategory.CONFIG for configuration - Added LogCategory.IO for file operations - Added LogCategory.ERROR for error tracking - Added LogCategory.UI for UI operations - Added debug() calls for detailed tracing 3. Enhanced logging in all copilot modules: - siliconflow_client.py: API request/response logging - copilot_manager.py: Operation lifecycle logging - agent_mode.py: Task execution logging - copilot_panel.py: UI interaction logging The QThread architecture already separates API calls from main process, preventing blocking. Reduced timeouts prevent long hangs that appear as freezes. Co-authored-by: HeDaas-Code <208586641+HeDaas-Code@users.noreply.github.com>
1 parent 305b774 commit 08fd84d

4 files changed

Lines changed: 54 additions & 29 deletions

File tree

src/components/copilot_panel.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from PyQt5.QtGui import QTextCursor
1414
from qfluentwidgets import (PushButton, LineEdit, ComboBox, TextEdit,
1515
SubtitleLabel, BodyLabel)
16-
from src.utils.logger import info, warning, error
16+
from src.utils.logger import info, warning, error, debug, LogCategory
1717
from src.copilot.agent_mode import AgentTask
1818
from datetime import datetime
1919

@@ -329,7 +329,7 @@ def _show_audit_dialog(self, task_id: str):
329329
# Signal parent to handle audit with error handling
330330
parent = self.parent()
331331
if parent is None or not hasattr(parent, "audit_task") or not callable(getattr(parent, "audit_task")):
332-
warning(f"CopilotPanel parent has no 'audit_task' method; cannot audit task {task_id}")
332+
warning(f"CopilotPanel parent has no 'audit_task' method; cannot audit task {task_id}", category=LogCategory.UI)
333333
QMessageBox.warning(
334334
self,
335335
"审计失败",
@@ -339,7 +339,7 @@ def _show_audit_dialog(self, task_id: str):
339339
try:
340340
parent.audit_task(task_id, approved, comment)
341341
except Exception as e:
342-
error(f"Error while auditing task {task_id}: {e}")
342+
error(f"Error while auditing task {task_id}: {e}", category=LogCategory.ERROR)
343343
QMessageBox.critical(
344344
self,
345345
"审计错误",

src/copilot/agent_mode.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import json
1212
import os
1313
from .siliconflow_client import SiliconFlowClient
14-
from src.utils.logger import info, warning, error
14+
from src.utils.logger import info, warning, error, debug, LogCategory
1515
from src.utils.git_manager import GitManager
1616

1717

@@ -80,7 +80,7 @@ def create_task(self, description: str, task_type: str) -> str:
8080
task_id = f"task_{self.task_counter}_{datetime.now().strftime('%Y%m%d%H%M%S')}"
8181
task = AgentTask(task_id, description, task_type)
8282
self.tasks[task_id] = task
83-
info(f"Created agent task: {task_id}")
83+
info(f"Created agent task: {task_id}", category=LogCategory.API)
8484
return task_id
8585

8686
def execute_task(self, task_id: str, context: Dict = None):
@@ -280,12 +280,12 @@ def audit_task(self, task_id: str, approved: bool, comment: str = ""):
280280

281281
if approved:
282282
task.status = 'approved'
283-
info(f"Task {task_id} approved")
283+
info(f"Task {task_id} approved", category=LogCategory.API)
284284
# Apply changes if needed
285285
self._apply_task_changes(task)
286286
else:
287287
task.status = 'rejected'
288-
warning(f"Task {task_id} rejected: {comment}")
288+
warning(f"Task {task_id} rejected: {comment}", category=LogCategory.API)
289289

290290
self.status_changed.emit(f"Task {'approved' if approved else 'rejected'}")
291291

@@ -314,9 +314,9 @@ def _apply_task_changes(self, task: AgentTask):
314314
with open(file_path, 'w', encoding='utf-8') as f:
315315
f.write(content)
316316

317-
info(f"Applied changes to {file_path} for task {task.task_id}")
317+
info(f"Applied changes to {file_path} for task {task.task_id}", category=LogCategory.IO)
318318
except Exception as e:
319-
error(f"Failed to apply changes for task {task.task_id}: {str(e)}")
319+
error(f"Failed to apply changes for task {task.task_id}: {str(e)}", category=LogCategory.ERROR)
320320
elif task.task_type == 'commit':
321321
# Commit was already made during execution
322322
pass

src/copilot/copilot_manager.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from typing import Dict, List, Optional, Callable
99
from PyQt5.QtCore import QObject, pyqtSignal, QThread, Qt
1010
from .siliconflow_client import SiliconFlowClient
11-
from src.utils.logger import info, warning, error
11+
from src.utils.logger import info, warning, error, debug, LogCategory
1212
from src.utils.config_manager import ConfigManager
1313

1414
# Configuration constants
@@ -51,16 +51,16 @@ def _load_config(self):
5151

5252
if api_key:
5353
self.client = SiliconFlowClient(api_key, model)
54-
info("Copilot client initialized")
54+
info("Copilot client initialized", category=LogCategory.API)
5555
else:
56-
warning("Copilot API key not configured")
56+
warning("Copilot API key not configured", category=LogCategory.CONFIG)
5757
except Exception as e:
58-
error(f"Failed to load copilot config: {str(e)}")
58+
error(f"Failed to load copilot config: {str(e)}", category=LogCategory.CONFIG)
5959

6060
def reload_config(self):
6161
"""Public method to reload copilot configuration"""
6262
self._load_config()
63-
info("Copilot configuration reloaded")
63+
info("Copilot configuration reloaded", category=LogCategory.CONFIG)
6464

6565
def set_api_key(self, api_key: str, model: str = None):
6666
"""
@@ -79,7 +79,7 @@ def set_api_key(self, api_key: str, model: str = None):
7979
self.client = SiliconFlowClient(api_key, model)
8080
self.enabled = True
8181
self.config_manager.set_plugin_setting('copilot', 'enabled', True)
82-
info("Copilot API key updated")
82+
info("Copilot API key updated", category=LogCategory.CONFIG)
8383

8484
def is_enabled(self) -> bool:
8585
"""Check if copilot is enabled"""
@@ -89,7 +89,7 @@ def set_enabled(self, enabled: bool):
8989
"""Enable or disable copilot"""
9090
self.enabled = enabled
9191
self.config_manager.set_plugin_setting('copilot', 'enabled', enabled)
92-
info(f"Copilot {'enabled' if enabled else 'disabled'}")
92+
info(f"Copilot {'enabled' if enabled else 'disabled'}", category=LogCategory.CONFIG)
9393

9494
def get_inline_completion(
9595
self,
@@ -106,11 +106,12 @@ def get_inline_completion(
106106
callback: Optional callback function for completion
107107
"""
108108
if not self.is_enabled():
109-
warning("Copilot is not enabled")
109+
warning("Copilot is not enabled", category=LogCategory.API)
110110
return
111111

112112
self.current_mode = 'inline'
113113
self.status_changed.emit("Generating completion...")
114+
debug("Starting inline completion request", category=LogCategory.API)
114115

115116
# Create completion thread
116117
thread = CompletionThread(
@@ -228,6 +229,7 @@ def _on_completion_ready(self, completion: str):
228229
self.completion_ready.emit(completion)
229230
self.status_changed.emit("Completion ready")
230231
self.current_mode = 'none'
232+
info(f"Completion ready, length: {len(completion)}", category=LogCategory.API)
231233

232234
def _on_edit_ready(self, edited_text: str):
233235
"""Handle edit ready"""
@@ -251,7 +253,7 @@ def _on_error(self, error_msg: str):
251253
self.error_occurred.emit(error_msg)
252254
self.status_changed.emit("Error occurred")
253255
self.current_mode = 'none'
254-
error(f"Copilot error: {error_msg}")
256+
error(f"Copilot error: {error_msg}", category=LogCategory.API)
255257

256258
def _cleanup_thread(self, thread: QThread):
257259
"""Remove finished thread from active threads list"""

src/copilot/siliconflow_client.py

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import requests
99
import json
1010
from typing import List, Dict, Optional, Generator
11-
from src.utils.logger import info, warning, error
11+
from src.utils.logger import info, warning, error, debug, LogCategory
1212

1313
class SiliconFlowClient:
1414
"""Client for SiliconFlow API"""
@@ -36,6 +36,7 @@ def __init__(self, api_key: str, model: str = None):
3636
'Authorization': f'Bearer {api_key}',
3737
'Content-Type': 'application/json'
3838
}
39+
info(f"SiliconFlow client initialized with model: {self.model}", category=LogCategory.API)
3940

4041
def chat_completion(
4142
self,
@@ -58,7 +59,7 @@ def chat_completion(
5859
"""
5960
# Validate temperature
6061
if not 0 <= temperature <= 2:
61-
warning(f"Temperature {temperature} out of range [0, 2], clamping")
62+
warning(f"Temperature {temperature} out of range [0, 2], clamping", category=LogCategory.API)
6263
temperature = max(0, min(2, temperature))
6364

6465
url = f"{self.BASE_URL}/chat/completions"
@@ -70,15 +71,23 @@ def chat_completion(
7071
'stream': stream
7172
}
7273

74+
debug(f"Sending API request to {url} with {len(messages)} messages", category=LogCategory.API)
75+
7376
try:
7477
if stream:
7578
return self._stream_chat_completion(url, data)
7679
else:
77-
response = requests.post(url, headers=self.headers, json=data, timeout=60)
80+
# Use shorter timeout to prevent UI freeze
81+
response = requests.post(url, headers=self.headers, json=data, timeout=30)
7882
response.raise_for_status()
79-
return response.json()
83+
result = response.json()
84+
info(f"API request successful, response size: {len(str(result))} chars", category=LogCategory.API)
85+
return result
86+
except requests.exceptions.Timeout as e:
87+
error(f"SiliconFlow API timeout after 30s: {str(e)}", category=LogCategory.API)
88+
raise
8089
except requests.exceptions.RequestException as e:
81-
error(f"SiliconFlow API error: {str(e)}")
90+
error(f"SiliconFlow API error: {str(e)}", category=LogCategory.API)
8291
raise
8392

8493
def _stream_chat_completion(self, url: str, data: Dict) -> Generator:
@@ -92,13 +101,14 @@ def _stream_chat_completion(self, url: str, data: Dict) -> Generator:
92101
Yields:
93102
Chunks of response text
94103
"""
104+
debug("Starting streaming API request", category=LogCategory.API)
95105
try:
96106
response = requests.post(
97107
url,
98108
headers=self.headers,
99109
json=data,
100110
stream=True,
101-
timeout=60
111+
timeout=30
102112
)
103113
response.raise_for_status()
104114

@@ -108,6 +118,7 @@ def _stream_chat_completion(self, url: str, data: Dict) -> Generator:
108118
if line.startswith('data: '):
109119
data_str = line[6:]
110120
if data_str.strip() == '[DONE]':
121+
info("Streaming completed", category=LogCategory.API)
111122
break
112123
try:
113124
chunk = json.loads(data_str)
@@ -117,8 +128,11 @@ def _stream_chat_completion(self, url: str, data: Dict) -> Generator:
117128
yield delta['content']
118129
except json.JSONDecodeError:
119130
continue
131+
except requests.exceptions.Timeout as e:
132+
error(f"SiliconFlow streaming timeout after 30s: {str(e)}", category=LogCategory.API)
133+
raise
120134
except requests.exceptions.RequestException as e:
121-
error(f"SiliconFlow streaming error: {str(e)}")
135+
error(f"SiliconFlow streaming error: {str(e)}", category=LogCategory.API)
122136
raise
123137

124138
def text_completion(
@@ -177,16 +191,23 @@ def get_embedding(self, text: str) -> List[float]:
177191
'input': text
178192
}
179193

194+
debug(f"Requesting embedding for text length: {len(text)}", category=LogCategory.API)
195+
180196
try:
181-
response = requests.post(url, headers=self.headers, json=data, timeout=30)
197+
response = requests.post(url, headers=self.headers, json=data, timeout=20)
182198
response.raise_for_status()
183199
result = response.json()
184200

185201
if 'data' in result and len(result['data']) > 0:
186-
return result['data'][0]['embedding']
202+
embedding = result['data'][0]['embedding']
203+
info(f"Embedding received, dimension: {len(embedding)}", category=LogCategory.API)
204+
return embedding
187205
return []
206+
except requests.exceptions.Timeout as e:
207+
error(f"SiliconFlow embedding timeout after 20s: {str(e)}", category=LogCategory.API)
208+
raise
188209
except requests.exceptions.RequestException as e:
189-
error(f"SiliconFlow embedding error: {str(e)}")
210+
error(f"SiliconFlow embedding error: {str(e)}", category=LogCategory.API)
190211
raise
191212

192213
def test_connection(self) -> bool:
@@ -196,10 +217,12 @@ def test_connection(self) -> bool:
196217
Returns:
197218
True if connection successful, False otherwise
198219
"""
220+
debug("Testing API connection", category=LogCategory.API)
199221
try:
200222
messages = [{'role': 'user', 'content': 'Hello'}]
201223
self.chat_completion(messages, max_tokens=10)
224+
info("API connection test successful", category=LogCategory.API)
202225
return True
203226
except Exception as e:
204-
error(f"Connection test failed: {str(e)}")
227+
error(f"Connection test failed: {str(e)}", category=LogCategory.API)
205228
return False

0 commit comments

Comments
 (0)