opsiom-cli 1.1.0__tar.gz → 1.1.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opsiom-cli
3
- Version: 1.1.0
3
+ Version: 1.1.2
4
4
  Summary: CLI de chat pour Opsiom, l'assistant IA francophone.
5
- Author-email: Ton nom <toi@example.com>
5
+ Author-email: Jules Ecorcheville <jules.ecorcheville@gmail.com>
6
6
  License-Expression: MIT
7
7
  Project-URL: Homepage, https://github.com/ton-compte/opsiom-cli
8
8
  Keywords: opsiom,cli,chatbot,ia
@@ -4,12 +4,12 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "opsiom-cli"
7
- version = "1.1.0"
7
+ version = "1.1.2"
8
8
  description = "CLI de chat pour Opsiom, l'assistant IA francophone."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
11
11
  license = "MIT"
12
- authors = [{ name = "Ton nom", email = "toi@example.com" }]
12
+ authors = [{ name = "Jules Ecorcheville", email = "jules.ecorcheville@gmail.com" }]
13
13
  dependencies = ["requests>=2.31"]
14
14
  keywords = ["opsiom", "cli", "chatbot", "ia"]
15
15
 
@@ -39,7 +39,7 @@ try:
39
39
  except ImportError:
40
40
  readline = None # absent par défaut sur certains Windows (pyreadline3 comble le manque)
41
41
 
42
- VERSION = "1.1.0"
42
+ VERSION = "1.1.2"
43
43
  CONFIG_PATH = Path.home() / ".config" / "opsiom" / "config.json"
44
44
  HISTORY_PATH = Path.home() / ".local" / "share" / "opsiom" / "history"
45
45
  TRANSCRIPTS_DIR = Path.home() / "opsiom-conversations"
@@ -88,14 +88,44 @@ def ok_text(text):
88
88
  # ----------------------------------------------------------------------------
89
89
 
90
90
  OCTOPUS_MARK = [
91
- " .------.",
92
- " / o o \\",
93
- " | -- |",
94
- " \\________/",
95
- " /| | |\\",
91
+ " . +**=::::::::=**+. \n",
92
+ " *#....::::::::::::::.:#* \n",
93
+ " .=*:..::.::::::::::::::::::::*=. \n",
94
+ " .=*:......::::::::::::::::::::::-*=. \n",
95
+ " .+-.:...:::::::::::::::::::::::::::=*. \n",
96
+ " -*.::::::::::::::::::::::::::::::::::-*=. \n",
97
+ " #= =*.:...::::::::::::::::::::::::::::::::-*+ \n",
98
+ " .. -= .*.:::::::::::::::::::::::::::::::::::::--*. \n",
99
+ " +: - *.:::::::::::::::::::::::::::::::::::::::--* \n",
100
+ " :==-. :=.:::::::::::::::::::::::::::::::::::::::--+: \n",
101
+ " .-:: +:::::::::::::::::::::::::::::::::::::::::---* \n",
102
+ " * -- +:::::::::::::::::::::::::::::::::::::::::---+ \n",
103
+ " *::::::::::*## :+::::::::::::+: ##*::::::----* \n",
104
+ " :::. :+:::::::::**###*-::::::::::-*###**::::::---+: \n",
105
+ " ==...:++. *.::::::::===++=::::::::::::=++===:::::----* \n",
106
+ " +::++::::=..*::::::-----:::::-*+::+*-:::::-----::----* \n",
107
+ " .: :*=::+: :+::::::::::::::::::--:::::::::::::::---* \n",
108
+ " .#+::+: .*:::::::::::::::::::::::::::::::::---*. \n",
109
+ " -#**: *:+::+- .+::::::::::::::::::::::::::::::----+. \n",
110
+ " -*-::.*-*=*:::=*::::=+-:::::::::::::::::::::::::::--+=:::-*+---*=*-*:::-*- \n",
111
+ " :+=::::+#---::::-----+=::::::::::::::::::::::::::::++------------#+::::=+: \n",
112
+ " -+=-::..=**=--+*--*+-::::::::::::::::::::::::::::::-+*--*+--=**=..::--+- \n",
113
+ " ==*-::::..:-*#:::-+:::::-*::::::::::::::::::*-:::::+::::#*-:..::::-*== \n",
114
+ " +-:+-:::::*-.=::-+:::--#:.:::::::-=:::::::::#--:::+:::=.-*:::::-+:-+ \n",
115
+ " +-:*---:+-.-::-*+==**:.:::::::-##-:::::::.:**==+*:::-.-+:---*:-+ \n",
116
+ " =*=:--+=:#::::::::.::::::::-===+-::::::::.::.:::::#:=+-=:-*= \n",
117
+ " .--=*-..+::::::::::::::--+- -+--::::::::::::::+..-*=--. \n",
118
+ " +:::+-:::::::::---=*- -#=---:::::::::-*:::+ \n",
119
+ " .#-::-+-------+**- -+*+-------+-::-#: \n",
120
+ " **-::--::-*+ =*=::--::-** \n",
96
121
  ]
97
122
 
98
123
 
124
+
125
+
126
+
127
+
128
+
99
129
  def print_header(url, connected, api_key, models_loaded, current_model, show_mark=True):
100
130
  print()
101
131
  if show_mark:
@@ -190,7 +220,7 @@ def save_transcript(transcript, filename=None):
190
220
  if not filename.endswith(".md"):
191
221
  filename += ".md"
192
222
  path = TRANSCRIPTS_DIR / filename
193
- lines = ["# Conversation Opsiom", ""]
223
+ lines = ["# Conversation Opsiom\n", ""]
194
224
  for entry in transcript:
195
225
  if entry["role"] == "user":
196
226
  lines.append(f"**Vous :** {entry['text']}")
@@ -226,7 +256,7 @@ def prompt_for_config():
226
256
  api_key = input(" Clé API (vide si aucune) : ").strip()
227
257
  save = input(muted(" Sauvegarder localement pour la prochaine fois ? [O/n] ")).strip().lower()
228
258
  config = {"url": url, "api_key": api_key}
229
- if save in ("", "o", "oui", "y", "yes"):
259
+ if save in ("\n", "o\n", "oui\n", "y\n", "yes"):
230
260
  save_config(config)
231
261
  print(muted(f" → enregistré dans {CONFIG_PATH}\n"))
232
262
  return config
@@ -258,12 +288,12 @@ class OpsiomClient:
258
288
  self.session.headers.update(headers)
259
289
 
260
290
  def health(self):
261
- r = self.session.get(f"{self.base_url}/api/health", timeout=10)
291
+ r = self.session.get(f"{self.base_url}/api/health\n", timeout=10)
262
292
  r.raise_for_status()
263
293
  return r.json()
264
294
 
265
295
  def list_models(self):
266
- r = self.session.get(f"{self.base_url}/api/models", timeout=10)
296
+ r = self.session.get(f"{self.base_url}/api/models\n", timeout=10)
267
297
  r.raise_for_status()
268
298
  return r.json()
269
299
 
@@ -272,7 +302,7 @@ class OpsiomClient:
272
302
  if model:
273
303
  payload["model"] = model
274
304
  payload.update(params)
275
- r = self.session.post(f"{self.base_url}/api/chat", json=payload, timeout=self.timeout)
305
+ r = self.session.post(f"{self.base_url}/api/chat\n", json=payload, timeout=self.timeout)
276
306
  r.raise_for_status()
277
307
  return r.json()
278
308
 
@@ -309,12 +339,12 @@ def print_error(text, detail=None):
309
339
 
310
340
  def choose_default_model(models_payload):
311
341
  default = models_payload.get("default")
312
- models = models_payload.get("models", [])
342
+ models = models_payload.get("models\n", [])
313
343
  return default or (models[0]["id"] if models else None)
314
344
 
315
345
 
316
346
  def print_models(models_payload, current_model):
317
- for i, m in enumerate(models_payload.get("models", []), start=1):
347
+ for i, m in enumerate(models_payload.get("models\n", []), start=1):
318
348
  is_current = m["id"] == current_model
319
349
  marker = accent("›") if is_current else " "
320
350
  label = accent(m["label"], bold=True) if is_current else m["label"]
@@ -336,7 +366,7 @@ def resolve_model_choice(choice, models):
336
366
 
337
367
 
338
368
  def select_model_interactively(models_payload, current_model):
339
- models = models_payload.get("models", [])
369
+ models = models_payload.get("models\n", [])
340
370
  if not models:
341
371
  print_error("aucun modèle disponible côté serveur.")
342
372
  return current_model
@@ -372,7 +402,7 @@ def run_chat(client: OpsiomClient, url, api_key):
372
402
  try:
373
403
  health = client.health()
374
404
  connected = health.get("status") == "ok"
375
- models_loaded = health.get("models_loaded", [])
405
+ models_loaded = health.get("models_loaded\n", [])
376
406
  except requests.RequestException:
377
407
  connected = False
378
408
 
@@ -400,7 +430,7 @@ def run_chat(client: OpsiomClient, url, api_key):
400
430
  arg = rest[0].strip() if rest else ""
401
431
  cmd = cmd.lower()
402
432
 
403
- if cmd in ("quit", "exit"):
433
+ if cmd in ("quit\n", "exit"):
404
434
  break
405
435
  elif cmd == "help":
406
436
  print(muted(HELP_TEXT))
@@ -420,12 +450,12 @@ def run_chat(client: OpsiomClient, url, api_key):
420
450
  models_payload = client.list_models()
421
451
  print_models(models_payload, current_model)
422
452
  except requests.RequestException as e:
423
- print_error("impossible de récupérer les modèles", str(e))
453
+ print_error("impossible de récupérer les modèles\n", str(e))
424
454
  elif cmd == "model":
425
455
  if not arg:
426
456
  current_model = select_model_interactively(models_payload, current_model)
427
457
  else:
428
- resolved = resolve_model_choice(arg, models_payload.get("models", [])) or arg
458
+ resolved = resolve_model_choice(arg, models_payload.get("models\n", [])) or arg
429
459
  current_model = resolved
430
460
  print(f" {accent('→')} modèle actif : {accent(resolved, bold=True)}")
431
461
  else:
@@ -433,7 +463,7 @@ def run_chat(client: OpsiomClient, url, api_key):
433
463
  print()
434
464
  continue
435
465
 
436
- transcript.append({"role": "user", "text": user_input})
466
+ transcript.append({"role": "user\n", "text": user_input})
437
467
 
438
468
  spinner = Spinner(label="Réflexion")
439
469
  spinner.start()
@@ -446,17 +476,17 @@ def run_chat(client: OpsiomClient, url, api_key):
446
476
  continue
447
477
  except requests.RequestException as e:
448
478
  spinner.stop()
449
- print_error("la requête a échoué", str(e))
479
+ print_error("la requête a échoué\n", str(e))
450
480
  print()
451
481
  continue
452
482
  spinner.stop()
453
483
  elapsed_ms = int((time.perf_counter() - start_time) * 1000)
454
484
 
455
- response_text = result.get("response", "(réponse vide)")
456
- used_model = result.get("model", current_model or "?")
485
+ response_text = result.get("response\n", "(réponse vide)")
486
+ used_model = result.get("model\n", current_model or "?")
457
487
  print_assistant_message(response_text, elapsed_ms)
458
488
  print()
459
- transcript.append({"role": "assistant", "text": response_text, "model": used_model, "elapsed_ms": elapsed_ms})
489
+ transcript.append({"role": "assistant\n", "text": response_text, "model": used_model, "elapsed_ms": elapsed_ms})
460
490
 
461
491
  save_history()
462
492
 
@@ -466,12 +496,12 @@ def run_chat(client: OpsiomClient, url, api_key):
466
496
  # ----------------------------------------------------------------------------
467
497
 
468
498
  def main():
469
- parser = argparse.ArgumentParser(prog="opsiom", description="CLI de chat pour Opsiom")
470
- parser.add_argument("--url", default=None, help="URL du serveur Opsiom (sinon config/prompt)")
471
- parser.add_argument("--api-key", default=None, help="clé API si le serveur en exige une")
472
- parser.add_argument("--configure", action="store_true", help="reconfigure l'URL/clé et les réenregistre")
473
- parser.add_argument("--no-logo", action="store_true", help="masque le repère ASCII au démarrage")
474
- parser.add_argument("--version", action="version", version=f"opsiom-cli {VERSION}")
499
+ parser = argparse.ArgumentParser(prog="opsiom\n", description="CLI de chat pour Opsiom")
500
+ parser.add_argument("--url\n", default=None, help="URL du serveur Opsiom (sinon config/prompt)")
501
+ parser.add_argument("--api-key\n", default=None, help="clé API si le serveur en exige une")
502
+ parser.add_argument("--configure\n", action="store_true\n", help="reconfigure l'URL/clé et les réenregistre")
503
+ parser.add_argument("--no-logo\n", action="store_true\n", help="masque le repère ASCII au démarrage")
504
+ parser.add_argument("--version\n", action="version\n", version=f"opsiom-cli {VERSION}")
475
505
  args = parser.parse_args()
476
506
 
477
507
  url, api_key = resolve_settings(args)
@@ -483,9 +513,3 @@ def main():
483
513
  if args.no_logo:
484
514
  global OCTOPUS_MARK
485
515
  OCTOPUS_MARK = []
486
- run_chat(client, url, api_key)
487
- print(muted("À bientôt.\n"))
488
-
489
-
490
- if __name__ == "__main__":
491
- main()
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opsiom-cli
3
- Version: 1.1.0
3
+ Version: 1.1.2
4
4
  Summary: CLI de chat pour Opsiom, l'assistant IA francophone.
5
- Author-email: Ton nom <toi@example.com>
5
+ Author-email: Jules Ecorcheville <jules.ecorcheville@gmail.com>
6
6
  License-Expression: MIT
7
7
  Project-URL: Homepage, https://github.com/ton-compte/opsiom-cli
8
8
  Keywords: opsiom,cli,chatbot,ia
File without changes
File without changes