Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

这篇文章将会讲述如何将Django项目部署到自己所购买的服务器上(腾讯云+Centos+django+nginx+uwsgi)

1、前言

这篇文章的形成可真是来之不易啊,本人通过一系列的方法通过三天时间才成功实现在服务器上部署对应的django项目,本来中途都打算放弃了但是经过朋友的提醒在B站上找到了相关视频后,就重新捡起了这个计划(毕竟一个服务器也不是随随便便就可以浪费的)总的来说,一开始虎头虎脑的跟着CSDN上的文章就做了起来,而由于之前没有任何相关的经验,所以很多东西下载了之后我都不知道有什么用,然后跟着教程一个个配置文件但是最后都是以失败告终;最后根据朋友的建议去B站发现了武沛齐老师的视频,然后跟着理解所有内容之后,实际搭建过程可能仅仅需要一个下午的时间而已😥😥😥。我也吸取到了对应的教训,只有先学懂知识才懂得如何应用,不然就算你的结果是对的,只要换个新的环境那么你又会遇到种种新的问题而不知如何解决

在这里我得先感谢一下武沛齐老师,在B站观看了他的讲解视频之后就突然茅塞顿开了,以及CSDN各个作者对我的帮助,这些文章链接都会在下文有所提到

2、Web项目部署本质

在开始配置之前,大家需要明白我们为什么要把对应的项目部署到服务器上。相信进行过django/flask开发的人应该都知道我们可以通过在本地的回环地址:指定端口号来开启我们的服务,但是这个服务仅仅适用于一个局域网下而已,比如一间大学宿舍,全部舍友都接入同个路由器,那么这个项目也就只有你们宿舍的人可以访问而已,所以我们需要通过将项目部署到服务器然后让其他地方的人都可以进行访问,而这个过程就分为以下几步:

  1. 将本地项目上传到服务器上并且支持各项功能
  2. 服务器开放对应端口,让各项服务请求可以进入服务器
  3. 服务器对请求进行处理并且进行相关响应

这里就借用武沛齐老师的图来给大家展示总体项目的框架

1

3、服务器配置

3.1、获得服务器

首先,我们需要获得一个服务器,大家可以去腾讯云或者阿里云租用对应的服务器,而且一般都有一个月的免费试用时间,大家可以用利用这段时间进行练手。

3.2、将项目部署到服务器上

在进行部署之前,我们需要知道哪些方法可以让我们去操作我们租用好的服务器。首先,如果你使用的是腾讯云的话(没用过阿里云🫠)它有内置对应的操作界面,只要直接登陆就可以了,不过这个界面经常

1

需要你进行验证登陆并且一会没有使用就会掉线;其次,就是使用一些专业的ssh软件,我本人使用的便是Xshell,操作一样简便,个人用的话也是免费的,它的操作延迟会比腾讯云的延迟低很多,操作体验很好,至于剩下的软件就交由大家进行探索啦……

当你拥有了属于自己的服务器并且能够正常的连接后,你就可以将自己的项目传到服务器了,当然了传输文件的方法也是很多。例如,腾讯云面板直接传输,还有Xshell的传输等等……

大家目前看到这里肯定觉得腾讯云有猫腻,既然是腾讯的产品怎么可能会不需要收费呢?收费点现在就来了,腾讯云的文件传输虽然方便但是超过500Mb的文件就要付费了,而Xshell则没有对应的限制,其传输方法可以参考这里

而现在最常用的方法就是通过git来进行传输,通过将本地的代码项目上传到对应的代码托管平台,然后在服务器中进行拉取操作就可以获得对应项目代码了,常见的代码托管平台就是github、gitee以及gitlab,如果是国内的小伙伴们,大家还是尽量选择gitee吧,不需要进行科学上网便可以直接访问,对应的操作这里便不详谈了。

3.3、相关环境配置

在你完成以上内容后,就可以配置对应的环境了。这里主要谈及的是python环境的配置。

  • 安装gcc

    1
    yum install gcc -y

    由于python的底层代码是用C语言编写的,所以我们需要下载gcc编译器来帮助我们编译python的源码。至于这里使用 yum是因为我使用的操作系统是Centos,如果是Ubuntu系统应该就是使用 apt-get指令了,最后的 -y是到时候你不需要手动输入yes就可以直接下载了。

  • 安装python依赖

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    yum install zlib zlib-devel -y
    yum install bzip2 bzip2-devel -y
    yum install ncurses ncurses-devel -y
    yum install readline readline-devel -y
    yum install openssl openssl-devel -y
    yum install xz lzma xz-devel -y
    yum install sqlite sqlite-devel
    yum install gdbm gdbm-devel -y
    yum install tk tk-devel -y
    yum install mysql-devel -y
    yum install python-devel -y
    yum install libffi-devel -y
    yum install libffi libffi-devel -y

    以上是常见的python依赖,不过这里稍微埋下了一个坑到后续我会揭晓这里的坑。

  • 下载源码

    1
    2
    3
    yum install wget -y

    wget https://www.python.org/ftp/python/3.9.5/Python-3.9.5.tgz

    这里的python版本按照大家自己的需求来就可以了,没有什么需要注意的地方

  • 解压&编译&安装

    • 解压

      1
      tar -xvf Python-3.9.5.tgz
    • 编译&安装

      1
      2
      ./configure
      make all && make install

      在这些步骤完成之后,大家可以去对应的文件夹进行查看

/usr/local/bin/pip3.9

/usr/local/bin/python3.9

注意这里的文件夹路径是usr而不是user,由于系统本身可能会自带python所以python3的版本一般不是你下载的版本,如果要让全局的python3都是这个版本就使用这个代码 sudo ln -sf /usr/local/bin/python3.9 /usr/bin/python3即可

  • 使用虚拟环境进行管理
    就像上面我们所遇到的关于python版本的种种问题,我们最好使用虚拟环境来对不同版本python进行管理

    • 安装virtualenv

      1
      pip3.9 install virtualenv
    • 创建虚拟环境
      在这一步中,我们需要了解一下项目开发的规范,一般我们将对应项目放到 /data/www/项目名路径下进行管理,而将虚拟环境统一放到 /envs/虚拟环境名路径下进行管理

      1
      2
      mkdir /envs
      virtualenv /envs/django --python=python3.9

      创建完对应的虚拟环境之后,我们便可以启动对应的虚拟环境,无论你现在身处哪个目录,只要输入以下命令均可以激活虚拟环境,后面的那个路径替换成自己虚拟环境的路径即可,要退出环境的话就下面那个指令就可以了

      1
      2
      source /envs/django/bin/activate
      deactivate

      至此,我们便完成了python环境的安装,然后在安装你项目需要的一些库函数就可以了。

      当你的项目不需要与数据库MySQL进行互动时,一切进展都是十分顺利的。可是当你需要与MySQL进行连接时,此时你会遇到一个最头疼的问题那就是当你使用 pip install mysqlclient时,你会遇到难以解决的报错,这个报错让我重装了好几次服务器的系统并且安装以及卸载了许多次MySQL。之所以,把这个提到这么前面来讲,是因为如果这个步骤你做好了,那么剩下你配置数据库的过程便不会再有其他问题了

  • mysqlclient下载问题解决

    这个问题我寻找了很多方法也问过了很多次GPT,到最后才在CSDN上找到最关键的一篇文章,跟着这篇文章操作下来是一定不会有问题的。正如这篇文章里面说的那样,Centos中mysql数据库以及mariadb二者是不兼容的,然后当初在你下载python依赖中,你有下载到相关的 mysql-devel的依赖库,但是这个库确实为mariadb所适配的,导致你没有mysql中的依赖然后导致整个下载过程出现问题;同样的,在服务器上下载Mysql也是一个比较麻烦的事情,而这篇文章的作者有强调下载那个依赖包而不是要下载mysql,但是你可以通过这个方法将mysql一起下载下来十分省事。

    • 当你按照作者所说的得到对应的RPM包并且已经解压之后,就可以执行以下命令然后安装mysql服务了(注意不要随便改变顺序)

      1
      2
      3
      4
      5
      sudo rpm -ivh mysql-community-common-5.7.44-1.el7.x86_64.rpm
      sudo rpm -ivh mysql-community-libs-5.7.44-1.el7.x86_64.rpm
      sudo rpm -ivh mysql-community-libs-compat-5.7.44-1.el7.x86_64.rpm
      sudo rpm -ivh mysql-community-client-5.7.44-1.el7.x86_64.rpm
      sudo rpm -ivh mysql-community-server-5.7.44-1.el7.x86_64.rpm
    • 接着,就可以启动mysql服务并且设置开机自启动

      1
      2
      sudo systemctl start mysqld
      sudo systemctl enable mysqld

      按照以上方法,你就可以完美解决下载 mysqlclient问题,并且成功下载好Mysql并且使用其的服务

3.4、Mysql配置

这部分是适用于需要mysql服务的,如果不需要则可以直接往后看。经过上面的操作,我们便需要对Mysql本身进行配置。

  • 初始化信息
    因为按照之前的方法,我们使用的是Mysql,所以我们需要先通过以下指令来获取初始密码然后进行登陆

    1
    2
    3
    sudo grep 'temporary password' /var/log/mysqld.log

    mysql -u root -p
  • 修改密码并且添加用户
    由于系统随机的初始密码比较难记所以需要你先更改掉对应的密码:

    1
    ALTER USER 'root'@'localhost' IDENTIFIED BY 'YourNewPassword';

    更改完密码之后,我们可以新建用户用于远程操作服务器上的数据库,不过授予用户权限之前还需要先创建数据库,然后将对应数据库的所有权限授予给那个用户,并且最后刷新权限即可

    1
    2
    3
    4
    CREATE USER 'yourname'@'%' IDENTIFIED BY 'YourNewPassword';
    create database baomi;
    grant all privileges on baomi.* to 'yourname'@'%';
    flush privileges;

    有些系统会自动设置防火墙,所以你为了能够在外面进行访问,记得退出mysql后,在终端中开启对应的端口,让你的远程电脑能够进行访问

    1
    2
    3
    systemctl start firewalld.service
    sudo firewall-cmd --zone=public --add-port=3306/tcp --permanent
    sudo firewall-cmd --reload

    因为我们都是使用服务器的,所以还需要在控制界面开放对应的端口:

1
  • 数据库内容导入
    经过以上步骤你就可以用你常用的数据库软件进行数据的导入,如果原先没有数据的话,就按照django的流程来迁移数据库即可,如果有数据的话直接导入到现有数据库就行,django也是会自动识别的。
3.5、django项目部署

由于我们使用了django框架,那么里面的 setting.py文件还是需要我们进行修改来适配现在的服务器环境。

  • 基础设置修改

    1
    2
    3
    DEBUG = True -> False

    ALLOWED_HOSTS = [] -> ["*"]

    上述的两个修改分别指的是将DEBUG模式调成False,然后接受访问的主体修改为‘*’也就是所有计算机都可以访问数据库的内容

  • 数据库连接设置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    DATABASES = {
    'default':{
    'ENGINE': 'django.db.backends.mysql', # 不用动
    'NAME': 'baomi', # 连接的数据库名
    'USER': 'root', # 登陆的用户
    'PASSWORD': '******', # 登陆密码
    'HOST': 'localhost', # 在web服务器上就是公网ip地址,localhost也可以
    'PORT': '3306', # 不用动
    }
    }
  • 静态文件的配置

    对于这部分的配置,在网上搜到的教程都是需要的,但是其实到后面只要nginx服务所指向的是你的static文件夹就不需要对此进行什么配置了。

    1
    2
    3
    4
    5
    import os
    STATIC_URL = '/static/'
    STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static"),
    ]

    如果要进行以上的静态文件配置的话,记得还需要执行以下命令将所有静态文件收集起来

    1
    python manage.py collectstatic
  • 踩坑点

    这里有一个十分细节的踩坑点,当时我的配置全部正确然后进行页面跳转的时候总是会出现问题,然后找了半天发现运行django项目时有这样的一个报错:

    1
    django.db.utils.NotSupportedError: MySQL 8 or later is required (found 5.7.44).

    而解决这个报错的方法也是比较简单,只要去找到你虚拟环境中的 base.py文件进行修改即可,我的路径是这样的 /envs/django/lib/python3.9/site-packages/django/db/backends/base/base.py这个我在网上找的时候,发现每个人的路径好像都不相同,但是大体肯定是这样的,自己找的时候留心一点就可以了。进去这个文件之后,直接查找 init_connection_state这个函数,然后将里面的 self.check_database_version_supported()语句注释掉就可以了。

    1
    2
    3
    4
    5
    6
    7

    def init_connection_state(self):
    """Initialize the database connection settings."""
    global RAN_DB_VERSION_CHECK
    if self.alias not in RAN_DB_VERSION_CHECK:
    # self.check_database_version_supported()
    RAN_DB_VERSION_CHECK.add(self.alias)

    当时因为直接使用nginx以及uwsgi导致django这边小小的问题并没有显示出来,而那些页面都是需要验证数据库数据进行跳转的页面,那由于这个报错那些页面自然也就无法成功跳转了。配置好以上这些,只需要我们进行网页的请求以及响应配置就可以让我们的django项目跑起来了。

4、网页请求与响应处理

在开始这部分的介绍前,我们需要先了解web中各个部件的原理,这里再次借用武沛齐老师的图片:

1

电脑上不可避免的会需要处理很多软件的需求,而这些不同软件的需求都会进入到不同的socket也就是指的各个端口,而处理完的信息也是通过各个端口发送到请求方。原先的django项目就是直接收集来自其他浏览器80端口的访问,并且返回对应的数据,可是django这种机制设计的并不稳定,所以我们需要利用uwsgi来代替django内部的插件来对互联网中的请求提供更稳定的接收,可是uwsgi本身对于html文件中的静态文件处理能力不行,所以还需要nginx来处理静态文件。总结而言,当其他浏览器对服务器进行访问时,如果是涉及静态文件的处理那么就由nginx自己来进行解决,而对于其他请求则转发给uwsgi,然后uwsgi在通过python代码来进行处理,最后一并返还给请求方,这就是总体的工作原理。

4.1、uwsgi的安装与配置
  • 安装uwsgi
    首先,让我们进入我们一开始设置好的虚拟环境进行uwsgi的下载

    1
    pip install uwsgi
  • 配置uwsgi
    接着,我们通过编写对应的配置文件来启动uwsgi,该配置文件 uwsgi.ini须放在项目的根目录下也就是与 manage.py文件同一级,以下就是配置文件的标准写法(复制过去后,记得将注释删除掉避免出现不必要的bug)

    1
    2
    3
    4
    5
    6
    7
    [uwsgi]
    socket = 127.0.0.1:8001 # 其中端口号可以自己修改
    chdir = /data/www/baomi/ # 你项目的根目录
    wsgi-file = baomi/wsgi.py # django项目中自动会有wsgi.py文件
    callable = application
    processes = 2 # 看你的服务器是几核就填几
    virtualenv = /envs/django/ # 虚拟环境路径
  • 启动/关闭uwsgi

    由于我们是在虚拟环境中下载的,所以我们需要先进入虚拟环境中,然后进入项目的根目录 /data/www/baomi在终端输入以下命令就可以启动该服务了

    1
    uwsgi --ini uwsgi.ini

    而如果要关闭服务那么按住Ctrl + C即可退出,如果后续你发现启动时有报错说有其他实例uwsgi在占用端口的话,你可以输入 ps -ef|grep uwsgi命令来查看现有进程:

    1

    找到其中是uwsgi –ini命令的进程号,然后输入 kill -9 进程号杀死该进程即可。
    那么还有人会说,当我启动服务之后我无论终端输入什么内容都没有作用,那么为了你能够在开启服务后还能使用该终端可以输入以下的命令:

    1
    uwsgi --ini uwsgi.ini &

    这样你就可以接着输入其他命令了。

4.2、nginx的安装与配置
  • 安装nginx
    与uwsgi不同,nginx可以不用只在虚拟环境下安装,因为其用的是 yum指令

    1
    yum install nginx -y
  • 配置nginx

    我们需要修改nginx的配置文件,而这个位置在 /etc/nginx/nginx.conf

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    # For more information on configuration, see:
    # * Official English Documentation: http://nginx.org/en/docs/
    # * Official Russian Documentation: http://nginx.org/ru/docs/

    user nginx;
    worker_processes auto;
    error_log /var/log/nginx/error.log;
    pid /run/nginx.pid;

    # Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
    include /usr/share/nginx/modules/*.conf;

    events {
    worker_connections 1024;
    }

    http {
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
    '$status $body_bytes_sent "$http_referer" '
    '"$http_user_agent" "$http_x_forwarded_for"';

    access_log /var/log/nginx/access.log main;

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 4096;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    # Load modular configuration files from the /etc/nginx/conf.d directory.
    # See http://nginx.org/en/docs/ngx_core_module.html#include
    # for more information.
    # include /etc/nginx/conf.d/*.conf;

    upstream django {
    server 127.0.0.1:8001; # 一定要与uwsgi.ini文件的一致
    }

    server {
    listen 80; #表示监听80端口
    listen [::]:80;

    # Load configuration files for the default server block.
    # include /etc/nginx/default.d/*.conf;

    location /static { #静态文件就是指定文件夹即可,有nginx自己处理
    alias /data/www/baomi/app01/static;
    }

    location / { #其他文件交给uwsgi处理
    uwsgi_pass django; # 名字与upstream那个相同
    include uwsgi_params; # 固定不用动
    }
    }
    }

    该配置中主要修改的就是server部分,按照这样修改就没有问题了。

4.3、nginx的启动
  • 启动

    1
    2
    3
    4
    5
    systemctl start nginx
    systemctl status nginx
    systemctl restart nginx

    systemctl enable nginx

    第一条语句是启动nginx服务,而第二条则是查看当前nginx服务的状态,第三条则是重启nginx服务,而最后一条命令就是设置开机自启动nginx服务,这样即使你断开与服务器的SSH连接,服务也会照样进行着

通过所有这些内容,你的项目已经可以跑动起来了,但是你会发现一点,当你中断与服务器的SSH连接时,虽然你的nginx服务不会中断,但是你的uwsgi服务会自动断联,这样你的服务器后续的服务也是无法进行的,所以我们需要来到最后一步,把你的uwsgi设置成跟nginx可以开机自启动。

4.4、systemd配置

为了进行配置,我们需要进入以下目录 /etc/systemd/system然后新建一个 uwsgi.service文件,并且填入以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[Unit]
Description=uWSGI service for Baomi project
Requires=network.target
After=network.target
After=syslog.target

[Service]
WorkingDirectory=/data/www/baomi # 项目根目录
ExecStart=/bin/bash -c "source /envs/django/bin/activate && uwsgi --ini uwsgi.ini" #终端输入的内容,先激活虚拟环境,然后开启服务(类似脚本的操作)
KillSignal=SIGQUIT
Type=simple
NotifyAccess=all
StandardError=syslog
RuntimeDirectory=uwsgi
[Install]
WantedBy=multi-user.target

这个配置文件的书写,我是参考这篇博客。不知道看到这里大家还是否记得当时我在配置文件中提到要将注释删除避免那些不必要的bug。当时我一直修改这个文件以为是自己写错了,结果一问GPT告诉我这里不支持内联的注释,所以要么换行要么删除,我一改就真的成功了,也算是一个刻骨铭心的经历了。

激活这个配置就简单了,看着是不是跟nginx的一模一样?启动之后,你就可以放心的关掉SSH连接并且尽情的访问自己的网站了。

1
2
3
sudo systemctl daemon-reload
sudo systemctl enable uwsgi.service
sudo systemctl start uwsgi.service

5、总结

这个项目的配置花了我整整3天时间,经历了太多的失败与报错,但是好在最后还是配置成功了,给自己留下了一个难忘的经历!以后一定要记住要先学好原理再办事,这样才是事半功倍的,不然就会本末倒置事倍功半了,写此篇与诸君共勉~

6、语音功能更新(edge-tts)

幸好之前写下了这篇配置文档,不然后续功能的更新有要花费很大力气了,这次功能的更新主要是更新了网页的语音功能,我看到网上都没有对应的教程所以也算是自己摸索出来的配置过程。首先,要实现文字转为语音我搜到的有3个库分别是 gTTS(Goole Text-to-Speech)pyttsx3edge-tts(微软 Netural TTS)这三者的区别如下所示:

特性 gTTS(Google TTS) pyttsx3(离线引擎) edge-tts(微软 TTS)
是否在线 ✅ 需要联网 ✅ 离线,可本地运行 ✅ 需要联网
音质 🌟🌟🌟(接近人声,但是断句不行) 🌟🌟(机械感较重) 🌟🌟🌟🌟🌟(提供多种人声选择,断句符合语言逻辑)
中文支持 ✅(支持多种语言) ❌(中文支持差,需要下载相应中文包) ✅(微软官方中文语音)
语音选择 ✅(Google 多种语音) ⚠️(取决于本地 TTS) ✅(微软 Neural 语音)
生成速度 ⚡ 快(云端处理) 🚀 非常快(本地计算) ⚡ 快(云端处理)
文件格式 MP3 WAV(不太常用) MP3
安装复杂度 ⚠️ 需要 pip install gtts ✅ 仅需 pip install pyttsx3 ✅ 需要 pip install edge-tts
服务器适用性 ⚠️(可能受 Google API 限制) ✅(完全本地,不依赖外部 API) ✅(适合服务器,微软云端支持)
TTS 引擎 Google TTS API 本地操作系统 TTS 微软 Edge Neural TTS
适用场景 需要高质量语音 ,但需要网络 本地离线运行 ,但音质较差 微软高质量语音 ,但需要网络

以上的三种方式,本人在部署服务器的时候均有尝试过,所以以上的建议也都是本人探索出来的,接下来就开始配置过程的叙述吧。

6.1 gTTS

在本地写gTTS的代码时,本地调试是可以正常运行的并且也生成了对应的语音文件,但是一移动到服务器上就出现各种问题,那我们先从本地开始配置:

首先,我们需要实现相关的语音逻辑,即先检查该项目的语音文件是否已经存在?若不存在则需要进行生成,若存在直接指向对应文件的URL即可(在配置之前记得要下载 gTTS库)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import os
from django.shortcuts import render, get_object_or_404
from django.conf import settings
from app01 import models
from gtts import gTTS

def term_detail(request, term_id):
# 获取术语详情
term = get_object_or_404(models.Terms, id=term_id)

# 确保音频文件存储目录存在
audio_dir = os.path.join(settings.MEDIA_ROOT, 'audio')
os.makedirs(audio_dir, exist_ok=True)

# 生成音频文件的路径
audio_filename = f"term_{term_id}.mp3"
audio_path = os.path.join(audio_dir, audio_filename)

# 如果音频文件不存在,则生成它
if not os.path.exists(audio_path):
tts = gTTS(text=term.exp, lang='zh', tld='cn') # 设定术语的语种为中文,并且采取中文服务器,不然是连接不通的
tts.save(audio_path)

# 生成音频文件的 URL
audio_file_url = f"{settings.MEDIA_URL}audio/{audio_filename}"

return render(request, 'term_detail.html', {'term': term, 'audio_file_url': audio_file_url})

上面代码的逻辑也是较好理解,不过一开始会先确认对应的媒体文件的文件夹是否存在,这个配置便需要修改 settings.py文件我们等会在说;然后就是实现我上面的逻辑,最后语音文件所在的URL传递给前端模板即可,以下是一个对应的前端模板。

1
2
3
4
5
6
7
8
9
{% if audio_file_url %}
<audio controls>
<source src="{{ audio_file_url }}" type="audio/mpeg">
您的浏览器不支持音频播放。
</audio>
<p>音频文件 URL: {{ audio_file_url }}</p>
{% else %}
<p>无法生成音频文件。</p>
{% endif %}

其生成的语音文件效果如下所示:

在配置过程中我遇到的问题:

问题1

ImportError: urllib3 v2 only supports OpenSSL 1.1.1+ 表示当前你的Python运行环境中的OpenSSL版本过低,而 urllib3需要OpenSSL 1.1.1 或更高版本

解决方法

先下载更新高版本的 openssl,然后对之前手动编译的 python库进行重编译即可(这个步骤在网上有很多教程,这里便不赘述了)

Folding 点击查看原因

gTTS 依赖 requests,而 requests 依赖 urllib3,而 urllib3 在新版 (v2.x) 开始强制要求 OpenSSL 1.1.1+

问题2

由于我在解决问题1时重编译并且删除了原有的 openssl以及 python导致 nginx被自动卸载了,而且问题1也没有解决

解决方法

只能重新将所有内容下载回来

Folding 点击查看原因

nginx的运行依赖就是 openssl所以删除原来的 openssl时,其也被连带删除了;并且其依赖的 openssl版本刚好就是 openssl.x86_64 1:1.0.2k-26.el7_9这个低版本的

所以想必大家也看出了问题1和问题2之间的冲突矛盾,而这个冲突也迫使我放弃了这个库的使用

6.2 pyttsx3

由于上面的方法对网络的需求较大,所以我便转向了使用 pyttsx3以便于可以在本地就生成对应的录音文件,代码的逻辑与上面的也是相同,不过需要更换库函数的使用,具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
def term_detail(request, term_id):
# 获取术语详情
term = get_object_or_404(models.Terms, id=term_id)

# 确保音频文件存储目录存在
audio_dir = os.path.join(settings.MEDIA_ROOT, 'audio')
os.makedirs(audio_dir, exist_ok=True)

# 生成音频文件的路径(使用.wav扩展名)
audio_filename = f"term_{term.name}.wav"
audio_path = os.path.join(audio_dir, audio_filename)

# 如果音频文件不存在,则生成它
if not os.path.exists(audio_path):
# 初始化语音引擎
engine = pyttsx3.init()

# 尝试设置中文语音(需要系统支持)
voices = engine.getProperty('voices')
for voice in voices:
# 根据系统实际支持的语音进行调整
if 'zh' in (voice.languages or []) or 'chinese' in voice.name.lower():
engine.setProperty('voice', voice.id)
break

# 设置语速(可选)
engine.setProperty('rate', 150)

# 生成并保存语音文件
engine.save_to_file(term.exp, audio_path)
engine.runAndWait() # 确保生成完成

# 生成音频文件的 URL
audio_file_url = f"{settings.MEDIA_URL}audio/{audio_filename}"

return render(request, 'term_detail.html', {
'term': term,
'audio_file_url': audio_file_url
})

需要注意的是,通过 pyttsx3生成的音频文件类型为 .wav,但是如果要转化为 .mp3也是有方法(网上也有很多教程),而对应的 html文件就是像上面提到的保留即可,其生成的语音文件效果如下所示:

可以听出来人机味还是比较重的,效果比较一般。在进行部署的环节中,要注意先下载对应的中文语音包(eg.espeak-ng)才可以使用。

在配置过程中我遇到的问题:

问题1

使用项目时出现这个报错ffmpeg: command not found

解决方法

1
2
sudo yum install -y epel-release
sudo yum install -y ffmpeg ffmpeg-devel
Folding 点击查看原因

FFmpeg,这是一个开源的音视频处理工具,许多 TTS(文本转语音) 库(如 gTTS、pyttsx3)在转换语音文件时依赖它。

问题2

安装完ffmpeg之后出现以下问题:
nasm not found or too old. Please install/update nasm
Threading is enabled, but no atomics are available
而且不知道要如何解决。

于是,我也不得以继续放弃这个库。

6.3 edge-tts

看到这里有人会问了“作者作者,怎么到现在一个成功的都没有,你这个更新是不是失败了?”,我的回答是真正的救星它终于来了!在我心灰意冷之际,我转向了最后的这个库,但是令我没想到的是,这个库特别的方便只需要稍微配置就成功了,也算是终结了我的烦恼,它的具体代码如下所示:(不要忘记安装 edge-tts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import os
import asyncio
import edge_tts
from django.conf import settings
from django.shortcuts import render, get_object_or_404

async def generate_audio(text, audio_path):
"""异步生成语音文件"""
voice = "zh-CN-XiaoxiaoNeural" # 选择微软的中文女声
tts = edge_tts.Communicate(text, voice)
await tts.save(audio_path) # 直接保存为 MP3 文件

def term_detail(request, term_id):
# 获取术语详情
term = get_object_or_404(models.Terms, id=term_id)

# 确保音频文件存储目录存在
audio_dir = os.path.join(settings.MEDIA_ROOT, 'audio')
os.makedirs(audio_dir, exist_ok=True)

# 生成音频文件路径(使用 .mp3 格式)
audio_filename = f"term_{term.id}.mp3"
audio_path = os.path.join(audio_dir, audio_filename)

# 如果音频文件不存在,则生成它
if not os.path.exists(audio_path):
asyncio.run(generate_audio(term.exp, audio_path))

# 生成可访问的音频 URL
audio_file_url = f"{settings.MEDIA_URL}audio/{audio_filename}"

return render(request, 'term_detail.html', {
'term': term,
'audio_file_url': audio_file_url
})

具体的代码逻辑都是相同的,而这个库生成的语音也是我最喜欢的一个,并且断句都非常符合人的直觉,所以算是我最喜欢的一个库了。

这个的配置过程没有任何问题,而且生成语音的速度还算不错,可以直接部署到服务器上。

6.4 相关配置

目前而言,我们只是处理好了 django中的代码逻辑,还需要进一步的将其配置到服务器上。之前的静态文件都是放在对应的 static文件夹中,而这次我们添加的媒体文件可以从路径上看是在 .../media/audio里面的,所以我们先要让 django知道我们放媒体文件的地址,打开 settings.py,添加如下代码:

1
2
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

由于,服务器上不会自动帮你生成media和audio文件夹,所以你就在项目的根目录里自行创建即可。

前面也有提到静态文件都是通过 nginx来帮我们处理的,所以我们也得将对应媒体文件的目录加到里面,我们再次对 /etc/nginx/nginx.conf进行修改,添加上这几句代码:

1
2
3
4
5
6
7
8
9
10
11
12
       location /static {       #静态文件就是指定文件夹即可,有nginx自己处理
alias /data/www/baomi/app01/static;
}

location /media { #注意只需要到media目录下就行,不需要继续往下
alias /data/www/baomi/media;
}

location / { #其他文件交给uwsgi处理
uwsgi_pass django; # 名字与upstream那个相同
include uwsgi_params; # 固定不用动
}

添加完代码后不要忘记重新 nginx服务:systemctl restart nginx,在这里还需要注意一点,我们需要修改media文件夹的权限,让 nginx有权限能够对该文件夹进行修改,这样才能将对应的音频文件生成并且放进去。

评论