{"id":4620,"date":"2025-07-15T22:17:14","date_gmt":"2025-07-15T13:17:14","guid":{"rendered":"https:\/\/eternalsphere.net\/echoes\/?p=4620"},"modified":"2026-06-06T10:20:14","modified_gmt":"2026-06-06T01:20:14","slug":"nw4qtvmrzi3u67x","status":"publish","type":"post","link":"https:\/\/eternalsphere.net\/echoes\/index.php\/2025\/07\/15\/nw4qtvmrzi3u67x\/","title":{"rendered":"Whisper \u670d\u52a1\u5668 + \u7f51\u9875\u524d\u7aef\u5b8c\u6574\u5b89\u88c5\u6559\u7a0b"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">\ud83c\udfaf \u529f\u80fd\u76ee\u6807<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">\u2705 \u670d\u52a1\u5668\u4e0a\u8fd0\u884c Whisper\uff08\u7528 GPU \u52a0\u901f\uff09<br>\u2705 \u7f51\u9875\u754c\u9762\u767b\u5f55\uff08\u8d26\u53f7\u5bc6\u7801\uff09<br>\u2705 \u4e0a\u4f20\u97f3\u9891\u6587\u4ef6\u8fdb\u884c\u8bc6\u522b<br>\u2705 \u53ef\u9009\u8bed\u8a00\uff08\u6216\u81ea\u52a8\u68c0\u6d4b\uff09<br>\u2705 \u8fd4\u56de\u6587\u672c\u7ed3\u679c<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udfe2 \u4e00\u3001\u670d\u52a1\u5668\u51c6\u5907<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">1\ufe0f\u20e3 \u786c\u4ef6<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>GPU\uff1aNVIDIA<\/li>\n\n\n\n<li>\u5185\u5b58\uff1a\u2265 8 GB<\/li>\n\n\n\n<li>\u7cfb\u7edf\uff1aLinux (\u63a8\u8350 Ubuntu 20.04+ \/ Arch Linux)<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h3 class=\"wp-block-heading\">2\ufe0f\u20e3 \u9a71\u52a8 &amp; CUDA<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u5b89\u88c5 NVIDIA \u9a71\u52a8 + CUDA\uff08\u4ee5 Ubuntu \u4e3a\u4f8b\uff09\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><code>sudo apt update<br>sudo apt install nvidia-driver-535 nvidia-cuda-toolkit<br><\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\u9a8c\u8bc1\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><code>nvidia-smi<br><\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udfe2 \u4e8c\u3001Python \u73af\u5883<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">1\ufe0f\u20e3 \u5b89\u88c5 Python<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u5efa\u8bae Python 3.9+<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><code>sudo apt install python3 python3-venv python3-pip<br><\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h3 class=\"wp-block-heading\">2\ufe0f\u20e3 \u521b\u5efa\u865a\u62df\u73af\u5883<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\"><code>python3 -m venv ~\/whisper-env<br>source ~\/whisper-env\/bin\/activate<br><\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udfe2 \u4e09\u3001\u5b89\u88c5\u4f9d\u8d56<\/h2>\n\n\n\n<pre class=\"wp-block-preformatted\"><code>pip install --upgrade pip<br>pip install openai-whisper flask flask-login werkzeug<br><\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udfe2 \u56db\u3001Flask \u5e94\u7528\u76ee\u5f55\u7ed3\u6784<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">\u5728\u670d\u52a1\u5668\u4e0a\u5efa\u4e00\u4e2a\u9879\u76ee\u76ee\u5f55\uff0c\u6bd4\u5982\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><code>~\/whisper-web\/<br>\u251c\u2500\u2500 app.py<br>\u251c\u2500\u2500 templates\/<br>\u2502   \u251c\u2500\u2500 login.html<br>\u2502   \u251c\u2500\u2500 upload.html<br>\u2502   \u2514\u2500\u2500 result.html<br>\u251c\u2500\u2500 static\/<br>\u2502   \u2514\u2500\u2500 style.css<br>\u251c\u2500\u2500 users.json<br><\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udfe2 \u4e94\u3001\u6838\u5fc3\u4ee3\u7801\uff08\u793a\u4f8b\uff09<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\"><code>app.py<\/code><\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\"><code>import os<br>import whisper<br>from flask import Flask, render_template, request, redirect, url_for, flash, session<br>from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user<br><br>app = Flask(__name__)<br>app.secret_key = 'your_secret_key'<br><br>login_manager = LoginManager()<br>login_manager.init_app(app)<br><br># \u7b80\u5355\u7528\u6237\u8868\uff08\u793a\u4f8b\uff09<br>USERS = {'admin': {'password': 'test123'}}<br><br>class User(UserMixin):<br>    def __init__(self, id):<br>        self.id = id<br><br>@login_manager.user_loader<br>def load_user(user_id):<br>    if user_id in USERS:<br>        return User(user_id)<br>    return None<br><br># \u52a0\u8f7d Whisper \u6a21\u578b\uff08\u53ef\u6539\u6210 large \/ medium\uff09<br>model = whisper.load_model(\"medium\", device=\"cuda\")<br><br>@app.route(\"\/\", methods=[\"GET\", \"POST\"])<br>def login():<br>    if request.method == \"POST\":<br>        username = request.form[\"username\"]<br>        password = request.form[\"password\"]<br>        if username in USERS and USERS[username]['password'] == password:<br>            user = User(username)<br>            login_user(user)<br>            return redirect(url_for(\"upload\"))<br>        else:<br>            flash(\"Invalid credentials\")<br>    return render_template(\"login.html\")<br><br>@app.route(\"\/upload\", methods=[\"GET\", \"POST\"])<br>@login_required<br>def upload():<br>    if request.method == \"POST\":<br>        if \"file\" not in request.files:<br>            flash(\"No file uploaded\")<br>            return redirect(request.url)<br>        file = request.files[\"file\"]<br>        language = request.form.get(\"language\", \"auto\")<br><br>        if file.filename == \"\":<br>            flash(\"No selected file\")<br>            return redirect(request.url)<br><br>        filename = os.path.join(\"uploads\", file.filename)<br>        os.makedirs(\"uploads\", exist_ok=True)<br>        file.save(filename)<br><br>        # \u5904\u7406\u8bc6\u522b<br>        if language == \"auto\":<br>            result = model.transcribe(filename)<br>        else:<br>            result = model.transcribe(filename, language=language)<br><br>        os.remove(filename)  # \u53ef\u4fdd\u7559\u6587\u4ef6\u4e5f\u884c<br><br>        return render_template(\"result.html\", text=result[\"text\"])<br>    return render_template(\"upload.html\")<br><br>@app.route(\"\/logout\")<br>@login_required<br>def logout():<br>    logout_user()<br>    return redirect(url_for(\"login\"))<br><br>if __name__ == \"__main__\":<br>    app.run(host=\"0.0.0.0\", port=5000)<br><\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h3 class=\"wp-block-heading\">HTML \u6587\u4ef6<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\"><code>templates\/login.html<\/code><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\"><code>&lt;!doctype html&gt;<br>&lt;title&gt;Login&lt;\/title&gt;<br>&lt;h2&gt;Login&lt;\/h2&gt;<br>&lt;form method=\"post\"&gt;<br>  Username: &lt;input type=\"text\" name=\"username\"&gt;&lt;br&gt;<br>  Password: &lt;input type=\"password\" name=\"password\"&gt;&lt;br&gt;<br>  &lt;input type=\"submit\" value=\"Login\"&gt;<br>&lt;\/form&gt;<br><\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h4 class=\"wp-block-heading\"><code>templates\/upload.html<\/code><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\"><code>&lt;!doctype html&gt;<br>&lt;title&gt;Upload Audio&lt;\/title&gt;<br>&lt;h2&gt;Upload Audio File&lt;\/h2&gt;<br>&lt;form method=\"post\" enctype=\"multipart\/form-data\"&gt;<br>  &lt;input type=\"file\" name=\"file\"&gt;&lt;br&gt;<br>  Language:<br>  &lt;select name=\"language\"&gt;<br>    &lt;option value=\"auto\"&gt;Auto Detect&lt;\/option&gt;<br>    &lt;option value=\"en\"&gt;English&lt;\/option&gt;<br>    &lt;option value=\"ja\"&gt;Japanese&lt;\/option&gt;<br>    &lt;option value=\"zh\"&gt;Chinese&lt;\/option&gt;<br>    &lt;!-- \u53ef\u6dfb\u52a0\u5176\u4ed6 --&gt;<br>  &lt;\/select&gt;&lt;br&gt;<br>  &lt;input type=\"submit\" value=\"Upload and Transcribe\"&gt;<br>&lt;\/form&gt;<br>&lt;a href=\"{{ url_for('logout') }}\"&gt;Logout&lt;\/a&gt;<br><\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h4 class=\"wp-block-heading\"><code>templates\/result.html<\/code><\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\"><code>&lt;!doctype html&gt;<br>&lt;title&gt;Result&lt;\/title&gt;<br>&lt;h2&gt;Transcription Result&lt;\/h2&gt;<br>&lt;pre&gt;{{ text }}&lt;\/pre&gt;<br>&lt;a href=\"{{ url_for('upload') }}\"&gt;Transcribe Another&lt;\/a&gt; |<br>&lt;a href=\"{{ url_for('logout') }}\"&gt;Logout&lt;\/a&gt;<br><\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udfe2 \u516d\u3001\u8fd0\u884c\u6d4b\u8bd5<\/h2>\n\n\n\n<pre class=\"wp-block-preformatted\"><code>source ~\/whisper-env\/bin\/activate<br>python app.py<br><\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\u6d4f\u89c8\u5668\u8bbf\u95ee\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><code>http:\/\/&lt;\u4f60\u7684\u670d\u52a1\u5668IP&gt;:5000<br><\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udfe2 \u4e03\u3001(\u53ef\u9009) Nginx + Gunicorn \u90e8\u7f72<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">\u5982\u679c\u9700\u8981\u751f\u4ea7\u73af\u5883\u4e0a\u7ebf\uff0c\u53ef\u7528 Gunicorn + Nginx\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><code>pip install gunicorn<br>gunicorn -w 4 -b 0.0.0.0:5000 app:app<br><\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\u7136\u540e Nginx \u914d\u7f6e\u4e00\u4e2a\u53cd\u5411\u4ee3\u7406\u5230 <code>127.0.0.1:5000<\/code>\u3002<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">\u2705 \u603b\u7ed3<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">\ud83c\udfaf \u529f\u80fd<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u767b\u5f55\u9a8c\u8bc1<\/li>\n\n\n\n<li>\u4e0a\u4f20\u97f3\u9891\u6587\u4ef6<\/li>\n\n\n\n<li>\u8bed\u8a00\u9009\u62e9<\/li>\n\n\n\n<li>Whisper GPU \u63a8\u7406<\/li>\n\n\n\n<li>\u7f51\u9875\u8fd4\u56de\u7ed3\u679c<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h3 class=\"wp-block-heading\">\ud83d\udd25 \u672a\u6765\u53ef\u6269\u5c55<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u6dfb\u52a0\u4efb\u52a1\u961f\u5217\uff08Celery\uff09<\/li>\n\n\n\n<li>\u6587\u4ef6\u5386\u53f2\u7ba1\u7406<\/li>\n\n\n\n<li>\u591a\u7528\u6237\u6ce8\u518c<\/li>\n\n\n\n<li>Docker \u4e00\u952e\u90e8\u7f72<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>\ud83c\udfaf \u529f\u80fd\u76ee\u6807 \u2705 \u670d\u52a1\u5668\u4e0a\u8fd0\u884c Whisper\uff08\u7528 GPU \u52a0\u901f\uff09\u2705 \u7f51\u9875\u754c\u9762\u767b\u5f55\uff08\u8d26\u53f7\u5bc6\u7801\uff09\u2705 \u4e0a\u4f20\u97f3\u9891\u6587\u4ef6\u8fdb\u884c\u8bc6\u522b\u2705 \u53ef\u9009\u8bed\u8a00\uff08\u6216\u81ea\u52a8\u68c0\u6d4b\uff09\u2705 \u8fd4\u56de\u6587\u672c\u7ed3\u679c \ud83d\udfe2 \u4e00\u3001\u670d\u52a1\u5668\u51c6\u5907 1\ufe0f\u20e3 \u786c\u4ef6 2\ufe0f\u20e3 \u9a71\u52a8 &amp; CUDA \u5b89\u88c5 NVIDIA \u9a71\u52a8 + CUDA\uff08\u4ee5 Ubuntu \u4e3a\u4f8b\uff09\uff1a sudo apt updatesudo apt install nvidia-driver-535 nvidia-cuda-toolkit \u9a8c\u8bc1\uff1a nvidia-smi \ud83d\udfe2 \u4e8c\u3001Python \u73af\u5883 1\ufe0f\u20e3 \u5b89\u88c5 Python \u5efa\u8bae Python 3.9+ sudo apt install python3 python3-venv python3-pip &hellip;<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[214],"tags":[],"class_list":["post-4620","post","type-post","status-publish","format-standard","hentry","category-aun400lvwmcv6sr"],"_links":{"self":[{"href":"https:\/\/eternalsphere.net\/echoes\/index.php\/wp-json\/wp\/v2\/posts\/4620","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/eternalsphere.net\/echoes\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/eternalsphere.net\/echoes\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/eternalsphere.net\/echoes\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/eternalsphere.net\/echoes\/index.php\/wp-json\/wp\/v2\/comments?post=4620"}],"version-history":[{"count":1,"href":"https:\/\/eternalsphere.net\/echoes\/index.php\/wp-json\/wp\/v2\/posts\/4620\/revisions"}],"predecessor-version":[{"id":4621,"href":"https:\/\/eternalsphere.net\/echoes\/index.php\/wp-json\/wp\/v2\/posts\/4620\/revisions\/4621"}],"wp:attachment":[{"href":"https:\/\/eternalsphere.net\/echoes\/index.php\/wp-json\/wp\/v2\/media?parent=4620"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/eternalsphere.net\/echoes\/index.php\/wp-json\/wp\/v2\/categories?post=4620"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/eternalsphere.net\/echoes\/index.php\/wp-json\/wp\/v2\/tags?post=4620"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}