2222import core .networking as net
2323from core import vendor
2424from core .mitm import MitmThread
25- from core .ollama_analyst import OllamaThread , fetch_ollama_models
25+ from core .llm_analyst import ( # pylint: disable=E0611
26+ ANTHROPIC_MODELS , AnthropicThread , OllamaThread , fetch_ollama_models
27+ )
2628from core .platform import get_os
2729from ui .ui_arpscan import Ui_DeviceDiscovery
2830
@@ -191,7 +193,7 @@ def __init__( # pylint: disable=too-many-arguments,too-many-positional-argument
191193 self .setCentralWidget (central_widget )
192194 self .resize (680 , 850 )
193195
194- self ._load_ollama_models ()
196+ self ._on_provider_changed ()
195197
196198 @Slot (bool )
197199 def _toggle_mitm (self , checked ):
@@ -247,8 +249,17 @@ def _build_packet_panel(self, layout: QVBoxLayout):
247249 )
248250 self ._user_context .returnPressed .connect (self ._analyse_packet )
249251
252+ # Provider selector
253+ self ._provider_combo = QComboBox ()
254+ self ._provider_combo .addItems (["Ollama (local)" , "Anthropic" ])
255+ self ._provider_combo .currentIndexChanged .connect (self ._on_provider_changed )
256+ provider_row = QHBoxLayout ()
257+ provider_row .addWidget (QLabel ("Provider:" ))
258+ provider_row .addWidget (self ._provider_combo , stretch = 1 )
259+
260+ # Model selector — contents change with provider
250261 self ._model_combo = QComboBox ()
251- self ._model_combo .setPlaceholderText ("Select Ollama model…" )
262+ self ._model_combo .setPlaceholderText ("Select model…" )
252263 self ._refresh_models_button = QPushButton ("↻" )
253264 self ._refresh_models_button .setFixedWidth (28 )
254265 self ._refresh_models_button .setToolTip ("Refresh available Ollama models" )
@@ -258,13 +269,37 @@ def _build_packet_panel(self, layout: QVBoxLayout):
258269 model_row .addWidget (self ._model_combo , stretch = 1 )
259270 model_row .addWidget (self ._refresh_models_button )
260271
272+ # Anthropic API key field (hidden when Ollama is selected)
273+ import os as _os # pylint: disable=import-outside-toplevel
274+ self ._api_key_edit = QLineEdit ()
275+ self ._api_key_edit .setPlaceholderText (
276+ "Anthropic API key (or set ANTHROPIC_API_KEY env var)"
277+ )
278+ self ._api_key_edit .setEchoMode (QLineEdit .EchoMode .Password )
279+ self ._api_key_edit .setText (_os .environ .get ("ANTHROPIC_API_KEY" , "" ))
280+ self ._api_key_edit .setVisible (False )
281+
261282 layout .addWidget (QLabel ("Captured packets:" ))
262283 layout .addWidget (pkt_splitter )
263284 layout .addWidget (QLabel ("Context:" ))
264285 layout .addWidget (self ._user_context )
286+ layout .addLayout (provider_row )
265287 layout .addLayout (model_row )
288+ layout .addWidget (self ._api_key_edit )
266289 layout .addWidget (self ._analyse_button )
267290
291+ def _on_provider_changed (self ):
292+ """Switch model list and API key visibility when the provider changes."""
293+ is_anthropic = self ._provider_combo .currentText () == "Anthropic"
294+ self ._api_key_edit .setVisible (is_anthropic )
295+ self ._refresh_models_button .setVisible (not is_anthropic )
296+ self ._model_combo .clear ()
297+ if is_anthropic :
298+ self ._model_combo .addItems (ANTHROPIC_MODELS )
299+ self ._model_combo .setEnabled (True )
300+ else :
301+ self ._load_ollama_models ()
302+
268303 def _load_ollama_models (self ):
269304 """Populate the model combo box with models available on the local Ollama server."""
270305 models = fetch_ollama_models ()
@@ -314,24 +349,35 @@ def _analyse_packet(self):
314349
315350 model = self ._model_combo .currentText ()
316351 if not model :
317- QMessageBox .warning (self , "No model" , "No Ollama model selected — click ↻ to refresh ." )
352+ QMessageBox .warning (self , "No model" , "No model selected." )
318353 return
319354
320355 pkt = self ._captured_packets [row ]
321356 pkt_text = _format_packet (pkt )
322357 user_context = self ._user_context .text ().strip ()
358+ is_anthropic = self ._provider_combo .currentText () == "Anthropic"
323359
324360 self ._llm_window = LlmAnalysisWindow (pkt .summary (), pkt_text , parent = self )
325361 self ._llm_window .set_analysing ()
326362 self ._llm_window .show ()
327363
328- self ._ollama_thread = OllamaThread (
329- pkt_text ,
330- model ,
331- user_context = user_context ,
332- device_vendor = self ._device_vendor ,
333- hostname = self ._hostname ,
334- )
364+ if is_anthropic :
365+ self ._ollama_thread = AnthropicThread (
366+ pkt_text ,
367+ model ,
368+ api_key = self ._api_key_edit .text ().strip (),
369+ user_context = user_context ,
370+ device_vendor = self ._device_vendor ,
371+ hostname = self ._hostname ,
372+ )
373+ else :
374+ self ._ollama_thread = OllamaThread (
375+ pkt_text ,
376+ model ,
377+ user_context = user_context ,
378+ device_vendor = self ._device_vendor ,
379+ hostname = self ._hostname ,
380+ )
335381 self ._ollama_thread .token .connect (self ._on_llm_token )
336382 self ._ollama_thread .error .connect (self ._on_llm_error )
337383 self ._ollama_thread .finished .connect (self ._on_llm_finished )
0 commit comments