动手系列之办公助手

235 阅读6分钟

每天早上来面对着满屏幕的程序,有时候可能要找半天才能找到我们想要的,这样不仅耽误了工作效率,还会引起我们眼睛的疲劳,而且中午吃饭的时候我们常常不能按时去,这样会影响我们的身体,到了晚上下班的时候,我们可能常常忘记打卡,这就会导致我们的考勤有问题。

那么这个时候我们就需要一款办公助手了,下面我们来动手用程序实践一下。

程序所需要的环境及依赖

  • mac
  • python
  • curses
  • os
  • pyttsx3 文字转语音
  • subprocess
  • PyQt5 创建UI

程序助手

为了解决我们一大早面对这么多程序的烦恼,精准的帮我们找到想要打开的程序,那么我们就需要这个程序助手了。

下面是程序截图

我们按下对应的键盘,就可以快速帮我们打开程序。

以下是代码

start.py

import curses
from curses import panel
import time
from task import Task
import os
import pyttsx3

class Menu(object):

    def __init__(self, items, stdscreen):
        self.window = stdscreen.subwin(0, 0)
        self.window.keypad(1)
        self.panel = panel.new_panel(self.window)
        self.panel.hide()
        panel.update_panels()

        self.position = 0
        self.items = items
        self.items.append(('exit', 'exit'))

        self.task = Task()


    def navigate(self, n):
        self.position += n
        if self.position < 0:
            self.position = 0
        elif self.position >= len(self.items):
            self.position = len(self.items)-1

    def display(self):
        self.panel.top()
        self.panel.show()
        self.window.clear()
        curses.init_pair(1, curses.COLOR_GREEN, curses.COLOR_BLACK)
        self.window.addstr(5, 20,'Robot Sallen为您服务\n', curses.color_pair(1))
        while True:
            self.window.refresh()
            curses.doupdate()
            for index, item in enumerate(self.items):
                if index == self.position:
                    mode = curses.color_pair(1)
                else:
                    mode = curses.A_NORMAL

                msg = '%d. %s' % (index, item[0])
                self.window.addstr(8+index, 21, msg,mode )

            key = self.window.getch()
            if key in [curses.KEY_ENTER, ord('\n')]:
                if self.position == len(self.items)-1:
                    break
                else:
                    self.items[self.position][1]()
            elif key == curses.KEY_UP:
                self.navigate(-1)

            elif key == curses.KEY_DOWN:
                self.navigate(1)

            self.task.handle_task(key)

        self.window.clear()
        self.panel.hide()
        panel.update_panels()
        curses.doupdate()


class MyApp(object):

    def __init__(self, stdscreen):

        self.screen = stdscreen
        curses.curs_set(0)

        submenu_items = [
                ('打开微信', curses.beep),
                ('打开Markdown', curses.flash),
                ('听QQ音乐', curses.beep),
                ('听网易云', curses.flash),
                ('打开VSCode', curses.beep),
                ('打开Wechat Tool', curses.flash),
                ('浏览掘金', curses.beep)
                ]
        submenu = Menu(submenu_items, self.screen)

        main_menu_items = [
                ('打开微信', curses.beep),
                ('打开Markdown', curses.flash),
                ('听QQ音乐', curses.beep),
                ('听网易云', curses.flash),
                ('打开VSCode', curses.beep),
                ('打开Wechat Tool', curses.flash),
                ('浏览掘金', curses.beep)
                ]
        main_menu = Menu(main_menu_items, self.screen)
        main_menu.display()


if __name__ == '__main__':
    curses.wrapper(MyApp)

task.py

import os

class Task(object):
    def __init__(self):
        self.command_dict = {
            ord('0'):"open /Applications/WeChat.app",
            ord('1'):"open /Applications/Typora.app",
            ord('2'):"open /Applications/QQMusic.app",
            ord('3'):"open /Applications/NeteaseMusic.app",
            ord('4'):"open https://juejin.cn",
            ord('5'):"open /Applications/Visual\ Studio\ Code.app",
            ord('6'):"open /Applications/wechatwebdevtools.app",
            }
    def handle_task(self,key):
        if key == ord('7'):
           exit()
        else:
            os.system(self.command_dict.get(key))

吃饭提醒/下班提醒

有时候我们忙着的时候,中午吃饭常常不按点,这对我们的身体不好,所以我们就需要一个提醒吃饭助手,当中午12点时候,我们的电脑将会提醒我们吃饭,话不多说,上代码。

同样的我们下班可能也常常忘记打卡,那么我们就需要一个提醒打卡的工具。为了避免我们忘记,程序会在电脑屏幕弹出一个框,让我们确认打卡。

核心代码:

import time
from apscheduler.schedulers.background import BackgroundScheduler
import os
import pyttsx3
from subprocess import call

def job():
    sys_time = time.strftime('%H:%M', time.localtime(time.time()))
    eat_time = '12:00'
    off_work_time = '18:00'
    if sys_time == eat_time:
        # 播放吃饭声音
        os.system("python3 xxxxx.py") # xxx.py为吃饭声音py文件
    if sys_time == off_work_time:
        # 播放下班声音
        os.system("python3 xxxxx.py") # xxx.py为下班声音py文件
        time.sleep(1)
        # 打开强制打卡框
        os.system("python3 xxxxx.py") # xxx.py为打开UIpy文件

if __name__ == '__main__':
    # 调大系统音量  
    # call(["osascript -e 'set volume output volume 80'"], shell=True)
    # BackgroundScheduler: 适合于要求任何在程序后台运行的情况,当希望调度器在应用后台执行时使用。
    scheduler = BackgroundScheduler()
    # 采用非阻塞的方式

    # 采用固定时间间隔(interval)的方式,每隔3秒钟执行一次
    scheduler.add_job(job, 'interval', seconds=3)
    # 这是一个独立的线程
    scheduler.start()

    while True:
        time.sleep(2)

播放声音的文件

import pyttsx3
if __name__ == '__main__':
     engine = pyttsx3.init()
     engine.say("下班了记得打卡   下班了记得打卡    下班了记得打卡")
     engine.runAndWait() 

打卡UI样式及文件

UI代码文件:

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QMessageBox,QPushButton,QDesktopWidget,QLabel
import os

class Example(QWidget):

 def __init__(self):
  super().__init__()

  self.initUI()

 def center(self):
    qr = self.frameGeometry()
    cp = QDesktopWidget().availableGeometry().center()
    qr.moveCenter(cp)
    self.move(qr.topLeft())

 def initUI(self):

  self.resize(250, 150)
  self.center()
  self.setWindowTitle('这是一个提示')  

  self.label_1=QLabel(self)
  self.label_1.setText("<a style='color:green'>下班了该打卡了!</a>")
  self.label_1.setAutoFillBackground(True)
  self.label_1.move(80, 50)  

  self.show()

 def closeEvent(self, event):

  reply = QMessageBox.question(self, '信息', '确认已经打卡了吗?', 
   QMessageBox.Yes | QMessageBox.No, QMessageBox.No)

  if reply == QMessageBox.Yes:
   event.accept()
  else:
   event.ignore()

if __name__ == '__main__':   

    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

优化

因为都是python脚本,所以每次需要打开几个文件也比较麻烦,逼格也不够高,那么我们继续优化。 通过语音识别指定关键字:我的是robot sallen,从而打开我们这几个脚本。以下是代码。

# -*- coding: utf-8 -*-
import pyttsx3
import sys
import json
import time
import speech_recognition as sr
import os
import requests
from subprocess import call
IS_PY3 = sys.version_info.major == 3

if IS_PY3:
    from urllib.request import urlopen
    from urllib.request import Request
    from urllib.error import URLError
    from urllib.parse import urlencode

    timer = time.perf_counter
else:
    import urllib2
    from urllib2 import urlopen
    from urllib2 import Request
    from urllib2 import URLError
    from urllib import urlencode

    if sys.platform == "win32":
        timer = time.clock
    else:
        # On most other platforms the best timer is time.time()
        timer = time.time



API_KEY = ''
SECRET_KEY = ''

# 需要识别的文件
AUDIO_FILE = './recording.wav'  # 只支持 pcm/wav/amr 格式,极速版额外支持m4a 格式
# 文件格式
FORMAT = AUDIO_FILE[-3:];  # 文件后缀只支持 pcm/wav/amr 格式,极速版额外支持m4a 格式

CUID = '123456PYTHON';
# 采样率
RATE = 16000;  # 固定值

# 普通版

DEV_PID = 1737;  # 1537 表示识别普通话,使用输入法模型。1536表示识别普通话,使用搜索模型。根据文档填写PID,选择语言及识别模型
ASR_URL = 'http://vop.baidu.com/server_api'
SCOPE = 'audio_voice_assistant_get'  # 有此scope表示有asr能力,没有请在网页里勾选,非常旧的应用可能没有

# 极速版

class DemoError(Exception):
    pass


"""  TOKEN start """

TOKEN_URL = 'http://openapi.baidu.com/oauth/2.0/token'


def fetch_token():
    params = {'grant_type': 'client_credentials',
              'client_id': API_KEY,
              'client_secret': SECRET_KEY}
    post_data = urlencode(params)
    if (IS_PY3):
        post_data = post_data.encode('utf-8')
    req = Request(TOKEN_URL, post_data)
    try:
        f = urlopen(req)
        result_str = f.read()
    except URLError as err:
        # print('token http response http code : ' + str(err.code))
        result_str = err.read()
    if (IS_PY3):
        result_str = result_str.decode()

    # print(result_str)
    result = json.loads(result_str)
    # print(result)
    if ('access_token' in result.keys() and 'scope' in result.keys()):
        if SCOPE and (not SCOPE in result['scope'].split(' ')):  # SCOPE = False 忽略检查
            raise DemoError('scope is not correct')
        # print('SUCCESS WITH TOKEN: %s ; EXPIRES IN SECONDS: %s' % (result['access_token'], result['expires_in']))
        return result['access_token']
    else:
        raise DemoError('MAYBE API_KEY or SECRET_KEY not correct: access_token or scope not found in token response')

def rec(rate=16000):
    r = sr.Recognizer()
    with sr.Microphone(sample_rate=rate) as source:
        print("please say something")
        audio = r.listen(source)
    with open("recording.wav", "wb") as f:
        f.write(audio.get_wav_data())


"""  TOKEN end """

def begin():
    token = fetch_token()
    rec()
    speech_data = []
    with open(AUDIO_FILE, 'rb') as speech_file:
        speech_data = speech_file.read()
    length = len(speech_data)
    if length == 0:
        raise DemoError('file %s length read 0 bytes' % AUDIO_FILE)

    params = {'cuid': CUID, 'token': token, 'dev_pid': DEV_PID}
    #测试自训练平台需要打开以下信息
    params_query = urlencode(params);

    headers = {
        'Content-Type': 'audio/' + FORMAT + '; rate=' + str(RATE),
        'Content-Length': length
    }

    url = ASR_URL + "?" + params_query
    # print post_data
    req = Request(ASR_URL + "?" + params_query, speech_data, headers)
    try:
        begin = timer()
        f = urlopen(req)
        result_str = f.read()
    except  URLError as err:
        result_str = err.read()

    if (IS_PY3):
        result_str = str(result_str)
    record_res =  json.loads(result_str)
    record_str = record_res['result'][-1]
    sheet = ['hi robot sallen']
    if (record_str in sheet):
        # 打开程序助手
        # 打开吃饭助手
        # ...


if __name__ == '__main__':

    begin()

运行这个脚本,就像我们平时用小爱同学一样,hi robot sallen,我们对着电脑说出关键字即可,通过百度识别出对应的文字信息,进行匹配。从而执行程序打开步骤。

更多思路

  • 由于程序助手,打开文件的程序都是我们预先录入常用的,所以存在易用问题,我们可以通过检测项目进度、或者任务的方式,智能排列我们的程序组合,而不是预先固定录入。

  • 由于每天都需要启动脚本,那么也是一件麻烦的事,同样的我们也可以利用mac 定时任务,每天早上帮我们执行脚本。

同名公众号

欢迎关注同名公众号,获取更多资源。人工智能、机器学习、计算机视觉等文章分享。干货实战技巧,一起精进技术。