ngpt 2.7.2__py3-none-any.whl → 2.8.0__py3-none-any.whl
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.
- ngpt/__init__.py +12 -1
- ngpt/cli.py +276 -48
- ngpt/cli_config.py +247 -0
- {ngpt-2.7.2.dist-info → ngpt-2.8.0.dist-info}/METADATA +72 -4
- ngpt-2.8.0.dist-info/RECORD +10 -0
- ngpt-2.7.2.dist-info/RECORD +0 -9
- {ngpt-2.7.2.dist-info → ngpt-2.8.0.dist-info}/WHEEL +0 -0
- {ngpt-2.7.2.dist-info → ngpt-2.8.0.dist-info}/entry_points.txt +0 -0
- {ngpt-2.7.2.dist-info → ngpt-2.8.0.dist-info}/licenses/LICENSE +0 -0
ngpt/__init__.py
CHANGED
@@ -3,8 +3,19 @@ __version__ = get_version("ngpt")
|
|
3
3
|
|
4
4
|
from .client import NGPTClient
|
5
5
|
from .config import load_config, get_config_path, get_config_dir
|
6
|
+
from .cli_config import (
|
7
|
+
load_cli_config,
|
8
|
+
set_cli_config_option,
|
9
|
+
get_cli_config_option,
|
10
|
+
unset_cli_config_option,
|
11
|
+
apply_cli_config
|
12
|
+
)
|
6
13
|
|
7
|
-
__all__ = [
|
14
|
+
__all__ = [
|
15
|
+
"NGPTClient", "__version__", "load_config", "get_config_path", "get_config_dir",
|
16
|
+
"load_cli_config", "set_cli_config_option", "get_cli_config_option",
|
17
|
+
"unset_cli_config_option", "apply_cli_config"
|
18
|
+
]
|
8
19
|
|
9
20
|
# Import cli last to avoid circular imports
|
10
21
|
from .cli import main
|
ngpt/cli.py
CHANGED
@@ -3,6 +3,14 @@ import sys
|
|
3
3
|
import os
|
4
4
|
from .client import NGPTClient
|
5
5
|
from .config import load_config, get_config_path, load_configs, add_config_entry, remove_config_entry
|
6
|
+
from .cli_config import (
|
7
|
+
set_cli_config_option,
|
8
|
+
get_cli_config_option,
|
9
|
+
unset_cli_config_option,
|
10
|
+
apply_cli_config,
|
11
|
+
list_cli_config_options,
|
12
|
+
CLI_CONFIG_OPTIONS
|
13
|
+
)
|
6
14
|
from . import __version__
|
7
15
|
|
8
16
|
# Try to import markdown rendering libraries
|
@@ -844,6 +852,143 @@ def prettify_streaming_markdown(renderer='rich', is_interactive=False, header_te
|
|
844
852
|
print(f"{COLORS['yellow']}Error setting up Rich streaming display: {str(e)}{COLORS['reset']}")
|
845
853
|
return None, None
|
846
854
|
|
855
|
+
def show_cli_config_help():
|
856
|
+
"""Display help information about CLI configuration."""
|
857
|
+
print(f"\n{COLORS['green']}{COLORS['bold']}CLI Configuration Help:{COLORS['reset']}")
|
858
|
+
print(f" {COLORS['cyan']}Command syntax:{COLORS['reset']}")
|
859
|
+
print(f" {COLORS['yellow']}ngpt --cli-config set OPTION VALUE{COLORS['reset']} - Set a default value for OPTION")
|
860
|
+
print(f" {COLORS['yellow']}ngpt --cli-config get OPTION{COLORS['reset']} - Get the current value of OPTION")
|
861
|
+
print(f" {COLORS['yellow']}ngpt --cli-config get{COLORS['reset']} - Show all CLI configuration settings")
|
862
|
+
print(f" {COLORS['yellow']}ngpt --cli-config unset OPTION{COLORS['reset']} - Remove OPTION from configuration")
|
863
|
+
print(f" {COLORS['yellow']}ngpt --cli-config list{COLORS['reset']} - List all available options")
|
864
|
+
|
865
|
+
print(f"\n {COLORS['cyan']}Available options:{COLORS['reset']}")
|
866
|
+
|
867
|
+
# Group options by context
|
868
|
+
context_groups = {
|
869
|
+
"all": [],
|
870
|
+
"code": [],
|
871
|
+
"interactive": [],
|
872
|
+
"text": [],
|
873
|
+
"shell": []
|
874
|
+
}
|
875
|
+
|
876
|
+
for option, meta in CLI_CONFIG_OPTIONS.items():
|
877
|
+
for context in meta["context"]:
|
878
|
+
if context in context_groups:
|
879
|
+
if context == "all":
|
880
|
+
context_groups[context].append(option)
|
881
|
+
break
|
882
|
+
else:
|
883
|
+
context_groups[context].append(option)
|
884
|
+
|
885
|
+
# Print general options (available in all contexts)
|
886
|
+
print(f" {COLORS['yellow']}General options (all modes):{COLORS['reset']}")
|
887
|
+
for option in sorted(context_groups["all"]):
|
888
|
+
meta = CLI_CONFIG_OPTIONS[option]
|
889
|
+
default = f"(default: {meta['default']})" if meta['default'] is not None else ""
|
890
|
+
exclusive = f" [exclusive with: {', '.join(meta['exclusive'])}]" if "exclusive" in meta else ""
|
891
|
+
print(f" {COLORS['green']}{option}{COLORS['reset']} - {meta['type']} {default}{exclusive}")
|
892
|
+
|
893
|
+
# Print mode-specific options
|
894
|
+
for mode, options in [
|
895
|
+
("code", "Code generation mode"),
|
896
|
+
("interactive", "Interactive mode"),
|
897
|
+
("text", "Text mode"),
|
898
|
+
("shell", "Shell mode")
|
899
|
+
]:
|
900
|
+
if context_groups[mode]:
|
901
|
+
print(f"\n {COLORS['yellow']}Options for {options}:{COLORS['reset']}")
|
902
|
+
for option in sorted(context_groups[mode]):
|
903
|
+
# Skip if already listed in general options
|
904
|
+
if option in context_groups["all"]:
|
905
|
+
continue
|
906
|
+
meta = CLI_CONFIG_OPTIONS[option]
|
907
|
+
default = f"(default: {meta['default']})" if meta['default'] is not None else ""
|
908
|
+
exclusive = f" [exclusive with: {', '.join(meta['exclusive'])}]" if "exclusive" in meta else ""
|
909
|
+
print(f" {COLORS['green']}{option}{COLORS['reset']} - {meta['type']} {default}{exclusive}")
|
910
|
+
|
911
|
+
print(f"\n {COLORS['cyan']}Example usage:{COLORS['reset']}")
|
912
|
+
print(f" {COLORS['yellow']}ngpt --cli-config set language java{COLORS['reset']} - Set default language to java for code generation")
|
913
|
+
print(f" {COLORS['yellow']}ngpt --cli-config set temperature 0.9{COLORS['reset']} - Set default temperature to 0.9")
|
914
|
+
print(f" {COLORS['yellow']}ngpt --cli-config set no-stream true{COLORS['reset']} - Disable streaming by default")
|
915
|
+
print(f" {COLORS['yellow']}ngpt --cli-config unset language{COLORS['reset']} - Remove language setting")
|
916
|
+
|
917
|
+
print(f"\n {COLORS['cyan']}Notes:{COLORS['reset']}")
|
918
|
+
print(f" - CLI configuration is stored in {COLORS['yellow']}~/.config/ngpt/ngpt-cli.conf{COLORS['reset']} (or equivalent for your OS)")
|
919
|
+
print(f" - Settings are applied based on context (e.g., language only applies to code generation mode)")
|
920
|
+
print(f" - Command-line arguments always override CLI configuration")
|
921
|
+
print(f" - Some options are mutually exclusive and will not be applied together")
|
922
|
+
|
923
|
+
def handle_cli_config(action, option=None, value=None):
|
924
|
+
"""Handle CLI configuration commands."""
|
925
|
+
if action == "list":
|
926
|
+
# List all available options
|
927
|
+
print(f"{COLORS['green']}{COLORS['bold']}Available CLI configuration options:{COLORS['reset']}")
|
928
|
+
for option in list_cli_config_options():
|
929
|
+
meta = CLI_CONFIG_OPTIONS[option]
|
930
|
+
default = f"(default: {meta['default']})" if meta['default'] is not None else ""
|
931
|
+
contexts = ', '.join(meta['context'])
|
932
|
+
if "all" in meta['context']:
|
933
|
+
contexts = "all modes"
|
934
|
+
print(f" {COLORS['cyan']}{option}{COLORS['reset']} - {meta['type']} {default} - Available in: {contexts}")
|
935
|
+
return
|
936
|
+
|
937
|
+
if action == "get":
|
938
|
+
if option is None:
|
939
|
+
# Get all options
|
940
|
+
success, config = get_cli_config_option()
|
941
|
+
if success and config:
|
942
|
+
print(f"{COLORS['green']}{COLORS['bold']}Current CLI configuration:{COLORS['reset']}")
|
943
|
+
for opt, val in config.items():
|
944
|
+
if opt in CLI_CONFIG_OPTIONS:
|
945
|
+
print(f" {COLORS['cyan']}{opt}{COLORS['reset']} = {val}")
|
946
|
+
else:
|
947
|
+
print(f" {COLORS['yellow']}{opt}{COLORS['reset']} = {val} (unknown option)")
|
948
|
+
else:
|
949
|
+
print(f"{COLORS['yellow']}No CLI configuration set. Use 'ngpt --cli-config set OPTION VALUE' to set options.{COLORS['reset']}")
|
950
|
+
else:
|
951
|
+
# Get specific option
|
952
|
+
success, result = get_cli_config_option(option)
|
953
|
+
if success:
|
954
|
+
if result is None:
|
955
|
+
print(f"{COLORS['cyan']}{option}{COLORS['reset']} is not set (default: {CLI_CONFIG_OPTIONS.get(option, {}).get('default', 'N/A')})")
|
956
|
+
else:
|
957
|
+
print(f"{COLORS['cyan']}{option}{COLORS['reset']} = {result}")
|
958
|
+
else:
|
959
|
+
print(f"{COLORS['yellow']}{result}{COLORS['reset']}")
|
960
|
+
return
|
961
|
+
|
962
|
+
if action == "set":
|
963
|
+
if option is None or value is None:
|
964
|
+
print(f"{COLORS['yellow']}Error: Both OPTION and VALUE are required for 'set' command.{COLORS['reset']}")
|
965
|
+
print(f"Usage: ngpt --cli-config set OPTION VALUE")
|
966
|
+
return
|
967
|
+
|
968
|
+
success, message = set_cli_config_option(option, value)
|
969
|
+
if success:
|
970
|
+
print(f"{COLORS['green']}{message}{COLORS['reset']}")
|
971
|
+
else:
|
972
|
+
print(f"{COLORS['yellow']}{message}{COLORS['reset']}")
|
973
|
+
return
|
974
|
+
|
975
|
+
if action == "unset":
|
976
|
+
if option is None:
|
977
|
+
print(f"{COLORS['yellow']}Error: OPTION is required for 'unset' command.{COLORS['reset']}")
|
978
|
+
print(f"Usage: ngpt --cli-config unset OPTION")
|
979
|
+
return
|
980
|
+
|
981
|
+
success, message = unset_cli_config_option(option)
|
982
|
+
if success:
|
983
|
+
print(f"{COLORS['green']}{message}{COLORS['reset']}")
|
984
|
+
else:
|
985
|
+
print(f"{COLORS['yellow']}{message}{COLORS['reset']}")
|
986
|
+
return
|
987
|
+
|
988
|
+
# If we get here, the action is not recognized
|
989
|
+
print(f"{COLORS['yellow']}Error: Unknown action '{action}'. Use 'set', 'get', 'unset', or 'list'.{COLORS['reset']}")
|
990
|
+
show_cli_config_help()
|
991
|
+
|
847
992
|
def main():
|
848
993
|
# Colorize description - use a shorter description to avoid line wrapping issues
|
849
994
|
description = f"{COLORS['cyan']}{COLORS['bold']}nGPT{COLORS['reset']} - Interact with AI language models via OpenAI-compatible APIs"
|
@@ -921,8 +1066,30 @@ def main():
|
|
921
1066
|
# Prompt argument
|
922
1067
|
parser.add_argument('prompt', nargs='?', default=None, help='The prompt to send')
|
923
1068
|
|
1069
|
+
# Add CLI configuration command
|
1070
|
+
config_group.add_argument('--cli-config', nargs='*', metavar='COMMAND',
|
1071
|
+
help='Manage CLI configuration (set, get, unset, list)')
|
1072
|
+
|
924
1073
|
args = parser.parse_args()
|
925
1074
|
|
1075
|
+
# Handle CLI configuration command
|
1076
|
+
if args.cli_config is not None:
|
1077
|
+
# Show help if no arguments or "help" argument
|
1078
|
+
if len(args.cli_config) == 0 or (len(args.cli_config) > 0 and args.cli_config[0].lower() == "help"):
|
1079
|
+
show_cli_config_help()
|
1080
|
+
return
|
1081
|
+
|
1082
|
+
action = args.cli_config[0].lower()
|
1083
|
+
option = args.cli_config[1] if len(args.cli_config) > 1 else None
|
1084
|
+
value = args.cli_config[2] if len(args.cli_config) > 2 else None
|
1085
|
+
|
1086
|
+
if action in ("set", "get", "unset", "list"):
|
1087
|
+
handle_cli_config(action, option, value)
|
1088
|
+
return
|
1089
|
+
else:
|
1090
|
+
show_cli_config_help()
|
1091
|
+
return
|
1092
|
+
|
926
1093
|
# Validate --all usage
|
927
1094
|
if args.all and not args.show_config:
|
928
1095
|
parser.error("--all can only be used with --show-config")
|
@@ -932,8 +1099,28 @@ def main():
|
|
932
1099
|
show_available_renderers()
|
933
1100
|
return
|
934
1101
|
|
935
|
-
#
|
936
|
-
|
1102
|
+
# Load CLI configuration early
|
1103
|
+
from .cli_config import load_cli_config
|
1104
|
+
cli_config = load_cli_config()
|
1105
|
+
|
1106
|
+
# Priority order for config selection:
|
1107
|
+
# 1. Command-line arguments (args.provider, args.config_index)
|
1108
|
+
# 2. CLI configuration (cli_config["provider"], cli_config["config-index"])
|
1109
|
+
# 3. Default values (None, 0)
|
1110
|
+
|
1111
|
+
# Get provider/config-index from CLI config if not specified in args
|
1112
|
+
effective_provider = args.provider
|
1113
|
+
effective_config_index = args.config_index
|
1114
|
+
|
1115
|
+
# Only apply CLI config for provider/config-index if not explicitly set on command line
|
1116
|
+
if not effective_provider and 'provider' in cli_config and '--provider' not in sys.argv:
|
1117
|
+
effective_provider = cli_config['provider']
|
1118
|
+
|
1119
|
+
if effective_config_index == 0 and 'config-index' in cli_config and '--config-index' not in sys.argv:
|
1120
|
+
effective_config_index = cli_config['config-index']
|
1121
|
+
|
1122
|
+
# Check for mutual exclusivity between provider and config-index
|
1123
|
+
if effective_config_index != 0 and effective_provider:
|
937
1124
|
parser.error("--config-index and --provider cannot be used together")
|
938
1125
|
|
939
1126
|
# Handle interactive configuration mode
|
@@ -943,22 +1130,22 @@ def main():
|
|
943
1130
|
# Handle configuration removal if --remove flag is present
|
944
1131
|
if args.remove:
|
945
1132
|
# Validate that config_index is explicitly provided
|
946
|
-
if '--config-index' not in sys.argv and not
|
1133
|
+
if '--config-index' not in sys.argv and not effective_provider:
|
947
1134
|
parser.error("--remove requires explicitly specifying --config-index or --provider")
|
948
1135
|
|
949
1136
|
# Show config details before asking for confirmation
|
950
1137
|
configs = load_configs(str(config_path))
|
951
1138
|
|
952
1139
|
# Determine the config index to remove
|
953
|
-
config_index =
|
954
|
-
if
|
1140
|
+
config_index = effective_config_index
|
1141
|
+
if effective_provider:
|
955
1142
|
# Find config index by provider name
|
956
|
-
matching_configs = [i for i, cfg in enumerate(configs) if cfg.get('provider', '').lower() ==
|
1143
|
+
matching_configs = [i for i, cfg in enumerate(configs) if cfg.get('provider', '').lower() == effective_provider.lower()]
|
957
1144
|
if not matching_configs:
|
958
|
-
print(f"Error: No configuration found for provider '{
|
1145
|
+
print(f"Error: No configuration found for provider '{effective_provider}'")
|
959
1146
|
return
|
960
1147
|
elif len(matching_configs) > 1:
|
961
|
-
print(f"Multiple configurations found for provider '{
|
1148
|
+
print(f"Multiple configurations found for provider '{effective_provider}':")
|
962
1149
|
for i, idx in enumerate(matching_configs):
|
963
1150
|
print(f" [{i}] Index {idx}: {configs[idx].get('model', 'Unknown model')}")
|
964
1151
|
|
@@ -1008,15 +1195,15 @@ def main():
|
|
1008
1195
|
config_index = None
|
1009
1196
|
|
1010
1197
|
# Determine if we're editing an existing config or creating a new one
|
1011
|
-
if
|
1198
|
+
if effective_provider:
|
1012
1199
|
# Find config by provider name
|
1013
1200
|
configs = load_configs(str(config_path))
|
1014
|
-
matching_configs = [i for i, cfg in enumerate(configs) if cfg.get('provider', '').lower() ==
|
1201
|
+
matching_configs = [i for i, cfg in enumerate(configs) if cfg.get('provider', '').lower() == effective_provider.lower()]
|
1015
1202
|
|
1016
1203
|
if not matching_configs:
|
1017
|
-
print(f"No configuration found for provider '{
|
1204
|
+
print(f"No configuration found for provider '{effective_provider}'. Creating a new configuration.")
|
1018
1205
|
elif len(matching_configs) > 1:
|
1019
|
-
print(f"Multiple configurations found for provider '{
|
1206
|
+
print(f"Multiple configurations found for provider '{effective_provider}':")
|
1020
1207
|
for i, idx in enumerate(matching_configs):
|
1021
1208
|
print(f" [{i}] Index {idx}: {configs[idx].get('model', 'Unknown model')}")
|
1022
1209
|
|
@@ -1032,14 +1219,14 @@ def main():
|
|
1032
1219
|
config_index = matching_configs[0]
|
1033
1220
|
|
1034
1221
|
print(f"Editing existing configuration at index {config_index}")
|
1035
|
-
elif
|
1222
|
+
elif effective_config_index != 0 or '--config-index' in sys.argv:
|
1036
1223
|
# Check if the index is valid
|
1037
1224
|
configs = load_configs(str(config_path))
|
1038
|
-
if
|
1039
|
-
config_index =
|
1225
|
+
if effective_config_index >= 0 and effective_config_index < len(configs):
|
1226
|
+
config_index = effective_config_index
|
1040
1227
|
print(f"Editing existing configuration at index {config_index}")
|
1041
1228
|
else:
|
1042
|
-
print(f"Configuration index {
|
1229
|
+
print(f"Configuration index {effective_config_index} is out of range. Creating a new configuration.")
|
1043
1230
|
else:
|
1044
1231
|
# Creating a new config
|
1045
1232
|
configs = load_configs(str(config_path))
|
@@ -1048,12 +1235,10 @@ def main():
|
|
1048
1235
|
add_config_entry(config_path, config_index)
|
1049
1236
|
return
|
1050
1237
|
|
1051
|
-
# Load configuration using the
|
1052
|
-
active_config = load_config(args.config,
|
1238
|
+
# Load configuration using the effective provider/config-index
|
1239
|
+
active_config = load_config(args.config, effective_config_index, effective_provider)
|
1053
1240
|
|
1054
1241
|
# Command-line arguments override config settings for active config display
|
1055
|
-
# This part is kept to ensure the active config display reflects potential overrides,
|
1056
|
-
# even though the overrides don't affect the stored configurations displayed with --all.
|
1057
1242
|
if args.api_key:
|
1058
1243
|
active_config["api_key"] = args.api_key
|
1059
1244
|
if args.base_url:
|
@@ -1070,9 +1255,9 @@ def main():
|
|
1070
1255
|
print(f"Total configurations: {len(configs)}")
|
1071
1256
|
|
1072
1257
|
# Determine active configuration and display identifier
|
1073
|
-
active_identifier = f"index {
|
1074
|
-
if
|
1075
|
-
active_identifier = f"provider '{
|
1258
|
+
active_identifier = f"index {effective_config_index}"
|
1259
|
+
if effective_provider:
|
1260
|
+
active_identifier = f"provider '{effective_provider}'"
|
1076
1261
|
print(f"Active configuration: {active_identifier}")
|
1077
1262
|
|
1078
1263
|
if args.all:
|
@@ -1081,8 +1266,8 @@ def main():
|
|
1081
1266
|
for i, cfg in enumerate(configs):
|
1082
1267
|
provider = cfg.get('provider', 'N/A')
|
1083
1268
|
active_str = '(Active)' if (
|
1084
|
-
(
|
1085
|
-
(not
|
1269
|
+
(effective_provider and provider.lower() == effective_provider.lower()) or
|
1270
|
+
(not effective_provider and i == effective_config_index)
|
1086
1271
|
) else ''
|
1087
1272
|
print(f"\n--- Configuration Index {i} / Provider: {COLORS['green']}{provider}{COLORS['reset']} {active_str} ---")
|
1088
1273
|
print(f" API Key: {'[Set]' if cfg.get('api_key') else '[Not Set]'}")
|
@@ -1112,8 +1297,8 @@ def main():
|
|
1112
1297
|
provider_display = f"{provider} {COLORS['yellow']}(duplicate){COLORS['reset']}"
|
1113
1298
|
|
1114
1299
|
active_marker = "*" if (
|
1115
|
-
(
|
1116
|
-
(not
|
1300
|
+
(effective_provider and provider.lower() == effective_provider.lower()) or
|
1301
|
+
(not effective_provider and i == effective_config_index)
|
1117
1302
|
) else " "
|
1118
1303
|
print(f"[{i}]{active_marker} {COLORS['green']}{provider_display}{COLORS['reset']} - {cfg.get('model', 'N/A')} ({'[API Key Set]' if cfg.get('api_key') else '[API Key Not Set]'})")
|
1119
1304
|
|
@@ -1173,6 +1358,9 @@ def main():
|
|
1173
1358
|
|
1174
1359
|
# Handle modes
|
1175
1360
|
if args.interactive:
|
1361
|
+
# Apply CLI config for interactive mode
|
1362
|
+
args = apply_cli_config(args, "interactive")
|
1363
|
+
|
1176
1364
|
# Interactive chat mode
|
1177
1365
|
interactive_chat_session(
|
1178
1366
|
client,
|
@@ -1188,6 +1376,9 @@ def main():
|
|
1188
1376
|
stream_prettify=args.stream_prettify
|
1189
1377
|
)
|
1190
1378
|
elif args.shell:
|
1379
|
+
# Apply CLI config for shell mode
|
1380
|
+
args = apply_cli_config(args, "shell")
|
1381
|
+
|
1191
1382
|
if args.prompt is None:
|
1192
1383
|
try:
|
1193
1384
|
print("Enter shell command description: ", end='')
|
@@ -1226,6 +1417,9 @@ def main():
|
|
1226
1417
|
print(f"\nError:\n{e.stderr}")
|
1227
1418
|
|
1228
1419
|
elif args.code:
|
1420
|
+
# Apply CLI config for code mode
|
1421
|
+
args = apply_cli_config(args, "code")
|
1422
|
+
|
1229
1423
|
if args.prompt is None:
|
1230
1424
|
try:
|
1231
1425
|
print("Enter code description: ", end='')
|
@@ -1236,30 +1430,55 @@ def main():
|
|
1236
1430
|
else:
|
1237
1431
|
prompt = args.prompt
|
1238
1432
|
|
1239
|
-
# Setup for
|
1433
|
+
# Setup for streaming and prettify logic
|
1240
1434
|
stream_callback = None
|
1241
1435
|
live_display = None
|
1242
|
-
should_stream =
|
1243
|
-
|
1436
|
+
should_stream = True # Default to streaming
|
1437
|
+
use_stream_prettify = False
|
1438
|
+
use_regular_prettify = False
|
1439
|
+
|
1440
|
+
# Determine final behavior based on flag priority
|
1244
1441
|
if args.stream_prettify:
|
1245
|
-
|
1246
|
-
|
1247
|
-
|
1248
|
-
|
1249
|
-
|
1250
|
-
|
1251
|
-
|
1442
|
+
# Highest priority: stream-prettify
|
1443
|
+
if has_markdown_renderer('rich'):
|
1444
|
+
should_stream = True
|
1445
|
+
use_stream_prettify = True
|
1446
|
+
live_display, stream_callback = prettify_streaming_markdown(args.renderer)
|
1447
|
+
if not live_display:
|
1448
|
+
# Fallback if live display fails
|
1449
|
+
use_stream_prettify = False
|
1450
|
+
use_regular_prettify = True
|
1451
|
+
should_stream = False
|
1452
|
+
print(f"{COLORS['yellow']}Live display setup failed. Falling back to regular prettify mode.{COLORS['reset']}")
|
1453
|
+
else:
|
1454
|
+
# Rich not available for stream-prettify
|
1455
|
+
print(f"{COLORS['yellow']}Warning: Rich is not available for --stream-prettify. Install with: pip install \"ngpt[full]\".{COLORS['reset']}")
|
1456
|
+
print(f"{COLORS['yellow']}Falling back to default streaming without prettify.{COLORS['reset']}")
|
1457
|
+
should_stream = True
|
1458
|
+
use_stream_prettify = False
|
1459
|
+
elif args.no_stream:
|
1460
|
+
# Second priority: no-stream
|
1461
|
+
should_stream = False
|
1462
|
+
use_regular_prettify = False # No prettify if no streaming
|
1463
|
+
elif args.prettify:
|
1464
|
+
# Third priority: prettify (requires disabling stream)
|
1465
|
+
if has_markdown_renderer(args.renderer):
|
1252
1466
|
should_stream = False
|
1253
|
-
|
1254
|
-
|
1255
|
-
|
1256
|
-
|
1257
|
-
|
1467
|
+
use_regular_prettify = True
|
1468
|
+
print(f"{COLORS['yellow']}Note: Streaming disabled to enable regular markdown rendering (--prettify).{COLORS['reset']}")
|
1469
|
+
else:
|
1470
|
+
# Renderer not available for prettify
|
1471
|
+
print(f"{COLORS['yellow']}Warning: Renderer '{args.renderer}' not available for --prettify.{COLORS['reset']}")
|
1472
|
+
show_available_renderers()
|
1473
|
+
print(f"{COLORS['yellow']}Falling back to default streaming without prettify.{COLORS['reset']}")
|
1474
|
+
should_stream = True
|
1475
|
+
use_regular_prettify = False
|
1476
|
+
# else: Default is should_stream = True
|
1258
1477
|
|
1259
1478
|
print("\nGenerating code...")
|
1260
1479
|
|
1261
1480
|
# Start live display if using stream-prettify
|
1262
|
-
if
|
1481
|
+
if use_stream_prettify and live_display:
|
1263
1482
|
live_display.start()
|
1264
1483
|
|
1265
1484
|
generated_code = client.generate_code(
|
@@ -1269,23 +1488,29 @@ def main():
|
|
1269
1488
|
temperature=args.temperature,
|
1270
1489
|
top_p=args.top_p,
|
1271
1490
|
max_tokens=args.max_tokens,
|
1272
|
-
|
1491
|
+
# Request markdown from API if any prettify option is active
|
1492
|
+
markdown_format=use_regular_prettify or use_stream_prettify,
|
1273
1493
|
stream=should_stream,
|
1274
1494
|
stream_callback=stream_callback
|
1275
1495
|
)
|
1276
1496
|
|
1277
1497
|
# Stop live display if using stream-prettify
|
1278
|
-
if
|
1498
|
+
if use_stream_prettify and live_display:
|
1279
1499
|
live_display.stop()
|
1280
1500
|
|
1281
|
-
|
1282
|
-
|
1501
|
+
# Print non-streamed output if needed
|
1502
|
+
if generated_code and not should_stream:
|
1503
|
+
if use_regular_prettify:
|
1283
1504
|
print("\nGenerated code:")
|
1284
1505
|
prettify_markdown(generated_code, args.renderer)
|
1285
1506
|
else:
|
1507
|
+
# Should only happen if --no-stream was used without prettify
|
1286
1508
|
print(f"\nGenerated code:\n{generated_code}")
|
1287
|
-
|
1509
|
+
|
1288
1510
|
elif args.text:
|
1511
|
+
# Apply CLI config for text mode
|
1512
|
+
args = apply_cli_config(args, "text")
|
1513
|
+
|
1289
1514
|
if args.prompt is not None:
|
1290
1515
|
prompt = args.prompt
|
1291
1516
|
else:
|
@@ -1447,6 +1672,9 @@ def main():
|
|
1447
1672
|
|
1448
1673
|
else:
|
1449
1674
|
# Default to chat mode
|
1675
|
+
# Apply CLI config for default chat mode
|
1676
|
+
args = apply_cli_config(args, "all")
|
1677
|
+
|
1450
1678
|
if args.prompt is None:
|
1451
1679
|
try:
|
1452
1680
|
print("Enter your prompt: ", end='')
|
ngpt/cli_config.py
ADDED
@@ -0,0 +1,247 @@
|
|
1
|
+
import os
|
2
|
+
import sys
|
3
|
+
import json
|
4
|
+
from pathlib import Path
|
5
|
+
from typing import Dict, Optional, Any, List, Union, Tuple
|
6
|
+
|
7
|
+
# CLI config options with their types and default values
|
8
|
+
CLI_CONFIG_OPTIONS = {
|
9
|
+
"language": {"type": "str", "default": "python", "context": ["code"]},
|
10
|
+
"provider": {"type": "str", "default": None, "context": ["all"]},
|
11
|
+
"temperature": {"type": "float", "default": 0.7, "context": ["all"]},
|
12
|
+
"top_p": {"type": "float", "default": 1.0, "context": ["all"]},
|
13
|
+
"max_tokens": {"type": "int", "default": None, "context": ["all"]},
|
14
|
+
"log": {"type": "str", "default": None, "context": ["interactive", "text"]},
|
15
|
+
"preprompt": {"type": "str", "default": None, "context": ["all"]},
|
16
|
+
"no-stream": {"type": "bool", "default": False, "context": ["all"], "exclusive": ["prettify", "stream-prettify"]},
|
17
|
+
"prettify": {"type": "bool", "default": False, "context": ["all"], "exclusive": ["no-stream", "stream-prettify"]},
|
18
|
+
"stream-prettify": {"type": "bool", "default": False, "context": ["all"], "exclusive": ["no-stream", "prettify"]},
|
19
|
+
"renderer": {"type": "str", "default": "auto", "context": ["all"]},
|
20
|
+
"config-index": {"type": "int", "default": 0, "context": ["all"]},
|
21
|
+
"web-search": {"type": "bool", "default": False, "context": ["all"]},
|
22
|
+
}
|
23
|
+
|
24
|
+
def get_cli_config_dir() -> Path:
|
25
|
+
"""Get the appropriate CLI config directory based on OS."""
|
26
|
+
if sys.platform == "win32":
|
27
|
+
# Windows
|
28
|
+
config_dir = Path(os.environ.get("APPDATA", "")) / "ngpt"
|
29
|
+
elif sys.platform == "darwin":
|
30
|
+
# macOS
|
31
|
+
config_dir = Path.home() / "Library" / "Application Support" / "ngpt"
|
32
|
+
else:
|
33
|
+
# Linux and other Unix-like systems
|
34
|
+
xdg_config_home = os.environ.get("XDG_CONFIG_HOME")
|
35
|
+
if xdg_config_home:
|
36
|
+
config_dir = Path(xdg_config_home) / "ngpt"
|
37
|
+
else:
|
38
|
+
config_dir = Path.home() / ".config" / "ngpt"
|
39
|
+
|
40
|
+
# Ensure the directory exists
|
41
|
+
config_dir.mkdir(parents=True, exist_ok=True)
|
42
|
+
return config_dir
|
43
|
+
|
44
|
+
def get_cli_config_path() -> Path:
|
45
|
+
"""Get the path to the CLI config file."""
|
46
|
+
return get_cli_config_dir() / "ngpt-cli.conf"
|
47
|
+
|
48
|
+
def load_cli_config() -> Dict[str, Any]:
|
49
|
+
"""Load CLI configuration from the config file."""
|
50
|
+
config_path = get_cli_config_path()
|
51
|
+
|
52
|
+
# Default empty config
|
53
|
+
config = {}
|
54
|
+
|
55
|
+
# Load from config file if it exists
|
56
|
+
if config_path.exists():
|
57
|
+
try:
|
58
|
+
with open(config_path, "r") as f:
|
59
|
+
config = json.load(f)
|
60
|
+
except (json.JSONDecodeError, IOError) as e:
|
61
|
+
print(f"Warning: Could not read CLI config file: {e}", file=sys.stderr)
|
62
|
+
|
63
|
+
return config
|
64
|
+
|
65
|
+
def save_cli_config(config: Dict[str, Any]) -> bool:
|
66
|
+
"""Save CLI configuration to the config file."""
|
67
|
+
config_path = get_cli_config_path()
|
68
|
+
|
69
|
+
try:
|
70
|
+
with open(config_path, "w") as f:
|
71
|
+
json.dump(config, f, indent=2)
|
72
|
+
return True
|
73
|
+
except Exception as e:
|
74
|
+
print(f"Error saving CLI configuration: {e}", file=sys.stderr)
|
75
|
+
return False
|
76
|
+
|
77
|
+
def set_cli_config_option(option: str, value: Any) -> Tuple[bool, str]:
|
78
|
+
"""Set a CLI configuration option.
|
79
|
+
|
80
|
+
Args:
|
81
|
+
option: The name of the option to set
|
82
|
+
value: The value to set
|
83
|
+
|
84
|
+
Returns:
|
85
|
+
Tuple of (success, message)
|
86
|
+
"""
|
87
|
+
# Check if option is valid
|
88
|
+
if option not in CLI_CONFIG_OPTIONS:
|
89
|
+
return False, f"Error: Unknown option '{option}'"
|
90
|
+
|
91
|
+
# Load current config
|
92
|
+
config = load_cli_config()
|
93
|
+
|
94
|
+
# Parse and validate the value based on option type
|
95
|
+
option_type = CLI_CONFIG_OPTIONS[option]["type"]
|
96
|
+
|
97
|
+
try:
|
98
|
+
if option_type == "str":
|
99
|
+
parsed_value = str(value)
|
100
|
+
elif option_type == "int":
|
101
|
+
parsed_value = int(value)
|
102
|
+
elif option_type == "float":
|
103
|
+
parsed_value = float(value)
|
104
|
+
elif option_type == "bool":
|
105
|
+
if isinstance(value, bool):
|
106
|
+
parsed_value = value
|
107
|
+
elif value.lower() in ("true", "yes", "1", "t", "y"):
|
108
|
+
parsed_value = True
|
109
|
+
elif value.lower() in ("false", "no", "0", "f", "n"):
|
110
|
+
parsed_value = False
|
111
|
+
else:
|
112
|
+
return False, f"Error: Invalid boolean value '{value}' for option '{option}'"
|
113
|
+
else:
|
114
|
+
return False, f"Error: Unsupported option type '{option_type}'"
|
115
|
+
|
116
|
+
# Handle mutual exclusivity for boolean options
|
117
|
+
if option_type == "bool" and "exclusive" in CLI_CONFIG_OPTIONS[option]:
|
118
|
+
if parsed_value: # If setting this option to True
|
119
|
+
# Set all other exclusive options to False
|
120
|
+
for excl_option in CLI_CONFIG_OPTIONS[option]["exclusive"]:
|
121
|
+
config[excl_option] = False
|
122
|
+
# No special handling needed if setting to False, just update the value
|
123
|
+
|
124
|
+
# Set the value in the config
|
125
|
+
config[option] = parsed_value
|
126
|
+
|
127
|
+
# Save the config
|
128
|
+
if save_cli_config(config):
|
129
|
+
return True, f"Successfully set {option}={parsed_value}"
|
130
|
+
else:
|
131
|
+
return False, "Error saving configuration"
|
132
|
+
|
133
|
+
except (ValueError, TypeError) as e:
|
134
|
+
return False, f"Error: {str(e)}"
|
135
|
+
|
136
|
+
def get_cli_config_option(option: str = None) -> Tuple[bool, Union[str, Dict[str, Any]]]:
|
137
|
+
"""Get a CLI configuration option or all options.
|
138
|
+
|
139
|
+
Args:
|
140
|
+
option: The name of the option to get, or None for all options
|
141
|
+
|
142
|
+
Returns:
|
143
|
+
Tuple of (success, value/message)
|
144
|
+
"""
|
145
|
+
# Load current config
|
146
|
+
config = load_cli_config()
|
147
|
+
|
148
|
+
# Return all options if no specific option requested
|
149
|
+
if option is None:
|
150
|
+
return True, config
|
151
|
+
|
152
|
+
# Check if option is valid
|
153
|
+
if option not in CLI_CONFIG_OPTIONS:
|
154
|
+
return False, f"Error: Unknown option '{option}'"
|
155
|
+
|
156
|
+
# Return the option value if set, otherwise the default
|
157
|
+
if option in config:
|
158
|
+
return True, config[option]
|
159
|
+
else:
|
160
|
+
return True, CLI_CONFIG_OPTIONS[option]["default"]
|
161
|
+
|
162
|
+
def unset_cli_config_option(option: str) -> Tuple[bool, str]:
|
163
|
+
"""Unset a CLI configuration option.
|
164
|
+
|
165
|
+
Args:
|
166
|
+
option: The name of the option to unset
|
167
|
+
|
168
|
+
Returns:
|
169
|
+
Tuple of (success, message)
|
170
|
+
"""
|
171
|
+
# Check if option is valid
|
172
|
+
if option not in CLI_CONFIG_OPTIONS:
|
173
|
+
return False, f"Error: Unknown option '{option}'"
|
174
|
+
|
175
|
+
# Load current config
|
176
|
+
config = load_cli_config()
|
177
|
+
|
178
|
+
# Remove the option if it exists
|
179
|
+
if option in config:
|
180
|
+
del config[option]
|
181
|
+
|
182
|
+
# Save the config
|
183
|
+
if save_cli_config(config):
|
184
|
+
return True, f"Successfully unset {option}"
|
185
|
+
else:
|
186
|
+
return False, "Error saving configuration"
|
187
|
+
else:
|
188
|
+
return True, f"Note: Option '{option}' was not set"
|
189
|
+
|
190
|
+
def apply_cli_config(args: Any, mode: str) -> Any:
|
191
|
+
"""Apply CLI configuration to args object, respecting context and not overriding explicit args.
|
192
|
+
|
193
|
+
Args:
|
194
|
+
args: The argparse namespace object
|
195
|
+
mode: The current mode ('interactive', 'shell', 'code', 'text', or 'all' for default)
|
196
|
+
|
197
|
+
Returns:
|
198
|
+
Updated args object
|
199
|
+
"""
|
200
|
+
# Load CLI config
|
201
|
+
cli_config = load_cli_config()
|
202
|
+
|
203
|
+
# Get command-line arguments provided by the user
|
204
|
+
explicit_args = set(arg for arg in sys.argv[1:] if arg.startswith('--'))
|
205
|
+
|
206
|
+
# For each option in CLI config, check if it should be applied
|
207
|
+
for option, value in cli_config.items():
|
208
|
+
# Skip if not a valid option
|
209
|
+
if option not in CLI_CONFIG_OPTIONS:
|
210
|
+
continue
|
211
|
+
|
212
|
+
# Check context
|
213
|
+
option_context = CLI_CONFIG_OPTIONS[option]["context"]
|
214
|
+
if "all" not in option_context and mode not in option_context:
|
215
|
+
continue
|
216
|
+
|
217
|
+
# Convert dashes to underscores for argparse compatibility
|
218
|
+
arg_name = option.replace("-", "_")
|
219
|
+
|
220
|
+
# Skip if explicitly set via command line
|
221
|
+
# Check common variants like --option
|
222
|
+
cli_option = f"--{option}"
|
223
|
+
if cli_option in explicit_args:
|
224
|
+
continue
|
225
|
+
|
226
|
+
# Check exclusivity constraints against *explicitly set* args
|
227
|
+
# Don't apply a CLI config option if an exclusive option was explicitly set
|
228
|
+
if "exclusive" in CLI_CONFIG_OPTIONS[option]:
|
229
|
+
skip = False
|
230
|
+
for excl_option in CLI_CONFIG_OPTIONS[option]["exclusive"]:
|
231
|
+
excl_cli_option = f"--{excl_option}"
|
232
|
+
if excl_cli_option in explicit_args:
|
233
|
+
skip = True
|
234
|
+
break # Skip applying this CLI config value
|
235
|
+
if skip:
|
236
|
+
continue
|
237
|
+
|
238
|
+
# Apply the value from CLI config
|
239
|
+
# Ensure the attribute exists on args before setting
|
240
|
+
if hasattr(args, arg_name):
|
241
|
+
setattr(args, arg_name, value)
|
242
|
+
|
243
|
+
return args
|
244
|
+
|
245
|
+
def list_cli_config_options() -> List[str]:
|
246
|
+
"""List all available CLI configuration options."""
|
247
|
+
return sorted(CLI_CONFIG_OPTIONS.keys())
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: ngpt
|
3
|
-
Version: 2.
|
3
|
+
Version: 2.8.0
|
4
4
|
Summary: A lightweight Python CLI and library for interacting with OpenAI-compatible APIs, supporting both official and self-hosted LLM endpoints.
|
5
5
|
Project-URL: Homepage, https://github.com/nazdridoy/ngpt
|
6
6
|
Project-URL: Repository, https://github.com/nazdridoy/ngpt
|
@@ -54,6 +54,7 @@ A lightweight Python CLI and library for interacting with OpenAI-compatible APIs
|
|
54
54
|
- [Python Library](#as-a-library)
|
55
55
|
- [Configuration](#configuration)
|
56
56
|
- [Command Line Options](#command-line-options)
|
57
|
+
- [CLI Configuration](#cli-configuration)
|
57
58
|
- [Interactive Configuration](#interactive-configuration)
|
58
59
|
- [Configuration File](#configuration-file)
|
59
60
|
- [Configuration Priority](#configuration-priority)
|
@@ -315,6 +316,72 @@ You can configure the client using the following options:
|
|
315
316
|
|
316
317
|
For a complete reference of all available options, see the [CLI Usage Guide](https://nazdridoy.github.io/ngpt/usage/cli_usage.html).
|
317
318
|
|
319
|
+
### CLI Configuration
|
320
|
+
|
321
|
+
NGPT offers a CLI configuration system that allows you to set default values for command-line options:
|
322
|
+
|
323
|
+
```bash
|
324
|
+
# Set default options
|
325
|
+
ngpt --cli-config set language typescript
|
326
|
+
ngpt --cli-config set temperature 0.9
|
327
|
+
ngpt --cli-config set prettify true
|
328
|
+
|
329
|
+
# View current settings
|
330
|
+
ngpt --cli-config get
|
331
|
+
|
332
|
+
# Get a specific setting
|
333
|
+
ngpt --cli-config get language
|
334
|
+
|
335
|
+
# Remove a setting
|
336
|
+
ngpt --cli-config unset prettify
|
337
|
+
|
338
|
+
# List all available options
|
339
|
+
ngpt --cli-config list
|
340
|
+
|
341
|
+
# Show help information
|
342
|
+
ngpt --cli-config help
|
343
|
+
```
|
344
|
+
|
345
|
+
Key features of CLI configuration:
|
346
|
+
- **Context-Aware**: Settings are applied based on the current command mode (e.g., `language` only applies in code generation mode `-c`).
|
347
|
+
- **Priority**: When determining option values, NGPT uses the following priority order (highest to lowest):
|
348
|
+
1. Command-line arguments
|
349
|
+
2. Environment variables
|
350
|
+
3. CLI configuration (ngpt-cli.conf)
|
351
|
+
4. Main configuration file (ngpt.conf)
|
352
|
+
5. Default values
|
353
|
+
- **Mutual Exclusivity**: For options like `no-stream`, `prettify`, and `stream-prettify`, setting one to `True` automatically sets the others to `False` in the configuration file, ensuring consistency.
|
354
|
+
- **Smart Selection**: The `provider` setting is used to select which configuration profile to use, offering a persistent way to select your preferred API.
|
355
|
+
|
356
|
+
Available options include:
|
357
|
+
- General options (all modes): `provider`, `temperature`, `top_p`, `max_tokens`, `preprompt`, `renderer`, `config-index`, `web-search`
|
358
|
+
- Mode-specific options: `language` (code mode only), `log` (interactive and text modes)
|
359
|
+
- Mutually exclusive options: `no-stream`, `prettify`, `stream-prettify`
|
360
|
+
|
361
|
+
#### Practical Examples
|
362
|
+
|
363
|
+
```bash
|
364
|
+
# Set Gemini as your default provider
|
365
|
+
ngpt --cli-config set provider Gemini
|
366
|
+
# Now you can run commands without specifying --provider
|
367
|
+
ngpt "Explain quantum computing"
|
368
|
+
|
369
|
+
# Configure code generation for TypeScript
|
370
|
+
ngpt --cli-config set language typescript
|
371
|
+
# Now in code mode, TypeScript will be used by default
|
372
|
+
ngpt -c "Write a function to sort an array"
|
373
|
+
|
374
|
+
# Set a higher temperature for more creative responses
|
375
|
+
ngpt --cli-config set temperature 0.9
|
376
|
+
```
|
377
|
+
|
378
|
+
The CLI configuration is stored in:
|
379
|
+
- Linux: `~/.config/ngpt/ngpt-cli.conf`
|
380
|
+
- macOS: `~/Library/Application Support/ngpt/ngpt-cli.conf`
|
381
|
+
- Windows: `%APPDATA%\ngpt\ngpt-cli.conf`
|
382
|
+
|
383
|
+
For more details, see the [CLI Configuration Guide](https://nazdridoy.github.io/ngpt/usage/cli_config.html).
|
384
|
+
|
318
385
|
### Interactive Configuration
|
319
386
|
|
320
387
|
The `--config` option without arguments enters interactive configuration mode, allowing you to add or edit configurations:
|
@@ -387,10 +454,11 @@ For details on the configuration file format and structure, see the [Configurati
|
|
387
454
|
|
388
455
|
nGPT determines configuration values in the following order (highest priority first):
|
389
456
|
|
390
|
-
1. Command line arguments (`--api-key`, `--base-url`, `--model
|
457
|
+
1. Command line arguments (`--api-key`, `--base-url`, `--model`, etc.)
|
391
458
|
2. Environment variables (`OPENAI_API_KEY`, `OPENAI_BASE_URL`, `OPENAI_MODEL`)
|
392
|
-
3.
|
393
|
-
4.
|
459
|
+
3. CLI configuration file (`ngpt-cli.conf`, managed with `--cli-config`)
|
460
|
+
4. Main configuration file `ngpt.conf` or `custom-config-file`
|
461
|
+
5. Default values
|
394
462
|
|
395
463
|
## Contributing
|
396
464
|
|
@@ -0,0 +1,10 @@
|
|
1
|
+
ngpt/__init__.py,sha256=awvycdj3tgcOr0BO81L4XU6DOtnToxFqkPHe1Pyu0Bw,652
|
2
|
+
ngpt/cli.py,sha256=8E65ovaJE0OJ3-M6aw_FqCNSy_1-x1h4NwhnsZOlXq4,81580
|
3
|
+
ngpt/cli_config.py,sha256=LatikOJTtohbmCfXM6AH44qplbpyAD-x1kMkmaJHRS0,9046
|
4
|
+
ngpt/client.py,sha256=Rv-JO8RAmw1v3gdLkwaPe_PEw6p83cejO0YNT_DDjeg,15134
|
5
|
+
ngpt/config.py,sha256=WYOk_b1eiYjo6hpV3pfXr2RjqhOnmKqwZwKid1T41I4,10363
|
6
|
+
ngpt-2.8.0.dist-info/METADATA,sha256=g6KOwGut4qU6t1fbpsEaH1FPw6_PSDRRT3kZUGqO2ws,17993
|
7
|
+
ngpt-2.8.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
8
|
+
ngpt-2.8.0.dist-info/entry_points.txt,sha256=1cnAMujyy34DlOahrJg19lePSnb08bLbkUs_kVerqdk,39
|
9
|
+
ngpt-2.8.0.dist-info/licenses/LICENSE,sha256=mQkpWoADxbHqE0HRefYLJdm7OpdrXBr3vNv5bZ8w72M,1065
|
10
|
+
ngpt-2.8.0.dist-info/RECORD,,
|
ngpt-2.7.2.dist-info/RECORD
DELETED
@@ -1,9 +0,0 @@
|
|
1
|
-
ngpt/__init__.py,sha256=ehInP9w0MZlS1vZ1g6Cm4YE1ftmgF72CnEddQ3Le9n4,368
|
2
|
-
ngpt/cli.py,sha256=kdEgC4mOml4I3uX_w1SsCZUqlaccdyIQGtox3IjPhbs,70115
|
3
|
-
ngpt/client.py,sha256=Rv-JO8RAmw1v3gdLkwaPe_PEw6p83cejO0YNT_DDjeg,15134
|
4
|
-
ngpt/config.py,sha256=WYOk_b1eiYjo6hpV3pfXr2RjqhOnmKqwZwKid1T41I4,10363
|
5
|
-
ngpt-2.7.2.dist-info/METADATA,sha256=J1epGacDeo1w9bWUUqAQ8LvUI1I-rEtKIxm6TwRA-7U,15452
|
6
|
-
ngpt-2.7.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
7
|
-
ngpt-2.7.2.dist-info/entry_points.txt,sha256=1cnAMujyy34DlOahrJg19lePSnb08bLbkUs_kVerqdk,39
|
8
|
-
ngpt-2.7.2.dist-info/licenses/LICENSE,sha256=mQkpWoADxbHqE0HRefYLJdm7OpdrXBr3vNv5bZ8w72M,1065
|
9
|
-
ngpt-2.7.2.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|