duchaba commited on
Commit
668da17
·
verified ·
1 Parent(s): 8c49149

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +532 -0
app.py ADDED
@@ -0,0 +1,532 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # [BEGIN OF pluto_happy]
2
+ # required pip install
3
+ import pynvml # for GPU info
4
+ ## standard libs, no need to install
5
+ import numpy
6
+ import PIL
7
+ import pandas
8
+ import matplotlib
9
+ import torch
10
+ # standard libs (system)
11
+ import json
12
+ import time
13
+ import os
14
+ import random
15
+ import re
16
+ import sys
17
+ import psutil
18
+ import socket
19
+ import importlib.metadata
20
+ import types
21
+ import cpuinfo
22
+ import pathlib
23
+ import subprocess
24
+ # define class Pluto_Happy
25
+ class Pluto_Happy(object):
26
+ """
27
+ The Pluto projects starts with fun AI hackings and become a part of my
28
+ first book "Data Augmentation with Python" with Packt Publishing.
29
+
30
+ In particular, Pluto_Happy is a clean and lite kernel of a simple class,
31
+ and using @add_module decoractor to add in specific methods to be a new class,
32
+ such as Pluto_HFace with a lot more function on HuggingFace, LLM and Transformers.
33
+
34
+ Args:
35
+ name (str): the display name, e.g. "Hanna the seeker"
36
+
37
+ Returns:
38
+ (object): the class instance.
39
+ """
40
+
41
+ # initialize the object
42
+ def __init__(self, name="Pluto",*args, **kwargs):
43
+ super(Pluto_Happy, self).__init__(*args, **kwargs)
44
+ self.author = "Duc Haba"
45
+ self.name = name
46
+ self._ph()
47
+ self._pp("Hello from class", str(self.__class__) + " Class: " + str(self.__class__.__name__))
48
+ self._pp("Code name", self.name)
49
+ self._pp("Author is", self.author)
50
+ self._ph()
51
+ #
52
+ # define class var for stable division
53
+ self.fname_requirements = './pluto_happy/requirements.txt'
54
+ #
55
+ self.color_primary = '#2780e3' #blue
56
+ self.color_secondary = '#373a3c' #dark gray
57
+ self.color_success = '#3fb618' #green
58
+ self.color_info = '#9954bb' #purple
59
+ self.color_warning = '#ff7518' #orange
60
+ self.color_danger = '#ff0039' #red
61
+ self.color_mid_gray = '#495057'
62
+ self._xkeyfile = '.xoxo'
63
+ return
64
+ #
65
+ # pretty print output name-value line
66
+ def _pp(self, a, b,is_print=True):
67
+
68
+ """
69
+ Pretty print output name-value line
70
+
71
+ Args:
72
+ a (str) :
73
+ b (str) :
74
+ is_print (bool): whether to print the header or footer lines to console or return a str.
75
+
76
+ Returns:
77
+ y : None or output as (str)
78
+
79
+ """
80
+ # print("%34s : %s" % (str(a), str(b)))
81
+ x = f'{"%34s" % str(a)} : {str(b)}'
82
+ y = None
83
+ if (is_print):
84
+ print(x)
85
+ else:
86
+ y = x
87
+ return y
88
+ #
89
+ # pretty print the header or footer lines
90
+ def _ph(self,is_print=True):
91
+ """
92
+ Pretty prints the header or footer lines.
93
+
94
+ Args:
95
+ is_print (bool): whether to print the header or footer lines to console or return a str.
96
+
97
+ Return:
98
+ y : None or output as (str)
99
+
100
+ """
101
+ x = f'{"-"*34} : {"-"*34}'
102
+ y = None
103
+ if (is_print):
104
+ print(x)
105
+ else:
106
+ y = x
107
+ return y
108
+ #
109
+
110
+ # Define a function to display available CPU and RAM
111
+ def fetch_info_system(self, is_print=False):
112
+
113
+ """
114
+ Fetches system information, such as CPU usage and memory usage.
115
+
116
+ Args:
117
+ None.
118
+
119
+ Returns:
120
+ s: (str) A string containing the system information.
121
+ """
122
+
123
+ s=''
124
+ # Get CPU usage as a percentage
125
+ cpu_usage = psutil.cpu_percent()
126
+ # Get available memory in bytes
127
+ mem = psutil.virtual_memory()
128
+ # Convert bytes to gigabytes
129
+ mem_total_gb = mem.total / (1024 ** 3)
130
+ mem_available_gb = mem.available / (1024 ** 3)
131
+ mem_used_gb = mem.used / (1024 ** 3)
132
+ #
133
+ # print it nicely
134
+ # save the results
135
+ s += f"Total memory: {mem_total_gb:.2f} GB\n"
136
+ s += f"Available memory: {mem_available_gb:.2f} GB\n"
137
+ # print(f"Used memory: {mem_used_gb:.2f} GB")
138
+ s += f"Memory usage: {mem_used_gb/mem_total_gb:.2f}%\n"
139
+ try:
140
+ cpu_info = cpuinfo.get_cpu_info()
141
+ s += f'CPU type: {cpu_info["brand_raw"]}, arch: {cpu_info["arch"]}\n'
142
+ s += f'Number of CPU cores: {cpu_info["count"]}\n'
143
+ s += f"CPU usage: {cpu_usage}%\n"
144
+ s += f'Python version: {cpu_info["python_version"]}'
145
+ if (is_print is True):
146
+ self._ph()
147
+ self._pp("System", "Info")
148
+ self._ph()
149
+ self._pp("Total Memory", f"{mem_total_gb:.2f} GB")
150
+ self._pp("Available Memory", f"{mem_available_gb:.2f} GB")
151
+ self._pp("Memory Usage", f"{mem_used_gb/mem_total_gb:.2f}%")
152
+ self._pp("CPU Type", f'{cpu_info["brand_raw"]}, arch: {cpu_info["arch"]}')
153
+ self._pp("CPU Cores Count", f'{cpu_info["count"]}')
154
+ self._pp("CPU Usage", f"{cpu_usage}%")
155
+ self._pp("Python Version", f'{cpu_info["python_version"]}')
156
+ except Exception as e:
157
+ s += f'CPU type: Not accessible, Error: {e}'
158
+ if (is_print is True):
159
+ self._ph()
160
+ self._pp("CPU", f"*Warning* No CPU Access: {e}")
161
+ return s
162
+ #
163
+ # fetch GPU RAM info
164
+ def fetch_info_gpu(self, is_print=False):
165
+
166
+ """
167
+ Function to fetch GPU RAM info
168
+
169
+ Args:
170
+ None.
171
+
172
+ Returns:
173
+ s: (str) GPU RAM info in human readable format.
174
+ """
175
+
176
+ s=''
177
+ mtotal = 0
178
+ mfree = 0
179
+ try:
180
+ nvml_handle = pynvml.nvmlInit()
181
+ devices = pynvml.nvmlDeviceGetCount()
182
+ for i in range(devices):
183
+ device = pynvml.nvmlDeviceGetHandleByIndex(i)
184
+ memory_info = pynvml.nvmlDeviceGetMemoryInfo(device)
185
+ mtotal += memory_info.total
186
+ mfree += memory_info.free
187
+ mtotal = mtotal / 1024**3
188
+ mfree = mfree / 1024**3
189
+ # print(f"GPU {i}: Total Memory: {memory_info.total/1024**3} GB, Free Memory: {memory_info.free/1024**3} GB")
190
+ s += f'GPU type: {torch.cuda.get_device_name(0)}\n'
191
+ s += f'GPU ready staus: {torch.cuda.is_available()}\n'
192
+ s += f'Number of GPUs: {devices}\n'
193
+ s += f'Total Memory: {mtotal:.2f} GB\n'
194
+ s += f'Free Memory: {mfree:.2f} GB\n'
195
+ s += f'GPU allocated RAM: {round(torch.cuda.memory_allocated(0)/1024**3,2)} GB\n'
196
+ s += f'GPU reserved RAM {round(torch.cuda.memory_reserved(0)/1024**3,2)} GB\n'
197
+ if (is_print is True):
198
+ self._ph()
199
+ self._pp("GPU", "Info")
200
+ self._ph()
201
+ self._pp("GPU Type", f'{torch.cuda.get_device_name(0)}')
202
+ self._pp("GPU Ready Status", f'{torch.cuda.is_available()}')
203
+ self._pp("GPU Count", f'{devices}')
204
+ self._pp("GPU Total Memory", f'{mtotal:.2f} GB')
205
+ self._pp("GPU Free Memory", f'{mfree:.2f} GB')
206
+ self._pp("GPU allocated RAM", f'{round(torch.cuda.memory_allocated(0)/1024**3,2)} GB')
207
+ self._pp("GPU reserved RAM", f'{round(torch.cuda.memory_reserved(0)/1024**3,2)} GB')
208
+ except Exception as e:
209
+ s += f'**Warning, No GPU: {e}'
210
+ if (is_print is True):
211
+ self._ph()
212
+ self._pp("GPU", f"*Warning* No GPU: {e}")
213
+ return s
214
+ #
215
+ # fetch info about host ip
216
+ def fetch_info_host_ip(self, is_print=True):
217
+ """
218
+ Function to fetch current host name and ip address
219
+
220
+ Args:
221
+ None.
222
+
223
+ Returns:
224
+ s: (str) host name and ip info in human readable format.
225
+ """
226
+ s=''
227
+ try:
228
+ hostname = socket.gethostname()
229
+ ip_address = socket.gethostbyname(hostname)
230
+ s += f"Hostname: {hostname}\n"
231
+ s += f"IP Address: {ip_address}\n"
232
+ if (is_print is True):
233
+ self._ph()
234
+ self._pp('Host and Notebook', 'Info')
235
+ self._ph()
236
+ self._pp('Host Name', f"{hostname}")
237
+ self._pp("IP Address", f"{ip_address}")
238
+ try:
239
+ from jupyter_server import serverapp
240
+ self._pp("Jupyter Server", f'{serverapp.__version__}')
241
+ except ImportError:
242
+ self._pp("Jupyter Server", "Not accessible")
243
+ try:
244
+ import notebook
245
+ self._pp("Jupyter Notebook", f'{notebook.__version__}')
246
+ except ImportError:
247
+ self._pp("Jupyter Notebook ", "Not accessible")
248
+ except Exception as e:
249
+ s += f"**Warning, No hostname: {e}"
250
+ if (is_print is True):
251
+ self._ph()
252
+ self._pp('Host Name and Notebook', 'Not accessible')
253
+ return s
254
+ #
255
+ #
256
+ # fetch import libraries
257
+ def _fetch_lib_import(self):
258
+
259
+ """
260
+ This function fetches all the imported libraries that are installed.
261
+
262
+ Args:
263
+ None
264
+
265
+ Returns:
266
+ x (list):
267
+ list of strings containing the name of the imported libraries.
268
+ """
269
+
270
+ x = []
271
+ for name, val in globals().items():
272
+ if isinstance(val, types.ModuleType):
273
+ x.append(val.__name__)
274
+ x.sort()
275
+ return x
276
+ #
277
+ # fetch lib version
278
+ def _fetch_lib_version(self,lib_name):
279
+
280
+ """
281
+ This function fetches the version of the imported libraries.
282
+
283
+ Args:
284
+ lib_name (list):
285
+ list of strings containing the name of the imported libraries.
286
+
287
+ Returns:
288
+ val (list):
289
+ list of strings containing the version of the imported libraries.
290
+ """
291
+
292
+ val = []
293
+ for x in lib_name:
294
+ try:
295
+ y = importlib.metadata.version(x)
296
+ val.append(f'{x}=={y}')
297
+ except Exception as e:
298
+ val.append(f'|{x}==unknown_*or_system')
299
+ val.sort()
300
+ return val
301
+ #
302
+ # fetch the lib name and version
303
+ def fetch_info_lib_import(self):
304
+ """
305
+ This function fetches all the imported libraries name and version that are installed.
306
+
307
+ Args:
308
+ None
309
+
310
+ Returns:
311
+ x (list):
312
+ list of strings containing the name and version of the imported libraries.
313
+ """
314
+ x = self._fetch_lib_version(self._fetch_lib_import())
315
+ return x
316
+ #
317
+ # write a file to local or cloud diskspace
318
+ def write_file(self,fname, in_data):
319
+
320
+ """
321
+ Write a file to local or cloud diskspace or append to it if it already exists.
322
+
323
+ Args:
324
+ fname (str): The name of the file to write.
325
+ in_data (list): The
326
+
327
+ This is a utility function that writes a file to disk.
328
+ The file name and text to write are passed in as arguments.
329
+ The file is created, the text is written to it, and then the file is closed.
330
+
331
+ Args:
332
+ fname (str): The name of the file to write.
333
+ in_data (list): The text to write to the file.
334
+
335
+ Returns:
336
+ None
337
+ """
338
+
339
+ if os.path.isfile(fname):
340
+ f = open(fname, "a")
341
+ else:
342
+ f = open(fname, "w")
343
+ f.writelines("\n".join(in_data))
344
+ f.close()
345
+ return
346
+ #
347
+
348
+ def fetch_installed_libraries(self):
349
+ """
350
+ Retrieves and prints the names and versions of Python libraries installed by the user,
351
+ excluding the standard libraries.
352
+
353
+ Args:
354
+ -----
355
+ None
356
+
357
+ Returns:
358
+ --------
359
+ dictionary: (dict)
360
+ A dictionary where keys are the names of the libraries and values are their respective versions.
361
+
362
+ Examples:
363
+ ---------
364
+ libraries = get_installed_libraries()
365
+ for name, version in libraries.items():
366
+ print(f"{name}: {version}")
367
+ """
368
+ # List of standard libraries (this may not be exhaustive and might need updates based on the Python version)
369
+ # Run pip freeze command to get list of installed packages with their versions
370
+ result = subprocess.run(['pip', 'freeze'], stdout=subprocess.PIPE)
371
+
372
+ # Decode result and split by lines
373
+ packages = result.stdout.decode('utf-8').splitlines()
374
+
375
+ # Split each line by '==' to separate package names and versions
376
+ installed_libraries = {}
377
+ for package in packages:
378
+ try:
379
+ name, version = package.split('==')
380
+ installed_libraries[name] = version
381
+ except Exception as e:
382
+ #print(f'{package}: Error: {e}')
383
+ pass
384
+ return installed_libraries
385
+ #
386
+ #
387
+ def fetch_match_file_dict(self, file_path, reference_dict):
388
+ """
389
+ Reads a file from the disk, creates an array with each line as an item,
390
+ and checks if each line exists as a key in the provided dictionary. If it exists,
391
+ the associated value from the dictionary is also returned.
392
+
393
+ Parameters:
394
+ -----------
395
+ file_path: str
396
+ Path to the file to be read.
397
+ reference_dict: dict
398
+ Dictionary against which the file content (each line) will be checked.
399
+
400
+ Returns:
401
+ --------
402
+ dict:
403
+ A dictionary where keys are the lines from the file and values are either
404
+ the associated values from the reference dictionary or None if the key
405
+ doesn't exist in the dictionary.
406
+
407
+ Raises:
408
+ -------
409
+ FileNotFoundError:
410
+ If the provided file path does not exist.
411
+ """
412
+
413
+ if not os.path.exists(file_path):
414
+ raise FileNotFoundError(f"The file at {file_path} does not exist.")
415
+
416
+ with open(file_path, 'r') as file:
417
+ lines = file.readlines()
418
+
419
+ # Check if each line (stripped of whitespace and newline characters) exists in the reference dictionary.
420
+ # If it exists, fetch its value. Otherwise, set the value to None.
421
+ results = {line.strip(): reference_dict.get(line.strip().replace('_', '-'), None) for line in lines}
422
+
423
+ return results
424
+ # print fech_info about myself
425
+ def print_info_self(self):
426
+
427
+ """
428
+ Prints information about the model/myself.
429
+
430
+ Args:
431
+ None
432
+
433
+ Returns:
434
+ None
435
+ """
436
+ self._ph()
437
+ self._pp("Hello, I am", self.name)
438
+ self._pp("I will display", "Python, Jupyter, and system info.")
439
+ self._pp("Note", "For doc type: help(pluto) ...or help(your_object_name)")
440
+ self._pp("Let Rock and Roll", "¯\_(ツ)_/¯")
441
+ # system
442
+ x = self.fetch_info_system(is_print=True)
443
+ # print(x)
444
+ # self._ph()
445
+ # gpu
446
+ # self._pp('GPU', 'Info')
447
+ x = self.fetch_info_gpu(is_print=True)
448
+ # print(x)
449
+ self._ph()
450
+ # lib used
451
+ self._pp('Installed lib from', self.fname_requirements)
452
+ self._ph()
453
+ x = self.fetch_match_file_dict(self.fname_requirements, self.fetch_installed_libraries())
454
+ for item, value in x.items():
455
+ self._pp(f'{item} version', value)
456
+ #
457
+ self._ph()
458
+ self._pp('Standard lib from', 'System')
459
+ self._ph()
460
+ self._pp('matplotlib version', matplotlib.__version__)
461
+ self._pp('numpy version', numpy.__version__)
462
+ self._pp('pandas version',pandas.__version__)
463
+ self._pp('PIL version', PIL.__version__)
464
+ self._pp('torch version', torch.__version__)
465
+ #
466
+ self.print_ml_libraries()
467
+ # host ip
468
+ x = self.fetch_info_host_ip()
469
+ # print(x)
470
+ self._ph()
471
+ #
472
+ return
473
+ #
474
+ def print_ml_libraries(self):
475
+ """
476
+ Checks for the presence of Gradio, fastai, huggingface_hub, and transformers libraries.
477
+
478
+ Prints a message indicating whether each library is found or not.
479
+ If a library is not found, it prints an informative message specifying the missing library.
480
+ """
481
+ self._ph()
482
+ self._pp("ML Lib", "Info")
483
+ try:
484
+ import fastai
485
+ self._pp("fastai", f"{fastai.__version__}")
486
+ except ImportError:
487
+ self._pp("fastai", "*Warning* library not found.")
488
+ #
489
+ try:
490
+ import transformers
491
+ self._pp("transformers", f"{transformers.__version__}")
492
+ except ImportError:
493
+ self._pp("transformers", "*Warning* library not found.")
494
+ #
495
+ try:
496
+ import diffusers
497
+ self._pp("diffusers", f"{diffusers.__version__}")
498
+ except ImportError:
499
+ self._pp("diffusers", "*Warning* library not found.")
500
+ #
501
+ try:
502
+ import gradio
503
+ self._pp("gradio", f"{gradio.__version__}")
504
+ except ImportError:
505
+ self._pp("Gradio", "*Warning* library not found.")
506
+
507
+ try:
508
+ import huggingface_hub
509
+ self._pp("HuggingFace Hub", f"{huggingface_hub.__version__}")
510
+ except ImportError:
511
+ self._pp("huggingface_hub", "*Warning* library not found.")
512
+ return
513
+ #
514
+ # add module/method
515
+ #
516
+ import functools
517
+ def add_method(cls):
518
+ def decorator(func):
519
+ @functools.wraps(func)
520
+ def wrapper(*args, **kwargs):
521
+ return func(*args, **kwargs)
522
+ setattr(cls, func.__name__, wrapper)
523
+ return func # returning func means func can still be used normally
524
+ return decorator
525
+ #
526
+ # [END OF pluto_happy]
527
+ if __name__ == "__main__":
528
+ hanna = Pluto_Happy('Hanna, the explorer and ranger.')
529
+ hanna.fname_requirements = 'requirements.txt'
530
+ hanna.print_info_self()
531
+ #
532
+