微CLI工具箱-WeToolkit

2023-10-31

当需要将一个Python脚本快速提供给用户使用时,直接提供纯命令行指令给用户,不友好。如果开发可视化的GUI界面,又太废时间,而且无法在Linux服务器上使用,于是就整了这个微CLI工具箱-WeToolkit,解决这个问题。

微CLI工具箱-WeToolkit,是一个可以快速集成Python脚本到GUI界面上的小轮子,因为GUI部分是直接使用命令行绘制实现,所以可以实现跨平台执行(只要支持命令行就行),具体实现的效果如下图。

示例应用Windows
示例应用Linux
微CLI工具箱-WeToolkit的核心代码只有一个 we_toolkit.py 文件,依赖的第三方库有两个。

  • pip install prompt_toolkit
  • pip install pyinstaller
import logging
from prompt_toolkit.buffer import Buffer
from prompt_toolkit import Application, HTML
from prompt_toolkit.layout.layout import Layout
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.layout.processors import BeforeInput
from prompt_toolkit.layout.margins import ScrollbarMargin
from prompt_toolkit.layout.controls import BufferControl, FormattedTextControl
from prompt_toolkit.layout.containers import VSplit, Window, HSplit, WindowAlign

for log_name, log_obj in logging.Logger.manager.loggerDict.items():
    # 让其他 Logging 保持沉默, 也可以通过 log_name 判断是否禁用
    log_obj.disabled = True


class WeToolkit:

    def __init__(
        self,
        app_title='示例应用',
        control_prompt=' - abc [state_value_1]  设置 state_value_1 的值  abc 123\n - Ctrl-C               退出程序'
    ):
        self.app_title = app_title
        self.control_prompt = FormattedTextControl(
            text=f'使用帮助:\n{control_prompt}')
        self.state_control = FormattedTextControl(text='当前状态:')
        self.show_control = FormattedTextControl()
        self.show_control_cache = []
        self.show_control_rows = 0
        self.show_control_offset = 0
        self.state_dict = {}
        self.input_buffer = Buffer()
        self.kb = KeyBindings()
        self.layout = self.__root_container()
        self.__binding_event()

    def __root_container(self):
        return Layout(container=HSplit(children=[
            Window(
                height=1,
                align=WindowAlign.CENTER,
                content=FormattedTextControl(text=HTML(
                    value=f'<b>{self.app_title}</b>', ), ),
            ),
            Window(height=1, char='-', style='class:line'),
            VSplit([
                HSplit([
                    Window(content=self.state_control, wrap_lines=True),
                    Window(height=1, char='-', style='class:line'),
                    Window(content=self.control_prompt, wrap_lines=True),
                ]),
                Window(width=1, char='|', style='class:line'),
                Window(
                    content=self.show_control,
                    wrap_lines=True,
                    right_margins=[
                        ScrollbarMargin(),
                    ],
                ),
            ]),
            Window(height=1, char='-', style='class:line'),
            Window(
                wrap_lines=True,
                content=BufferControl(
                    buffer=self.input_buffer,
                    input_processors=[
                        BeforeInput('$ '),
                    ],
                ),
            ),
        ], ), )

    def __refresh(self):
        self.show_control.text = HTML(value='\n'.join(
            self.show_control_cache[self.show_control_offset:]), )
        state_list = []
        for state_k, state_v in self.state_dict.items():
            if type(state_v) is list:
                state_list.append(
                    f'{state_k} = {type(state_v)}[{len(state_v)}]')
            elif type(state_v) is str:
                vs = state_v
                if len(vs) > 13:
                    vs = f'{vs[:13]}...'
                state_list.append(
                    f'{state_k} = {type(state_v)}[{len(state_v)}] {vs}')
            else:
                state_list.append(f'{state_k} = {state_v}')
        self.state_control.text = '当前状态:\n' + '\n'.join(state_list)

    def _log(self, message: str, level: str = ''):
        if level == 'warning':
            mag = f'<ansiyellow>{message}</ansiyellow>'
        elif level == 'error':
            mag = f'<ansired>{message}</ansired>'
        elif level == 'info':
            mag = f'<ansigreen>{message}</ansigreen>'
        elif level == 'debug':
            mag = f'<ansiblue>{message}</ansiblue>'
        else:
            mag = f'<ansiwhite>{message}</ansiwhite>'
        self.show_control_cache.insert(
            0, f'<i>[{self.show_control_rows}]</i> {mag}')
        self.show_control_rows += 1
        self.__refresh()

    def functional_event(self, event: str):
        if 'abc ' in event:
            self._log(message='functional_event 函数准备设置状态')
            self._log(message='Debug 输出', level='debug')
            self._log(message='Info 输出', level='info')
            self._log(message='Warning 输出', level='warning')
            self.state_dict['state_value_1'] = event.split(' ')[1]
            self._log(message='functional_event 函数完成状态设置')
        else:
            self._log(message=f'无法识别 {event} 指令', level='error')

    def __binding_event(self):

        @self.kb.add('c-m')
        def _(event):
            """ 按 Enter 触发 """
            if not self.input_buffer.text:
                return
            self.functional_event(self.input_buffer.text)
            self.__refresh()
            self.input_buffer.text = ''

        @self.kb.add('up')
        def _(event):
            """ 按 方向上键 触发 """
            if self.show_control_offset < self.show_control_rows:
                self.show_control_offset += 1
                self.__refresh()

        @self.kb.add('down')
        def _(event):
            """ 按 方向下键 触发 """
            if self.show_control_offset >= 1:
                self.show_control_offset -= 1
                self.__refresh()

        @self.kb.add('c-c')
        def _(event):
            """ 按 Ctrl-C 触发 """
            event.app.exit()

    def run(self):
        app = Application(
            layout=self.layout,
            key_bindings=self.kb,
            full_screen=True,
        )
        app.run()


if __name__ == '__main__':
    # pyinstaller -F we_toolkit.py -n 示例应用
    app = WeToolkit()
    app.run()

具体开发时,可以使用下面的命令快速生成虚拟环境:

python -m venv venv
# Linux下进入虚拟环境
# source venv/bin/activate
# Windows下进入虚拟环境
venv/Scripts/activate

快速使用一:IOU计算工具

使用微CLI工具箱-WeToolkit很简单,只需要在开头导入 WeToolkit (from we_toolkit import WeToolkit) 就可以快速编写脚本功能,比如下面创建的一个 compute_iou.py 文件。

from we_toolkit import WeToolkit


class ComputeIOU(WeToolkit):

    def __init__(self):
        super(ComputeIOU, self).__init__(
            '计算IOU',
            '\n'.join([
                '''
   (rec_1)
   1--------1
   1   1----1------1
   1---1----1      1
       1           1
       1-----------1 (rec_2)
                ''',
                ' - rec_1 x1,y1,x2,y2  设置第1个框   rec_1 254,22,562,217',
                ' - rec_2 x1,y1,x2,y2  设置第2个框   rec_2 352,133,409,217',
                ' - compute            计算IOU数值',
                ' - Ctrl-C             退出程序',
            ]),
        )

    def functional_event(self, event: str):
        if 'rec_1 ' in event:
            self.state_dict['rec_1'] = event.split(' ')[1].split(',')
            self._log(
                message=f'第1个框 {self.state_dict["rec_1"]}',
                level='info',
            )
        elif 'rec_2 ' in event:
            self.state_dict['rec_2'] = event.split(' ')[1].split(',')
            self._log(
                message=f'第2个框 {self.state_dict["rec_2"]}',
                level='info',
            )
        elif 'compute' in event:
            rec_1 = (int(self.state_dict['rec_1'][0]),
                     int(self.state_dict['rec_1'][1]),
                     int(self.state_dict['rec_1'][2]),
                     int(self.state_dict['rec_1'][3]))
            rec_2 = (int(self.state_dict['rec_2'][0]),
                     int(self.state_dict['rec_2'][1]),
                     int(self.state_dict['rec_2'][2]),
                     int(self.state_dict['rec_2'][3]))
            s_rec1 = (rec_1[2] - rec_1[0]) * (rec_1[3] - rec_1[1])
            self._log(message=f'第1个框(长*宽)的面积 {s_rec1}')
            s_rec2 = (rec_2[2] - rec_2[0]) * (rec_2[3] - rec_2[1])
            self._log(message=f'第2个框(长*宽)的面积 {s_rec2}')
            sum_s = s_rec1 + s_rec2
            self._log(message=f'总面积 {sum_s}')
            left = max(rec_1[0], rec_2[0])
            self._log(message=f'并集左上角顶点横坐标 {left}')
            right = min(rec_1[2], rec_2[2])
            self._log(message=f'并集右下角顶点横坐标 {right}')
            bottom = max(rec_1[1], rec_2[1])
            self._log(message=f'并集左上角顶点纵坐标 {bottom}')
            top = min(rec_1[3], rec_2[3])
            self._log(message=f'并集右下角顶点纵坐标 {top}')
            if left >= right or top <= bottom:  # 不存在并集的情况
                iou = 0
            elif s_rec1 > s_rec2:
                if rec_2[0] >= rec_1[0] and rec_2[2] <= rec_1[2] and rec_2[
                        1] >= rec_1[1] and rec_2[3] <= rec_1[3]:
                    self._log(message='第1个框完全覆盖第一个框', level='debug')
                    iou = 1.0
            else:
                inter = (right - left) * (top - bottom)  # 求并集面积
                iou = (inter / (sum_s - inter)) * 1.0  # 计算IOU
            self.state_dict['iou'] = iou
            self._log(
                message=f'当前IOU值 {self.state_dict["iou"]}',
                level='info' if self.state_dict['iou'] else 'warning',
            )
        else:
            self._log(message=f'无法识别 {event} 指令', level='error')


if __name__ == '__main__':
    # pyinstaller -F compute_iou.py -n 计算IOU
    app = ComputeIOU()
    app.run()

然后在 LinuxWindows 环境下执行 pyinstaller -F compute_iou.py -n 计算IOU 就可以生成一个可执行文件。

计算IOU例子

快速使用二:词频提取工具

要实现文本词频和关键词提取,需要依赖下面两个第三方库。

  • pip install zhon
  • pip install jieba

同样在开头导入 WeToolkit (from we_toolkit import WeToolkit),再创建一个 word_frequency.py 文件。

import string
import jieba
# https://blog.csdn.net/lucyTheSlayer/article/details/92795220
import jieba.analyse
import operator
from zhon.hanzi import punctuation
from we_toolkit import WeToolkit


class WordFrequency(WeToolkit):

    def __init__(self):
        super(WordFrequency, self).__init__(
            '词频与关键词提取',
            '\n'.join([
                ' - load [txt_file]    加载文件       load demo.txt',
                ' - frequency          文本词频分析',
                ' - extraction         文本关键词提取',
                ' - export [txt_file]  导出结果文件   export export.txt',
                ' - Ctrl-C             退出程序',
            ]),
        )

    def functional_event(self, event: str):
        if 'load ' in event:
            self.state_dict['file_path'] = event.split(' ')[1]
            file_str = open(self.state_dict['file_path'],
                            'r',
                            encoding='UTF-8').read()
            self.state_dict['raw_rows'] = file_str.split('\n')
            # 删除文本中的空格/回车/换行/中英文符号
            for rs in [' ', '\n', '\r']:
                file_str = file_str.replace(rs, '')
            for i in punctuation:
                file_str = file_str.replace(i, '')
            for j in string.punctuation:
                file_str = file_str.replace(j, '')
            self.state_dict['file_str'] = file_str
            # 切词并返回结果列表
            self.state_dict['words'] = jieba.lcut(file_str)
        elif 'frequency' in event:
            counts = {}  # 存储关键词和词频的字典
            # 遍历切词后的列表 words
            for word in self.state_dict['words']:
                # 如果没有该键名则先赋值为 0
                counts[word] = counts.get(word, 0) + 1
            # 按字典每个键值对的第二个元素进行降序排序
            self.state_dict['items'] = sorted(
                counts.items(),
                key=operator.itemgetter(1),
                reverse=True,
            )
            self._log(message=f'切词共发现 {len(self.state_dict["words"])} 个词语',
                      level='debug')
        elif 'extraction' in event:
            # 关键词提取
            self.state_dict['keywords'] = jieba.analyse.extract_tags(
                self.state_dict['file_str'],  # 导入的文本内容
                topK=10,  # 提取前几个的关键词
                withWeight=True,  # 是否返回每个关键词的权重
                allowPOS=(  # 仅过滤出指定词性的关键词
                    'n',  # 名词
                    'ns',  # 地名
                    'nt',  # 机构团体名
                    'nz',  # 其他专名
                    'v',  # 动词
                ),
            )
            for ki in range(len(self.state_dict['keywords'])):
                self._log(
                    message=f'第 {ki+1} 位关键词 {self.state_dict["keywords"][ki]}',
                    level='info')
        elif 'export ' in event:
            export_path = event.split(' ')[1]
            export_str = '前10位关键词:\n'
            for item in self.state_dict['keywords']:
                export_str += f'{item[0]} {item[1]}\n'
            export_str += '\n词语按出现次数排序:\n'
            for i in range(len(self.state_dict['items'])):
                word, count = self.state_dict['items'][i]
                export_str += f'{word} {count}\n'
            with open(export_path, 'w', encoding='utf-8') as f:
                f.write(export_str)
        else:
            self._log(message=f'无法识别 {event} 指令', level='error')


if __name__ == '__main__':
    # pyinstaller -F word_frequency.py -n 词频提取
    app = WordFrequency()
    app.run()

然后再执行 pyinstaller -F word_frequency.py -n 词频提取 生成可执行文件。

词频提取例子

快速使用三:视频CV2读取

要实现视频图片帧提取,需要依赖 opencv-python-headless 库。

  • pip install opencv-python-headless

同样在开头导入 WeToolkit (from we_toolkit import WeToolkit),再创建一个 VideoCV2Read.py 文件。

import os
import cv2
from pathlib import Path
from we_toolkit import WeToolkit

class VideoCV2Read(WeToolkit):

    def __init__(self):
        super(VideoCV2Read, self).__init__(
            '视频CV2读取',
            '\n'.join([
                ' - load [video_file]      加载文件        load demo.mp4',
                ' - export [export_files]  导出帧图片目录  export exports/',
                ' - read                   开始读取视频',
                ' - Ctrl-C                 退出程序',
            ]),
        )

    def functional_event(self, event: str):
        if 'load ' in event:
            self.state_dict['video_file'] = event.split(' ')[1]
            self.state_dict['video_obj'] = cv2.VideoCapture(self.state_dict['video_file'])
            self.state_dict['frame_w'] = int(self.state_dict['video_obj'].get(cv2.CAP_PROP_FRAME_WIDTH))
            self.state_dict['frame_h'] = int(self.state_dict['video_obj'].get(cv2.CAP_PROP_FRAME_HEIGHT))
            self.state_dict['frame_count'] = int(self.state_dict['video_obj'].get(cv2.CAP_PROP_FRAME_COUNT))
            self.state_dict['read_frame_count'] = 0
        elif 'export ' in event:
            _file = Path(event.split(' ')[1])
            if _file.is_dir():
                self.state_dict['export_files'] = event.split(' ')[1]
                self._log(message=f'配置 {event.split(" ")[1]} 目录')
            else:
                self._log(
                    message=f'找不到 {event.split(" ")[1]} 目录',
                    level='warning',
                )
        elif 'read' in event:
            self._log(message='开始读取和导出视频帧...')
            while True:
                ret, frame = self.state_dict['video_obj'].read()
                if ret is False:
                    break
                self.state_dict['read_frame_count'] += 1
                m_sec = self.state_dict['video_obj'].get(cv2.CAP_PROP_POS_MSEC)
                cv2.imwrite(f'{self.state_dict["export_files"]}{self.state_dict["read_frame_count"]}-{m_sec}.png', frame)
            self._log(message='完成读取和导出视频帧!')
        else:
            self._log(message=f'无法识别 {event} 指令', level='error')

if __name__ == '__main__':
    # pyinstaller -F VideoCV2Read.py -n 视频CV2读取
    app = VideoCV2Read()
    app.run()

最后再执行 pyinstaller -F VideoCV2Read.py -n 视频CV2读取 生成可执行文件。

视频CV2读取

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

微CLI工具箱-WeToolkit 的相关文章

随机推荐

  • 银河麒麟创建sh脚本快捷方式的方法

    本文旨在将 sh 做成快捷方式放到桌面上 一 将解压后的文件中的 sh 做成快捷方式放到桌面上 1 在桌面打开终端命令行 2 创建 desktop文件 在打开的终端命令行中 输入vim 快捷方式名称 desktop 3 在vim编辑器中按如
  • 如何在Windows 10上下载并安装Linux Bash Shell?

    Bash is the command line interface for Linux distributions like Ubuntu CentOS Debian Mint Kali RedHat Fedora etc Bash pr
  • Opencv的使用小教程3——利用轮廓检测实现二维码定位

    Opencv的使用小教程3 利用轮廓检测实现二维码定位 二维码具有什么特征 实现效果 识别二维码的流程 1 预处理图像 2 寻找轮廓 3 通过寻找到的轮廓确定 回 的位置 4 创建一张新图 并在新图上画出识别到的 回 并连线 5 寻找直角
  • 论文阅读:(ECCV 2022)Simple Baseline for Image Restoration

    Simple Baseline for Image Restoration ECCV 2022 2022 08 26 两个月的时间终于把那个材料完成了 今天一看虽然审核完了还有些小问题 老板没有怪我还说他会去搞定这个事 TAT 我要做老板的
  • 如何利用python处理excel

    利用Python处理Excel数据可以帮助我们更高效地进行数据分析和处理 以下是一些常用的Python库和工具 Pandas Pandas是一个用于数据处理和分析的Python库 它提供了丰富的数据结构和函数 可以方便地读取 清洗 转换和分
  • 存储器IP核生成 非对齐读写 vivado

    存储器制作 含非对齐读写 1 创建ROM 和 RAM IP核 参考马德老师lab0PPT 1 新建一个项目ROM 选择芯片 创建 2 搜索memory generator 3 双击 4 设置好后点击OK width写32 另一个写1024
  • eclipse中文注释缩进异常

    最近更新了eclipse 发现格式化代码后 中文的注释缩进出现了问题 如下图 这个问题 我们可以通过更改字体解决 推荐修改生成支持中文的字体 最简单的方法就是更改成与系统一致 依次点击 Window gt Preferences gt Ge
  • Shell中sort命令使用

    一 sort命令工作原理 sort命令将文件的每一行作为比较对象 通过将不同行进行相互比较 从而得到最终结果 比较原则是从首字符开始 向后依次按ASCII码值进行比较 最后将结果按升序输出 比较前的结果 rocrocket rocrocke
  • java :基本递归(阶乘,斐波那契数列,猴子吃桃,迷宫,汉诺塔,八皇后)

    1 求一个非负数的阶乘 package ex import java util public class ex1 public static void main String args Scanner myscanner new Scann
  • Hive3 启动 提示:com.ctc.wstx.exc.WstxParsingException: Illegal character entity: expansion character

    Windows10 系统启动Hive3 提示如下错误信息 com ctc wstx exc WstxParsingException Illegal character entity expansion character code 0x8
  • 7.全志H3-准备焊接

    上面是我的微信和QQ群 欢迎新朋友的加入 20201203 CPU和DDR已到 20201207 板子到了 开始焊接 20201208 下班继续焊接 发现少了一个料 漏买了 赶紧淘宝补一个 现在就把手上的板子拆了个芯片先用着 焊接完成 测试
  • Partition Pruning和Partition-Wise Joins

    Partition Pruning Partition pruning is an essential performance feature for data warehouses In partition pruning the opt
  • Android Bitmap图像处理(1)- 图片压缩

    一直以来Bitmap都是开发中很棘手的问题 这个问题就是传说中的OOM java lang OutofMemoryError 内存溢出 那么Bitmap为何如此丧失 令无数Android开发者所懊恼 一 Bitmap引发OOM的原因 由于每
  • 介绍中国传统节日的网页html,关于中国传统节日介绍的作文

    关于中国传统节日介绍的作文 春节的另一名称叫过 是我国的传统节日之一 小编为大家收集整理的传统节日作文 欢迎感兴趣的小伙伴们前来查阅 中国传统节日介绍的作文 过春节了 孩子的脸上露出了春节特有的快乐 大人们一年的劳累得到了安抚 春节是多么重
  • 【自监督论文阅读 3】DINOv1

    文章目录 一 摘要 二 引言 三 相关工作 3 1 自监督学习 3 2 自训练与知识蒸馏 四 方法 4 1 SSL with Knowledge Distillation 4 2 教师网络 4 3 网络架构 4 4 避免坍塌 五 实验与评估
  • Python软件基本操作

    经过这几天关于Python的分享 下面我们分享一下关于Python的小操作 顺便编写一些小程序供大家一起学习 探讨 一 个税的计算 从网上我们找到了关于税率的内容 我提取了一些重要的部分 下面我们根据这些内容 我们用Python它编写为小程
  • 湍流系数计算器_雷诺数Re计算公式与在线计算器_三贝计算网_23bei.com

    输入雷诺数Re 流速v m s 密度 kg m 3 动力黏性系数 Pa s 特征长度 内径 d mm m 等5个变量中任意4个已知变量 选择输入特征长度的单位 点击计算按钮 可快速求出未知变量 雷诺数是作为判别流体流动状态的准则 计算公式如
  • H5 手机适配

    刘海屏 水滴屏 小黑条适配 兼容ios 安卓 当我们在写h5页面的时候 常常会遇到刘海屏 水滴屏 小黑条等手机 加入以下css 即可以解决适配 padding constant safe area inset top constant sa
  • 码住!IC设计常用工具合集!

    芯片设计过程中 选择和使用适合的工具是非常重要的 芯片设计工具通常分为三类 EDA工具 模拟仿真工具和布局工具 一 EDA工具 EDA工具是芯片设计的核心 它包括原理图绘制 逻辑综合 门级仿真工具和物理版图编辑等 可以帮助设计师设计出电路的
  • 微CLI工具箱-WeToolkit

    当需要将一个Python脚本快速提供给用户使用时 直接提供纯命令行指令给用户 不友好 如果开发可视化的GUI界面 又太废时间 而且无法在Linux服务器上使用 于是就整了这个微CLI工具箱 WeToolkit 解决这个问题 微CLI工具箱