寫在前面的話:
作者是一名終身學(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的縮寫璧针。
這時可以獲得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)文本的功能估灿。
相關(guān)鏈接
2.CI(Continuous Integration)——Flask從制作到起飛,零件級顆粒度制造
1.初始化——Flask從制作到起飛缤剧,零件級顆粒度制造