main
HuangHai 2 weeks ago
parent 0c7d934f31
commit d9182594cc

@ -0,0 +1,49 @@
import subprocess
from pathlib import Path
def convert_mp4_to_wav(
input_mp4: str,
ffmpeg_path: str = r"d:\ffmpeg\ffmpeg.exe",
output_path: str = None # 新增输出路径参数
):
"""
将指定MP4文件转换为WAV格式
参数
input_mp4 - 输入的MP4文件路径
ffmpeg_path - FFmpeg可执行文件路径
output_path - 可选输出路径可指定完整路径或目录
"""
input_path = Path(input_mp4)
# 处理输出路径逻辑
if output_path:
output_path = Path(output_path)
if output_path.is_dir(): # 如果传入的是目录
output_path = output_path / f"{input_path.stem}.wav"
output_path.parent.mkdir(parents=True, exist_ok=True)
else:
# 默认输出到wav目录
output_dir = Path("wav")
output_dir.mkdir(exist_ok=True)
output_path = output_dir / f"{input_path.stem}.wav"
cmd = [
ffmpeg_path,
"-i", str(input_path),
"-acodec", "pcm_s16le",
"-ac", "1",
"-ar", "16000",
"-y",
str(output_path) # 使用处理后的输出路径
]
try:
# 执行转换命令
subprocess.run(cmd, check=True, capture_output=True)
print(f"转换成功:{input_path} -> {output_path}")
except subprocess.CalledProcessError as e:
print(f"转换失败:{e.stderr.decode('gbk')}")
except FileNotFoundError:
print(f"FFmpeg未找到请确认路径是否正确{ffmpeg_path}")

@ -0,0 +1,21 @@
from B1_Mp4ToWav import *
from B2_WavToText import *
from B3_TextSummarize import *
if __name__ == '__main__':
# 1、根据云校的视频课程下载视频文件
# 2、调用ffmpeg将视频文件转成wav文件
# convert_mp4_to_wav(r"D:\backup\七年级第三单元复习课.mp4",
# output_path=r"D:\backup\123.wav")
# 3、将转换完成的WAV上传到阿里云
# 4、调用阿里云的语音识别API将wav文件转成文字
#audio_url = "https://ylt.oss-cn-hangzhou.aliyuncs.com/HuangHai/123.wav"
#ShiBie(audio_url, Path("识别结果.txt"))
# 2.5元一小时本音频文件45分钟约2元
# 6、生成总结
input_file = Path(r"D:\dsWork\QingLong\AI\音频文本.txt")
output_file = Path(r"D:\dsWork\QingLong\AI\分析结果.txt")
analyzer_action(input_file, output_file)

@ -0,0 +1,189 @@
# -*- coding: utf-8 -*-
import json
import time
from typing import Dict, Tuple
from pathlib import Path
from aliyunsdkcore.acs_exception.exceptions import ClientException, ServerException
from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.request import CommonRequest
from Config import *
from Config.Config import ALY_AK, ALY_SK
# 服务常量配置
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 = {
"appkey": app_key,
"file_link": file_link,
"version": "4.0",
"enable_words": False
}
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:
response = client.do_action_with_exception(request)
response_data = json.loads(response)
if response_data.get("StatusText") != "SUCCESS":
raise TaskSubmissionError(f"任务提交失败: {response_data.get('StatusText', '未知错误')}")
return response_data["TaskId"]
except (ServerException, ClientException) as e:
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:
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:
raise TaskSubmissionError(f"识别失败,状态: {status}")
except (ServerException, ClientException) as e:
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:
output_path.parent.mkdir(parents=True, exist_ok=True)
output_path.write_text(str(result['Sentences']), 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": ALY_AK,
"access_key_secret": ALY_SK,
"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)

@ -0,0 +1,173 @@
# -*- coding: utf-8 -*-
from typing import Optional, Tuple, Iterator
from openai import OpenAI, APIError, APITimeoutError
import time
import httpx
from pathlib import Path
from Config.Config import LLM_API_KEY, LLM_BASE_URL, LLM_MODEL_NAME
class ContentAnalyzer:
"""课程内容分析器(流式版本)"""
def __init__(
self,
api_key: str = LLM_API_KEY,
base_url: str = LLM_BASE_URL,
model: str = LLM_MODEL_NAME,
max_retries: int = 10,
initial_timeout: int = 300
):
self._show_progress("🔧", "初始化分析器...", level=0)
self.client = OpenAI(api_key=api_key, base_url=base_url)
self.model = model
self.max_retries = max_retries
self.initial_timeout = initial_timeout
self._check_network()
self._show_progress("", "分析器准备就绪", level=0)
def _show_progress(self, emoji: str, message: str, level: int = 1):
indent = " " * level
timestamp = time.strftime("%H:%M:%S")
print(f"{indent}{emoji} [{timestamp}] {message}")
def _check_network(self):
try:
with httpx.Client(timeout=30) as client:
client.get("https://dashscope.aliyuncs.com")
self._show_progress("🌐", "网络连接正常", level=1)
except Exception as e:
self._show_progress("", f"网络异常: {str(e)}", level=1)
raise
def _retry_delay(self, attempt: int) -> int:
"""指数退避延迟"""
return min(2 ** attempt, 60) # 最大延迟60秒
def analyze_content_stream(
self,
content: str,
prompt_template: str = "帮我梳理:这节课分了几个部分,每部分的名称和开始的时间是多少:{}"
) -> Iterator[Tuple[bool, str]]:
"""流式分析内容"""
for attempt in range(self.max_retries + 1):
try:
current_timeout = self.initial_timeout + attempt * 5
self._show_progress("⏱️", f"尝试 {attempt + 1}/{self.max_retries} (超时: {current_timeout}s)", level=2)
full_prompt = prompt_template.format(content)
stream = self.client.chat.completions.create(
model=self.model,
messages=[{'role': 'user', 'content': full_prompt}],
timeout=current_timeout,
stream=True # 启用流式模式
)
buffer = []
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
content_chunk = chunk.choices[0].delta.content
buffer.append(content_chunk)
yield True, content_chunk # 实时返回每个片段
# 返回完整结果
if buffer:
yield True, ''.join(buffer)
return
except APITimeoutError as e:
if attempt < self.max_retries:
delay = self._retry_delay(attempt)
self._show_progress("", f"{delay}s后重试...", level=2)
time.sleep(delay)
else:
yield False, f"API请求超时已重试{self.max_retries}"
return
except APIError as e:
yield False, f"API错误: {str(e)}"
return
except Exception as e:
yield False, f"未处理的异常: {str(e)}"
return
def analyze_file(
self,
file_path: Path,
output_path: Optional[Path] = None,
encoding: str = 'utf-8'
) -> Tuple[bool, str]:
"""处理文件全流程(流式版本)"""
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}"
if file_path.stat().st_size > 10 * 1024 * 1024:
self._show_progress("⚠️", "注意:大文件可能影响处理速度", level=2)
# 读取内容
self._show_progress("📖", "读取文件内容...", level=1)
try:
content = file_path.read_text(encoding=encoding)
except UnicodeDecodeError:
self._show_progress("🔠", "解码失败尝试GBK编码...", level=2)
content = file_path.read_text(encoding='gbk')
# 流式分析
self._show_progress("🧠", "开始流式分析...", level=1)
result_buffer = []
has_error = False
error_msg = ""
for status, chunk in self.analyze_content_stream(content):
if not status:
has_error = True
error_msg = chunk
break
print(chunk, end='', flush=True) # 实时输出
result_buffer.append(chunk)
if has_error:
self._show_progress("", f"分析失败: {error_msg}", level=1)
return False, error_msg
final_result = ''.join(result_buffer)
# 保存结果
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(final_result, encoding=encoding)
self._show_progress("", "保存成功", level=2)
except Exception as e:
self._show_progress("", f"保存失败: {str(e)}", level=2)
return False, f"结果保存失败: {str(e)}"
self._show_progress("🎉", "处理完成!", level=0)
return True, final_result
except Exception as e:
self._show_progress("💣", f"严重错误: {str(e)}", level=1)
return False, f"文件处理失败: {str(e)}"
def analyzer_action(input_file, output_file):
print("\n" + "=" * 50)
print(" 🚀 长春云校视频课程智能打标记系统 ".center(50, ""))
print("=" * 50)
analyzer = ContentAnalyzer(initial_timeout=300)
success, result = analyzer.analyze_file(Path(input_file), Path(output_file))
print("\n" + "=" * 50)
if success:
print("\n✅ 分析成功!结果已保存至:", output_file)
else:
print(f"\n❌ 分析失败:{result}")
print("=" * 50)

@ -1,3 +1,7 @@
# 阿里云的配置信息
ALY_AK = 'LTAI5tE4tgpGcKWhbZg6C4bh'
ALY_SK = 'oizcTOZ8izbGUouboC00RcmGE8vBQ1'
# 大模型 【DeepSeek深度求索官方】 # 大模型 【DeepSeek深度求索官方】
# LLM_API_KEY = "sk-44ae895eeb614aa1a9c6460579e322f1" # LLM_API_KEY = "sk-44ae895eeb614aa1a9c6460579e322f1"
# LLM_BASE_URL = "https://api.deepseek.com" # LLM_BASE_URL = "https://api.deepseek.com"

Binary file not shown.

After

Width:  |  Height:  |  Size: 858 KiB

@ -0,0 +1,82 @@
# 视频课程
# 七年级第三单元复习课
https://yx.ccsjy.cn/ChangChunCloudSchool/index.html#/course-detail/99f50f9c61bd52f61d359e15e3903153
D:\anaconda3\envs\py310\python.exe D:\dsWork\QingLong\AI\T3_TextSummarize.py
==================================================
✨✨✨✨✨✨✨✨✨✨✨✨✨✨ 🚀 长春云校视频课程智能打标记系统 ✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨
==================================================
🔧 [14:13:57] 初始化分析器...
🌐 [14:13:58] 网络连接正常
✅ [14:13:58] 分析器准备就绪
📂 [14:13:58] 开始处理文件: D:\dsWork\QingLong\AI\音频文本.txt
🔍 [14:13:58] 验证文件...
📖 [14:13:58] 读取文件内容...
🧠 [14:13:58] 开始分析...
⏱️ [14:13:58] 尝试 1/10 (超时: 300s)
✅ [14:16:57] 请求成功
💾 [14:16:57] 保存到: D:\dsWork\QingLong\AI\分析结果.txt
✅ [14:16:57] 保存成功
🎉 [14:16:57] 处理完成!
==================================================
✅ 分析成功!结果如下:
以下是本节课的结构梳理按时间顺序分为5大部分
**1. 课程导入与目标说明8,940-73,100 ms**
- 单元复习导入8,940-23,219
- 单元目标说明73,100-100,259
一、总结学习之道
二、积累成语运用
三、掌握默读技巧
**2. 任务一温故知新106,400-417,500 ms**
- 核心内容:
- 四篇课文学习之道分析
•《从百草园到三味书屋》
•《往事依依》
•《再塑生命的人》
•《论语十二章》
- 系统归纳表格梳理366,160-417,500
**3. 任务二成语积累421,840-807,480 ms**
- 活动一成语展示475,800-606,440
- 课文成语解析
- 论语演化成语
- 活动二成语运用646,860-807,480
- 语段填空练习
- 片段写作训练
**4. 任务三阅读方法936,420-1,655,800 ms**
- 默读技巧讲解936,420-1,177,420
- 三到原则(眼到/心到/手到)
- 关键信息捕捉
- 朗读vs默读对比1,188,780-1,405,180
- 特点/作用/适用场景差异
- 综合训练1,407,180-1,655,800
- 文章分析《读书声最美》
- 阅读方法实践
**5. 总结与作业1,625,580-1,959,179 ms**
- 单元要点回顾1,625,580-1,656,080
- 拓展作业布置1,656,166-1,959,179
- 阅读《悬崖边的树》
- 总结学习之道
**时间轴完整结构:**
| 部分名称 | 开始时间ms | 主要内容 |
|------------------------|----------------|--------------------------------------------------------------------------|
| 课程导入与目标说明 | 8,940 | 单元概述、教学目标设定 |
| 任务一:温故知新 | 106,400 | 四篇课文学习之道深度解析 |
| 任务二:成语积累 | 421,840 | 成语知识系统梳理与运用实践 |
| 任务三:阅读方法 | 936,420 | 默读技巧训练/朗读与默读对比分析 |
| 总结与作业 | 1,625,580 | 单元知识结构化总结/拓展阅读《悬崖边的树》 |
时间单位为毫秒ms完整课程时长约32分钟1,959,179 ms ≈ 1,959秒
==================================================
进程已结束,退出代码为 0
Loading…
Cancel
Save