3.AI語音轉(zhuǎn)文本——Flask從制作到起飛,零件級顆粒度制造

寫在前面的話:
作者是一名終身學(xué)習(xí)者跨晴,橫跨環(huán)境欧聘、教育和IT三個行業(yè)。
IT是當前正在精進的行業(yè)端盆,作者相信專業(yè)精神怀骤,崇尚知行合一。
作者以這個系列文章向每一個腳踏實地的web開發(fā)者致敬焕妙,希望能寫出高度實用又有深度的文章幫路上的你清除障礙蒋伦,歡迎你的指正和技術(shù)交流。

1. AI 工具準備

語音轉(zhuǎn)文本是AI的一個子領(lǐng)域焚鹊,本文使用百度提供的免費接口實現(xiàn)痕届,專注在web server的開發(fā)上。
首先在百度AI注冊相關(guān)賬號末患,在應(yīng)用列表中創(chuàng)建應(yīng)用研叫,這里起名為asr_test,asr是automatic speech recognition的縮寫璧针。

image

這時可以獲得AppID, APIKey, Secret Key嚷炉,作為后續(xù)web server功能的原材料化撕。

2. package 管理

首先安裝百度語音的相關(guān)SDK糊肤,同時更新requirements.txt,會發(fā)現(xiàn)baidu-aip會依賴其他的一些package,例如requests, urllib3众雷。

$ pip install baidu-aip
$ pip freeze > requirements.txt

如果想要更好的了解package的依賴關(guān)系,可以使用pipdeptree package輔助:

$ pip install pipdeptree
$ pipdeptree
baidu-aip==2.2.10.0
  - requests [required: Any, installed: 2.21.0]
    - certifi [required: >=2017.4.17, installed: 2018.11.29]
    - chardet [required: >=3.0.2,<3.1.0, installed: 3.0.4]
    - idna [required: >=2.5,<2.9, installed: 2.8]
    - urllib3 [required: >=1.21.1,<1.25, installed: 1.24.1]
Flask==1.0.2
  - click [required: >=5.1, installed: 7.0]
  - itsdangerous [required: >=0.24, installed: 1.1.0]
  - Jinja2 [required: >=2.10, installed: 2.10]
    - MarkupSafe [required: >=0.23, installed: 1.1.0]
  - Werkzeug [required: >=0.14, installed: 0.14.1]
pipdeptree==0.13.1
  - pip [required: >=6.0.0, installed: 18.1]
pytest-cov==2.6.0
  - coverage [required: >=4.4, installed: 4.5.2]
  - pytest [required: >=2.9, installed: 4.0.2]
    - atomicwrites [required: >=1.0, installed: 1.2.1]
    - attrs [required: >=17.4.0, installed: 18.2.0]
    - more-itertools [required: >=4.0.0, installed: 4.3.0]
      - six [required: >=1.0.0,<2.0.0, installed: 1.12.0]
    - pluggy [required: >=0.7, installed: 0.8.0]
    - py [required: >=1.5.0, installed: 1.7.0]
    - setuptools [required: Any, installed: 40.6.3]
    - six [required: >=1.10.0, installed: 1.12.0]
wheel==0.32.3
$ pip freeze > requirements.txt

pipdeptree可以清晰說明package的依賴關(guān)系辙芍,當前開發(fā)主要安裝了兩個package缝其,一個是Flask,另一個是pytest-cov忌栅。Flask核心是兩個package车酣,Jinja2提供前端模板渲染,Werkzeug提供uWSGI服務(wù)索绪。pytest-cov的代碼覆蓋率由coverage實現(xiàn)湖员,test由pytest實現(xiàn)。

3. config 設(shè)置

然后搭建config體系瑞驱,用于設(shè)置連接百度 AI 的相關(guān)參數(shù)娘摔,主要分為public和private兩個部分。public部分在git版本控制中唤反,配置應(yīng)用于所有開發(fā)者的參數(shù)和無需保密的參數(shù)凳寺,例如debug和數(shù)據(jù)庫的查詢打印開關(guān)。private部分不在git版本控制中彤侍,配置私密參數(shù)肠缨,例如密鑰和鹽。

3.1 public config

在根路徑下創(chuàng)建config.py盏阶,用來加載基本運行參數(shù)晒奕,目錄結(jié)構(gòu)和配置參數(shù)如下:

- FlaskTemplate
    - .circleci
        - config.yml
    - server
        - __init__.py
        - core.py
    - tests
        - unit_tests
            - __init__.py
            - test_index.py
        - __init__.py
    - venv
    - .gitignore  # 非git版本管理文件
    - config.py  # git版本管理配置參數(shù)
    - README.md  # 創(chuàng)建git倉庫時選擇生成的說明文檔
    - requirements.txt  # 項目 package 安裝說明
# -*- coding: utf8 -*-

DEBUG = False  # 非調(diào)試模式
SQLALCHEMY_ECHO = False  # 不輸出數(shù)據(jù)庫相關(guān)echo,未來連接數(shù)據(jù)庫時使用

3.2 private config

在根路徑下創(chuàng)建 instance directory名斟,因為 Flask 默認 instance/ 下面加載 private config 文件脑慧。在 instance 路徑下創(chuàng)建 defalut, development, production, staging 4個 python 文件,default 一般用于 local 開發(fā)砰盐,development 一般用于 dev 開發(fā)闷袒,produciton 一般用于線上生產(chǎn),staging 一般用于新版本前測試岩梳。

- FlaskTemplate
    - .circleci
        - config.yml
    - instance
        - __init__.py
        - default.py  # local 配置
        - development.py  # dev 配置
        - production.py  # prod 配置
        - staging.py  # staging 配置
    - server
        - __init__.py
        - core.py
    - tests
        - unit_tests
            - __init__.py
            - test_index.py
        - __init__.py
    - venv
    - .gitignore  # 非git版本管理文件
    - config.py  # git版本管理配置參數(shù)
    - README.md  # 創(chuàng)建git倉庫時選擇生成的說明文檔
    - requirements.txt  # 項目 package 安裝說明
# default.py

# -*- coding: utf8 -*-

# Default values, to be used for all environments or overridden by individual environments.
# An example might be setting DEBUG = False in config/default.py and DEBUG = True in config/development.py.

DEBUG = True
SQLALCHEMY_ECHO = True

# Baidu Automatic Speech Recognition
APP_ID = "xxx"
API_KEY = "xxx"
SECRET_KEY = "xxx"
# 上面三個參數(shù)是在本文第一部分創(chuàng)建百度 AI 應(yīng)用獲取的參數(shù)

4. 項目啟動更新

隨著 config 的引入囊骤,項目的啟動方式也需要更新,一來要添加配置和運行實例的綁定蒋腮,二來要適應(yīng)不同環(huán)境不同方式的啟動淘捡。所以將過去的 core.py 的功能進行拆分,項目啟動的代碼拆分到 run.py 放在根路徑中池摧,項目配置的代碼保留在 core.py 文件中焦除,引入 config 和項目實例的綁定。

- FlaskTemplate
    - .circleci
        - config.yml
    - instance
        - __init__.py
        - default.py  # local 配置
        - development.py  # dev 配置
        - production.py  # prod 配置
        - staging.py  # staging 配置
    - server
        - __init__.py
        - core.py
    - tests
        - unit_tests
            - __init__.py
            - test_index.py
        - __init__.py
    - venv
    - .gitignore  # 非git版本管理文件
    - config.py  # git版本管理配置參數(shù)
    - README.md  # 創(chuàng)建git倉庫時選擇生成的說明文檔
    - requirements.txt  # 項目 package 安裝說明
    - run.py  # 項目啟動文件
# core.py

# -*- coding: utf8 -*-

from flask import Flask


def create_app():
    # instance_relative_config 默認為False作彤,設(shè)為True的時候允許 public config 文件被 instance 下的 private config 配置覆蓋
    app = Flask(__name__, instance_relative_config=True)  
    # load public default configuration
    app.config.from_object('config')
    # load private default configuration
    app.config.from_pyfile('default.py')

    @app.route('/')
    def index():
        return "<h1>This is an index page.<h1/>"

    return app
# run.py

# -*- coding: utf8 -*-

from server.core import create_app

app = create_app()  # 放在這里的原因是方便后續(xù)服務(wù)器對項目的啟動

# 通常作為本地開發(fā)項目啟動的入口
if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

啟動項目檢驗設(shè)置情況:

Connected to pydev debugger (build 182.4505.26)
 * Serving Flask app "server.core" (lazy loading)
 * Environment: production
   WARNING: Do not use the development server in a production environment.
   Use a production WSGI server instead.
 * Debug mode: on
 * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
 * Restarting with stat
pydev debugger: process 68382 is connecting

 * Debugger is active!
 * Debugger PIN: 335-533-553

debug mode 處于開啟狀態(tài)膘魄,符合配置需求乌逐,雖然 public config 設(shè)置 debug 為 False,但 private config 設(shè)置 debug 為 True创葡,配置正確浙踢。

5. instance_relative_config源碼解析

Flask能夠更新config配置,是由創(chuàng)建運行實例時的 instance_relative_config 參數(shù)控制實現(xiàn)的灿渴。

flask/app.py

class Flask(_PackageBoundObject):
    :param instance_relative_config: if set to ``True`` relative filenames for loading the config are assumed to be relative to the instance path instead of the application root.
    # 這個注釋解釋了instance_relative_config的作用是確定config加載地址洛波,如果為 True,則加載 instance/ 下面的 private config
    
    # instance_relative_config 默認是 False骚露,即 app 的 config 默認由 root 路徑下的 public config 加載蹬挤。
    def __init__(
        self,
        import_name,
        static_url_path=None,
        static_folder='static',
        static_host=None,
        host_matching=False,
        subdomain_matching=False,
        template_folder='templates',
        instance_path=None,
        instance_relative_config=False,
        root_path=None
    ):
        #: The configuration dictionary as :class:`Config`.  This behaves
        #: exactly like a regular dictionary but supports additional methods
        #: to load a config from files.
        self.config = self.make_config(instance_relative_config)
    
    def make_config(self, instance_relative=False):
        """Used to create the config attribute by the Flask constructor.
        The `instance_relative` parameter is passed in from the constructor
        of Flask (there named `instance_relative_config`) and indicates if
        the config should be relative to the instance path or the root path
        of the application.

        .. versionadded:: 0.8
        """
        root_path = self.root_path
        if instance_relative:  # 判定 config 的加載路徑
            root_path = self.instance_path
        defaults = dict(self.default_config)
        defaults['ENV'] = get_env()  # 設(shè)置 ENV 參數(shù)
        defaults['DEBUG'] = get_debug_flag()
        return self.config_class(root_path, defaults)

上面是源碼相關(guān)部分的簡化版本,詳細 app 的所有參數(shù)可以參看源碼棘幸。

6. Blueprint 設(shè)置

接著開發(fā) AI 語音轉(zhuǎn)文本的具體實現(xiàn)焰扳,從后續(xù)功能擴展開發(fā)的角度考慮,使用 Blueprint 的配置更適合管理代碼結(jié)構(gòu)误续。先修改 core.py 下的藍圖加載

core.py 

# -*- coding: utf8 -*-

from flask import Flask


def create_app():
    app = Flask(__name__, instance_relative_config=True)
    # load public default configuration
    app.config.from_object('config')
    # load private default configuration
    app.config.from_pyfile('default.py')

    setup_blueprints(app)  # 加載藍圖

    @app.route('/')
    def index():
        return "<h1>This is an index page.<h1/>"

    return app


def setup_blueprints(app):
    from server.AI.view import blueprint as AI  # 使用 MVC 結(jié)構(gòu)在 server 中為 AI 功能創(chuàng)建相應(yīng)的 view controller

    # 藍圖參數(shù)的配置 list
    blueprints = [
        {'handler': AI, 'url_prefix': '/AI'}
    ]

    # 循環(huán)加載服務(wù)中的所有藍圖到 app 實例中
    for bp in blueprints:
        app.register_blueprint(bp['handler'], url_prefix=bp['url_prefix'])

7. AI 語音轉(zhuǎn)文本

有了前面的配置鋪墊吨悍,相應(yīng)功能有了結(jié)構(gòu)支撐,可以快速開發(fā)完成蹋嵌。在 server 路徑下新建 AI 路徑育瓜,用來處理所有 AI 的相關(guān)功能,在 AI 路徑下栽烂,創(chuàng)建 view.py 用來處理視圖功能爆雹,創(chuàng)建 controller.py 用來處理邏輯,暫時不引入 model 層愕鼓,簡化功能的實現(xiàn)。

- FlaskTemplate
    - .circleci
        - config.yml
    - instance
        - __init__.py
        - default.py  # local 配置
        - development.py  # dev 配置
        - production.py  # prod 配置
        - staging.py  # staging 配置
    - server
        - AI
            - __init__.py
            - controller.py
            - view.py
        - __init__.py
        - core.py
    - tests
        - unit_tests
            - __init__.py
            - test_index.py
        - __init__.py
    - venv
    - .gitignore  # 非git版本管理文件
    - config.py  # git版本管理配置參數(shù)
    - README.md  # 創(chuàng)建git倉庫時選擇生成的說明文檔
    - requirements.txt  # 項目 package 安裝說明
    - run.py  # 項目啟動文件
# -*- coding: utf8 -*-

from flask import Blueprint

from server.AI import controller

blueprint = Blueprint('AI', __name__)  # 生成 AI 的藍圖實例慧起,在 core.py 會 import 并在 app 中 register


@blueprint.route('/asr')
def asr():
    rsp = controller.asr().pop()  # 調(diào)用 controller 中的處理邏輯菇晃,完成相關(guān)功能

    return rsp
# -*- coding: utf8 -*-

from flask import current_app  # 引入當前實例

from aip import AipSpeech  # 引入百度 AI 的工具

from uploads import uploads_path

# 讀取本地音頻文件內(nèi)容
def read_file(path):
    """
    read file content
    :param path: 
    :return: 
    """
    with open(path, 'rb') as f:
        return f.read()


def asr():
    """
    automatic speech recognition
    :return: 
    """
    # Baidu Cloud AI, get config params
    app_id = current_app.config['APP_ID']
    api_key = current_app.config['API_KEY']
    secret_key = current_app.config['SECRET_KEY']

    # 生成百度 AI 實例連接的 client
    client = AipSpeech(app_id, api_key, secret_key)
    # 
    def asr():
    """
    automatic speech recognition
    :return: 
    """
    # Baidu Cloud AI
    app_id = current_app.config['APP_ID']
    api_key = current_app.config['API_KEY']
    secret_key = current_app.config['SECRET_KEY']

    # 創(chuàng)建連接百度 AI 的 client
    client = AipSpeech(app_id, api_key, secret_key)
    # 連接 AI 模型返回語音轉(zhuǎn)文本的結(jié)果
    rsp = client.asr(read_file(f'{uploads_path}/stock.wav'), 'wav', 16000, {'dev_pid': 1536})

    return rsp['result']

這一期的開發(fā)不涉及前端錄音的功能,先實現(xiàn)本地錄音的語音轉(zhuǎn)文本功能蚓挤,本地語音文件放在根目錄下的 uploads 下磺送,設(shè)置如下:

- FlaskTemplate
    - .circleci
        - config.yml
    - instance
        - __init__.py
        - default.py  # local 配置
        - development.py  # dev 配置
        - production.py  # prod 配置
        - staging.py  # staging 配置
    - server
        - AI
            - __init__.py
            - controller.py
            - view.py
        - __init__.py
        - core.py
    - tests
        - unit_tests
            - __init__.py
            - test_index.py
        - __init__.py
    - uploads
        - __init__.py  # 存放當前路徑的變量
        - stock.wav  # 語音轉(zhuǎn)文本本地 demo 文件
    - venv
    - .gitignore  # 非git版本管理文件
    - config.py  # git版本管理配置參數(shù)
    - README.md  # 創(chuàng)建git倉庫時選擇生成的說明文檔
    - requirements.txt  # 項目 package 安裝說明
    - run.py  # 項目啟動文件

因為文件使用需要相應(yīng)路徑,所以在 uploads/init.py 中寫入了獲取當前路徑的變量

# -*- coding: utf8 -*-

import os

# 獲取當前路徑
uploads_path = os.path.abspath(os.path.dirname(__file__))

8. 實現(xiàn)

通過上面的開發(fā)灿意,實現(xiàn)了對項目中根路徑下 uploads/stock.wav 的自動語音轉(zhuǎn)文本的功能估灿。


image

相關(guān)鏈接
2.CI(Continuous Integration)——Flask從制作到起飛,零件級顆粒度制造
1.初始化——Flask從制作到起飛缤剧,零件級顆粒度制造

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末馅袁,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子荒辕,更是在濱河造成了極大的恐慌汗销,老刑警劉巖犹褒,帶你破解...
    沈念sama閱讀 222,627評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異弛针,居然都是意外死亡叠骑,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評論 3 399
  • 文/潘曉璐 我一進店門削茁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來宙枷,“玉大人,你說我怎么就攤上這事茧跋∥看裕” “怎么了?”我有些...
    開封第一講書人閱讀 169,346評論 0 362
  • 文/不壞的土叔 我叫張陵厌衔,是天一觀的道長璧帝。 經(jīng)常有香客問我,道長富寿,這世上最難降的妖魔是什么睬隶? 我笑而不...
    開封第一講書人閱讀 60,097評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮页徐,結(jié)果婚禮上苏潜,老公的妹妹穿的比我還像新娘。我一直安慰自己变勇,他們只是感情好恤左,可當我...
    茶點故事閱讀 69,100評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著搀绣,像睡著了一般飞袋。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上链患,一...
    開封第一講書人閱讀 52,696評論 1 312
  • 那天巧鸭,我揣著相機與錄音,去河邊找鬼麻捻。 笑死纲仍,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的贸毕。 我是一名探鬼主播郑叠,決...
    沈念sama閱讀 41,165評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼明棍!你這毒婦竟也來了乡革?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,108評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎署拟,沒想到半個月后婉宰,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,646評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡推穷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,709評論 3 342
  • 正文 我和宋清朗相戀三年心包,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片馒铃。...
    茶點故事閱讀 40,861評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡蟹腾,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出区宇,到底是詐尸還是另有隱情娃殖,我是刑警寧澤,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布议谷,位于F島的核電站炉爆,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏卧晓。R本人自食惡果不足惜芬首,卻給世界環(huán)境...
    茶點故事閱讀 42,196評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望逼裆。 院中可真熱鬧郁稍,春花似錦、人聲如沸胜宇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽桐愉。三九已至财破,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間从诲,已是汗流浹背狈究。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留盏求,地道東北人。 一個月前我還...
    沈念sama閱讀 49,287評論 3 379
  • 正文 我出身青樓亿眠,卻偏偏與公主長得像碎罚,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子纳像,可洞房花燭夜當晚...
    茶點故事閱讀 45,860評論 2 361

推薦閱讀更多精彩內(nèi)容