I4-0-Client-CLI 20.0.0__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.
@@ -0,0 +1,455 @@
1
+ from I40Client import configuration as config
2
+ from I40Client import server_connection as server
3
+ from I40ClientUtils import chatbot_tools
4
+ import os
5
+ import sys
6
+ import json
7
+ import base64
8
+ import traceback
9
+ import asyncio
10
+
11
+ def main() -> None:
12
+ system = sys.platform
13
+ configFile = None
14
+ conversation = {"conv": [], "params_user": {}, "params_prompt": {
15
+ "tools": chatbot_tools.GetDefaultTools()
16
+ }}
17
+ conversationFile = None
18
+
19
+ if (
20
+ system != "win32" and
21
+ system != "darwin" and
22
+ system != "linux"
23
+ ):
24
+ raise OSError("Unsupported OS.")
25
+
26
+ if (system == "win32"):
27
+ homePath = os.environ["LOCALAPPDATA"] + "/I4.0-Client"
28
+ elif (system == "darwin"):
29
+ homePath = f"{os.path.expanduser('~')}/Library/Application Support/I4.0-Client"
30
+ elif (system == "linux"):
31
+ homePath = f"{os.path.expanduser('~')}/.local/share/I4.0-Client"
32
+
33
+ if (not os.path.exists(homePath)):
34
+ os.mkdir(homePath)
35
+
36
+ for arg in sys.argv:
37
+ if (arg.startswith("--config=")):
38
+ configFile = arg[9:]
39
+
40
+ if (not os.path.exists(configFile) or not os.path.isfile(configFile)):
41
+ configFile = None
42
+ elif (arg.startswith("--conv-file=")):
43
+ conversationFile = arg[12:]
44
+
45
+ if (os.path.exists(conversationFile) and os.path.isfile(conversationFile)):
46
+ with open(conversationFile, "r") as f:
47
+ conversation = json.loads(f.read())
48
+ else:
49
+ with open(conversationFile, "x") as f:
50
+ f.write(json.dumps(conversation, indent = 4))
51
+
52
+ if (configFile is None):
53
+ configFile = f"{homePath}/config.json"
54
+
55
+ if (not os.path.exists(configFile)):
56
+ conf = config.ClientConfiguration()
57
+
58
+ setattr(conf, "CLIENT_ConType", input("Connection type ('websocket'): "))
59
+ setattr(conf, "CLIENT_Host", input("Server to connect (Host): "))
60
+ setattr(conf, "CLIENT_Port", int(input("Server to connect (Port): ")))
61
+ setattr(conf, "CLIENT_Secure", bool(int(input("Server to connect (Secure) ('0', '1'): "))))
62
+ setattr(conf, "CLIENT_ModelName", input("Model name: "))
63
+ setattr(conf, "CLIENT_Scrape_FollowGuidelines", bool(int(input("Follow websites guidelines when scrapping? ('0', '1'): "))))
64
+
65
+ with open(configFile, "x") as f:
66
+ f.write(json.dumps(conf.ToDict(SavePublicKey = False), indent = 4))
67
+
68
+ conf = None
69
+
70
+ if (conversationFile is None):
71
+ conversationFile = f"{homePath}/conversation.json"
72
+
73
+ if (not os.path.exists(conversationFile)):
74
+ with open(conversationFile, "x") as f:
75
+ f.write(json.dumps(conversation, indent = 4))
76
+
77
+ with open(configFile, "r") as f:
78
+ conf = json.loads(f.read())
79
+
80
+ with open(conversationFile, "r") as f:
81
+ conversation = json.loads(f.read())
82
+
83
+ conf = config.ClientConfiguration.FromDict(conf)
84
+ chatbot_tools.internet.FollowScrapeGuidelines = getattr(conf, "CLIENT_Scrape_FollowGuidelines")
85
+
86
+ print(f"Got {len(conversation['conv'])} messages from the conversation.", flush = True)
87
+
88
+ async def __socket__() -> None:
89
+ async def __send__(AllowTools: bool = True, Service: str = "inference") -> None:
90
+ await socket.Connect(Host = getattr(conf, "CLIENT_Host"), Port = getattr(conf, "CLIENT_Port"), Secure = getattr(conf, "CLIENT_Secure"))
91
+
92
+ modelInfo = await socket.GetModelInfo(getattr(conf, "CLIENT_ModelName"))
93
+ modelMaxSimulUsers = modelInfo["max_simul_users"] if ("max_simul_users" in modelInfo) else 1
94
+ queueData = await socket.GetQueueData(getattr(conf, "CLIENT_ModelName"))
95
+
96
+ if (queueData["processing_users"] >= modelMaxSimulUsers):
97
+ usersBefore = queueData["processing_users"] + queueData["waiting_users"]
98
+ print(f"{usersBefore} users are using this model. You must wait until the queue of users is less than {modelMaxSimulUsers}.", flush = True)
99
+
100
+ gen = socket.AdvancedSendAndReceive(
101
+ ModelName = getattr(conf, "CLIENT_ModelName"),
102
+ Key = None,
103
+ PromptConversation = conversation["conv"],
104
+ PromptParameters = conversation["params_prompt"],
105
+ UserParameters = conversation["params_user"],
106
+ Service = Service
107
+ )
108
+ errors = 0
109
+ tools = []
110
+
111
+ async for token in gen:
112
+ if ("conversation_result" in token):
113
+ conversation["conv"] = token["conversation_result"]
114
+
115
+ if ("response" in token):
116
+ if ("text" in token["response"]):
117
+ print(token["response"]["text"], end = "", flush = True)
118
+
119
+ if ("files" in token["response"]):
120
+ for file in token["response"]["files"]:
121
+ if (file["type"] == "image"):
122
+ fileExtension = "webp"
123
+ elif (file["type"] == "audio"):
124
+ fileExtension = "wav"
125
+ elif (file["type"] == "video"):
126
+ fileExtension = "webm"
127
+ else:
128
+ fileExtension = file["type"]
129
+
130
+ fileData = base64.b64decode(file[file["type"]])
131
+ fileID = 0
132
+ fileName = f"./file_{fileID}.{fileExtension}"
133
+
134
+ while (os.path.exists(fileName)):
135
+ fileID += 1
136
+ fileName = f"./file_{fileID}.{fileExtension}"
137
+
138
+ with open(fileName, "wb") as f:
139
+ f.write(fileData)
140
+
141
+ print(f"\nFile saved at '{fileName}'.", flush = True)
142
+
143
+ if ("extra" in token["response"]):
144
+ if ("tools" in token["response"]["extra"]):
145
+ tools += token["response"]["extra"]["tools"]
146
+ token["response"]["extra"].pop("tools")
147
+
148
+ if ("thinking" in token["response"]["extra"]):
149
+ token["response"]["extra"].pop("thinking")
150
+
151
+ if (len(token["response"]["extra"]) > 0):
152
+ print(f"Received extra data: {token['response']['extra']}", flush = True)
153
+
154
+ if ("warnings" in token):
155
+ for warning in token["warnings"]:
156
+ print(f"\nWARNING: {warning}", flush = True)
157
+
158
+ if ("errors" in token):
159
+ for error in token["errors"]:
160
+ print(f"\nERROR: {error}", flush = True)
161
+
162
+ errors += len(token["errors"])
163
+
164
+ if (len(tools) > 0 and AllowTools and modelInfo["service"] == "chatbot"):
165
+ toolsResponse = []
166
+
167
+ for tool in tools:
168
+ toolName = tool["name"]
169
+ toolArgs = tool["arguments"]
170
+
171
+ try:
172
+ toolR = chatbot_tools.ExecuteTool(toolName, toolArgs, modelInfo["ctx"], "")
173
+
174
+ if (toolR is not None):
175
+ toolsResponse += toolR
176
+ except Exception as ex:
177
+ print(f"\nERROR: Error processing tool ({type(ex)}): {ex}", flush = True)
178
+ errors += 1
179
+
180
+ if (len(toolsResponse) > 0):
181
+ print("", flush = True)
182
+
183
+ conversation["conv"].append({
184
+ "role": "tool",
185
+ "content": toolsResponse
186
+ })
187
+ await __send__(False, Service)
188
+
189
+ return
190
+
191
+ print("", flush = True)
192
+
193
+ if (errors > 0):
194
+ confirm = input("Errors during inference. Save conversation anyway? [y/N] ").strip().lower() == "y"
195
+
196
+ if (not confirm):
197
+ await socket.Close()
198
+ return
199
+
200
+ with open(conversationFile, "w") as f:
201
+ f.write(json.dumps(conversation, indent = 4))
202
+
203
+ await socket.Close()
204
+
205
+ socket = server.ClientSocket(
206
+ Type = getattr(conf, "CLIENT_ConType"),
207
+ Configuration = conf
208
+ )
209
+
210
+ while (True):
211
+ try:
212
+ mode = input("Mode ['e', 'scc', 'cc', 'pp', 'up', 'sc', 'cls', 'cs', 'h', 'c'*]: ").lower()
213
+
214
+ if (mode == "e"):
215
+ break
216
+ elif (mode == "sc"):
217
+ for msg in conversation["conv"]:
218
+ msgContent = ""
219
+
220
+ for content in msg["content"]:
221
+ if (content["type"] == "text"):
222
+ msgContent += content["text"]
223
+ else:
224
+ msgContent += "--FILE DATA--"
225
+
226
+ print(f"Message #{conversation['conv'].index(msg)}:\nRole: {msg['role']}\nContent:\n```\n{msgContent}\n```\n", flush = True)
227
+
228
+ continue
229
+ elif (mode == "cls"):
230
+ CLEAR_CMDS = ["cls", "clear"]
231
+ exitCode = None
232
+
233
+ for c in CLEAR_CMDS:
234
+ exitCode = os.system(c)
235
+
236
+ if (exitCode == 0):
237
+ break
238
+
239
+ if (exitCode != 0):
240
+ print("Could not clear screen.", flush = True)
241
+
242
+ continue
243
+ elif (mode == "h"):
244
+ print((
245
+ "'e' - Exit - Closes the client.\n"
246
+ "'scc' - Selective Clear Conversation - Delete conversation messages selectively.\n"
247
+ "'cc' - Clear Conversation - Clear the whole conversation.\n"
248
+ "'pp' - Prompt Parameters - Change the prompt parameters.\n"
249
+ "'up' - User Parameters - Change the user parameters.\n"
250
+ "'sc' - Show Conversation - Show the current conversation.\n"
251
+ "'cls' - Clear screen.\n"
252
+ "'h' - Help - Show this help message.\n"
253
+ "'cs' - Custom Service - Run different services.\n"
254
+ "'c' - Continue - Continue with inference.\n\n"
255
+ "* - Default option."
256
+ ), flush = True)
257
+ continue
258
+ elif (mode == "scc"):
259
+ msgID = 0
260
+
261
+ while (msgID < len(conversation["conv"])):
262
+ msgContent = []
263
+
264
+ for content in conversation["conv"][msgID]["content"]:
265
+ cont = f" Type: {content['type']}\n Data: "
266
+
267
+ if (content["type"] == "text"):
268
+ cont += content["text"]
269
+ else:
270
+ cont += "--FILE DATA--"
271
+
272
+ msgContent.append(cont)
273
+
274
+ msgContent = "\n".join(msgContent)
275
+ print(f"Message #{msgID + 1}:\n Role: {conversation['conv'][msgID]['role']}\n Content:\n{msgContent}", flush = True)
276
+
277
+ confirm = input("Delete this message? [y/N] ").strip().lower() == "y"
278
+
279
+ if (confirm):
280
+ conversation["conv"].remove(conversation["conv"][msgID])
281
+ continue
282
+
283
+ msgID += 1
284
+
285
+ print("No more messages to delete.", flush = True)
286
+
287
+ with open(conversationFile, "w") as f:
288
+ f.write(json.dumps(conversation, indent = 4))
289
+
290
+ continue
291
+ elif (mode == "cc"):
292
+ confirm = input("WARNING!\nThis will delete ALL OF YOUR MESSAGES.\nContinue? [y/N] ").strip().lower() == "y"
293
+
294
+ if (not confirm):
295
+ continue
296
+
297
+ conversation["conv"].clear()
298
+
299
+ with open(conversationFile, "w") as f:
300
+ f.write(json.dumps(conversation, indent = 4))
301
+
302
+ continue
303
+ elif (mode == "pp"):
304
+ params = {}
305
+
306
+ while (True):
307
+ name = input("Prompt Parameter name (empty = continue): ")
308
+
309
+ if (len(name) == 0):
310
+ break
311
+
312
+ val = input("Prompt Parameter value (json:DATA, str:TEXT, int:INTEGER, float:FLOAT, bool:BOOLEAN): ")
313
+
314
+ if (val.lower().startswith("json:")):
315
+ val = json.loads(val[5:])
316
+ elif (val.lower().startswith("int:")):
317
+ val = int(val[4:])
318
+ elif (val.lower().startswith("float:")):
319
+ val = float(val[6:])
320
+ elif (val.lower().startswith("bool:")):
321
+ val = bool(val[5:])
322
+ elif (not val.lower().startswith("str:")):
323
+ print("Invalid value type. Try again.", flush = True)
324
+ continue
325
+
326
+ params[name] = val
327
+
328
+ conversation["params_prompt"] = params
329
+
330
+ with open(conversationFile, "w") as f:
331
+ f.write(json.dumps(conversation, indent = 4))
332
+
333
+ continue
334
+ elif (mode == "up"):
335
+ params = {}
336
+
337
+ while (True):
338
+ name = input("User Parameter name (empty = continue): ")
339
+
340
+ if (len(name) == 0):
341
+ break
342
+
343
+ val = input("User Parameter value (json:DATA, str:TEXT, int:INTEGER, float:FLOAT, bool:BOOLEAN): ")
344
+
345
+ if (val.lower().startswith("json:")):
346
+ val = json.loads(val[5:])
347
+ elif (val.lower().startswith("int:")):
348
+ val = int(val[4:])
349
+ elif (val.lower().startswith("float:")):
350
+ val = float(val[6:])
351
+ elif (val.lower().startswith("bool:")):
352
+ val = bool(val[5:])
353
+ elif (not val.lower().startswith("str:")):
354
+ print("Invalid value type. Try again.", flush = True)
355
+ continue
356
+
357
+ params[name] = val
358
+
359
+ conversation["params_user"] = params
360
+
361
+ with open(conversationFile, "w") as f:
362
+ f.write(json.dumps(conversation, indent = 4))
363
+
364
+ continue
365
+ elif (mode == "cs"):
366
+ service = input("Service: ")
367
+ elif (len(mode) > 0 and mode != "c"):
368
+ print("Invalid mode. Try again.")
369
+ continue
370
+ else:
371
+ service = "inference"
372
+
373
+ if (len(conversation["conv"]) > 0 and conversation["conv"][-1]["role"] == "user"):
374
+ confirm = input((
375
+ "The last message in the saved conversation is a user message.\n"
376
+ "Adding another user message to the conversation may result in unexpected behaviour.\n\n"
377
+ "Send current conversation? [Y/n] "
378
+ )).strip().lower() != "n"
379
+
380
+ if (confirm):
381
+ await __send__(Service = service)
382
+ continue
383
+
384
+ while (True):
385
+ msgRole = input(f"Message #{len(conversation['conv']) + 1} role (empty = continue): ")
386
+
387
+ if (len(msgRole) == 0):
388
+ break
389
+
390
+ msgContent = []
391
+
392
+ while (True):
393
+ content = {}
394
+ content["type"] = input(f"Message #{len(conversation['conv']) + 1} content #{len(msgContent) + 1} type (empty = continue): ")
395
+
396
+ if (len(content["type"]) == 0):
397
+ break
398
+ elif (content["type"] == "text"):
399
+ contTxt = ""
400
+
401
+ while (True):
402
+ contTxt += input("TEXT > ")
403
+
404
+ if (contTxt.endswith(" \\")):
405
+ contTxt = contTxt[:-2] + "\n"
406
+ continue
407
+ elif (contTxt.split("\n")[-1] == "\\"):
408
+ contTxt = contTxt[:-1] + "\n"
409
+ continue
410
+
411
+ break
412
+
413
+ content[content["type"]] = contTxt
414
+ else:
415
+ fp = input("FILE PATH > ")
416
+
417
+ if (not os.path.exists(fp)):
418
+ print("File does not exist. Try again.")
419
+ continue
420
+
421
+ with open(fp, "rb") as f:
422
+ content[content["type"]] = base64.b64encode(f.read()).decode("utf-8")
423
+
424
+ msgContent.append(content)
425
+
426
+ conversation["conv"].append({"role": msgRole, "content": msgContent})
427
+
428
+ await __send__(Service = service)
429
+
430
+ with open(conversationFile, "w") as f:
431
+ f.write(json.dumps(conversation, indent = 4))
432
+ except KeyboardInterrupt:
433
+ print("", flush = True)
434
+ continue
435
+ except Exception as ex:
436
+ print(f"Unexpected error (Type: {type(ex)}): {ex}", flush = True)
437
+ confirm = input("Ignore unexpected error? [Y/n/d] ").strip().lower()
438
+
439
+ if (confirm == "d"):
440
+ traceback.print_exception(ex)
441
+ confirm = input("Ignore unexpected error? [Y/n] ").strip().lower()
442
+
443
+ if (confirm == "n"):
444
+ break
445
+ finally:
446
+ await socket.Close()
447
+
448
+ await socket.Close()
449
+
450
+ asyncio.set_event_loop(asyncio.new_event_loop())
451
+ asyncio.get_event_loop().run_until_complete(__socket__())
452
+ asyncio.get_event_loop().close()
453
+
454
+ if (__name__ == "__main__"):
455
+ main()
@@ -0,0 +1,15 @@
1
+ Metadata-Version: 2.4
2
+ Name: I4_0-Client-CLI
3
+ Version: 20.0.0
4
+ Summary: Client-side CLI for I4.0.
5
+ Author: TAO71-AI
6
+ License: TAO71 I4.0 License (version 2)
7
+ Project-URL: Homepage, https://github.com/TAO71-AI/I4.0-NEW
8
+ Project-URL: Source, https://github.com/TAO71-AI/I4.0-NEW/tree/master/Client/CLI
9
+ Project-URL: License, https://github.com/TAO71-AI/I4.0-NEW/blob/master/LICENSE.md
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: License :: Other/Proprietary License
12
+ Classifier: Operating System :: OS Independent
13
+ Requires-Python: >=3.11
14
+ Requires-Dist: I4_0-Client-PY>=20.0.0
15
+ Requires-Dist: I4_0-Client-Utils>=20.0.0
@@ -0,0 +1,8 @@
1
+ pyproject.toml
2
+ I40ClientCLI/main.py
3
+ I4_0_Client_CLI.egg-info/PKG-INFO
4
+ I4_0_Client_CLI.egg-info/SOURCES.txt
5
+ I4_0_Client_CLI.egg-info/dependency_links.txt
6
+ I4_0_Client_CLI.egg-info/entry_points.txt
7
+ I4_0_Client_CLI.egg-info/requires.txt
8
+ I4_0_Client_CLI.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ I40C = I40ClientCLI.main:main
@@ -0,0 +1,2 @@
1
+ I4_0-Client-PY>=20.0.0
2
+ I4_0-Client-Utils>=20.0.0
@@ -0,0 +1 @@
1
+ I40ClientCLI
@@ -0,0 +1,15 @@
1
+ Metadata-Version: 2.4
2
+ Name: I4_0-Client-CLI
3
+ Version: 20.0.0
4
+ Summary: Client-side CLI for I4.0.
5
+ Author: TAO71-AI
6
+ License: TAO71 I4.0 License (version 2)
7
+ Project-URL: Homepage, https://github.com/TAO71-AI/I4.0-NEW
8
+ Project-URL: Source, https://github.com/TAO71-AI/I4.0-NEW/tree/master/Client/CLI
9
+ Project-URL: License, https://github.com/TAO71-AI/I4.0-NEW/blob/master/LICENSE.md
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: License :: Other/Proprietary License
12
+ Classifier: Operating System :: OS Independent
13
+ Requires-Python: >=3.11
14
+ Requires-Dist: I4_0-Client-PY>=20.0.0
15
+ Requires-Dist: I4_0-Client-Utils>=20.0.0
@@ -0,0 +1,31 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "I4_0-Client-CLI"
7
+ version = "20.0.0"
8
+ description = "Client-side CLI for I4.0."
9
+ authors = [{name = "TAO71-AI"}]
10
+ license = {text = "TAO71 I4.0 License (version 2)"}
11
+ requires-python = ">=3.11"
12
+ dependencies = [
13
+ "I4_0-Client-PY>=20.0.0",
14
+ "I4_0-Client-Utils>=20.0.0"
15
+ ]
16
+ classifiers = [
17
+ "Programming Language :: Python :: 3",
18
+ "License :: Other/Proprietary License",
19
+ "Operating System :: OS Independent"
20
+ ]
21
+
22
+ [project.urls]
23
+ Homepage = "https://github.com/TAO71-AI/I4.0-NEW"
24
+ Source = "https://github.com/TAO71-AI/I4.0-NEW/tree/master/Client/CLI"
25
+ License = "https://github.com/TAO71-AI/I4.0-NEW/blob/master/LICENSE.md"
26
+
27
+ [project.scripts]
28
+ I40C = "I40ClientCLI.main:main"
29
+
30
+ [tool.setuptools.packages.find]
31
+ include = ["I40ClientCLI", "I40ClientCLI.*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+