mirror of
https://github.com/zhouxiaoka/autoclip.git
synced 2026-09-03 06:24:14 +08:00
- 修复Redis连接地址硬编码问题,使用环境变量REDIS_URL - 添加缺失的Python依赖:pysrt和psutil - 修复Docker构建中的Rollup兼容性问题,使用node:18-slim - 修复容器启动脚本的node环境检查问题 - 修复data目录权限问题 - 修复docker-compose.yml版本警告 - 创建专门的Docker启动脚本和开发环境配置 - 优化Dockerfile构建流程和错误处理 解决的主要问题: 1. 构建阶段失败 - Rollup模块兼容性 2. 依赖缺失 - pysrt和psutil 3. 运行时失败 - Redis硬编码和权限问题 4. 开发环境vite命令找不到问题 现在Docker部署应该可以正常工作。
195 lines
5.0 KiB
Python
195 lines
5.0 KiB
Python
"""
|
||
简化的进度服务 - 固定阶段 + 固定权重
|
||
基于你提出的"做笨做稳"方案
|
||
"""
|
||
|
||
import time
|
||
import json
|
||
import logging
|
||
from typing import List, Tuple, Optional, Dict, Any
|
||
import redis
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
# 固定阶段定义 - 根据你的项目实际调整
|
||
STAGES: List[Tuple[str, int]] = [
|
||
("INGEST", 10), # 下载/就绪
|
||
("SUBTITLE", 15), # 字幕/对齐
|
||
("ANALYZE", 20), # 语义分析/大纲
|
||
("HIGHLIGHT", 25), # 片段定位/打分
|
||
("EXPORT", 20), # 导出/封装
|
||
("DONE", 10), # 校验/归档
|
||
]
|
||
|
||
# 阶段权重映射
|
||
WEIGHTS = {name: w for name, w in STAGES}
|
||
# 阶段顺序
|
||
ORDER = [name for name, _ in STAGES]
|
||
|
||
# Redis连接 - 使用项目现有的Redis配置
|
||
try:
|
||
# 从环境变量获取Redis URL,默认为本地地址
|
||
redis_url = os.getenv("REDIS_URL", "redis://127.0.0.1:6379/0")
|
||
r = redis.Redis.from_url(redis_url, decode_responses=True)
|
||
# 测试连接
|
||
r.ping()
|
||
logger.info("Redis连接成功")
|
||
except Exception as e:
|
||
logger.error(f"Redis连接失败: {e}")
|
||
r = None
|
||
|
||
|
||
def compute_percent(stage: str, subpercent: Optional[float] = None) -> int:
|
||
"""
|
||
计算阶段对应的百分比
|
||
|
||
Args:
|
||
stage: 当前阶段名称
|
||
subpercent: 子进度百分比 (0-100),可选
|
||
|
||
Returns:
|
||
总进度百分比 (0-100)
|
||
"""
|
||
# 累加之前阶段权重
|
||
done = 0
|
||
for s in ORDER:
|
||
if s == stage:
|
||
break
|
||
done += WEIGHTS[s]
|
||
|
||
# 当前阶段
|
||
cur = WEIGHTS.get(stage, 0)
|
||
|
||
if subpercent is None:
|
||
# 阶段切换时,显示到当前阶段开始
|
||
return min(100, done + cur) if stage == "DONE" else min(99, done)
|
||
else:
|
||
# 带子进度,按权重线性换算
|
||
subpercent = max(0, min(100, subpercent))
|
||
return min(99, done + int(cur * subpercent / 100))
|
||
|
||
|
||
def emit_progress(project_id: str, stage: str, message: str = "", subpercent: Optional[float] = None):
|
||
"""
|
||
发送进度事件
|
||
|
||
Args:
|
||
project_id: 项目ID
|
||
stage: 当前阶段
|
||
message: 进度消息
|
||
subpercent: 子进度百分比,可选
|
||
"""
|
||
if not r:
|
||
logger.warning("Redis未连接,跳过进度发送")
|
||
return
|
||
|
||
percent = compute_percent(stage, subpercent)
|
||
payload = {
|
||
"project_id": project_id,
|
||
"stage": stage,
|
||
"percent": percent,
|
||
"message": message,
|
||
"ts": int(time.time())
|
||
}
|
||
|
||
try:
|
||
# 1) 持久化最新快照(给轮询/刷新用)
|
||
r.hset(f"progress:project:{project_id}", mapping={
|
||
"stage": stage,
|
||
"percent": str(percent),
|
||
"message": message,
|
||
"ts": str(payload["ts"])
|
||
})
|
||
|
||
# 2) 即时广播(可选,用于WebSocket)
|
||
r.publish(f"progress:project:{project_id}", json.dumps(payload))
|
||
|
||
logger.info(f"进度事件已发送: {project_id} - {stage} ({percent}%) - {message}")
|
||
|
||
except Exception as e:
|
||
logger.error(f"发送进度事件失败: {e}")
|
||
|
||
|
||
def get_progress_snapshot(project_id: str) -> Optional[Dict[str, Any]]:
|
||
"""
|
||
获取项目进度快照
|
||
|
||
Args:
|
||
project_id: 项目ID
|
||
|
||
Returns:
|
||
进度快照数据,如果不存在返回None
|
||
"""
|
||
if not r:
|
||
return None
|
||
|
||
try:
|
||
h = r.hgetall(f"progress:project:{project_id}")
|
||
if not h:
|
||
return None
|
||
|
||
return {
|
||
"project_id": project_id,
|
||
"stage": h.get("stage", ""),
|
||
"percent": int(h.get("percent", 0)),
|
||
"message": h.get("message", ""),
|
||
"ts": int(h.get("ts", 0))
|
||
}
|
||
except Exception as e:
|
||
logger.error(f"获取进度快照失败: {e}")
|
||
return None
|
||
|
||
|
||
def get_multiple_progress_snapshots(project_ids: List[str]) -> List[Dict[str, Any]]:
|
||
"""
|
||
批量获取多个项目的进度快照
|
||
|
||
Args:
|
||
project_ids: 项目ID列表
|
||
|
||
Returns:
|
||
进度快照列表
|
||
"""
|
||
if not r:
|
||
return []
|
||
|
||
results = []
|
||
for project_id in project_ids:
|
||
snapshot = get_progress_snapshot(project_id)
|
||
if snapshot:
|
||
results.append(snapshot)
|
||
|
||
return results
|
||
|
||
|
||
def clear_progress(project_id: str):
|
||
"""
|
||
清除项目进度数据
|
||
|
||
Args:
|
||
project_id: 项目ID
|
||
"""
|
||
if not r:
|
||
return
|
||
|
||
try:
|
||
r.delete(f"progress:project:{project_id}")
|
||
logger.info(f"已清除项目进度数据: {project_id}")
|
||
except Exception as e:
|
||
logger.error(f"清除进度数据失败: {e}")
|
||
|
||
|
||
# 阶段名称映射(用于显示)
|
||
STAGE_NAMES = {
|
||
"INGEST": "素材准备",
|
||
"SUBTITLE": "字幕处理",
|
||
"ANALYZE": "内容分析",
|
||
"HIGHLIGHT": "片段定位",
|
||
"EXPORT": "视频导出",
|
||
"DONE": "处理完成"
|
||
}
|
||
|
||
def get_stage_display_name(stage: str) -> str:
|
||
"""获取阶段的显示名称"""
|
||
return STAGE_NAMES.get(stage, stage)
|