One of the most important aspects of Python Web development is developing interfaces, and the best tool for developing interfaces is flash FastAPI, which, as its name suggests, is very fast. Of course, there are some mature REST API frameworks out there, such as Django REST Framework, Flask-restful, etc., and if performance is a priority, then FastAPI is definitely your choice.

Combined with the popular text-to-speech application scenarios, this article shows how to use FastAPI to quickly develop a text-to-speech interface, listing each step in detail, you will not find me “wechat somenzz”.

Main Contents:

  • Let me write the main function first
  • Convert functions to Web APIS
  • Write a front-end interface
  • Publish as a Docker image

1. Write the main function first

First of all, the text-to-voice interface has at least two functions, one is to convert files to voice and the other is to download voice files. These two functions are written first:

def convert_text_to_voice(text: str) - >str:
	Convert a file to a voice file, return the voice file name.
    file_name = text_to_voice(text) # text_to_voice converts text to a voice file
    return file_name

def download_file(filename: str) :
    """ Return the FileResponse object ""
    returnThe file objectCopy the code

A text_to_voice functions in the above code, the logic is the text to speech, returns the voice file filename, due to the file name and not to the user interest, so you can use text md5 code as a filename, implement different text audio files, if the corresponding file already exists, do not need to repeat, Pyttsx3 pyttSX3 pyttSX3 pyttSX3 pyTTSX3 PyTTSX3 PyTTSX3 PyTTSX3

Text_to_voice main code is as follows:

# file name text2voice.py
import pyttsx3
from pathlib import Path
import hashlib

def text_to_voice(text: str, is_man: bool = False) - >str:
    assert text and text.replace(' '.' '), "Text cannot be empty."
    filename = hashlib.md5(text.encode()).hexdigest() + ".mp3"
    filepath = Path('voices') / Path(filename)
    if filepath.exists():
        return filename
    engine = pyttsx3.init()  # object creation
    engine.save_to_file(text, filepath.as_posix())
    engine.runAndWait()
    engine.stop()
    return filename

if __name__ == '__main__':
    path = text_to_voice("Python # 7, Learn a Python trick every day.")
    print(path)
Copy the code

Now you have everything except FastAPI.

2. Turn functions into Web APIS

If you are using FastAPI for the first time, please read the official document fastapi.tiangolo.com/ and read the user guide at least once:

You can then easily convert the function in Step 1 to the corresponding Web API:

from text2voice import text_to_voice
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
from starlette.responses import FileResponse
from pathlib import Path


app = FastAPI()

@app.get("/text2voice/")
def convert_text_to_voice(text: str) :
    filename = text_to_voice(text)
    return {"filename": filename}

@app.get("/download/{filename}")
def download_file(filename:str) :
    file_path = Path('voices') / Path(filename)
    return FileResponse(file_path.as_posix(), filename=filename)
Copy the code

Py. Run uvicorn API :app –host 0.0.0.0 –port 8000 –reload to start the HTTP service on port 8000.

Browser to access http://localhost:8000/docs now, you’ll be able to these two interfaces to test.

3. Write a front-end interface

If you are not satisfied with interface development, you can write a front-end interface to play a play, front-end, I recommend Vue, other no time need not learn, this is enough. Install Node.js before using Vue.

Before using Vue, please learn the life cycle, syntax, conditional rendering, componentize and other knowledge of Vue at cn.vuejs.org/index.html.

Step 1: Install Vue scaffolding.

npm install -g @vue/cli
# OR
yarn global add @vue/cli
Copy the code

To verify this, run vue –version:

(Py38env) ➜ ~ vue -- version@vue /cli 4.5.13Copy the code

Step 2: Create a project.

Perform:

vue create front_end
Copy the code

Select the latest Vue 3

Then wait for the initialization to complete.

Step 3: Install dependencies.

To make the components more aesthetically pleasing, I’m going to introduce element-UI,

cd front_end
vue add element-plus
Copy the code

I don’t care about the size of the js file, select import all here, select CN for the following locale.

To interact with the back end, use Axios:

npm install axios
Copy the code

Step 4: Write the front-end Vue file.

infront_end/src/componentsCreate a new one in the directoryText2Voice.vue

The content of the document is as follows:

<template> <div class="hello"> <h1> <el-input type="textarea" :rows="3" placeholder=" placeholder" style="width:500px;" v-model="textarea"> </el-input> <div style="padding-top:20px"> <el-button type="primary" </el-button> </div> <div V-if ="convert" style="padding-top:20px"> </label><br/> <el-link type="primary" :href="download_url" >{{voice_name}}</el-link> </div> </div> </template> <script> Const API = "http://127.0.0.1:8000"; const axios = require('axios'); export default { name: 'Text2Voice', props: { msg: String }, data(){ return { textarea: '', voice_name: 'xxxx.mp3', download_url: '', convert: false } }, methods: {onConvert(){if(this.textarea === ""){this.$message({message: 'text cannot be empty ', type: 'warning'}); return; } axios.get(`${api}/text2voice/? text=${this.textarea}`) .then( res => { console.log(res); this.voice_name = res.data.filename; this.download_url = `${api}/download/${res.data.filename}`; console.log(this.download_url) this.convert = true; }) } } } </script>Copy the code

Then replace all HelloWorld with Text2Voice in app. vue and run NPM run serve. Open http://localhost:8080/ in your browser and you can see something like this:

Open the browser debugging tool console, and enter the text test, find the interface error:

Because localhost:8080 and localhost:8000 are two different domains, there are two solutions. One is to let the Vue go proxy, and the other is to let the back end turn on the cross-domain whitelist. I’m using the second one here. Add a whitelist to the file api.py, and the resulting code looks like this:


from text2voice import text_to_voice
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
from starlette.responses import FileResponse
from pathlib import Path
from fastapi.middleware.cors import CORSMiddleware



app = FastAPI()


origins = [
    "http://localhost:8080",
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],)@app.get("/text2voice/")
def convert_text_to_voice(text: str) :
    filename = text_to_voice(text)
    return {"filename": filename}

@app.get("/download/{filename}")
def download_file(filename:str) :
    file_path = Path('voices') / Path(filename)
    return FileResponse(file_path.as_posix(), filename=filename)

app.mount("/", StaticFiles(directory="front_end/dist",html = True), name="static")
Copy the code

At this point, you should be able to use the interface normally.

Step 5: Compile. NPM run build generates static resources such as index.html, js, and CSS, and then points the fastAPI static resources to this directory.

app.mount("/", StaticFiles(directory="front_end/dist",html = True), name="static")
Copy the code

If you open http://localhost:8000, you can access the front-end interface. In this case, cross-domain problems do not exist, and the cross-domain whitelist is not affected. For formal deployment, you can change the interface to this:

axios.get(`/text2voice/? text=${this.textarea}`) .then( res => { console.log(res); this.voice_name = res.data.filename; this.download_url = `${api}/download/${res.data.filename}`; console.log(this.download_url) this.convert = true; })Copy the code

4. Publish as a Docker image

How will other people use what you write? At present, the most popular way is to publish a Docker image, users do not need to step by step to deal with the environment configuration, a Docker run command can use your program, very efficient.

Create a new file Dockerfile in the same directory as the api.py file, with the following contents:

FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7
RUN apt update && apt -y install espeak ffmpeg libespeak1
COPY ./ /app
Copy the code

Of course, in order not to make the Docker image too large, we need to ignore some unnecessary files, with the.dockerignore file to do this, the content is as follows:

front_end/node_modules
front_end/public
front_end/src
front_end/package.json
front_end/package-lock.json
front_end/babel.config.js
voices
__pycache__
front_end/.DS_Store
/front_end/.git/
Copy the code

Docker build -t text2Voice. Package the image file.

Perform docker images | grep text2voice check already packaged good image:

Then start the container and test it:

docker run -d -p 80:80 -e MODULE_NAME="api" -e PORT=80 text2voice
Copy the code

Note: -e MODULE_NAME=” API “-e PORT=80 -p 80:80 indicates that port 80 of the container is exposed to port 80 of the host. Now open a browser and type http://localhost to see the effect:

OK, here we go. Start by signing up for an account at hub.docker.com/ and creating a repository, such as Text2Voice.

Note that the repository we created is text2Voice, if your id is somenzz, so docker tag text2Voice somenzz/ text2Voice to tag the image. Then execute docker push somenzz/ text2Voice to upload the local image to hub.docker.com.

Next, someone can execute a command to use your program, provided Docker is installed:

docker run -d -p 80:80 -e MODULE_NAME="api" -e PORT=80 somenzz/text2voice
Copy the code

Docker automatically downloads the image and launches a container that others can access from their browser at http://localhost. Interface documentation: http://localhost/docs.

The last word

The sparrow is the smallest and has all the organs. The above mentioned interface development, front-end development, release Docker and other links, although simple, but also shows a set of Web development process, if it is helpful to your Web development, please look at, like support.

Now that you’ve seen this, are you sure you don’t want to pay attention?