1+ import open_taranis as T
2+
3+ import subprocess
4+ import sys
5+ import os
6+ import curses
7+
8+ argv = sys .argv
9+
10+ # ==============================
11+ # The TUI
12+ # ==============================
13+
14+ LOGO_ASCII = """
15+ ░ ░░░ ░░░ ░░░░ ░░░ ░░░ ░░ ░░░ ░░
16+ ▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒ ▒▒ ▒▒▒▒ ▒▒ ▒▒▒▒ ▒▒ ▒▒ ▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒▒▒
17+ ▓▓▓▓ ▓▓▓▓▓ ▓▓ ▓▓▓ ▓▓ ▓ ▓ ▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓
18+ ████ █████ ████ ██ ███ ███ ████ ██ ██ █████ ███████████ █
19+ ████ █████ ████ ██ ████ ██ ████ ██ ███ ██ ███ ██"""
20+
21+ # Contraintes minimales
22+ MIN_HEIGHT = 24
23+ MIN_WIDTH = 80
24+
25+ def run (stdscr ):
26+ # Configuration basique de curses
27+ curses .curs_set (1 ) # Curseur visible
28+ curses .start_color ()
29+ curses .use_default_colors ()
30+
31+ # Initialisation des paires de couleurs
32+ curses .init_pair (1 , curses .COLOR_RED , - 1 ) # Pour le logo
33+ curses .init_pair (2 , curses .COLOR_WHITE , - 1 ) # Pour le texte standard
34+ curses .init_pair (3 , curses .COLOR_YELLOW , - 1 )# Pour les erreurs
35+
36+ input_buffer = ""
37+ display_mode = "NONE" # États possibles : "NONE", "HELP", "API", etc.
38+
39+ while True :
40+ # Récupération dynamique des dimensions du terminal
41+ height , width = stdscr .getmaxyx ()
42+
43+ # Vérification des contraintes minimales
44+ if height < MIN_HEIGHT or width < MIN_WIDTH :
45+ stdscr .clear ()
46+ msg = f"Terminal too small: { width } x{ height } (min { MIN_WIDTH } x{ MIN_HEIGHT } )"
47+ y , x = height // 2 , max (0 , (width - len (msg )) // 2 )
48+ try :
49+ stdscr .addstr (y , x , msg , curses .color_pair (3 ) | curses .A_BOLD )
50+ stdscr .addstr (y + 1 , x , "Resize or press 'q' to quit" , curses .color_pair (2 ))
51+ except :
52+ pass
53+ stdscr .refresh ()
54+ if stdscr .getch () == ord ('q' ):
55+ break
56+ continue
57+
58+ # Nettoyage de l'écran pour le rafraîchissement
59+ stdscr .clear ()
60+
61+ # --- Calcul dynamique du Layout ---
62+
63+ # 1. Traitement du Logo (Haut Gauche)
64+ logo_lines = LOGO_ASCII .split ('\n ' )
65+ logo_height = len (logo_lines )
66+
67+ for i , line in enumerate (logo_lines ):
68+ if i < height - 2 :
69+ try :
70+ truncated = line [:width - 1 ]
71+ stdscr .addstr (i , 0 , truncated , curses .color_pair (1 ))
72+ except curses .error :
73+ pass
74+
75+ # 2. Zone de Contenu (Centre)
76+ content_start = logo_height + 1
77+ content_end = height - 3
78+
79+ # --- Affichage du contenu central selon le mode ---
80+ if display_mode == "HELP" :
81+ text = [
82+ "Commands :" ,
83+ "- /exit = quit the TUI" ,
84+ "- /help = show the command list" ,
85+ "- /show api = show registered API"
86+ ]
87+
88+ elif display_mode == "API" :
89+ text = [
90+ "APIs registered :" ,
91+ ("- [x]" if os .environ .get ('OPENROUTER_API' ) else "- [ ]" ) + " openrouter" ,
92+ ("- [x]" if os .environ .get ('HF_API' ) else "- [ ]" ) + " huggingface" ,
93+ ("- [x]" if os .environ .get ('VENICEAI_API' ) else "- [ ]" ) + " venice.ai" ,
94+ ("- [x]" if os .environ .get ('DEEPSEEK_API' ) else "- [ ]" ) + " deepseek.ai" ,
95+ ("- [x]" if os .environ .get ('XAI_API' ) else "- [ ]" ) + " x.ai" ,
96+ ("- [x]" if os .environ .get ('GROQ_API' ) else "- [ ]" ) + " groq" ,
97+ "" ,
98+ "To show the env var : /show more"
99+ ]
100+
101+ elif display_mode == 'MORE_API' :
102+ text = [
103+ "APIs registered :" ,
104+ "- openrouter = 'OPENROUTER_API'" ,
105+ "- huggingface = 'HF_API'" ,
106+ "- venice.ai = 'VENICEAI_API'" ,
107+ "- deepseek.ai = 'DEEPSEEK_API'" ,
108+ "- x.ai = 'XAI_API'" ,
109+ "- groq = 'GROQ_API'" ,
110+ ]
111+
112+ if display_mode != "NONE" :
113+ current_line = content_start
114+ for line in text :
115+ if current_line < content_end :
116+ try :
117+ stdscr .addstr (current_line , 0 , line , curses .color_pair (2 ))
118+ except :
119+ pass
120+ current_line += 1
121+
122+
123+ # 3. Footer / Invite de commande (Bas)
124+ sep_y = height - 2
125+ input_y = height - 1
126+
127+ separator = "-" * min (width - 1 , 60 )
128+ try :
129+ stdscr .addstr (sep_y , 0 , separator , curses .color_pair (2 ) | curses .A_DIM )
130+ except :
131+ pass
132+
133+ prompt = f"> { input_buffer } "
134+ display_prompt = prompt [:width - 1 ]
135+ try :
136+ stdscr .addstr (input_y , 0 , display_prompt , curses .color_pair (2 ))
137+ cursor_x = min (len (prompt ), width - 1 )
138+ stdscr .move (input_y , cursor_x )
139+ except :
140+ pass
141+
142+ stdscr .refresh ()
143+
144+ # --- Gestion des entrées clavier ---
145+ key = stdscr .getch ()
146+
147+ if key == curses .KEY_RESIZE :
148+ continue
149+
150+ elif key in (10 , 13 ): # Entrée
151+ command = input_buffer .strip ()
152+
153+ if command == "/exit" :
154+ break
155+
156+ elif command == "/help" :
157+ display_mode = "HELP"
158+
159+ elif command == "/show api" :
160+ display_mode = "API"
161+
162+ elif command == "/show more" and display_mode == "API" :
163+ display_mode = 'MORE_API'
164+
165+ else :
166+ # Commande invalide ou vide : on efface l'affichage central
167+ display_mode = None
168+
169+ input_buffer = ""
170+
171+ elif key in (127 , curses .KEY_BACKSPACE , ord ('\b ' )): # Backspace
172+ input_buffer = input_buffer [:- 1 ]
173+
174+ elif key == 27 : # Échap
175+ input_buffer = ""
176+
177+ elif 32 <= key <= 126 : # Caractères imprimables ASCII
178+ input_buffer += chr (key )
179+
180+ # ==============================
181+ # The args
182+ # ==============================
183+
184+ def main ():
185+ if len (argv ) == 1 or argv [1 ] == "help" :
186+ print (f"""=== open-taranis { T .__version__ } ===
187+
188+ help : Show this...
189+
190+ open : Open the TUI
191+
192+ update : upgrade the framework
193+ """ )
194+
195+ elif argv [1 ] == "open" :
196+ # Lancement de la boucle curses
197+ curses .wrapper (run )
198+
199+ elif argv [1 ] == "update" :
200+ print ("Updating open-taranis via pip..." )
201+ try :
202+ # On lance pip install -U sur le paquet actuel
203+ subprocess .check_call ([sys .executable , "-m" , "pip" , "install" , "-U" , "open-taranis" ])
204+ print ("Update successful." )
205+ except subprocess .CalledProcessError as e :
206+ print (f"Error during update: { e } " )
0 commit comments