news 2026/5/22 1:08:05

树莓派4B跑ovos+在线stt模型

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
树莓派4B跑ovos+在线stt模型

这年头说实在有了peering coding之后,写这些都是笑话。今天算记一个互动类程序的常识吧。简言之,程序里面一定要带多线程,这是一个基本思路。以下代码由可可爱爱花了钱的opus 4.7写的flask本地小服务端转送语音请求去googleapis的speech-to-text云上服务。

""" Bridge HTTP service: emulates the ovos-stt-plugin-server endpoint and forwards the audio to Google Cloud Speech-to-Text REST API using an API key (AIza...). OVOS side: POST /stt multipart/form-data audio = <wav file> lang = en-US (optional) -> 200 text/plain "<transcription>" Google side: POST https://speech.googleapis.com/v1/speech:recognize?key=<API_KEY> """ import base64 import io import logging import os import wave import requests from flask import Flask, request from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry API_KEY = os.environ.get("STT_PW", "").strip() DEFAULT_LANG = os.environ.get("STT_LANG", "en-US") GOOGLE_URL = "https://speech.googleapis.com/v1/speech:recognize" app = Flask(__name__) logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s") log = app.logger # Reuse TCP/TLS to Google + auto-retry on transient failures. # urllib3 Retry on POST also retries on connection errors (e.g. RemoteDisconnected). _session = requests.Session() _session.mount( "https://", HTTPAdapter(max_retries=Retry( total=1, connect=1, read=0, backoff_factor=0.5, status_forcelist=(500, 502, 503, 504), allowed_methods=frozenset(["POST"]), respect_retry_after_header=True, )), ) def _wav_to_pcm(wav_bytes: bytes): """Return (raw_pcm_bytes, sample_rate, channels). If not a valid WAV, assume raw 16-bit mono 16 kHz PCM (what OVOS records by default).""" try: with wave.open(io.BytesIO(wav_bytes), "rb") as w: sr = w.getframerate() ch = w.getnchannels() sw = w.getsampwidth() frames = w.readframes(w.getnframes()) if sw != 2: raise ValueError(f"unsupported sample width {sw}") return frames, sr, ch except (wave.Error, EOFError, ValueError) as e: log.warning("Not a valid WAV (%s) — treating as raw 16k mono PCM", e) return wav_bytes, 16000, 1 @app.route("/stt", methods=["POST"]) def stt(): if not API_KEY: return "STT_PW not set on server", 500 if "audio" in request.files: audio_bytes = request.files["audio"].read() else: audio_bytes = request.get_data() or b"" if not audio_bytes: return "no audio", 400 lang = request.form.get("lang") or request.args.get("lang") or DEFAULT_LANG pcm, sr, ch = _wav_to_pcm(audio_bytes) payload = { "config": { "encoding": "LINEAR16", "sampleRateHertz": sr, "audioChannelCount": ch, "languageCode": lang, "enableAutomaticPunctuation": True, }, "audio": {"content": base64.b64encode(pcm).decode("ascii")}, } import time as _time t0 = _time.monotonic() log.info("recv lang=%s sr=%s ch=%s bytes=%d", lang, sr, ch, len(pcm)) try: r = _session.post( GOOGLE_URL, params={"key": API_KEY}, json=payload, timeout=(5, 15), # (connect, read) — fail fast so OVOS gets an error within its 30s window ) except requests.RequestException as e: log.error("Google request failed after %.1fs: %s", _time.monotonic() - t0, e) return f"google request failed: {e}", 502 if r.status_code != 200: log.error("Google error %s: %s", r.status_code, r.text[:500]) return f"google error {r.status_code}: {r.text}", 502 data = r.json() transcript = "" for res in data.get("results", []): alts = res.get("alternatives") or [] if alts: transcript = alts[0].get("transcript", "") break transcript = transcript.strip() log.info("done %.2fs -> %r", _time.monotonic() - t0, transcript) return transcript, 200, {"Content-Type": "text/plain; charset=utf-8"} @app.route("/", methods=["GET"]) def index(): return "ok", 200 if __name__ == "__main__": port = int(os.environ.get("PORT", "9090")) app.run(host="127.0.0.1", port=port, threaded=True)
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/22 1:05:11

1987年6月27日下午13-15点出生性格、运势和命运

1987年6月17日&#xff0c;下午15点到17点之间&#xff0c;正值盛夏时节&#xff0c;阳光炽烈而漫长。这一天出生的孩子&#xff0c;是中国改革开放后“黄金十年”中诞生的又一批弄潮儿。他们的成长轨迹&#xff0c;与全球化浪潮的涌入、市场经济的深化以及互联网的萌芽几乎同步…

作者头像 李华
网站建设 2026/5/22 1:04:00

如何10倍提升英语学习效率:词达人自动化助手终极教程

如何10倍提升英语学习效率&#xff1a;词达人自动化助手终极教程 【免费下载链接】cdr 微信词达人&#xff0c;高正确率&#xff0c;高效简洁。支持班级任务及自选任务 项目地址: https://gitcode.com/gh_mirrors/cd/cdr 核心关键词&#xff1a;词达人自动化助手、Pytho…

作者头像 李华
网站建设 2026/5/22 0:49:22

14. 声明文件(Declaration Files)

14. 声明文件&#xff08;Declaration Files&#xff09; 1. 概述 声明文件&#xff08;.d.ts 文件&#xff09;用于描述 JavaScript 库的类型信息&#xff0c;让 TypeScript 能够理解和使用纯 JavaScript 编写的代码。声明文件只包含类型定义&#xff0c;不包含实现代码。 ┌─…

作者头像 李华
网站建设 2026/5/22 0:47:33

【软考高级架构】论文预测——论基于ATAM的架构评估方法

论基于ATAM的架构评估方法 摘要 软件架构评估是保障系统质量属性满足业务目标的关键环节。架构权衡分析方法(Architecture Trade-off Analysis Method,ATAM)作为一种系统化的架构评估方法,通过场景捕获、质量属性分析、敏感点与权衡点识别、风险与非风险决策分类等结构化…

作者头像 李华
网站建设 2026/5/22 0:43:55

Token销毁机制深度解析:从原理到实战,开发者必读指南

Token销毁机制深度解析&#xff1a;从原理到实战&#xff0c;开发者必读指南 引言 在加密经济的浪潮中&#xff0c;Token销毁机制已从简单的“通缩工具”演变为驱动项目价值、调控市场供需、甚至重塑治理模式的核心引擎。无论是引爆市场的EIP-1559&#xff0c;还是各大平台币…

作者头像 李华