From bf026cb27a2d849a08d3ed688e9d5e851205fe58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B5=B7?= <10402852@qq.com> Date: Sun, 16 Feb 2025 13:51:15 +0800 Subject: [PATCH] 'commit' --- AI/T1_Mp4ToWav.py | 3 - AI/T1_Start.py | 19 ++ AI/T2_WavToText.py | 298 ++++++++++-------- AI/T3_TextSummarize.py | 203 ++++++++++-- AI/__pycache__/T1_Mp4ToWav.cpython-310.pyc | Bin 0 -> 1318 bytes AI/__pycache__/T2_WavToText.cpython-310.pyc | Bin 0 -> 5753 bytes .../T3_TextSummarize.cpython-310.pyc | Bin 0 -> 3443 bytes 7 files changed, 367 insertions(+), 156 deletions(-) create mode 100644 AI/T1_Start.py create mode 100644 AI/__pycache__/T1_Mp4ToWav.cpython-310.pyc create mode 100644 AI/__pycache__/T2_WavToText.cpython-310.pyc create mode 100644 AI/__pycache__/T3_TextSummarize.cpython-310.pyc diff --git a/AI/T1_Mp4ToWav.py b/AI/T1_Mp4ToWav.py index c329325b..50b1e30b 100644 --- a/AI/T1_Mp4ToWav.py +++ b/AI/T1_Mp4ToWav.py @@ -47,6 +47,3 @@ def convert_mp4_to_wav( except FileNotFoundError: print(f"FFmpeg未找到,请确认路径是否正确:{ffmpeg_path}") - -# 使用示例(替换为实际MP4文件名) -convert_mp4_to_wav(r"D:\backup\七年级第三单元复习课.mp4", output_path=r"D:\backup\七年级第三单元复习课.wav") \ No newline at end of file diff --git a/AI/T1_Start.py b/AI/T1_Start.py new file mode 100644 index 00000000..b3f7a2f7 --- /dev/null +++ b/AI/T1_Start.py @@ -0,0 +1,19 @@ +from T1_Mp4ToWav import * +from T2_WavToText import * +from T3_TextSummarize import * +if __name__ == '__main__': + # 1、根据云校的视频课程下载视频文件 + + # 2、调用ffmpeg将视频文件转成wav文件 + # convert_mp4_to_wav(r"D:\backup\七年级第三单元复习课.mp4", + # output_path=r"D:\backup\七年级第三单元复习课.wav") + # 3、将转换完成的WAV上传到阿里云 + + # 4、调用阿里云的语音识别API,将wav文件转成文字 + #audio_url = "https://ylt.oss-cn-hangzhou.aliyuncs.com/HuangHai/123.wav" + # 5、 调用dashscope的API,将文字转成markdown文件 + #ShiBie(audio_url, "识别结果.txt") + # 6、生成总结 + input_file = Path(r"D:\dsWork\QingLong\AI\音频文本.txt") + output_file = Path(r"D:\dsWork\QingLong\AI\分析结果.txt") + analyzerAction(input_file, output_file) diff --git a/AI/T2_WavToText.py b/AI/T2_WavToText.py index 659ad8d7..4c7b0d52 100644 --- a/AI/T2_WavToText.py +++ b/AI/T2_WavToText.py @@ -1,143 +1,189 @@ -# -*- coding: utf8 -*- +# -*- coding: utf-8 -*- import json import time +from pathlib import Path +from typing import Dict, Tuple + from aliyunsdkcore.acs_exception.exceptions import ClientException, ServerException from aliyunsdkcore.client import AcsClient from aliyunsdkcore.request import CommonRequest -# 录音文件识别 -# https://common-buy.aliyun.com/?spm=5176.11801677.0.0.44e77a33oMMyT6&commodityCode=nlsService&orderType=UPGRADE&instanceId=1546399445482588 -# 1. 开通商用即为付费使用服务,根据后付费梯度计费,标准单价为2.5元/小时; -# 2. 商用服务可在最长3小时内完成识别并返回识别文本; -# 3. 注意:已经“商用”后再切换“试用”,等同于立即关停线上服务,请谨慎操作; - -def fileTrans(akId, akSecret, appKey, fileLink): - # 服务配置 - REGION_ID = "cn-shanghai" - PRODUCT = "nls-filetrans" - DOMAIN = "filetrans.cn-shanghai.aliyuncs.com" - API_VERSION = "2018-08-17" - - # 请求参数 - KEY_APP_KEY = "appkey" - KEY_FILE_LINK = "file_link" - KEY_VERSION = "version" - KEY_ENABLE_WORDS = "enable_words" - KEY_TASK = "Task" - KEY_TASK_ID = "TaskId" - KEY_STATUS_TEXT = "StatusText" - KEY_RESULT = "Result" - - # 状态码 - STATUS_SUCCESS = "SUCCESS" - STATUS_RUNNING = "RUNNING" - STATUS_QUEUEING = "QUEUEING" - - # 初始化客户端 - client = AcsClient(akId, akSecret, REGION_ID) - - # 构建任务参数 + +# 服务常量配置 +CONFIG = { + "REGION_ID": "cn-shanghai", + "PRODUCT": "nls-filetrans", + "DOMAIN": "filetrans.cn-shanghai.aliyuncs.com", + "API_VERSION": "2018-08-17", + "MAX_RETRIES": 20, + "POLL_INTERVAL": 10 +} + + +class TranscriptionError(Exception): + """自定义语音识别异常基类""" + pass + + +class APIConnectionError(TranscriptionError): + """API连接异常""" + pass + + +class TaskSubmissionError(TranscriptionError): + """任务提交异常""" + pass + + +class TaskTimeoutError(TranscriptionError): + """任务超时异常""" + pass + + +def submit_transcription_task(client: AcsClient, app_key: str, file_link: str) -> str: + """提交语音识别任务 + + :param client: 阿里云客户端实例 + :param app_key: 应用密钥 + :param file_link: 音频文件URL + :return: 任务ID + :raises TaskSubmissionError: 任务提交失败时抛出 + """ task_config = { - KEY_APP_KEY: appKey, - KEY_FILE_LINK: fileLink, - KEY_VERSION: "4.0", - KEY_ENABLE_WORDS: False + "appkey": app_key, + "file_link": file_link, + "version": "4.0", + "enable_words": False } - task_json = json.dumps(task_config) - print("任务配置:", task_json) - - # 提交识别请求 - postRequest = CommonRequest() - postRequest.set_domain(DOMAIN) - postRequest.set_version(API_VERSION) - postRequest.set_product(PRODUCT) - postRequest.set_action_name("SubmitTask") - postRequest.set_method('POST') - postRequest.add_body_params(KEY_TASK, task_json) + + request = CommonRequest() + request.set_domain(CONFIG["DOMAIN"]) + request.set_version(CONFIG["API_VERSION"]) + request.set_product(CONFIG["PRODUCT"]) + request.set_action_name("SubmitTask") + request.set_method('POST') + request.add_body_params("Task", json.dumps(task_config)) try: - postResponse = client.do_action_with_exception(postRequest) - postData = json.loads(postResponse) - print("提交响应:", postData) + response = client.do_action_with_exception(request) + response_data = json.loads(response) - if postData.get(KEY_STATUS_TEXT) != STATUS_SUCCESS: - print(f"任务提交失败: {postData.get(KEY_STATUS_TEXT, '未知错误')}") - return None + if response_data.get("StatusText") != "SUCCESS": + raise TaskSubmissionError(f"任务提交失败: {response_data.get('StatusText', '未知错误')}") - taskId = postData[KEY_TASK_ID] - print(f"任务ID: {taskId}") + return response_data["TaskId"] except (ServerException, ClientException) as e: - print(f"API请求异常: {e}") - return None - except KeyError: - print("响应缺少关键字段") - return None - - # 查询任务结果 - getRequest = CommonRequest() - getRequest.set_domain(DOMAIN) - getRequest.set_version(API_VERSION) - getRequest.set_product(PRODUCT) - getRequest.set_action_name("GetTaskResult") - getRequest.set_method('GET') - getRequest.add_query_param(KEY_TASK_ID, taskId) - - retry_count = 0 - max_retries = 20 # 最多等待200秒 (20次*10秒) - - while retry_count < max_retries: + raise APIConnectionError(f"API连接异常: {str(e)}") from e + except KeyError as e: + raise TaskSubmissionError("响应缺少TaskId字段") from e + + +def poll_transcription_result(client: AcsClient, task_id: str) -> Dict: + """轮询识别任务结果 + + :param client: 阿里云客户端实例 + :param task_id: 任务ID + :return: 识别结果字典 + :raises TaskTimeoutError: 超时未完成时抛出 + """ + request = CommonRequest() + request.set_domain(CONFIG["DOMAIN"]) + request.set_version(CONFIG["API_VERSION"]) + request.set_product(CONFIG["PRODUCT"]) + request.set_action_name("GetTaskResult") + request.set_method('GET') + request.add_query_param("TaskId", task_id) + + retries = 0 + while retries < CONFIG["MAX_RETRIES"]: try: - getResponse = client.do_action_with_exception(getRequest) - resultData = json.loads(getResponse) - print(f"轮询结果({retry_count + 1}/{max_retries}):", resultData) - - status = resultData.get(KEY_STATUS_TEXT, "") - if status == STATUS_SUCCESS: - return resultData.get(KEY_RESULT, {}) - elif status in (STATUS_RUNNING, STATUS_QUEUEING): - time.sleep(10) - retry_count += 1 + response = client.do_action_with_exception(request) + result = json.loads(response) + status = result.get("StatusText", "") + + if status == "SUCCESS": + return result.get("Result", {}) + if status in ("RUNNING", "QUEUEING"): + time.sleep(CONFIG["POLL_INTERVAL"]) + retries += 1 else: - print(f"识别失败,最终状态: {status}") - return None + raise TaskSubmissionError(f"识别失败,状态: {status}") except (ServerException, ClientException) as e: - print(f"查询异常: {e}") - return None - - print("超过最大重试次数,任务未完成") - return None - - -# 配置信息(请替换为实际值) -accessKeyId = "LTAI5tE4tgpGcKWhbZg6C4bh" -accessKeySecret = "oizcTOZ8izbGUouboC00RcmGE8vBQ1" -appKey = "OIpiw501l4o6MYEe" -fileLink = "https://ylt.oss-cn-hangzhou.aliyuncs.com/HuangHai/123.wav" - -# 执行识别 -result = fileTrans(accessKeyId, accessKeySecret, appKey, fileLink) - -# 处理结果 -if not result: - print("未获取到有效结果") - exit(1) - -text_content = [] -if 'Sentences' in result: - for sentence in result['Sentences']: - text_content.append(sentence.get("Text", "")) - full_text = ''.join(text_content) -else: - print("响应中未包含有效文本") - exit(1) - -# 保存结果 -output_file = "识别结果.txt" -try: - with open(output_file, 'w', encoding='utf-8') as f: - f.write(full_text) - print(f"结果已保存至 {output_file}") -except Exception as e: - print(f"文件保存失败: {str(e)}") - exit(1) \ No newline at end of file + raise APIConnectionError(f"查询异常: {str(e)}") from e + + raise TaskTimeoutError(f"超过最大重试次数({CONFIG['MAX_RETRIES']}),任务未完成") + + +def save_transcription_result(result: Dict, output_path: Path) -> Path: + """保存识别结果到文件 + + :param result: 识别结果字典 + :param output_path: 输出文件路径 + :return: 实际保存路径 + :raises IOError: 文件保存失败时抛出 + """ + if not result.get('Sentences'): + raise ValueError("识别结果为空") + + try: + full_text = ''.join(s.get("Text", "") for s in result['Sentences']) + output_path.parent.mkdir(parents=True, exist_ok=True) + output_path.write_text(full_text, encoding='utf-8') + return output_path.resolve() + except (IOError, PermissionError) as e: + raise IOError(f"文件保存失败: {str(e)}") from e + + +def transcribe_audio_file( + access_key_id: str, + access_key_secret: str, + app_key: str, + audio_url: str, + output_path: Path = Path("识别结果.txt") +) -> Tuple[bool, Path, str]: + """语音识别主流程 + + :param access_key_id: 阿里云访问密钥ID + :param access_key_secret: 阿里云访问密钥 + :param app_key: 应用密钥 + :param audio_url: 音频文件URL + :param output_path: 输出文件路径 + :return: (成功标志, 输出路径, 错误信息) + """ + client = AcsClient(access_key_id, access_key_secret, CONFIG["REGION_ID"]) + + try: + task_id = submit_transcription_task(client, app_key, audio_url) + print(f"任务已提交,ID: {task_id}") + + result = poll_transcription_result(client, task_id) + saved_path = save_transcription_result(result, output_path) + + return True, saved_path, "" + + except TranscriptionError as e: + return False, Path(), str(e) + except Exception as e: + return False, Path(), f"未处理的异常: {str(e)}" + +def ShiBie(audio_url, output_path): + # 配置参数(应通过环境变量或配置文件获取) + CREDENTIALS = { + "access_key_id": "LTAI5tE4tgpGcKWhbZg6C4bh", + "access_key_secret": "oizcTOZ8izbGUouboC00RcmGE8vBQ1", + "app_key": "OIpiw501l4o6MYEe", + "audio_url":audio_url, + "output_path": output_path + } + + # 执行识别 + success, path, error = transcribe_audio_file(**CREDENTIALS) + + if success: + print(f"✅ 识别成功,文件已保存至: {path}") + else: + print(f"❌ 识别失败: {error}") + exit(1) + + diff --git a/AI/T3_TextSummarize.py b/AI/T3_TextSummarize.py index 326511c1..7e9f5969 100644 --- a/AI/T3_TextSummarize.py +++ b/AI/T3_TextSummarize.py @@ -1,28 +1,177 @@ -from openai import OpenAI +# -*- coding: utf-8 -*- +import time from pathlib import Path -# https://help.aliyun.com/zh/model-studio/developer-reference/deepseek?spm=a2c4g.11186623.0.0.274b1d1c4GY0Zd - -API_KEY = "sk-01d13a39e09844038322108ecdbd1bbc" -client = OpenAI( - api_key=API_KEY, - base_url="https://dashscope.aliyuncs.com/compatible-mode/v1" -) - -# 读取文本文件内容 -file_path = Path(r"D:\dsWork\QingLong\音频文本.txt") - -if file_path.exists(): - # 自动处理文件编码(默认utf-8),读取内容 - content = file_path.read_text(encoding='utf-8') -else: - print(f"文件 {file_path} 不存在") - exit(0) - -completion = client.chat.completions.create( - model="deepseek-v3", # 此处以 deepseek-r1 为例,可按需更换模型名称。 - messages=[ - {'role': 'user', 'content': "帮我梳理:这节课分了几个部分,每部分的名称和开始的时间是多少:"+content} - ] -) -# 通过content字段打印最终答案 -print(completion.choices[0].message.content) +from typing import Optional, Tuple + +from openai import OpenAI, APIError + + +class ContentAnalyzer: + """课程内容分析器(带Emoji进度展示)""" + + def __init__( + self, + api_key: str = "sk-01d13a39e09844038322108ecdbd1bbc", + base_url: str = "https://dashscope.aliyuncs.com/compatible-mode/v1", + model: str = "deepseek-r1" + ): + """ + 初始化分析器 + :param api_key: 阿里云API密钥 + :param base_url: API基础地址 + :param model: 使用的模型名称 + """ + self.client = OpenAI(api_key=api_key, base_url=base_url) + self.model = model + + def _show_progress(self, emoji: str, message: str, level: int = 1, delay: float = 0.3): + """进度展示方法 + :param emoji: 表情符号 + :param message: 进度信息 + :param level: 缩进层级(0-无缩进,1-一级缩进) + :param delay: 展示后的延迟时间 + """ + indent = " " * level + progress_line = f"{indent}{emoji} {message}" + print(progress_line) + time.sleep(delay) # 增加进度展示的节奏感 + + def analyze_content( + self, + content: str, + prompt_template: str = "帮我梳理:这节课分了几个部分,每部分的名称和开始的时间是多少:{}" + ) -> Tuple[bool, str]: + """ + 分析课程内容结构 + :param content: 需要分析的文本内容 + :param prompt_template: 提示词模板 + :return: (成功标志, 分析结果或错误信息) + """ + try: + # 构建提示词 + self._show_progress("📝", "正在构建提示词...", level=1) + full_prompt = prompt_template.format(content) + + # 发送API请求 + self._show_progress("📡", "正在发送API请求...", level=1) + start_time = time.time() + completion = self.client.chat.completions.create( + model=self.model, + messages=[{'role': 'user', 'content': full_prompt}] + ) + cost_time = time.time() - start_time + + # 处理响应 + self._show_progress("✅", f"收到API响应(耗时{cost_time:.1f}s)", level=1) + if not completion.choices: + self._show_progress("❌", "响应内容为空", level=2) + return False, "API响应中未包含有效结果" + + # 解析结果 + self._show_progress("🔍", "正在解析结果内容...", level=1) + return True, completion.choices[0].message.content + + except APIError as e: + self._show_progress("🚨", f"API异常: {str(e)}", level=2) + return False, f"API调用失败: {str(e)}" + except Exception as e: + self._show_progress("💥", f"未处理的异常: {str(e)}", level=2) + return False, f"未处理的异常: {str(e)}" + + def analyze_file( + self, + file_path: Path, + output_path: Optional[Path] = None, + encoding: str = 'utf-8' + ) -> Tuple[bool, str]: + """ + 从文件读取内容并分析 + :param file_path: 输入文件路径 + :param output_path: 输出文件路径(可选) + :param encoding: 文件编码格式 + :return: (成功标志, 最终结果或错误信息) + """ + try: + self._show_progress("📂", f"开始处理文件: {file_path}", level=0) + + # 检查文件存在性 + self._show_progress("🔎", "检查文件是否存在...", level=1) + if not file_path.exists(): + self._show_progress("❌", "文件不存在", level=2) + return False, f"文件不存在: {file_path}" + + # 读取文件内容 + self._show_progress("📖", "正在读取文件内容...", level=1) + try: + content = file_path.read_text(encoding=encoding) + except UnicodeDecodeError: + self._show_progress("🔠", f"解码失败(当前编码: {encoding})", level=2) + return False, f"文件解码失败,请尝试使用正确的编码格式" + + # 分析内容 + self._show_progress("🧠", "开始分析内容...", level=1) + success, result = self.analyze_content(content) + + if not success: + self._show_progress("⚠️", "内容分析失败", level=2) + return False, result + + # 保存结果 + if output_path: + self._show_progress("💾", f"正在保存结果到: {output_path}", level=1) + try: + output_path.parent.mkdir(parents=True, exist_ok=True) + output_path.write_text(result, encoding=encoding) + self._show_progress("✅", "文件保存成功", level=2) + except IOError as e: + self._show_progress("❌", f"保存失败: {str(e)}", level=2) + return False, f"结果保存失败: {str(e)}" + + self._show_progress("🎉", "文件处理完成", level=0) + return True, result + + except Exception as e: + self._show_progress("💣", f"意外错误: {str(e)}", level=2) + return False, f"文件处理异常: {str(e)}" + + +def show_banner(): + """显示启动横幅""" + print("\n" + "=" * 50) + print("🌟 课程内容智能分析系统 🌟".center(50)) + print("=" * 50 + "\n") + + +def analyzer_action(input_file: str, output_file: Optional[str] = None): + """执行分析流程 + :param input_file: 输入文件路径 + :param output_file: 输出文件路径(可选) + """ + show_banner() + + analyzer = ContentAnalyzer() + input_path = Path(input_file) + output_path = Path(output_file) if output_file else None + + success, result = analyzer.analyze_file(input_path, output_path) + + print("\n" + "=" * 50) + if success: + print("✅ 最终分析结果:".center(50)) + print("-" * 50) + print(result) + print("-" * 50) + if output_path: + print(f"结果已保存至:{output_path.resolve()}") + else: + print(f"❌ 分析失败:{result}") + print("=" * 50 + "\n") + + +if __name__ == "__main__": + # 示例配置 + input_file = r"D:\dsWork\QingLong\AI\音频文本.txt" + output_file = r"D:\dsWork\QingLong\AI\分析结果.txt" + + # 执行分析 + analyzer_action(input_file, output_file) \ No newline at end of file diff --git a/AI/__pycache__/T1_Mp4ToWav.cpython-310.pyc b/AI/__pycache__/T1_Mp4ToWav.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..85ec4b9f9e339141b94d320c8bb069b94a02ba55 GIT binary patch literal 1318 zcmZ8h-D?|15Z~SV(CNdDtvY#VTB?V?RicN2e!RA94_Bc!wQCvegAxRC_NseF?m*SYlsccA8fuS1Gyh>wK zTT^l}#nUL8cn(Z7nZ;b5Dmn`CsoKTIR0&N772Yt zs>qZ;m$u;&jkJTP3=G+mL%p(%G4ka9u`pE~#gndKaY49rf+lH-_JIzfm6EGU^R%N@ zVxAIu?%$R$ax{9%lOXbd2k~!142)(GeQO%Y2(a;$MT}NejGAdc4ti=Ov7e;r0}NR3 zDX?DvdR6^W6`W|bgn^q{xsH+Oz#H;j;{|#eEurjb_ixBdA_L98cRkoz_gi~crpAMt z>(Bmr*m?4Mu>Iq+KOfIt`aIZg`|X_wxbs!8d+(&Z7w%qHBr}}p9DVD5efM~8?Tw2^ zhyKx82<)jBKqn?dZT+3YVDp#G!B#im8+1=W0S&n4S2ujiu4e9dS|pyPNcZih3L%gDexAh zF4(x?fAa%mswroNFJ^iy{+;`s2Y123rP5q=(j5g(l#<~4--68}e*+S{)j520e9-E& z?sV_=-JyTu=irZ@Knc`rA0t5HYS}K(GUKxC7odTzFe%;3_2B=K4#2hT(uo)Fp!W2NCh99DA$Zh)0r^c1`Q$E7?U9`Q^W+X z0m>z!k3jr=xkR^eVQ{@pIW~Sp>@2`up8M!Rp4zh}tL8r|H%gzHjZ*&7C;6GN!WC0C^kq z=dgA)g@-Wtm%R(@EMekVn9M3H4N`my&O)s`7iN$Rf+~cC=j@r@5m@bmx=G!daS@&m ZWS@aaLn%xYg5_5P0uVy}AyWUV{{U60t_c7D literal 0 HcmV?d00001 diff --git a/AI/__pycache__/T2_WavToText.cpython-310.pyc b/AI/__pycache__/T2_WavToText.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..13e8a4120469b032e333db1f9c34c26e302cebd9 GIT binary patch literal 5753 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 P{a#X~?*f|t+d%NYAZX^4 literal 0 HcmV?d00001 diff --git a/AI/__pycache__/T3_TextSummarize.cpython-310.pyc b/AI/__pycache__/T3_TextSummarize.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c95e6dfbc05344df9bbb4b87dc47372719ee60fb GIT binary patch literal 3443 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 Juo(Koe*t;oY>fZ_ literal 0 HcmV?d00001