吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 29184|回复: 75
收起左侧

[Python 原创] 【原创源码】【python】讯飞听见语音转文字免费版

  [复制链接]
chinapython 发表于 2021-6-24 21:49
本帖最后由 chinapython 于 2021-6-24 21:51 编辑
# -*- coding: utf-8 -*-
# ☯ Author:  ******
# ☯ Email : ******@****.***
# ☯ Date  : 2021/06/24 20:13
import os
import re
import time
import random
import logging
import datetime
import requests
from logging import handlers
from collections import OrderedDict
from urllib3 import encode_multipart_formdata

# 日志模块
class LogGer(object):
    def __init__(self, name):
        os.makedirs("./log") if not os.path.exists("./log") else None  # 创建日志文件文件夹
        get_logger_a = logging.getLogger()
        get_logger_a.setLevel(logging.INFO)  # 设置默认级别
        formatter = logging.Formatter('%(levelname)s %(asctime)s %(filename)s[line:%(lineno)d]: %(message)s')
        log_file_path = './log/{}_{}.log'.format(name, time.strftime('%Y%m%d'))
        rotating_handler = handlers.RotatingFileHandler(
            log_file_path, maxBytes=20 * 1024 * 1024, backupCount=10, encoding='utf-8')
        rotating_handler.setFormatter(formatter)
        get_logger_a.addHandler(rotating_handler)
        stream_handler = logging.StreamHandler()
        stream_handler.setFormatter(formatter)
        get_logger_a.addHandler(stream_handler)
        # 过滤级别:控制台输出INFO和WARNING级别,文件只记录WARNING级别
        info_filter = logging.Filter()
        info_filter.filter = lambda record: record.levelno < logging.WARNING  # 设置过滤等级
        warn_filter = logging.Filter()
        warn_filter.filter = lambda record: record.levelno >= logging.WARNING
        # stream_handler.addFilter(info_filter)
        rotating_handler.addFilter(warn_filter)

# 爬虫主程序
class TestSpider:
    LogGer(str(os.path.basename(__file__))[:-3])
    logging.info('system is working now.')

    def __init__(self):
        pass

    # 随机头
    @staticmethod
    def random_ua():
        return "Mozilla/5.0 (Windows NT {}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/{} Safari/537.36".format(
            random.choice([
                '10.0; Win64; x64', '10.0; WOW64', '10.0',
                '6.2; WOW64', '6.2; Win64; x64', '6.2',
                '6.1', '6.1; Win64; x64', '6.1; WOW64'
            ]), random.choice([
                '70.0.3538.16', '70.0.3538.67', '70.0.3538.97', '71.0.3578.137', '71.0.3578.30', '71.0.3578.33',
                '71.0.3578.80', '72.0.3626.69', '72.0.3626.7', '73.0.3683.20', '73.0.3683.68', '74.0.3729.6',
                '75.0.3770.140', '75.0.3770.8', '75.0.3770.90', '76.0.3809.12', '76.0.3809.126', '76.0.3809.25',
                '76.0.3809.68', '77.0.3865.10', '77.0.3865.40', '78.0.3904.105', '78.0.3904.11', '78.0.3904.70',
                '79.0.3945.16', '79.0.3945.36', '80.0.3987.106', '80.0.3987.16', '81.0.4044.138', '81.0.4044.20',
                '81.0.4044.69', '83.0.4103.14', '83.0.4103.39', '84.0.4147.30', '85.0.4183.38', '85.0.4183.83',
                '85.0.4183.87', '86.0.4240.22', '87.0.4280.20', '87.0.4280.88', '88.0.4324.27'
            ]))

    # 下载器
    def requester(self, url, retry=3, **kwargs):
        """
        :param url: 必须传入的url
        :param retry: 不需要自己传,自动忽视
        :param kwargs: 传递需要的参数,必须“参数名=参数”
        :return: 返回正常访问的内容或者返回None
        """
        try:
            return requests.request(
                url=url,
                method=kwargs.get('method') if kwargs.get('method') else 'get',
                timeout=kwargs.get('timeout') if kwargs.get('timeout') else 30,
                params=kwargs.get('params'),
                data=kwargs.get('data'),
                files=kwargs.get('files'),
                json=kwargs.get('json'),
                cookies=kwargs.get('cookies'),
                allow_redirects=True if kwargs.get('allow_redirects') in [None, True] else False,
                proxies={
                    'http': 'http://{}'.format(kwargs.get('proxies')),
                    'https': 'http://{}'.format(kwargs.get('proxies'))
                } if kwargs.get('proxies') else None,
                headers=kwargs.get('headers') if kwargs.get('headers') else {
                    'Accept': '*/*',
                    'Connection': 'close',
                    'Accept-Encoding': 'gzip, deflate, br',
                    'User-Agent': self.random_ua()
                },
                verify=False
            )
        except Exception as e:
            return logging.warning('request error:%s' % e) if retry < 1 else self.requester(url, retry - 1, **kwargs)

    def upload(self, file_path: str, **kwargs: any) -> None or dict:
        c = str(kwargs.get("code")) if kwargs.get("code") and len(str(kwargs.get("code"))) == 16 else "s4Qyl0knnW8pjpDK"
        response = self.requester(
            method="post",
            url="https://www.iflyrec.com/AudioStreamService/v1/audios",
            params={"type": "whole", "folder": f"{random.randint(10000000000000000, 99999999999999999)}"},
            headers={
                'Host': 'www.iflyrec.com',
                'Connection': 'close',
                'User-Agent': self.random_ua(),
                'X-Biz-Id': 'xftj',
                'Content-Type': f'multipart/form-data; boundary=----WebKitFormBoundary{c}',
                'Accept': '*/*',
                'Origin': 'https://www.iflyrec.com',
                'Referer': 'https://www.iflyrec.com/html/addMachineOrder.html',
                'Accept-Encoding': 'gzip, deflate',
                'Accept-Language': 'zh-CN,zh;q=0.9'
            },
            data=encode_multipart_formdata(OrderedDict([
                ("language", (None, 1, 'multipart/form-data')),
                ("id", (None, 'WU_FILE_0', 'multipart/form-data')),
                ('name', (None, os.path.basename(file_path), 'multipart/form-data')),
                ('type', (None, 'audio/wav', 'multipart/form-data')),
                ('lastModifiedDate', (
                    None, datetime.datetime.utcnow().strftime('%a %b %d %Y %H:%M:%S GMT+0800') + " (中国标准时间)",
                    'multipart/form-data'
                )),
                ('size', (None, os.path.getsize(file_path), 'multipart/form-data')),
                ('file', (os.path.basename(file_path), open(file_path, "rb").read(), 'audio/wav')),
            ]), boundary=f'----WebKitFormBoundary{c}')[0],
            proxies=kwargs.get('proxies')
        )
        # request error
        if response is None:
            return logging.warning(f"上传失败了,请测试网络连接情况,file:{file_path}")
        # response error
        if "uploadedSize" not in response.text:
            return logging.warning(f"上传响应结果中不不包含关键字,file:{file_path}")
        elif response.json().get('biz').get('uploadedSize') is None:
            return logging.warning(f"上传响应中关键值缺失,file:{file_path}")
        return response.json()

    def crc32check(self, fileid: str, crc32: str) -> None or bool:
        response = self.requester(
            url=f"https://www.iflyrec.com/TranscriptOrderService/v1/tempAudios/{fileid}/initAudioInfo?crc32={crc32}",
            method="post",
            headers={
                'Host': 'www.iflyrec.com',
                'Connection': 'close',
                'Accept': 'application/json, text/javascript, */*; q=0.01',
                'X-Requested-With': 'XMLHttpRequest',
                'User-Agent': self.random_ua(),
                'X-Biz-Id': 'xftj',
                'Origin': 'https://www.iflyrec.com',
                'Referer': 'https://www.iflyrec.com/html/addMachineOrder.html',
                'Accept-Encoding': 'gzip, deflate',
                'Accept-Language': 'zh-CN,zh;q=0.9',
            })
        if response is None:
            return logging.warning("校验失败:网络不通...")
        return True if "000000" in response.text else False

    def distinguish(self, path, mode=False):
        response = self.requester(
            method="get" if mode else "post",
            url="https://www.iflyrec.com/TranscriptPreviewService/v1/aiTranscriptPreviews",
            headers={
                'Host': 'www.iflyrec.com',
                'Connection': 'close',
                'Accept': 'application/json',
                'X-Requested-With': 'XMLHttpRequest',
                'User-Agent': "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36",
                'X-Biz-Id': 'xftj',
                'Content-Type': 'application/json;charset=UTF-8',
                'Origin': 'https://www.iflyrec.com',
                'Referer': 'https://www.iflyrec.com/html/addMachineOrder.html',
                'Accept-Encoding': 'gzip, deflate',
                'Accept-Language': 'zh-CN,zh;q=0.9'
            },
            params={"filePath": path, "transcriptLanguage": 1},
            json={"filePath": path, "transcriptLanguage": 1} if mode is False else None,
        )
        if response is None:
            return logging.warning("识别失败:网络故障")
        if mode is False and "true" in response.text:
            return self.distinguish(path, True)

        if mode is True and "speaker" in response.text:
            info = response.json()['biz']['transcriptResult']
            return "".join([i.strip() for i in re.findall(r'''"content":"([\S\s]*?)"''', info)])
        else:
            return logging.warning("识别失败:未知错误")

    @staticmethod
    def write2txt(path, content):
        with open(path, "a+", encoding="utf-8") as f:
            f.write(content + "\n")

    # 运行入口
    def run(self):
        # 提交数据
        res = self.upload(r"C:\Users\Administrator\Desktop\英语\4.wav")
        if res is None:
            return
        # crc32 验证
        msg = self.crc32check(**{"fileid": res['biz']['fileId'], "crc32": res['biz']['crc32']})
        if msg is not True:
            return
        # 开始识别
        text = self.distinguish(res['biz']['transPreviewPath'])
        print(f"获取响应结果:{text}")

if __name__ == '__main__':
    start = TestSpider()
    start.run()

自己写的玩的,见笑了......开发30分钟,调试3小时................无奈 无奈------------- 评分啥  你随意......留言回复是对我最大的鼓励......

这个只能  转录  中文 和 英文,免费的嘛多多少少有限制的哇, 还有最大限制,不能超过3分钟哦,是不是很鸡肋,我那个音频实际是日文的,没英文的,日文在这里肯定转录不对撒,只是做个测试,大家自由玩耍.....

上图:


.
无标题.png

免费评分

参与人数 15吾爱币 +12 热心值 +12 收起 理由
baopeiguo3 + 1 + 1 谢谢@Thanks!
nebula6543 + 1 热心回复!
Wycyt1994 + 1 + 1 鼓励转贴优秀软件安全工具和文档!
welcome7758521 + 1 我很赞同!
shockhack + 1 谢谢@Thanks!
hkf369 + 1 + 1 热心回复!
xaibin + 1 + 1 谢谢@Thanks!
xiao164 + 1 + 1 谢谢@Thanks!
hxw0204 + 1 + 1 热心回复!
dbu00956 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
虔来学习 + 1 + 1 谢谢@Thanks!
olhoscn + 1 + 1 我很赞同!
sam喵喵 + 1 用心讨论,共获提升!
netspirit + 1 谢谢@Thanks!
ccwuax + 1 + 1 我很赞同!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

QQending 发表于 2021-6-27 15:21
chinapython 发表于 2021-6-25 11:30
很抱歉哦,没有接口文档呀...这不是简单套用...  复用代码,这些模块都是我之前开发好的....讯飞这边几个 ...

哦哦,我后来想了一下,也是……
有些的确是各位通过抓包分析的,只不过有一些常用的app,github上也有人分析过接口了,官方虽然没放出来,但是似乎也不反对讨论。

还有,这些免费接口限时,可以通过截断音频,再稍微分析下音频的音量,选择没有声音的地方截断,免得截的太突兀,更无法识别了。

不过,似乎免费的接口,不论是语音识别还是翻译,似乎都不太理想。

扯远了,谢谢楼主分享源码

 楼主| chinapython 发表于 2021-6-25 11:30
QQending 发表于 2021-6-25 01:35
其实我挺好奇,30分钟开发,是不是这里面很多代码都是直接复用直接写好了的,比如日志的参数之类的。
主要 ...

很抱歉哦,没有接口文档呀...这不是简单套用...  复用代码,这些模块都是我之前开发好的....讯飞这边几个接口都是通过抓包获取,每个接口功能,如何在众多接口中找出关键接口,接口调通、优化业务流程,这些都要考虑,不是你理解的那样....
 楼主| chinapython 发表于 2021-6-24 21:58
sam喵喵 发表于 2021-6-24 21:57
感谢分享,是你做的限制还是引用库做了限制啊

那是讯飞网页免费试用,我把他接口化了
QQending 发表于 2021-6-25 01:35
其实我挺好奇,30分钟开发,是不是这里面很多代码都是直接复用直接写好了的,比如日志的参数之类的。
主要还是根据讯飞的接口文档来测试吧。
netspirit 发表于 2021-6-24 21:55
收藏了

自己写的玩的,见笑了......开发30分钟,调试3小时................无奈 无奈------------- 评分啥  你随意......留言回复是对我最大的鼓励......
sam喵喵 发表于 2021-6-24 21:57
感谢分享,是你做的限制还是引用库做了限制啊
dadaoshuai1990 发表于 2021-6-24 22:26
666很努力了,加油
继续路过 发表于 2021-6-24 22:34
谢谢分享
jjl 发表于 2021-6-24 23:51
谢谢分享,加油学Python!
zz1181 发表于 2021-6-25 06:45
已经很棒棒啦,谢谢分享
liuzhijie0329 发表于 2021-6-25 06:47
下载去试一试
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 22:13

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表