语音查询天气程序

一、程序概述

本程序是一个基于 Python 的语音查询天气系统,它结合了百度语音识别、百度语音合成和和风天气 API,允许用户通过语音输入查询指定城市和日期(今天、明天、后天)的天气信息,并以语音形式输出查询结果。

二、环境准备

2.1 依赖库安装

在运行本程序之前,需要安装以下 Python 库:

  • requests:用于发送 HTTP 请求,获取和风天气的天气信息。
  • baidu-aip:百度 AI 开放平台的 Python SDK,用于语音识别和语音合成。
  • sounddevice:用于录制音频。
  • numpy:用于处理音频数据。
  • re:Python 内置的正则表达式库,用于解析用户输入的语音文本。
  • urllib.parse:Python 内置库,用于对城市名进行 URL 编码。

可以使用以下命令进行安装:

bash

pip install requests baidu-aip sounddevice numpy

2.2 API 密钥获取

  • 百度语音识别和合成
    • 访问 百度 AI 开放平台,注册并登录账号。
    • 创建一个语音识别和语音合成的应用,获取 BAIDU_APP_IDBAIDU_API_KEYBAIDU_SECRET_KEY
  • 和风天气

2.3 代码配置

将代码中的 BAIDU_APP_IDBAIDU_API_KEYBAIDU_SECRET_KEYHEWEATHER_KEY 替换为你自己的 API 密钥。

import requests
from aip import AipSpeech
from datetime import datetime, timedelta
import sounddevice as sd
import numpy as np
import re
from urllib.parse import quote

# 百度语音识别配置
BAIDU_APP_ID = '百度ID'
BAIDU_API_KEY = '百度key'
BAIDU_SECRET_KEY = '百度key'

# 和风天气配置
HEWEATHER_KEY = '和风api'

# 初始化百度语音客户端
aip_client = AipSpeech(BAIDU_APP_ID, BAIDU_API_KEY, BAIDU_SECRET_KEY)


def speech_recognition(file_path):
    """百度语音识别"""
    with open(file_path, 'rb') as f:
        audio_data = f.read()

    result = aip_client.asr(audio_data, 'pcm', 16000, {
        'dev_pid': 1537  # 普通话(支持简单的英文识别)
    })

    if'result' in result:
        return result['result'][0]
    else:
        raise Exception("语音识别失败:" + str(result))


# def parse_query(text):
    """解析查询文本"""
    # 提取城市和日期信息
    city = None
    date_keyword = '今天'

    # 简单模式匹配
    patterns = [
        r'(.*?)的?(今天|明天|后天)天气',
        r'(今天|明天|后天)(.*?)的天气'
    ]

    for pattern in patterns:
        match = re.search(pattern, text)
        if match:
            groups = match.groups()
            if len(groups) == 2:
                city = groups[0] if groups[0] not in ['今天', '明天', '后天'] else groups[1]
                date_keyword = groups[1] if groups[1] in ['今天', '明天', '后天'] else groups[0]
                break

    # 日期转换
    today = datetime.now()
    date_map = {
        '今天': 0,
        '明天': 1,
        '后天': 2
    }
    target_date = today + timedelta(days=date_map.get(date_keyword, 0))

    return city.strip(), target_date.strftime('%Y-%m-%d')


# def parse_query(text):
    """解析查询文本"""
    # 提取城市和日期信息
    city = None
    date_keyword = '今天'

    # 简单模式匹配
    patterns = [
        r'(.*?)的?(今天|明天|后天)天气',
        r'(今天|明天|后天)(.*?)的天气'
    ]

    for pattern in patterns:
        match = re.search(pattern, text)
        if match:
            print(f"匹配结果: {match.groups()}")  # 添加调试信息
            groups = match.groups()
            if len(groups) == 2:
                city = groups[0] if groups[0] not in ['今天', '明天', '后天'] else groups[1]
                date_keyword = groups[1] if groups[1] in ['今天', '明天', '后天'] else groups[0]
                break

    if city is None:
        print("未识别到有效的城市信息,请重新录制。")
        return None, None

    # 日期转换
    today = datetime.now()
    date_map = {
        '今天': 0,
        '明天': 1,
        '后天': 2
    }
    target_date = today + timedelta(days=date_map.get(date_keyword, 0))

    return city.strip(), target_date.strftime('%Y-%m-%d')




# def get_weather_info(city_name, date):
    """获取天气信息"""
    # 获取城市ID
    location_url = f"https://geoapi.qweather.com/v2/city/lookup?location={city_name}&key={HEWEATHER_KEY}"
    res = requests.get(location_url)
    location_data = res.json()

    if location_data['code'] != '200':
        raise Exception("城市查询失败")

    city_id = location_data['location'][0]['id']

    # 获取天气预报
    weather_url = f"https://devapi.qweather.com/v7/weather/3d?location={city_id}&key={HEWEATHER_KEY}"
    res = requests.get(weather_url)
    weather_data = res.json()

    if weather_data['code'] != '200':
        raise Exception("天气查询失败")

    # 匹配目标日期
    for forecast in weather_data['daily']:
        if forecast['fxDate'] == date:
            return {
                'date': date,
                'city': city_name,
                'day_weather': forecast['textDay'],
                'night_weather': forecast['textNight'],
                'max_temp': forecast['tempMax'],
                'min_temp': forecast['tempMin']
            }

    raise Exception("未找到对应日期的天气信息")

def parse_query(text):
    """解析查询文本"""
    # 提取城市和日期信息
    city = None
    date_keyword = '今天'

    # 简单模式匹配
    patterns = [
        r'(.*?)(今天|明天|后天)的?天气',
        r'(今天|明天|后天)(.*?)的?天气'
    ]

    for pattern in patterns:
        match = re.search(pattern, text)
        if match:
            print(f"匹配结果: {match.groups()}")
            groups = match.groups()
            if len(groups) == 2:
                city = groups[0] if groups[0] not in ['今天', '明天', '后天'] else groups[1]
                date_keyword = groups[1] if groups[1] in ['今天', '明天', '后天'] else groups[0]
                break

    if city is None:
        print("未识别到有效的城市信息,请重新录制。")
        return None, None

    # 日期转换
    today = datetime.now()
    date_map = {
        '今天': 0,
        '明天': 1,
        '后天': 2
    }
    target_date = today + timedelta(days=date_map.get(date_keyword, 0))

    return city.strip(), target_date.strftime('%Y-%m-%d')

# def get_weather_info(city_name, date):
    """获取天气信息"""
    # 获取城市ID
    location_url = f"https://geoapi.qweather.com/v2/city/lookup?location={city_name}&key={HEWEATHER_KEY}"
    res = requests.get(location_url)
    location_data = res.json()
    print(f"城市查询返回数据: {location_data}")  # 添加调试信息

    try:
        if location_data['code'] != '200':
            raise Exception("城市查询失败")
    except KeyError:
        raise Exception(f"城市查询返回数据格式错误: {location_data}")

    city_id = location_data['location'][0]['id']

    # 获取天气预报
    weather_url = f"https://devapi.qweather.com/v7/weather/3d?location={city_id}&key={HEWEATHER_KEY}"
    res = requests.get(weather_url)
    weather_data = res.json()
    print(f"天气查询返回数据: {weather_data}")  # 添加调试信息

    try:
        if weather_data['code'] != '200':
            raise Exception("天气查询失败")
    except KeyError:
        raise Exception(f"天气查询返回数据格式错误: {weather_data}")

    # 匹配目标日期
    for forecast in weather_data['daily']:
        if forecast['fxDate'] == date:
            return {
                'date': date,
                'city': city_name,
                'day_weather': forecast['textDay'],
                'night_weather': forecast['textNight'],
                'max_temp': forecast['tempMax'],
                'min_temp': forecast['tempMin']
            }

    raise Exception("未找到对应日期的天气信息")


def get_weather_info(city_name, date):
    """获取天气信息"""
    # 对城市名进行 URL 编码
    encoded_city_name = quote(city_name)
    # 获取城市ID
    location_url = f"https://geoapi.qweather.com/v2/city/lookup?location={encoded_city_name}&key={HEWEATHER_KEY}"
    res = requests.get(location_url)
    location_data = res.json()
    print(f"城市查询返回数据: {location_data}")
    try:
        if location_data['code'] != '200':
            raise Exception("城市查询失败")
    except KeyError:
        raise Exception(f"城市查询返回数据格式错误: {location_data}")
    city_id = location_data['location'][0]['id']
    # 获取天气预报
    weather_url = f"https://devapi.qweather.com/v7/weather/3d?location={city_id}&key={HEWEATHER_KEY}"
    res = requests.get(weather_url)
    weather_data = res.json()
    print(f"天气查询返回数据: {weather_data}")
    try:
        if weather_data['code'] != '200':
            raise Exception("天气查询失败")
    except KeyError:
        raise Exception(f"天气查询返回数据格式错误: {weather_data}")
    # 匹配目标日期
    for forecast in weather_data['daily']:
        if forecast['fxDate'] == date:
            return {
                'date': date,
                'city': city_name,
                'day_weather': forecast['textDay'],
                'night_weather': forecast['textNight'],
                'max_temp': forecast['tempMax'],
                'min_temp': forecast['tempMin']
            }
    raise Exception("未找到对应日期的天气信息")


def text_to_speech(text):
    """文本转语音"""
    result = aip_client.synthesis(text, 'zh', 1, {
        'vol': 5,
        'per': 0  # 0-女声,1-男声
    })

    if not isinstance(result, dict):
        with open('output.mp3', 'wb') as f:
            f.write(result)
        return 'output.mp3'
    else:
        raise Exception("语音合成失败")


def record_speech():
    """录制语音"""
    input("请按回车键开始录制语音,录制时长为5秒...")
    # 采样频率
    fs = 16000
    # 录制时长
    duration = 5
    print("开始录制...")
    recording = sd.rec(int(duration * fs), samplerate=fs, channels=1, dtype=np.int16)
    sd.wait()
    print("录制完成。")
    # 保存为PCM文件
    with open('input.pcm', 'wb') as f:
        f.write(recording.tobytes())


def main():
    try:
        # 1. 录制语音
        record_speech()

        # 2. 语音识别
        text = speech_recognition('input.pcm')
        print(f"识别结果:{text}")

        if not text:
            print("语音识别未得到有效文本,请重新录制。")
            return

        # 3. 解析查询内容
        city, date = parse_query(text)
        print(f"解析结果:城市={city}, 日期={date}")

        # 4. 获取天气信息
        weather = get_weather_info(city, date)
        response_text = (
            f"{weather['city']}{date}的天气预报:"
            f"白天{weather['day_weather']},"
            f"夜间{weather['night_weather']},"
            f"最高气温{weather['max_temp']}度,"
            f"最低气温{weather['min_temp']}度"
        )
        print(response_text)

        # 5. 生成语音反馈
        audio_file = text_to_speech(response_text)
        print(f"语音反馈已生成:{audio_file}")

    except Exception as e:
        print(f"处理出错:{str(e)}")


if __name__ == '__main__':
    main()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值