
    $gDjj                       d Z ddlZddlZddlZddlZddlZddlZddlZddlZddl	Z	ddl
Z
ddlZddlZddlZddlZddlmZ ddlmZ ddlmZmZ ddlmZ d ZdZd	Zd
ZdZdZdZdZ ed          Z e dz  Z!e dz  Z"e dz  Z#e dz  Z$e dz  Z%e dz  Z&e dz  Z'e!e"e#e$e%e&e'fD ]Z(e()                    dd           e dz  Z*e dz  Z+e dz  Z,dZ-dZ.ddl
Z/ e/j0                     e/j0                     e/j0                    dZ1d\dZ2d\d Z3d! Z4d" Z5d# Z6d$ Z7d% Z8d& Z9d' Z:d( Z;d) Z<d\d*Z=d]d,Z>d^d/Z?d_d2Z@d`d3ZAdad6ZB	 	 dbd<ZC	 dcd=ZD G d> d?          ZE G d@ dA          ZF G dB dC          ZG G dD dE          ZH eH            ZI G dF dGee          ZJ G dH dIe          ZKeLdJk    r' eMdK            eMdL            eMdK            eMdMe-             eMdNe              eM              eMdO            eMdP            eMdQ            eMdR            eMdS            eM              eMdT            eMdU            eMdV            eMdW            eMdX            eM              eJdYe-feK          ZN eMdZe-            	 eNO                                 dS # eP$ r#  eMd[           eNQ                                 Y dS w xY wdS )du^  
数字人口播服务 v2.0 - Duix.Avatar + GPT-SoVITS + RMBG-2.0
RTX 5060 Ti (15.9GB VRAM) + CUDA 13.0

架构:
1. 背景抠图:   RMBG-2.0 (via ComfyUI :8188) → 透明通道 PNG 序列
2. 声音克隆:   GPT-SoVITS API (:9880)         → Few-shot 高质量声音克隆
3. 口型驱动:   Duix.Avatar  (WSL2 :8383)       → 高质量唇形同步
4. 视频合成:   FFmpeg                          → 透明/合成背景输出

API 端点:
  GET  /api/digital-human/v2/list              - 列出所有数字人
  GET  /api/digital-human/v2/status            - 服务状态
  GET  /api/digital-human/v2/tasks             - 任务列表
  GET  /api/digital-human/v2/task/:id          - 任务详情
  POST /api/digital-human/v2/upload            - 上传视频
  POST /api/digital-human/v2/train             - 训练数字人 (RMBG+Duix)
  POST /api/digital-human/v2/generate          - 生成口播视频
  POST /api/digital-human/v2/generate-batch    - 批量生成
  DELETE /api/digital-human/v2/delete/:id      - 删除数字人
  
  GET  /api/digital-human/v2/voices            - 声音库列表
  POST /api/digital-human/v2/voice/train       - Few-shot 声音克隆
  POST /api/digital-human/v2/voice/synthesize  - 合成克隆语音
  POST /api/digital-human/v2/voice/preview     - 试听声音
  DELETE /api/digital-human/v2/voice/delete    - 删除声音
  GET  /api/digital-human/v2/voice/audio/:id   - 获取音频文件
  
  GET  /api/digital-human/v2/videos            - 视频列表
  GET  /api/digital-human/v2/video/:file       - 获取视频文件
  DELETE /api/digital-human/v2/video/delete/:id- 删除视频
    N)Path)datetime)
HTTPServerSimpleHTTPRequestHandler)ThreadingMixInc                     t          |                               dd          }t          |          dk    r5|d         dk    r)|d                                         }d| |dd          }|S )	u   
    将 Windows 路径转换为 WSL2 可访问路径。
    Duix.Avatar 运行在 WSL2 (Linux) 中，无法识别 Windows 盘符路径，
    必须转换为 /mnt/d/... 格式。
    
    例: D:\AI-Ad-Agent\xxx.wav → /mnt/d/AI-Ad-Agent/xxx.wav
    \/      :r   z/mnt/N)strreplacelenlower)win_pathpdrives      0D:\AI-Ad-Agent\portal\digital_human_server_v2.pyto_wsl_pathr   8   sj     	HdC((A
1vv{{qts{{!

"E"1QRR5""H    zhttp://127.0.0.1:8383zhttp://127.0.0.1:18180zws://127.0.0.1:10095zhttp://127.0.0.1:9880zhttp://127.0.0.1:8188z$D:\AI-Ad-Agent\ffmpeg\bin\ffmpeg.exez%D:\AI-Ad-Agent\ffmpeg\bin\ffprobe.exezD:\AI-Ad-Agent\digital_human_v2uploadstrainedoutputstempvoicesmodelsbackgroundsTparentsexist_okzdigital_humans.jsonzvoices.jsonz
tasks.jsoni>"  uT   您好，我是山西正方元数字人{name}，为您提供在线数字人口播！)digital_humansr   tasksc                     |i }	 |                                  r>t          | dd          5 }t          j        |          cd d d            S # 1 swxY w Y   n# t          $ r Y nw xY w|S )Nrutf-8encoding)existsopenjsonload	Exception)pathdefaultfs      r   
_load_jsonr1   o   s    ;;== 	$dC'222 $ay||$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $   Ns4   &A A A AA AA 
A&%A&c                    	 t          |           } |                     d          }|                     d          }|rt                              |          nd}|r|                                 	 t          |dd          5 }t          j        ||dd	           ddd           n# 1 swxY w Y   |                                 r4	 |	                    d
           | 
                    |           n#  Y nxY w|
                    |            |r|                                 dS dS # |r|                                 w w xY w# t          $ r }t          d|  d|            Y d}~dS d}~ww xY w)uZ   线程安全 + 原子写入（先写临时文件，再原子替换，防止数据丢失）z.tmpz	.json.bakNwr&   r'   Fr   )ensure_asciiindentT
missing_oku   [保存JSON失败] : )r   with_suffix_json_locksgetacquirer*   r+   dumpr)   unlinkrenamereleaser-   print)r.   data	lock_nametmp_pathbak_pathlockr0   es           r   
_save_jsonrH   z   s   1Dzz##F++##K00-6@{y)))D 	LLNNN	hg666 A!	$a@@@@A A A A A A A A A A A A A A A{{}} OOtO444KK))))DOOD!!!  t  1 1 1/D//A//0000000001sl   A-E 0D) B'D) 'B++D) .B+/D) +C3 2D) 3C75D) E )EE 
E/E**E/c                  ,    t          t          i           S N)r1   DIGITAL_HUMANS_FILE r   r   _load_digital_humansrM      s    )2...r   c                 4    t          t          | d           d S )Nr"   rC   )rH   rK   rB   s    r   _save_digital_humansrQ      s    "D4DEEEEEEr   c                  ,    t          t          i           S rJ   )r1   VOICES_FILErL   r   r   _load_voicesrT      s    k2&&&r   c                 4    t          t          | d           d S )Nr   rO   )rH   rS   rP   s    r   _save_voicesrV      s    {DH555555r   c                  ,    t          t          i           S rJ   )r1   
TASKS_FILErL   r   r   _load_tasksrY      s    j"%%%r   c                 Z    t                      }||| <   t          t          |d           d S Nr#   rO   )rY   rH   rX   )task_id	task_datar#   s      r   
_save_taskr^      s/    MMEE'Nz5G444444r   c                     t                      }| |v r4||                              |           t          t          |d           d S d S r[   )rY   updaterH   rX   )r\   kwargsr#   s      r   _update_taskrb      sQ    MME%gf%%%:u888888 r   c           
         t           ddddddt          |           g}t          j        |dd          }|j        d	k    rt          j        |j                  }|                    d
g           D ]}|                    d          dk    r|                    dd          }|	                    d          }t          |          dk    r+t          |d	                   t          |d                   z  nd}|t          |                    di                               dd	                    |                    dd	          |                    dd	          dc S dd	d	d	dS )u1   获取视频信息 (fps, duration, width, height)-vquiet-print_formatr+   z-show_streams-show_formatTcapture_outputtextr   streams
codec_typevideor_frame_ratez25/1r
   r   r   g      9@formatdurationwidthheight)fpsrp   rq   rr   )FFPROBE_PATHr   
subprocessrun
returncoder+   loadsstdoutr;   splitr   float)filepathcmdresultinfostreamfps_str	fps_partsrs   s           r   get_video_infor      si   wR`befnbobo
pC^C4@@@FAz&-((hhy"-- 
	 
	Fzz,''722 **^V<<#MM#..	CFy>>UVCVCVeIaL))E)A,,?,???\` %dhhx&<&<&@&@Q&O&O P P#ZZ33$jj155	    	 3 Qa@@@r   c                     t           ddt          |           ddddddt          |          g}t          j        |d	d	
          }|j        dk    S )u3   从视频提取音频 (16kHz WAV，标准化格式)-y-i-acodec	pcm_s16le-ac1-ar16000Trh   r   )FFMPEG_PATHr   ru   rv   rw   )
video_path
audio_pathr}   r~   s       r   extract_audior      sV     	T4Z;sE7JC
 ^C4@@@F!!r   c                 R   t          |                              dd           |rd| nd}t          ddt          |           dd| d	g}|r9|                    d
d           |                    dt          |                     t          j        |dd          }|j        dk    S )u   提取视频帧为 PNG 序列Tr   z-r  r   r   -fimage2	/%06d.png   z-r   rh   r   )r   mkdirr   r   insertru   rv   rw   )r   
frames_dirrs   
fps_filterr}   r~   s         r   extract_framesr      s    4$777 #+sJT4Zh:000C   

1d

1c#hh^C4@@@F!!r      c                    t          t          t          |                              d                              }t          t          t          |                               d                              }|dk    rdS |dk    rdS t          ddt          |          d|  d	dt          |          d| d	d
dddddddddt          |          g}t          j        |dd          }|j        dk    rdd|j	        dd          fS t          |          }|
                                sdd| fS |                                j        dk    rdd| fS dS )u   
    将原始帧 + Alpha 蒙版合成为带透明通道的 WebM 视频
    frames_dir: 原始 PNG 帧目录
    alpha_dir:  RMBG-2.0 输出的 Alpha 蒙版目录
    output_path: 输出 WebM 文件路径
    返回: (success: bool, error_msg: str)
    *.pngr   FC   Alpha 帧目录为空 (0 个 PNG 文件)，无法合成透明视频C   原始帧目录为空 (0 个 PNG 文件)，无法合成透明视频r   z
-framerater   r   -filter_complexz[0:v][1:v]alphamerge-c:v
libvpx-vp9-pix_fmtyuva420p-b:v0-crf15Trh   u   FFmpeg 合成失败: N,  u   合成后文件未生成: u   合成后文件大小为0: Tok)Fr   )Fr   )r   listr   globr   r   ru   rv   rw   stderrr)   statst_size)	r   	alpha_diroutput_pathrs   alpha_countframes_countr}   r~   output_files	            r   frames_to_transparent_videor      s    d4	??//8899::KtD,,11'::;;<<La\\q\\ 	Tc#hh&&&c#hh%%%1JVTKC ^C4@@@FACfmDSD.ACCCC {##K A@;@@@@!Q&&AKAAAA:r   r         ?c                    	 ddl m} ddl}t          dddddt	          |           g}t          j        |d	d	d
          }t          j        |j	                  }t          |                    di                               dd                    }|dz  }	|dz  |z  }
g }g }t          |          D ]}|	||
z  z   }t          ddt	          |          dt	          |           dddddddddg}t          j        |d	d          }|j	        rt          |j	                  dk     rrt          j        t          ddddd d!d"d#t	          |           g
d	d	d
          }t          j        |j	                  }|                    d$i g          d         }|                    d%d&          |                    d'd(          }}||z  dz  }t          |j	                  |k     r*|                    |j	        d|         |j        )                              ||df          }|d*z  |d*z  }}t%          |d+z            t%          |d+z            }}||d*z  z
  ||d*z  z
  }}||||z   |||z   f         }|dddddf                             t                    |ddddd,f                             t                    |ddddd*f                             t                    } }}||d-z  k    || d-z  k    z  |d.k    z  }!|!                                |!j        z  }"|                    |"           |"d/k    r_||!         }#t          |#          dk    rD|                    |#d0                              t$                    }$|                    |$           |sd1S t)          |          t          |          z  }%|%|k    }&|rN|                    |d0                              t$                    }'d2|'d         d3|'d,         d3|'d*         d3}(nd4}(t1          d5|%d6d7|( d8|&rd9nd:            |&|%|(fS # t2          $ r})t1          d;|) d<           Y d})~)d1S d})~)ww xY w)=u   
    检测视频是否为绿幕背景。
    采样若干帧，分析中央区域的绿色占比，并提取主导绿色值。
    返回: (is_green_screen: bool, green_ratio: float, green_hex: str)
    r   )ImageNrd   re   rf   r+   rg   T
   ri   rj   timeoutro   rp   r   g333333?g?r   -ssr   z-vframesr   r   
image2piper   rgb24z-vcodecrawvideo-   )ri   r   d   z-select_streamszv:0z-show_entrieszstream=width,heightrk   rq   i  rr   i  )dtyper   333333?r   g?P   皙?)axis)Fg        0x00FF000x02Xr   u#   [绿幕检测] 平均绿色占比: z.1%u   , 主导绿色: u
   , 判定: u   绿幕   自然背景u   [绿幕检测] 检测失败: u   , 默认为自然背景)PILr   numpyrt   r   ru   rv   r+   rx   ry   r{   r;   ranger   r   
frombufferuint8reshapeintastypesumsizeappendmedianrA   r-   )*r   sample_framesgreen_thresholdr   np	probe_cmdr~   r   rp   
start_timeintervalgreen_ratiosall_green_colorsi	seek_timer}   vinfovdatar   r3   hexpected_size	img_arraycxcycrop_wcrop_hx1y1cropr%   gb
green_maskgreen_ratiogreen_pixelsmedian_color	avg_greenis_greendominant	green_hexrG   s*                                             r   detect_green_screenr     s'   V& "4/6#S__6		$TSUVVVz&-(((B//33JBBCC ^
sNm3}%% 0	: 0	:A"Q\1IeS^^T3z??sD,
Gj#/C  ^CbIIIF= C$6$6$<$< NL$RX#4e_#8#j//$K 26D"N N NE Ju|,,EYYy2$//2F::gs++VZZ#-F-FqAEAIM6=!!M11fmN]N&C28TT\\^_abde]fggI !VQ!VB S\\3q3w<<FF&A+%rFaK'7BR6	\2bi<78D 111QQQq5k((//aaa!e1C1CE1J1JDQRQRQRSTSTSTUVQVKL^L^_dLeLe!qA a#g+!a#g+6!b&AJ$..**Z_<K,,, T!!#J/|$$s**#%99\9#B#B#I#I##N#NL$++L999 	*))%%L(9(99	.  	#yy!1y::AA#FFHPXa[PPhqkPPx{PPPII"I  SI  S  S  SS\  S  St|  iQhphp  CQ  S  S  	T  	T  	TI-- & & &HaHHHIII%%%%%%&s   NP. BP. .
Q8QQ333333?皙?c                 r   t           ddt          |           dd| d| dddd	d
dddddt          |          g}t          j        |ddd          }|j        dk    rdd|j        dd          fS t          |          }|                                r|                                j	        dk    rdd| fS dS )ux   
    使用 FFmpeg colorkey 滤镜去除绿幕，输出透明通道 WebM。
    返回: (success: bool, error: str)
    r   r   -vfzcolorkey=0x00FF00:similarity=z:blend=r   r   r   r   r   2Mr   10-auto-alt-refr   Tr   r   r   Fu   FFmpeg 绿幕抠除失败: Nu   绿幕抠除后文件无效: r   
r   r   ru   rv   rw   r   r   r)   r   r   )input_videooutput_video
similarityblendr}   r~   r   s          r   chromakey_remove_greenr  e  s     	Tc+IzII%IIJfdL	C ^C4MMMFAIFM$3$4GIIII|$$K E;#3#3#5#5#=#B#BDlDDDD:r   c                    |r|rd| d| d| d| d	}nd}t           ddt          |           dt          |          d|d	d
dddddddddt          |          g}t          j        |ddd          }|j        dk    rdd|j        dd          fS t          |          }|                                r|                                j	        dk    rdd| fS dS )un   
    将前景视频（带透明通道）与背景图片合成。
    返回: (success: bool, error: str)
    z[1:v]scale=r   *:force_original_aspect_ratio=decrease,pad=z9:(ow-iw)/2:(oh-ih)/2[bg];[0:v][bg]overlay=(W-w)/2:(H-h)/2z5[1:v]scale=iw:ih[bg];[0:v][bg]overlay=(W-w)/2:(H-h)/2r   r   r   r   libx264-presetmediumr   18-c:acopy	-shortestr   yuv420pTr   r   r   Fu   FFmpeg 背景合成失败: Nu   背景合成后文件无效: r   r  )	foreground_videobg_imager  target_wtarget_hfilter_complexr}   r~   r   s	            r   composite_video_with_bgr    sK     QH Q0( 0 0X 0 00 0&0 0 0 	 Q 	Tc"##c(mm>	9hIL	C ^C4MMMFAIFM$3$4GIIII|$$K E;#3#3#5#5#=#B#BDlDDDD:r   color#00FF00c                 (   |dk    r1t          j        t          |           t          |                     dS |dk    r|                    d          }t	          |dd         d          t	          |dd         d          t	          |dd	         d          }}}t
          d
dt          |           dd| dddddddt          |          g}	t          j        |	dd          }
|
j        dk    S |dk    rf|rdt
          d
dddt          |          dt          |           dddddddddddt          |          g}	t          j        |	dd          }
|
j        dk    S |dk    r1t          j        t          |           t          |                     dS dS )u   
    将透明背景视频与背景合成
    bg_mode: 'transparent' (保持透明), 'color' (纯色), 'image' (背景图), 'natural' (原始背景)
    transparentTr  #r   r      r      r   r   r   z [0:v]format=yuva420p[v];color=0xz7:size=1920x1080[bg];[bg][v]overlay=0:0:format=auto[out]-map[out]r   r  r   r  rh   image-loopr   z>[1:v]format=yuva420p[fg];[0:v][fg]overlay=0:0:format=auto[out]z1:a?r  naturalF)	shutilcopy2r   lstripr   r   ru   rv   rw   )r  	bg_sourcer   bg_modebg_colorr  r%   r   r   r}   r~   s              r   compose_video_with_bgr+    s   
 -S%%s;'7'7888t	G		$$eAaCj"%%s51:r':':Cac
B<O<Oa1 #k""mummmGIz9
 DtDDD A%%	G				S$I#k""_GVVIz9	
 DtDDD A%%	I		S%%s;'7'7888t5r   r   Q?r        c                 0   d| d| d| d| d| d| d| d}t           ddt          |           dd	dt          |          d
|dddddddddddddt          |          g}	t          d| d| d|            t          j        |	ddd          }
|
j        dk    r5t          |
j                  dk    r|
j        dd          n|
j        }d!d"| fS t          |          }|	                                r|
                                j        dk    rd!d#| fS d$S )%u  
    【单阶段方案】chromakey 去绿幕 + 背景图合成，一步完成。
    避免两阶段处理（WebM 中间编码）导致的 alpha 通道丢失。
    
    参数:
        input_video:   Duix 输出的原始视频（含绿幕背景）
        bg_image_path: 背景图片路径
        output_video:  输出 MP4 路径
        green_hex:     绿幕颜色 (如 '0x68CA50')，从 detect_green_screen 检测得出
        similarity:    chromakey 相似度 (0.01-1.0)，越小越严格
        blend:         边缘混合 (0.0-1.0)，越大边缘越柔和
        target_w/h:    目标分辨率
    
    返回: (success: bool, error: str)
    z[0:v]chromakey=r   z[fg];[1:v]scale=r
  zI:(ow-iw)/2:(oh-ih)/2:color=black[bg];[bg][fg]overlay=(W-w)/2:(H-h)/2[out]r   r   r#  r   r   r   r!  z0:a?r   r  r  r  r   r  r   r  r  u   [绿幕合成] chromakey=, similarity=, blend=Tr   r   r     iNFu   FFmpeg 绿幕合成失败: u   绿幕合成后文件无效: r   r   r   rA   ru   rv   rw   r   r   r   r)   r   r   )r  bg_image_pathr  r   r  r  r  r  r  r}   r~   stderr_tailr   s                r   green_screen_compositer6    s   .	0) 	0 	0j 	0 	05 	0 	0	0 	0!)	0 	0	0 	0"	0 	0 	0  	Tc+dC..>	9hILC 

Yi
Y
Yj
Y
YRW
Y
YZZZ^C4MMMFA.1&-.@.@3.F.FfmDEE**FMAKAAAA|$$K E;#3#3#5#5#=#B#BDlDDDD:r   c                    t           ddt          |           dd| d| d| dddd	d
dddddt          |          g}t          d| d| d|            t          j        |ddd          }|j        dk    r5t          |j                  dk    r|j        dd         n|j        }dd| fS t          |          }|	                                r|
                                j        dk    rdd| fS dS )u   
    chromakey 去绿幕 → 输出透明通道 WebM（无背景图时使用）。
    
    返回: (success: bool, error: str)
    r   r   r   z
chromakey=r   r   r   r   r   r   r   r   r  r  r   u   [去绿幕→透明] chromakey=r0  r1  Tr   r   r   NFu   FFmpeg 去绿幕失败: u   去绿幕后文件无效: r   r3  )	r  r  r   r  r  r}   r~   r5  r   s	            r   green_screen_to_transparentr9    sA    	Tc+<I<<
<<U<<JfdL	C 

_I
_
_J
_
_X]
_
_```^C4MMMFA.1&-.@.@3.F.FfmDEE**FM>>>>>|$$K B;#3#3#5#5#=#B#BA<AAAA:r   c                   ,    e Zd ZdZd Zd Zd ZddZdS )RMBGMattingEngineu*   通过 ComfyUI RMBG-2.0 进行逐帧抠图c                     t           | _        d S rJ   )COMFYUI_URLcomfyui_urlselfs    r   __init__zRMBGMattingEngine.__init__*  s    &r   c                     	 t           j                            | j         d          }t           j                            |d          5 }|j        dk    cddd           S # 1 swxY w Y   dS # t          $ r Y dS w xY w)u$   检查 ComfyUI RMBG-2.0 是否可用z/system_statsr   r      NF)urllibrequestRequestr>  urlopenstatusr-   r@  reqresps      r   check_availablez!RMBGMattingEngine.check_available-  s    	.((D,<)K)K)KLLC''Q'77 *4{c)* * * * * * * * * * * * * * * * * * 	 	 	55	s6   AA/ 
A"A/ "A&&A/ )A&*A/ /
A=<A=c                 
   ddl }t          |d          5 }|                                }ddd           n# 1 swxY w Y   ddl}| j         d}t
          j                            |          }dt          j	                    j
                                        z   }	g }
|
                    d|	z              |
                    d| d                                           |
                    d	           |
                    d
           |
                    |           |
                    d|	z              |
                    d           |
                    d
           |
                    d           |
                    d|	z   dz              d                    |
          }t          j                            ||ddd|	                                 i          }t          j                            |d          5 }t'          j        |                                          }ddd           n# 1 swxY w Y   |                    d|          }dd|dddddddgiddddgdt          j	                    j
        dd          d d!dd"i}| j         d#}t          j                            |t'          j        |                                          ddd$i          }t          j                            |d%          5 }t'          j        |                                          }ddd           n# 1 swxY w Y   |                    d&          }t/          d'          D ]}t1          j        d(           | j         d)| }t          j                            |          }t          j                            |d*          5 }t'          j        |                                          }ddd           n# 1 swxY w Y   ||v r7||                             d+i           }|                                D ]\  }}|                    d,g           }|r|d         }| j         d-|d.          d/|d0          d1|                    d2d3           }t          j                            |          }t          j                            |d          5 }t          |d4          5 }|                    |                                           ddd           n# 1 swxY w Y   ddd           n# 1 swxY w Y     d5S  nd6S )7uU   
        使用 ComfyUI API 抠图单帧
        返回抠图后的 RGBA PNG
        r   Nrbz/upload/images   ----FormBoundary   --z8Content-Disposition: form-data; name="image"; filename=""s   Content-Type: image/pngr   s+   Content-Disposition: form-data; name="type"s   input   
POSTContent-Typezmultipart/form-data; boundary=rB   methodheaders   rC  nameprompt	LoadImager"  )r"  upload)
class_typeinputsBRIA_RMBG_Zhor   z
Image Save2rmbg_   PNG)imagesfilename_prefix	file_type)r   r`  3z/promptapplication/jsonr   	prompt_idx   r   z	/history/   r   rd  z/view?filename=filenamez&type=typez&subfolder=	subfolderr   wbTF)base64r*   readior>  osr.   basenameuuiduuid4hexencoder   joinrE  rF  rG  decoderH  r+   rx   r;   dumpsr   timesleepitemswrite)r@  
input_pathr   rp  r0   img_datarr  
upload_urlrl  boundary
body_partsbodyrK  rL  upload_resultuploaded_nameworkflow
prompt_urlprompt_resultri  _history_urlhistoryr   node_idnode_outputrd  img_infoimg_urls                                r   _rmbg_single_framez$RMBGMattingEngine._rmbg_single_frame6  s   
 	 *d## 	 qvvxxH	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  				(777
7##J//&)9)@)@)B)BB
%(*+++`U]```ggiijjj4555#(###%(*+++HIII#(###%(*U2333||J''n$$T&#%YhooFWFW%Y%YZ % 
 
 ^##C#44 	4 Jtyy{{33M	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 &))&(;; "-(5II 
 #2&a1 
 #/#&(+I4:<<3CBQB3G+I+I%*   
, (111
n$$H%%,,..#%78	 % 
 
 ^##C#44 	4 Jtyy{{33M	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 "%%k22	 s 	 	AJqMMM!-CC	CCK.((55C''Q'77 24*TYY[[112 2 2 2 2 2 2 2 2 2 2 2 2 2 2G##!),00B??,3MMOO 	$ 	$(G[(__Xr::F $#)!9%)%5  #_  #_hzFZ  #_  #_bjkqbr  #_  #_  @H  @L  @L  MX  Z\  @]  @]  #_  #_$n44W==#^33C3DD 5!%k4!8!8 5A !		 4 4 45 5 5 5 5 5 5 5 5 5 5 5 5 5 55 5 5 5 5 5 5 5 5 5 5 5 5 5 5  $ttt$  $ usx   6::'H44H8;H8'L;;L?L?'P  P	P	T4)(T	T4T!!T4$T!%T44T8;T8Nc           
         t          |                              dd           t          |          j        dt          j                    j        dd          z  }|                    dd           t          d|            t          |t          |                    sdS t          d |
                    d	          D                       }t          |          }t          d
| d           d}t          |          D ]\  }}	t          |          |dz   ddz  }
	 |                     t          |	          t          |
                    rD|dz  }|r=|dz  dk    r4t          |dz   |z  dz            }t          ||d|dz    d| d           # t           $ r"}t          d|dz    d|            Y d}~d}~ww xY wt#          j        t          |          d           t          d| d| d           |S )uu   
        从视频逐帧提取 Alpha 蒙版
        返回: alpha_dir 中的 PNG 序列，同时返回帧数
        Tr   raw_frames_Nrb  u   [RMBG] 提取视频帧: r   c                     g | ]}|S rL   rL   ).0r0   s     r   
<listcomp>z>RMBGMattingEngine.extract_alpha_from_video.<locals>.<listcomp>  s    BBBAaBBBr   r   u   [RMBG] 共 u    帧，开始逐帧抠图...r   06d.pngr   r   u   抠图进度: r
   u    帧progressmessageu   [RMBG] 帧 u    抠图失败: ignore_errorsu   [RMBG] 抠图完成: u
    帧成功)r   r   parentru  rv  rw  rA   r   r   sortedr   r   	enumerater  r   rb   r-   r%  rmtree)r@  r   r   r\   r   frame_filestotal_framessuccess_countr   
frame_fileout_pathr  rG   s                r   extract_alpha_from_videoz*RMBGMattingEngine.extract_alpha_from_video  sg   
 	YdT::: )__+.RDJLL<LRaR<P.R.RR
555555666j#j//:: 	1 BB)A)ABBBCC;''FLFFFGGG &{33 
	= 
	=MAzIAaC)9)9)9)99H=**3z??CMMJJ W!Q&M W1r6Q;;#&A'='C#D#D$Wx,UQqS,U,U<,U,U,UW W W W = = =;AaC;;;;<<<<<<<<= 	c*ooT::::NmNNlNNNOOOs   #A4F
G"F??GrJ   )__name__
__module____qualname____doc__rA  rM  r  r  rL   r   r   r;  r;  '  s_        44' ' '  ` ` `D( ( ( ( ( (r   r;  c                       e Zd ZdZ ej                    Zd Zd Ze	d             Z
d Z	 	 	 dd
Z	 	 ddZd ZddZddZd Zd ZdS )GPTSoVITSEngineu   GPT-SoVITS v2 API 封装
    
    并发安全: 类级别互斥锁，确保同一时间只有一个声音合成请求在执行。
    GPT-SoVITS 是单模型服务，并发请求会导致音色混淆和发音错误。
    c                 ,    t           | _        d | _        d S rJ   )GPT_SOVITS_URLbase_urlcurrent_voice_idr?  s    r   rA  zGPTSoVITSEngine.__init__  s    & $r   c                     	 t           j                            | j         d          }t           j                            |d          5 }	 ddd           dS # 1 swxY w Y   dS # t
          $ r Y dS w xY w)u   检查 GPT-SoVITS 是否可用z/docsr   rC  NTF)rE  rF  rG  r  rH  r-   rJ  s      r   rM  zGPTSoVITSEngine.check_available  s    	.((DM)@)@)@AAC''Q'77 4                  	 	 	55	s6   AA& 
AA& AA&  A!A& &
A43A4c                     | s| S ddl }|                    dd|           } |                    dd|           } |                    dd|           } |                    d	d
|           } | r| d         dvr| dz  } | S )un  
        中文文本智能预处理：提升 GPT-SoVITS 语音合成质量
        
        处理内容:
        1. 修正中文标点符号（半角→全角，确保 TTS 引擎正确解析停顿）
        2. 在句号/感叹号/问号后添加语义停顿标记
        3. 自动补齐缺失的标点符号
        4. 处理英文/数字与中文混排
        r   Nz((?<=[^\x00-\x7F])\.(?=\s|$|[^\x00-\x7F])u   。z'(?<=[^\x00-\x7F]),(?=\s|$|[^\x00-\x7F])u   ，z'(?<=[^\x00-\x7F])!(?=\s|$|[^\x00-\x7F])u   ！z((?<=[^\x00-\x7F])\?(?=\s|$|[^\x00-\x7F])u   ？u!   。！？.!?…~～、)）"」』)resub)rj   r  s     r   _preprocess_chinese_textz(GPTSoVITSEngine._preprocess_chinese_text  s      	K			 vvA5$OOvv@%NNvv@%NNvvA5$OO  	DH$GGGEMD
 r   c                    	 | j          dt          j                            |           }t          j                            |          }t          j                            |d          5 }t          j        |	                                          }ddd           n# 1 swxY w Y   | j          dt          j                            |           }t          j                            |          }t          j                            |d          5 }t          j        |	                                          }ddd           n# 1 swxY w Y   dS # t          $ r}t          d|            Y d}~dS d}~ww xY w)	u   切换 GPT-SoVITS 模型z/set_gpt_weights?weights_path=rX  rC  Nz!/set_sovits_weights?weights_path=Tu!   [GPT-SoVITS] 切换模型失败: F)r  rE  parsequoterF  rG  rH  r+   rx   rq  r-   rA   )r@  gpt_weights_pathsovits_weights_pathurlrK  rL  r~   rG   s           r   	set_modelzGPTSoVITSEngine.set_model  s   	]hh&,BTBTUeBfBfhhC.((--C''R'88 1DDIIKK001 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ]nnV\EWEWXkElElnnC.((--C''R'88 1DDIIKK001 1 1 1 1 1 1 1 1 1 1 1 1 1 1 4 	 	 	9a99:::55555	sa   A)E +'BE B""E %B"&A,E 'E9E E		E E	E 
E9E44E9Nr   zh      ?c	                 f   ddl |dv r|                     |          }j         | j                            d          }	|	st          d          	 |r+|                     |          }
|                     |
           nd}
|                     |
           |r|r|                     ||           |||
|||ddd	d
ddddd}d	                    fd|
                                D                       }| j         d| }j                            |          }t          |          }t          t!          |dz  d          d          }j                            ||          5 }|                                }ddd           n# 1 swxY w Y   |ret'          |d          5 }|                    |           ddd           n# 1 swxY w Y   t+          |          | j                                         S || j                                         S # | j                                         w xY w)u  
        合成语音（增强版 - 高质量中文发音）
        text: 待合成文本
        ref_audio_path: 参考音频路径或 None（使用默认音色）
        ref_text: 参考音频对应文本（可选，提升发音准确度）
        language: zh/en/ja/ko/yue/auto
        speed: 语速倍率
        gpt_weights/sovits_weights: 可选，切换到指定声音模型
        output_path: 保存路径，None 则返回音频字节
        
        质量优化:
        - 智能中文文本预处理（添加停顿标记和标点修正）
        - 固定随机种子（seed=42）确保可重现
        - 降低温度参数提高发音准确度
        r   N)r  yueautor   rC  uY   GPT-SoVITS 模型正忙（有其他用户的语音合成在进行中），请稍后重试r   wavcut0r      g?*   )rj   	text_langref_audio_pathprompt_langprompt_textspeed_factor
media_typestreaming_modetext_split_method
batch_sizetop_ktop_ptemperatureseed&c              3   v   K   | ]3\  }}| d j                             t          |                     V  4dS )=N)r  r  r   )r  kvrE  s      r   	<genexpr>z-GPTSoVITSEngine.synthesize.<locals>.<genexpr>L  sK      #c#cDAqq$G$G6<+=+=c!ff+E+E$G$G#c#c#c#c#c#cr   z/tts?rk  rj  X  ro  )urllib.parser  r  _model_lockr<   r-   _prepare_ref_audio_preload_ref_audior  ry  r~  r  rF  rG  r   minmaxrH  rq  r*   r  r   r@   )r@  rj   r  ref_textlanguagespeedgpt_weightssovits_weightsr   _model_lock_acquiredprocessed_refparamsquery_stringr  rK  text_lenr   rL  
audio_datar0   rE  s                       @r   
synthesizezGPTSoVITSEngine.synthesize  s   $ 	 ,,,0066D  $/777DD# 	ywxxx0	' 7 $ 7 7 G G''6666 !#''666  <~ <{N;;; %"/'' %#"#%+# F" 88#c#c#c#cTZT`T`TbTb#c#c#cccL]7777C.((--C4yyH#h!mS11377G''W'== )!YY[[
) ) ) ) ) ) ) ) ) ) ) ) ) ) )  (+t,, (GGJ'''( ( ( ( ( ( ( ( ( ( ( ( ( ( (;'' $$&&&& $$&&&&D$$&&&&s[   DH 'F<H FH FH %G;H GH GH :H H0c                 8   dt          t          j                               }|
t          |z  }t          |          }|                    dd           |dz  }t
          ddt          |          dd	d
dddt          |          g}t          j        |d           d}		 | 	                    t          |                    }
|
}	n)# t          $ r}t          d|            Y d}~nd}~ww xY w|||t          |          |	dddt          j                                                    |                     t          |                    d
}|| dz  }|| dz  }|                                r)t          |          |d<   t          |          |d<   d|d<   ||fS )ug  
        Few-shot 声音克隆训练
        audio_path: 1分钟左右的参考音频
        注意: GPT-SoVITS 的训练需要完整的 WebUI 流程，API 暂不支持直接调用训练
        这里我们使用 Zero-shot 模式，将参考音频保存用于推理时直接使用
        (For full Few-shot training, use GPT-SoVITS WebUI at :9880)
        vc_NTr   reference.wavr   r   r   r   r   r   r   r   ri   r   u1   [GPT-SoVITS] ASR 失败，使用空参考文本: 	zero_shot)
idrY  r  	ref_audior  r  r  mode
created_atrp   z	_gpt.ckptz_sovits.pthr  r  few_shotr  )r   r|  
VOICES_DIRr   r   r   r   ru   rv   _transcribe_audior-   rA   r   now	isoformat_get_audio_durationr)   )r@  r   
voice_namer  
output_dirr\   voice_idr  r}   r  
asr_resultrG   
voice_info	gpt_modelsovits_models                  r   train_voicezGPTSoVITSEngine.train_voice_  s    ,TY[[))++#h.J*%%
555 $o5tS__{E3w

 	s40000 	K//N0C0CDDJ!HH 	K 	K 	KIaIIJJJJJJJJ	K
  ^,, "",..224400^1D1DEE
 

 H!7!7!77	!x$<$<$<< 	,(+IJ}%+.|+<+<J'(!+Jv##s    $C 
C+C&&C+c                    ddl }ddl}	 g fd}|                                }|                    t          d           |                    t          j        ddd                     t          |d	          5 }d
}	 |	                    |          }|sn|
                    |           .	 ddd           n# 1 swxY w Y   |                    t          j        ddi                     ddl}	t          j                    }
t          j                    |
z
  dk     rX	 |                    d           |                                } |||           n#  Y nxY wt          j                    |
z
  dk     X|                                 d                              }|rt#          d|dd          d           |S n)# t$          $ r}t#          d|            Y d}~nd}~ww xY wdS )u(   使用 Duix ASR (WebSocket) 转录音频r   Nc                     	 t          j        |          }|                    d|                    dd                    }|r                    |           d S d S #  Y d S xY w)Nrj   r~   r   )r+   rx   r;   r   )wsr  rB   rj   result_texts       r   
on_messagez5GPTSoVITSEngine._transcribe_audio.<locals>.on_message  st    :g..D88FDHHXr,B,BCCD 1#**4000001 1DDs   AA A!r   rC  startr  )rm  langrO  i   Trm  endrk  r  r   u   [ASR] 转录成功: 2   ...u   [ASR] 失败: )asyncio	websocket	WebSocketconnectDUIX_ASR_URLsendr+   r{  r*   rq  send_binaryselectr|  
settimeoutrecvclosery  rA   r-   )r@  r   r  r  r
  r  r0   
chunk_sizechunkr  timeout_startmsg	full_textrG   r	  s                 @r   r  z!GPTSoVITSEngine._transcribe_audio  s~   /	(K     $$&&BJJ|RJ000 GGDJ>>??@@@j$'' *1!
*FF:..E  NN5)))	* * * * * * * * * * * * * * * * GGDJ//000 MMM IKKM)++-11MM#&&&''))CJr3''''E )++-11 HHJJJ,,I !@Yss^@@@AAA  !  	( 	( 	(&1&&''''''''	( rsV   A1G <2B;/G ;B??G B?AG !5E G EA&G 
G'G""G'c                    ||                      |          }t          |          j        }t          |dz            }t          |                                          r	 |                      |          }t          |                                          j        }d|cxk    rdk    rn n|dk    r|S t          |                                           nC# t          $ r6 	 t          |                                           n# t          $ r Y nw xY wY nw xY w|dk     r|S d}t          |dz
  d          }||z
  }	|	d	k    rd	}	||	z   }d
| d| d}
t          ddt          |          d|
dddddd|g}t          j        |dd          }|j        dk    oJt          |                                          o)t          |                                          j        dk    }|r?|                      |          }d|cxk    rdk    rn nt          d|dd|dd           |S t          d|j        dd                     	 t          |                                           n# t          $ r Y nw xY wt          |dz            }t          ddt          |          d t          |          d!d"dddddd|g}t          j        |dd          }|j        dk    rt          |                                          ret          |                                          j        dk    r;|                      |          }d|cxk    rdk    rn nt          d#|dd           |S t          d$           |S )%u   
        预处理参考音频以提升克隆质量:
        1. 确保在 3-10 秒范围内（GPT-SoVITS 要求）
        2. 去除首尾静音
        3. 音量归一化（-16dB LUFS）
        4. 验证输出有效，否则回退到原音频
        Nzref_processed.wavr   r     r   r  g      "@g      !@zatrim=r   z,asetpts=PTS-STARTPTS,silenceremove=start_periods=1:start_duration=0.2:start_threshold=-45dB:stop_periods=1:stop_duration=0.2:stop_threshold=-45dB,loudnorm=I=-16:TP=-1.5:LRA=11r   r   z-afr   r   r   r   r   r   Trh   r   u   [GPT-SoVITS] 音频预处理: .1fu   s → su<   [GPT-SoVITS] 高级预处理失败，回退到简单截取: i8zref_trimmed.wavr   -tz8.5u!   [GPT-SoVITS] 简单截取成功: u@   [GPT-SoVITS] 音频预处理全部失败，回退到原始音频)r  r   r  r   r)   r   r   r>   r-   r  r   ru   rv   rw   rA   r   )r@  r  rp   r  processed_pathdurr   
trim_starttrim_endtrim_durfilter_chainr}   r~   successprocessed_durfallback_pathfallback_cmd	fb_resultfb_durs                      r   r  z"GPTSoVITSEngine._prepare_ref_audio  s2    //??Hn%%,V&99:: &&(( 	..~>>N++0022:>>>>r>>>>>dTkk))^$$++----   ((//1111    D a<<!! 
x#~s++j(c>>H!H,H h
  h  hX  h  h  h tS%8%8<{E3w	
 DtDDD$) >d>.B.B.I.I.K.K >'',,..6= 	  	& 44^DDMM''''R'''''_x___=____```%% 	cV][_[`[`Maccddd	  '')))) 	 	 	D	 F%6677tS%8%83z??D%{E3w	
 N<4PPP	1$$m)<)<)C)C)E)E$$}J]J]JbJbJdJdJlosJsJs--m<<FF    b     G&GGGGHHH$$PQQQsO    AC 3!C 
D !DD
DDDDD?!I! !
I.-I.r   r   c                     	 |                      |          }t          |                                          j        }||cxk    o|k    nc o|dk    S # t          $ r Y dS w xY w)u0   验证音频是否有效且时长在规定范围r!  F)r  r   r   r   r-   )r@  r   min_durationmax_durationr&  r   s         r   _validate_audiozGPTSoVITSEngine._validate_audio'  s    	**:66C
##((**2D36666,6666F4$;F 	 	 	55	s   AA 
A! A!c                 *   	 t           ddddd|g}t          j        |dd          }|j        dk    rPt	          j        |j                  }t          |                    d	i                               d
d                    S n# t          $ r Y nw xY wdS )u   获取音频时长rd   re   rf   r+   rg   Trh   r   ro   rp   )
rt   ru   rv   rw   r+   rx   ry   r{   r;   r-   )r@  r   r}   r~   r   s        r   r  z#GPTSoVITSEngine._get_audio_duration0  s    	wYcdC^C4HHHF A%%z&-00TXXh3377
AFFGGG &  	 	 	D	qs   A?B 
BBc                    	 t           j                            dt          |          i          }| j         d| }t           j                            |          }t           j                            |d          5 }t          j	        |
                                          }|                    d          dk    r	 ddd           dS 	 ddd           n# 1 swxY w Y   n)# t          $ r}t          d	|            Y d}~nd}~ww xY wd
S )uN   在 GPT-SoVITS 中预加载参考音频（提升后续合成速度和质量）refer_audio_pathz/set_refer_audio?r   rC  r  r+  NTu*   [GPT-SoVITS] 预加载参考音频失败: F)rE  r  	urlencoder   r  rF  rG  rH  r+   rx   rq  r;   r-   rA   )r@  r  r  r  rK  rL  r~   rG   s           r   r  z"GPTSoVITSEngine._preload_ref_audio<  so   		D\++-?^ATAT,UVVF]==V==C.((--C''R'88  DDIIKK00::i((I55               5                               	D 	D 	DBqBBCCCCCCCC	DusC   A:C# <AC=C# C# CC# CC# #
D	-DD	)Nr   r  r  NNN)r  NNrJ   )r   r   )r  r  r  r  	threadingLockr  rA  rM  staticmethodr  r  r  r  r  r  r4  r  r  rL   r   r   r  r    s        
 !).""K% % %     \>  ( KO?C#O' O' O' O'b <@-18$ 8$ 8$ 8$t6 6 6pT T T Tl   
 
 
    r   r  c                   >    e Zd ZdZd Zd ZddZdd	ZddZddZ	dS )DuixAvatarEngineu   Duix.Avatar WSL2 服务封装c                 6    t           | _        t          | _        d S rJ   )DUIX_VIDEO_URL	video_urlDUIX_TTS_URLtts_urlr?  s    r   rA  zDuixAvatarEngine.__init__P  s    '#r   c                 B   	 t           j                            | j         d          }t           j                            |d          5 }|j        dk     cddd           S # 1 swxY w Y   dS # t           j        j        $ r}|j        dk     cY d}~S d}~wt          $ r~ 	 ddl
}|
                    |j        |j                  }|                    d           |                    d          }|                                 |dk    cY S # t          $ r Y Y dS w xY ww xY w)	u1   检查 Duix.Avatar 视频合成服务是否可用r
   r   rC  r2  Nr   )z	127.0.0.1i   F)rE  rF  rG  r@  rH  rI  error	HTTPErrorcoder-   socketAF_INETSOCK_STREAMr  
connect_exr  )r@  rK  rL  herG  sockr~   s          r   rM  z DuixAvatarEngine.check_availableT  s   	.((DN)=)=)=>>C''Q'77 )4{S() ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) )|% 	! 	! 	!7S=       
	 
	 
	}}V^V5GHH""")<==

{"""   uuu
	sg   AA/ 
A"A/ "A&&A/ )A&*A/ /D
BDD!A'DD
DDDDr  c                    t           j                            |          }t          |d          5 }|                                }ddd           n# 1 swxY w Y   t          j        ddt          d                              |          	                                 |d          
                                }t          j                            | j         d|dd	d
i          }t          j                            |d          5 }t          j        |                                          }	ddd           n# 1 swxY w Y   |	                    d          |	                    dd          fS )uy   
        Duix TTS 预处理（声音特征提取）
        返回: (asr_format_audio_url, reference_audio_text)
        rO  N.wavzdata:audio/wav;base64,rp  )ro   reference_audior  z/v1/preprocess_and_tranrS  rT  rh  rU  rj  rC  asr_format_audio_urlreference_audio_textr   )rs  r.   rt  r*   rq  r+   r{  
__import__	b64encoderz  rx  rE  rF  rG  rB  rH  rx   r;   )
r@  r   r  rl  r0   r  request_bodyrK  rL  r~   s
             r   preprocess_voicez!DuixAvatarEngine.preprocess_voicei  s   
 7##J// *d## 	"qJ	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" zm
88L8L8V8VWa8b8b8i8i8k8kmm#
 #
   688	 	 n$$|444#%78	 % 
 
 ^##C#55 	-Z		,,F	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- zz0116::>TVX3Y3YYYs#   AAA	'D<<E E N<   r   c                    | t          t          j                              }t          |          }t          |          }t	          j        |||dddd                                          }d}	t          |dz             D ]}
	 t          j	        
                    | j         d|dddi	          }t          j	                            |d
          5 }t	          j        |                                          }ddd           n# 1 swxY w Y   |                    d          }|                    dd          }|dk    r5|
dk    rt!          d|
 d|            nt!          d| d|            |c S d|v s
d|v s|dk    r:|
|k     r4t!          d| d|
dz    d| d           t#          j        |           |}	>t'          d|pd           # t          j        j        $ rd}|
|k     rGt!          d| d|
dz    d| d|            t#          j        |           t          |          }	Y d}~t'          d|           d}~ww xY wt'          d | d!|	           )"u  
        提交视频合成任务（带自动重试，Duix 单任务限制）
        audio_path: 口播音频 (GPT-SoVITS 合成的克隆语音)
        video_path: 数字人底视频 (抠图后的透明背景视频)
        max_retries: 最大重试次数（默认30次，每次间隔10秒，最长等待5分钟）
        retry_delay: 重试间隔（秒）
        返回: task_code
        Nr   r   )	audio_urlr@  rF  chaofenwatermark_switchpnz/easy/submitrS  rT  rh  rU  rX  rC  rF  r  r   '  u   [Duix] 提交成功 (重试u   次后): audio=u   [Duix] 提交任务: audio=z, video=   忙碌   繁忙i'  u   [Duix] 服务忙碌中，u   秒后重试 (r
   )...u   Duix 任务提交失败: u   未知错误u   [Duix] 网络错误，z): u   Duix 连接失败: u   Duix 任务提交失败（u   次重试后仍忙碌）: )r   ru  rv  r   r+   r{  rx  r   rE  rF  rG  r@  rH  rx   rq  r;   rA   r|  r}  r-   rD  URLError)r@  r   r   	task_codemax_retriesretry_delay	wsl_audio	wsl_videorT  
last_errorattemptrK  rL  r~   rF  r  rG   s                    r   submit_video_taskz"DuixAvatarEngine.submit_video_task  s2    DJLL))I  
++	
++	z"" !#
 #
   688 	 
[1_-- '	; '	;G&;n,,~333%!+-?@	 -   ^++C+<< 5!Z		44F5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 zz&))jj++5=={{_G__T]__````ZIZZyZZ[[[$$$$ s??h#oo,,r+rrU\]^U^rralrrrsss
;///%(
    SC<Q> S STTT<( ; ; ;[((m;mmgVWimmZemmjkmmnnnJ{+++!$QJHHHH 9a 9 9:::; h[hh\fhhiiisR   AG'D;GD	GD	A&G8AG GI(AI5IIr  c                    t          j                     }t          j                     |z
  |k     r	 t          j                            | j         d|           }t          j                            |d          5 }t          j        |                                          }ddd           n# 1 swxY w Y   |	                    d          }|dk    r|	                    di           }|	                    d          }	|	d	k    ro|	                    d
d          }
|

                    d          r"|
                    d          }d| }d| }|}n|
}|
}|
}d||||	                    dd          dS |	dk    rd|	                    dd          dS |	                    dd          }d|dS n)# t          $ r}t          d|            Y d}~nd}~ww xY wt          j        d           t          j                     |z
  |k     dddS )u   
        查询视频合成任务状态
        返回: {'status': 'completed'/'processing'/'failed', 'video_url': ...}
        z/easy/query?code=r   rC  NrF  r\  rB   rI  r   r~   r   r
   z/code/data/temp/z"\\wsl$\duix-avatar\code\data\temp\	completedvideo_durationr   )rI  r@  wsl_pathr   rp   r   failedr  u   生成失败)rI  rD  r  
processing)rI  r  u   [Duix] 查询任务失败: r   u   任务超时)r|  rE  rF  rG  r@  rH  r+   rx   rq  r;   
startswithr'  r-   rA   r}  )r@  ra  r   r   rK  rL  r~   status_coderB   task_statusresult_pathrl  wsl_full_pathwin_full_pathr@  r  rG   s                    r   query_video_taskz!DuixAvatarEngine.query_video_task  s   
 Y[[
ikkJ&00)9n,,~CC	CC  ^++C+<< 5!Z		44F5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 %jj00%''!::fb11D"&((8"4"4K"a''&*hhx&<&< '11#66 	4'2'9'9#'>'>H,Ix,I,IM,bX`,b,bM(5II,7M,7M(3I&1)2(5(5(,1A1(E(E     %))*2TXXe^=\=\]]]#'88J#:#:*6HMMM; (>  9 9 97A77888888889 JqMMMY ikkJ&00\ $n===sI   A
F. :'B-!F. -B11F. 4B15B=F. 3F. F. .
G8GGc                 
   t          t          j                              }|rt          |dd           	 |                     t          |          t          |          |           n9# t
          $ r,}t          |          }d|v sd|v rt          d           d}~ww xY w|rt          |dd	           t          j                    }d
}t          j                    |z
  |k     r
|                     |d          }	|	d         dk    r*|rt          |dd           |	                    dd          S |	d         dk    r%t          d|	                    d                     |	d         dk    rQ|r:d	t          |	                    dd          dz            z   }
t          ||
           t          j
        d           nt          j
        d           t          j                    |z
  |k     
t          d|dz   d          )u   
        生成视频（阻塞直到完成，自动重试忙碌状态）
        返回 Duix 生成的视频 URL 或本地路径
        uF   提交 Duix.Avatar 视频生成任务（如忙碌将自动重试）...r   )r  r  r]  r^  uM   Duix 服务临时不可用，请稍后重试。队列会自动重新调度。Nu$   Duix.Avatar 唇形同步生成中...   i  rC  rI  rj  u   Duix.Avatar 视频生成完成r   r@  r   rm  u   Duix 生成失败: rD  rn  r  r   r   )r  rk  u   Duix.Avatar 生成超时（rV  u	   分钟）)r   ru  rv  rb   rh  r-   r|  ru  r;   r   r}  )r@  r   r   r\   ra  rG   	error_strr  r   rI  r  s              r   generate_video_blockingz(DuixAvatarEngine.generate_video_blocking  s=   
 
%%	 	A*r}  A  A  A  A	""3z??C
OOYOOOO 	 	 	AI9$$I(=(= pqqq	  	_*P[]^^^^ 	ikkE!G++**9b*AAFh;.. a 2R]_````zz+r222!X-- Kfjj6I6I K KLLL!\11 =!C

:q(A(AC(G$H$HHH 8<<<<
1
1 ikkE!G++" LgrkLLLMMMs   1A( (
B2'BB)r  )NrV  r   )r  rJ   )
r  r  r  r  rA  rM  rU  rh  ru  ry  rL   r   r   r=  r=  M  s        ''$ $ $  *Z Z Z Z:Cj Cj Cj CjJ5> 5> 5> 5>n*N *N *N *N *N *Nr   r=  c                       e Zd ZdZ ej                    Z e            Zd Z	d Z
ed             Zed             Zed             Zd Zd ZddZ	 	 	 ddZ	 	 	 ddZd Zd Zd Zd
S )DigitalHumanEngineV2uE  数字人口播引擎 v2.0（内部串行队列架构）
    
    并发安全设计:
    - GPT-SoVITS 模型锁: 确保同一时间只有一个语音合成/训练在进行
    - 生成队列: 串行化 Duix.Avatar 视频合成请求
    - 任务取消: 支持前端取消正在执行的任务，自动清理临时文件
    c                 (   t                      | _        t                      | _        t	                      | _        t          j                    | _        d| _	        t          j        | j        d          | _        | j                                         d S )NTtargetdaemon)r;  rmbgr  
gpt_sovitsr=  duixqueueQueue_generate_queue_worker_runningr9  Thread_process_queue_worker_threadr  r?  s    r   rA  zDigitalHumanEngineV2.__init__>  sx    %''	)++$&&	  %{}}#'.d6IRVWWW!!#####r   c                     d| _         dS )u   优雅关闭工作线程FN)r  r?  s    r   shutdownzDigitalHumanEngineV2.shutdownI  s    $r   c                 ^    | j                             |           t          d|            dS )u   取消指定任务u   [任务取消] N)_cancelled_tasksaddrA   clsr\   s     r   cancel_taskz DigitalHumanEngineV2.cancel_taskM  s8     	  ))))))*****r   c                     || j         v S )u   检查任务是否已被取消)r  r  s     r   is_cancelledz!DigitalHumanEngineV2.is_cancelledS  s     #...r   c                 :    | j                             |           dS )u   清理取消标记N)r  discardr  s     r   clear_cancelledz$DigitalHumanEngineV2.clear_cancelledX  s!     	$$W-----r   c           	      z   | j         r	 | j                            d          \  }}n# t          j        $ r Y 9w xY w|                     |          rAt          |dd           |                     |           | j                                         	 | j        	                                }|dk    rt          |ddd| d	
           nt          |ddd
            | j
        |fi | na# t          $ rT}t          j                    }t          d| d|            t          |ddt          |                      Y d}~nd}~ww xY w| j                                         |                     |           n3# | j                                         |                     |           w xY w| j         dS dS )uH   后台工作线程：依次处理生成队列中的任务，支持取消r   rC  	cancelled   任务已取消rI  r  r   rn  u.   排队完成，开始生成（队列中还有 u    个任务等待）...rI  r  r     开始生成口播视频...u   [队列生成失败] task=r8   rm     生成失败: N)r  r  r;   r  Emptyr  rb   r  	task_doneqsize_do_generater-   	traceback
format_excrA   r   )r@  r\   r  	remainingrG   	error_msgs         r   r  z#DigitalHumanEngineV2._process_queue]  s]   " 	."&"6":":1":"E"E;      )) W[BSTTTT$$W---$..000. 06688	q== (zYb(z(z(z| | | | | !(EG G G G "!'44V4444 ? ? ?%022	I7IIiIIJJJWX$=SVV$=$=? ? ? ? ? ? ? ? ?? $..000$$W---- $..000$$W----? " 	. 	. 	. 	. 	.s>   ) ;;AC. -E> .
E8A
EE> EE> >0F.c                     | j                                         | j                                        | j                                        dS )u   获取所有服务状态)rmbg_availablegpt_sovits_availableduix_available)r  rM  r  r  r?  s    r   
get_statuszDigitalHumanEngineV2.get_status  sF     #i7799$(O$C$C$E$E"i7799
 
 	
r   r$  Nc                 b   	 |dk    rd}t          |ddd           t                              |          r.t          |dd	           t                              |           d
S t	          |          }t
          |z  }|                    dd           t          t          |                    }|d         }	|d         }
t          |dd|d          d|d          d|	dd|
dd	           t          |dd           t          t          |                    \  }}}|dk    r|rt          |dd|dd           d}nU|dk    r|st          |dd |dd!           n5|dk    rt          |dd"|dd#           nt          |dd$|dd%           t          |d&d'           t	          d(          }|                    dd           || d)z  }|j
                                        }|d)k    r0t          j        t          |          t          |                     nkt          d*d+t          |          d,d-d.d/t          |          g	}t          j        |dd0          }|j        d1k    rt%          d2|j        d3d
                    t          |d4d5| d6           t          |d7d8           d9}d9}| d:}t(                              |;          }|d<z  }d=}| j                                        r	 t          |d>d?           | j                            |d
d9d@dAt          |          B           |                                r1|                                j        dCk    rd}t          |dDdE           n*# t$          $ r}t9          dF| dG           Y d
}~nd
}~ww xY w|s| j                                        r	 t          |dHdI           |                     |t          |                     |                                r|                                j        dCk    rd}n)# t$          $ r}t9          dJ|            Y d
}~nd
}~ww xY w|s5t          |dDdK           |                     |t          |                     |                                ru|                                j        dCk    rWt          |          }	 dL| }t@          |z  }|                    dd           |dMz  }t          j        |t          |                     t          |          }n)# t$          $ r}t9          dN|            Y d
}~nd
}~ww xY w	 tC                      }||d@||d
d
dO|pd9tE          j#                    $                                | j        %                    |          dP|dQ}|||<   tM          |           t          |dRdS|            nM# t$          $ r.}t9          dT|            t          |dRdU           Y d
}~nd
}~ww xY wt          |dRdV           t          |dWdX           tO                      } i dY|dZ|d[|d\t          |          d]t          |          d^d9d_|d`|da|dbt          |          dc|pd9ddtE          j#                    $                                d|d         d|d         d|	d|
detQ          |          dfdgi| |<   tS          |            |dk    rdhndi}!|rdjndV}"t          |dkdldm|! dn|" |o           t9          dp| dq| dr| dstQ          |                      d
S # t$          $ rR}tU          j+                    }#t9          dt|#            t          |dudvt          |           	           Y d
}~d
S d
}~ww xY w)wu  
        训练数字人 - 快速模式
        
        bg_mode:
          'auto'        - 自动检测绿幕（默认）
          'transparent' - 强制透明模式（绿幕抠图）
          'natural'     - 强制自然背景（不抠图）
        
        声音处理：
          有声音 - 提取音频并自动注册到声音库（Zero-shot 参考音频）
          无声音 - 跳过音频步骤，仅保存视频
        r  r$  rn  rk  u   开始训练数字人...r  r  r  r  NTr   rs   rp   r   u   视频信息: rq   xrr   z, r"  zfps, r#  r     u!   正在检测视频背景类型...   u,   ⚠️ 检测到绿幕背景（绿色占比 z.0%u*   ），已自动切换为透明背景模式r  u/   ℹ️ 未检测到明显绿幕（绿色占比 u   ），将尝试 AI 抠图u)   ✅ 检测为自然背景（绿色占比 u   ），跳过抠图u)   ✅ 检测到绿幕背景（绿色占比 u   ），将生成透明通道rX  u"   准备 Duix.Avatar 训练数据...D:\heygem_data\face2face\videos.mp4r   r   r   r  r  aacrh   r   u   视频格式转换失败: r8  r  u   视频已准备 (u   背景模式)7   u   生成默认训练语音...r   u   （默认音色）)rY  zdefault_voice.wavFrV  u/   GPT-SoVITS 生成默认语音（高质量）...r  r  rj   r  r  r  r  r   r!  A   u   GPT-SoVITS 语音合成完成u"   [默认语音] GPT-SoVITS 失败: u   ，尝试 Duix TTS...>   u   Duix TTS 生成默认语音...u#   [默认语音] Duix TTS 也失败: u.   TTS 均不可用，生成静音占位音频...r  r  u,   [默认语音] 复制到声音目录失败: default_ttsdigital_human_train)r  rY  r  r  r  r  r  r  ownerr  rp   source
digital_idK   u,   默认语音已生成并注册到声音库: u   [声音库注册失败] u6   默认语音生成完成（注册失败，可忽略）u   默认语音生成失败Z   u   保存数字人配置...r  rY  r)  r   original_videotransparent_videor   r   r   	train_dirr  r  	has_audiorI  readyu!   透明背景（生成时抠图）r   u   默认语音已注册rj  r   u    数字人训练完成！背景: z | )rI  r  r  r  u   [训练完成] 数字人  (z) bg=z audio=u   [训练失败] rm  u   训练失败: ),rb   r{  r  r  r   	TRAIN_DIRr   r   r   r   suffixr   r%  r&  r   ru   rv   rw   r-   r   DEFAULT_TRAINING_TEXTro   r  rM  r  r)   r   r   rA   r  _generate_default_tts_generate_silence_ttsr  rT   r   r  r  r  rV   rM   boolrQ   r  r  )$r@  r\   r   r  rY  r)  r  r  
video_infors   rp   r   r   r   heygem_video_dirduix_video_pathextr}   r~   r   voice_id_from_trainvoice_name_displaytraining_texttrain_audio_pathtts_okrG   	voice_dirvoice_ref_pathcopy_errr   r  ver"   bg_labelaudio_labelr  s$                                       r   trainzDigitalHumanEngineV2.train  s
   @	V&  #Keffff $0099 W[BSTTTT$44W===j))J!J.IOOD4O888 (J88JU#C!*-H2 |G1D | |zRZG[ | |_b | | |mu | | | |~ ~ ~ ~ 27Z[[[[/B3z??/S/S,Hk9)###Wr %OS^  %O  %O  %O  %OP P P P'M))()Wr %AVa  %A  %A  %A  %AB B B B BI%%Wr$sP[$s$s$s$su u u u u Wr$|P[$|$|$|$|~ ~ ~ ~ 27[\\\\#$FGG""4$"??? /J1D1D1DDO#))++Cf}}S__c/.B.BCCCC #D$Jy&%_9M9MO#DtLLL$))#$WtuuAU$W$WXXX27a77a7a7abbbb
 27TUUUUJ"$$(!<!<!< 288d8CCM  )+>>F ..00 YY 2?pqqqq O..*'+!#!%!$'(8$9$9 /    (..00 d5E5J5J5L5L5TW[5[5[!%$WrCbcccc  Y Y YWqWWWXXXXXXXXY  Edi7799 EE 2?_````..}cBR>S>STTT'..00 &5E5J5J5L5L5TW[5[5[!%  E E ECCCDDDDDDDDE  QWr;kllll**=#>N:O:OPPP&&(( &W-=-B-B-D-D-Lt-S-S !122
U*<
*<*<' *-@ @IOOD4O@@@%.%@NLS-@-@AAA!$^!4!4JJ  U U USSSTTTTTTTTUy)^^F1 2$(%/$1'+*. -!&"&.lnn&>&>&@&@$(O$G$G
$S$S"7&0" "J 3=F./ ((( 2(kWi(k(km m m m m  y y y9R99::: 2?wxxxxxxxxxy Wr;UVVVV 27QRRRR133N*j** 7* c/22	*
 !#j//* $R* j* /* Y* S^^* "* hlnn6688* G,* *X.* s*  H!*" T*--#*$ '%* *N:&( !000 ?F>V>V::\jH6Ii22OiKs ]8 ] ]P[ ] ]#-/ / / / ijiiDiiwiiW[\fWgWgiijjjjj 	V 	V 	V!,..I/I//000;TCPQFF;T;TUUUUUUUUUU	Vs   A!] %J] >BN ] 
N*N% ] %N**] 	A(P2 1] 2
Q<Q] QA<] AT2 1] 2
U<U] U] BW!  ] !
X+$X] XD7] 
^.A^))^.r  r  r  
horizontalc
                     | j                                         dz   }
|
dk    rt          |ddd|
 d|
dz
   d           nt          |ddd           | j                             |||||||||	d	f           d
S )u   
        加入生成队列（所有请求串行处理，根治 Duix "忙碌中"）
        前端通过 task_id 轮询进度即可
        
        output_size: 'horizontal' (横版 1280×720) / 'vertical' (竖版 720×1280)
        r   queuedr   u   排队中（第 u    位），前方 u    个任务等待...r  u'   已加入队列，即将开始生成...)r  rj   r   r)  r*  r4  r  output_sizeN)r  r  rb   put)r@  r\   r  rj   r   r)  r*  r4  r  r  	queue_poss              r   generatezDigitalHumanEngineV2.generateW  s     (..0014	q==A o9 o oyYZ{ o o oq q q q q A IK K K K 	  '$  *&	,
 	,
 	" 		 		 		 		 		r   c
                 R   |	dk    rd\  }
}nd\  }
}	 t          |ddd           t                              |          r.t          |dd	
           t                              |           dS t	                      }||vrt          d| d          ||         }t          |z  }|                    dd           t          |dd           |dz  }|r| j        	                                rt                      }||v rt          |dd           ||         }| j                            |d         |                    dd                    }| j                            |||                    dd          |                    dd          ||                    d          |                    d          t          |                     n9|                    d          rt          |d                                                   rbt          |dd            |d         }| j                            |          }| j                            ||dd|t          |          !           nt          d"| d#          |                    d          rdt          |d                                                   r=t          |d$d%           |                     ||d         t          |                     nt          d&          |                                st          d'          t          |d(d)           | j        	                                st          d*          |                    d+d          }|r!t          |                                          st          d,|           | j                            t          |          ||-          }t          |d.d/           |d0z  }|                    d1          rt*          j                            |          }t*          j                            |d23          5 }t3          t          |          d4          5 }|                    |                                           ddd           n# 1 swxY w Y   ddd           n# 1 swxY w Y   n|                    d5          rt          |                              d6d5          }d7|d8d          }d9| d:| d;}t;          j        |ddd<          }|j        dk    r.tA          d=|j!                    t          d>|j!                   nVt          |                                          r#tE          j#        |t          |                     nt          d?|           t          |d@dA           tH          | dB| dCz  }|dDk    r5|                    dEdF          }|r{t          |                                          rYt          |dGdH| dI|
 dJ| dK           tK          t          |          |t          |          |dLdM|
|N          \  } }!| stA          dO|! dP           |dQz  }"tM          t          |          t          |"          |dLdMR          \  }#}$|#rwtO          t          |"          |t          |          |
|S          \  }%}&|%sBtA          dT|& dU           tE          j#        t          |          t          |                     ntA          dV|$ dU           tE          j#        t          |          t          |                     nt          |dGdW| dX           tH          | dB| dYz  }'tM          t          |          t          |'          |dLdMR          \  } }!| r|'}nVtA          dZ|! d[           tE          j#        t          |          t          |                     nt          |dGd\|
 dJ| dK           |d]z  }(tP          d^d_t          |          d`da|
 db| dc|
 db| dd	dedfdgdhdidjdkdldmt          |(          g})t;          j        |)dddno          }*|*j        dk    rD|(                                r0tE          j#        t          |(          t          |                     nOtA          dp|*j!        ddq          dr           tE          j#        t          |          t          |                     |                                st          ds|           |j)        *                                dYk    }+|+rOtH          | dB| dtz  },tP          d^d_t          |          d_t          |          dedudvdwdxdydxdzd{t          |,          g}nNtH          | dB| d|z  },tP          d^d_t          |          d_t          |          dedudvd}dxdydxdzd{t          |,          g}t;          j        |dd~          }|j        dk    r-|,                                r|+                    d           |,}n1tA          dtY          |d          r|j!        ddq         nd            |                                st          d|           |-                                j.        }-|-dk    rt          d|           tE          j/        t          |          d           |j0        }.d|. }/t          |ddd|/t          |          |/|.|-	  	         tA          d| d| d|- d           dS # t
          $ rR}0tc          j2                    }1tA          d|1            t          |ddt          |0           
           Y d}0~0dS d}0~0ww xY w)u  
        实际执行生成口播视频（由队列工作线程调用）
        1. GPT-SoVITS 合成克隆语音
        2. Duix.Avatar 驱动数字人
        3. FFmpeg 合成背景
        
        output_size: 'horizontal' (1280×720) / 'vertical' (720×1280)
        vertical)r.  r-  )r-  r.  rn  rk  r  r  r  r  r  Nu
   数字人 u
    不存在Tr   r   u    GPT-SoVITS 合成克隆语音...r  ztts_output.wavr  r  rp   r   r  r   r  r  r  r  rj   r  r  r  r  r  r  r   r   u<   声音库条目丢失，使用数字人音频回退合成...r  u   声音 u    不存在且无回退音频r   u&   使用 Duix 内置 TTS 合成语音...u&   GPT-SoVITS 不可用且无参考音频u*   语音合成失败：音频文件未生成rX  u*   语音合成完成，开始口型驱动...uH   Duix.Avatar 视频合成服务不可用，请确认 WSL2 服务已启动r   u   数字人底视频不存在: )r   r   r\   R   u   下载生成视频...zduix_output.mp4httprj  rC  ro  r
   r	   z/mnt/d/r   zwsl -d duix-avatar -- cp "z" "rQ  )shellri   rj   u   [WSL复制失败] u#   无法从 WSL2 复制 Duix 输出: u    无法获取 Duix 输出视频: X   u   合成最终视频...r  r  r  r   r   r  u   绿幕合成 (u   ) + 背景图 →    ×r  r,  r   )r   r  r  r  r  u    [绿幕合成] 单阶段失败: u   ，尝试降级方案...ztransparent_fallback.webm)r   r  r  )r  r  u   [降级合成] 也失败: u   ，输出原始视频u   [降级 chromakey] 也失败: u   chromakey 去绿幕 (u   ) → 透明 WebM....webmu   [去绿幕] 失败: u   ，降级为直接输出u   自然背景模式，缩放至 zscaled_natural.mp4r   r   r   zscale=r   r
  z:(ow-iw)/2:(oh-ih)/2r   r  r  fastr   r  r   r  z-anr   r   u   [自然缩放] 失败: rD  u   ，使用原始输出u    背景合成后文件不存在: z_final.webmr  r  libopusr   z0:vz1:ar  z
_final.mp4r  rh   r6   u   [音频合并] r   u   ffmpeg错误u    最终视频文件生成失败: u   最终视频文件大小为0: r  /api/digital-human/v2/video/rj  r   u   视频生成完成！)rI  r  r  r@  r   
output_urlrl  	file_sizeu   [生成完成] 任务 u   ，视频: r  z bytes)u   [生成失败] rm  r  )3rb   r{  r  r  rM   r-   TEMP_DIRr   r  rM  rT   r  r;   r  r   r   r)   _synthesize_with_duixr  ry  ro  rE  rF  rG  rH  r*   r  rq  r   ru   rv   rw   rA   r   r%  r&  
OUTPUT_DIRr6  r9  r  r   r  r   r>   hasattrr   r   r  rY  r  r  )2r@  r\   r  rj   r   r)  r*  r4  r  r  r  r  r"   dhtask_diraudio_outputr   voicer  dh_audio
base_videoduix_video_url
raw_outputrK  rL  r0   win_destwsl_destr}   r~   final_outputr   r   errr  ok_fberr_fbok2err2transparent_outputtemp_scaled	cmd_scaleresult_scaleis_webmfinal_with_audior  video_filenamevideo_full_urlrG   r  s2                                                     r   r  z!DigitalHumanEngineV2._do_generatet  s    *$$!*Hhh!*Hhr	VKhiiii $0099 W[BSTTTT$44W===133N// CZ C C CDDD
+B')HNN4$N777 27YZZZZ#&66L &NDO;;== &N%v%% 2?abbbb"8,E $ B Bk*EIIj!,D,D!F !FIO..!'0!&:r!:!:!&:t!<!<#$)IIm$<$<',yy1A'B'B$'$5$5 / 	 	 	 	 VVL)) Vd2l3C.D.D.K.K.M.M V 2?}~~~~!,/H $ B B8 L LIO..!'0!#!%#$'$5$5 /     $$Th$T$T$TUUU 66,'' NDL1A,B,B,I,I,K,K N 2?ghhhh..tR5Es<GXGXYYYY#$LMMM&&(( N LMMM27cdddd 9,,.. l jkkk b11J NT*%5%5%<%<%>%> N L
 L LMMM "Y>>|,,% ?  N 27NOOOO!$55J((00 Un,,^<<^++C+== -c*oot44 -		,,,- - - - - - - - - - - - - - -- - - - - - - - - - - - - - -  **3// Uz??224==3Xabb\33Q>QQhQQQ#4SWXXX$))>v}>>???#$Y&-$Y$YZZZ * n%%,,.. U^S__==== S> S STTT 27NOOOO%7(E(EZ(E(E(EEL-''FF;
;;	  'IT-%8%8%?%?%A%A 'I 2(o(o(oV^(o(obj(o(o(oq q q q4JL8I8I"+D!)H> > >GB
  M^^^^___,47R,R)(C
OOS1B-C-C&/D)N )N )Nv ! 	M(? #$5 6 6s<GXGX)1H)F )F )FIC $' Q %&^4&^&^&^ _ _ _ &S__c,>O>O P P P!"`6"`"`"`aaa"LZ#l:K:KLLL !2(_	(_(_(_a a a a)36T6T:6T6T6T)T&9J-?)@)@"+DJ J JGB  I'9RSRRRSSSS__c,6G6GHHHH Wr;v]e;v;viq;v;v;vwwww&)==#j//  MH  M  Mx  M  Mck  M  Mnv  M  M  MIy&&$	5$$	  *~iSWadeee*a//K4F4F4H4H/L[!1!13|3D3DEEEEdL4G4MdddeeeLZ#l2C2CDDD  &&(( S Q< Q QRRR #)//11W<G #-70T0TZ0T0T0T#T #l++#l++FFIE65()) $.70S0SZ0S0S0S#S #l++#l++FFEE65())  ^C4HHHF A%%*:*A*A*C*C%##t#444/ nwvx?X?X(ldsd(;(;^lnnooo  &&(( S Q< Q QRRR$))++3IA~~ O O OPPP M#h--t<<<<).NLNLLNs 7"0#&|#4#4#1!/"+- - - - a7aa|aayaaabbbbb 	V 	V 	V!,..I/I//000;TCPQFF;T;TUUUUUUUUUU	Vsi   Am
 .Om
 R0%(RR0R	R0 R	!R0$m
 0R44m
 7R48Zm
 

n&An!!n&c                 ^   ddl }t          j        |dddd                                          }|j                            t           d|ddd	i
          }|j                            |d          5 }t          j        |	                                          }ddd           n# 1 swxY w Y   |
                    di           
                    dd          }|r|                    d          r|n
t           | }	|j                            |	          }
|j                            |
d          5 }t          |d          5 }|                    |	                                           ddd           n# 1 swxY w Y   ddd           dS # 1 swxY w Y   dS t          d          )uC   使用 Duix TTS 生成默认训练语音（不需要参考音频）r   Nr   r  rj   rP  rQ  r  
/v1/invokerS  rT  rh  rU  rV  rC  rB   rX  r  ro  u   Duix TTS 未返回音频 URL)urllib.requestr+   r{  rx  rF  rG  rA  rH  rx   rq  r;   ro  r*   r  r-   )r@  rj   r   rE  r  rK  rL  rB   rX  full_urlreq2resp2r0   s                r   r  z*DigitalHumanEngineV2._generate_default_ttsx  su   z$&$&	
 
  
 688 	 n$$'''#%78	 % 
 
 ^##C#44 	+:diikk**D	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ HHVR((,,["==	 	<$-$8$8$@$@byyFbW`FbFbH>))(33D''b'99 *U+t,, *GGEJJLL)))* * * * * * * * * * * * * * ** * * * * * * * * * * * * * * * * * :;;;sH   4'B''B+.B+6F(E;/F;E?	?FE?	FFFc                     t          t          |          dz  d          }t          ddddddt          |          d	d
t          |          g}t	          j        |d           dS )u<   用 FFmpeg 生成最长3秒的占位音频（回退方案）r   r   r   r   lavfir   zanullsrc=r=24000:cl=monor$  r   r   Tr  N)r  r   r   r   ru   rv   )r@  rj   r   est_durationr}   s        r   r  z*DigitalHumanEngineV2._generate_silence_tts  sm     3t99q=!,,'4!<#l##{
 	s4000000r   c                    	 | j                             |          }| j                            |          \  }}t	          j        |||dd                                          }t          j        	                    t           d|dddi          }t          j                            |d	          5 }	t	          j        |	                                          }
d
d
d
           n# 1 swxY w Y   |
                    di                               dd          }|rt          j        	                    |                    d          r|n
t           |           }t          j                            |d	          5 }	t!          |d          5 }|                    |	                                           d
d
d
           n# 1 swxY w Y   d
d
d
           d
S # 1 swxY w Y   d
S d
S # t$          $ r}t'          d|             d
}~ww xY w)u#   使用 Duix 内置 TTS 合成语音r  r  r  rS  rT  rh  rU  rj  rC  NrB   rX  r   r  rV  ro  u   [Duix TTS] 合成失败: )r  r  r  rU  r+   r{  rx  rE  rF  rG  rA  rH  rx   rq  r;   ro  r*   r  r-   rA   )r@  rj   r  r   r  asr_urlr  rT  rK  rL  rB   rX  r0   rG   s                 r   r  z*DigitalHumanEngineV2._synthesize_with_duix  s   	 O>>yIIM $	 : := I IGX:(/(0	' '  
 vxx  .((+++!');<	 )  C ''S'99 /Tz$))++../ / / / / / / / / / / / / / / ,,00bAAI -n,,):N:Nv:V:V-xYY_k\xmv\x\xyy^++C+<< -k400 -A		,,,- - - - - - - - - - - - - - -- - - - - - - - - - - - - - - - - -- -
  	 	 	1a11222	s   B0G( 2'C%G( %C))G( ,C)-BG( <G(G5GG	GG		GG( GG(  G!G( (
H
2HH
)r$  N)Nr  r  Nr  r  )r  r  r  r  r9  r:  _gptsovits_locksetr  rA  r  classmethodr  r  r  r  r  r  r  r  r  r  r  rL   r   r   r{  r{  1  s]         %in&&Osuu	$ 	$ 	$% % % + + [+
 / / [/ . . [.!. !. !.F
 
 
MV MV MV MV^ <@JN(4   : @DNR,8BV BV BV BVH< < <>1 1 1         r   r{  c                       e Zd ZdZdS )ThreadingHTTPServerTN)r  r  r  daemon_threadsrL   r   r   r  r    s        NNNr   r  c                       e Zd Zd Zd Zd Zd Zd Zd%dZd Z	d	 Z
d
 Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Z d  Z!d! Z"d" Z#d# Z$d$S )&DigitalHumanV2Handlerc                     d S rJ   rL   )r@  ro   argss      r   log_messagez!DigitalHumanV2Handler.log_message  s    r   c                 |   t          j        |d                              d          }|                     |           |                     dd           |                     dt          |                     |                     dd           |                                  | j                            |           d S )	NF)r4   r&   rT  zapplication/json; charset=utf-8Content-LengthAccess-Control-Allow-Origin*)	r+   r{  rx  send_responsesend_headerr   end_headerswfiler  )r@  rI  rB   r  s       r   _json_responsez$DigitalHumanV2Handler._json_response  s    z$U333::7CC6""")JKKK)3t995556<<<
r   c                     |                      dd           |                      dd           |                      dd           d S )Nr#  r$  zAccess-Control-Allow-MethodszGET, POST, DELETE, OPTIONSzAccess-Control-Allow-Headersz5Content-Type, Authorization, X-Auth-User, X-Auth-Role)r&  r?  s    r   _send_cors_headersz(DigitalHumanV2Handler._send_cors_headers  sO    6<<<79UVVV79pqqqqqr   c                 <    | j                             dd          pdS )u:   从 X-Auth-User 头获取当前用户（由代理注入）zX-Auth-Userr   N)rW  r;   r?  s    r   _get_auth_userz$DigitalHumanV2Handler._get_auth_user  s    |r22:d:r   c                 f    |                                  }|s|                     dddi           dS |S )u"   要求认证，未认证返回 401  rD  u-   未登录或登录已过期，请重新登录N)r-  r)  )r@  usernames     r   _require_authz#DigitalHumanV2Handler._require_auth  sA    &&(( 	g/^%_```4r      资源c                     |                                  }|s|                     dddi           dS |                    dd          }|r#||k    r|                     ddd| i           dS |sd	S d	S )
u7   检查数据所有权，不属于当前用户返回 403r/  rD  u	   未登录Fr  r   i  u   无权访问此T)r-  r)  r;   )r@  rB   resource_typer0  r  s        r   _check_ownershipz&DigitalHumanV2Handler._check_ownership  s    &&(( 	g{%;<<<5"%% 	Uh&&g/P/P/P%QRRR5 	4tr   c                     |                      d           |                                  |                                  d S )NrD  )r%  r+  r'  r?  s    r   
do_OPTIONSz DigitalHumanV2Handler.do_OPTIONS  s@    3!!!r   c                    | j                             d          d         }|dk    r|                                  d S |dk    r|                                  d S |dk    r|                                  d S |                    d          r2|                    d          d         }|                     |           d S |                    d	          r2|                    d          d         }|                     |           d S |d
k    r|                                  d S |                    d          r| 	                    |           d S |dk    r| 
                                 d S |                    d          rd|vr|                     |           d S |                    d          r|                     |           d S |                     d           d S )N?r   z/api/digital-human/v2/listz/api/digital-human/v2/statusz/api/digital-human/v2/tasksz/api/digital-human/v2/task/r
   r  /api/digital-human/v2/preview/z/api/digital-human/v2/voices"/api/digital-human/v2/voice/audio/z/api/digital-human/v2/videosr  delete/api/digital-human/v2/bg/  )r.   rz   _list_digital_humans_get_status_list_tasksro  	_get_task_preview_digital_human_list_voices_serve_voice_audio_list_videos_serve_video_serve_bg_image
send_error)r@  r.   r\   r  s       r   do_GETzDigitalHumanV2Handler.do_GET  s   ys##A&///%%'''''333222__:;; 	!jjoob)GNN7#####__=>> 	!C,J''
33333333__ABB 		!##D)))))333__;<< 	!XQUEUEUd#####__899 	!  &&&&&OOC     r   c                    | j                             d          d         }|dk    r|                                  d S |dk    r|                                  d S |dk    r|                                  d S |dk    r|                                  d S |dk    r|                                  d S |dk    r|                                  d S |d	k    r|                                  d S |d
k    r| 	                                 d S |
                    d          r2|                    d          d         }|                     |           d S |dk    r|                                  d S |                     d           d S )Nr9  r   z/api/digital-human/v2/uploadz/api/digital-human/v2/trainz/api/digital-human/v2/generatez$/api/digital-human/v2/generate-batchz/api/digital-human/v2/bg/uploadz"/api/digital-human/v2/voice/uploadz!/api/digital-human/v2/voice/trainz&/api/digital-human/v2/voice/synthesizez/api/digital-human/v2/cancel/r
   r  z#/api/digital-human/v2/voice/previewr>  )r.   rz   _handle_upload_handle_train_handle_generate_handle_generate_batch_handle_bg_upload_handle_voice_upload_handle_voice_train_handle_voice_synthesizero  _handle_cancel_task_handle_voice_previewrI  )r@  r.   r\   s      r   do_POSTzDigitalHumanV2Handler.do_POST  s   ys##A&111!!!!!222     555!!#####;;;'')))))666""$$$$$999%%'''''888$$&&&&&===))+++++__<== 	!jjoob)G$$W-----:::&&(((((OOC     r   c                    | j                             d          d         }|                    d          r2|                    d          d         }|                     |           d S |                    d          r2|                    d          d         }|                     |           d S |                    d          r2|                    d          d         }|                     |           d S |                    d          r2|                    d          d         }|                     |           d S |                     d	           d S )
Nr9  r   z/api/digital-human/v2/delete/r
   r  z#/api/digital-human/v2/voice/delete/z#/api/digital-human/v2/video/delete/z"/api/digital-human/v2/task/delete/r>  )r.   rz   ro  _delete_digital_human_delete_voice_delete_video_delete_taskrI  )r@  r.   r  r   video_idr\   s         r   	do_DELETEzDigitalHumanV2Handler.do_DELETE:  s>   ys##A&??:;; 	!C,J&&z22222__BCC 
	!zz#r*Hx(((((__BCC 	!zz#r*Hx(((((__ABB 	!jjoob)Gg&&&&&OOC     r   c                     t                                           }|                    d|d         rdnd|d         rdnd|d         rdndd	d
           |                     d|           d S )Nz2.0r  u	   运行中u	   未运行r  r  u   可用u	   不可用)duix_avatarr  r  )versionservicesrD  )enginer  r`   r)  )r@  rI  s     r   r@  z!DigitalHumanV2Handler._get_statusN  s    ""$$.45E.FW{{K-34J-K\kkQ\$*+;$<M+ 
 
 	 	 	 	C(((((r   c                    t                      }||vr|                     dddi           dS ||         }|                     |d          sdS |                    d          p|                    dd          }|r!t	          |                                          sSt	          d	          | d
z  }|                                rt          |          }n|                     dddi           dS t	          |          }|                                j        }|j	        
                                }|dk    rdnd}|                     d           |                     d|           |                     d|           |                     dd           |                                  |                                  t          t          |          d          5 }	t!          j        |	| j                   ddd           dS # 1 swxY w Y   dS )u   预览数字人原始视频r>  rD     数字人不存在N	   数字人r  r   r   r  r  u   视频文件不存在r  
video/webm	video/mp4rD  rT  r"  Accept-RangesbytesrO  )rM   r)  r5  r;   r   r)   r   r   r   r  r   r%  r&  r+  r'  r*   r%  copyfileobjr(  )
r@  r  dhsr  r   heygem_pathr  r  content_typer0   s
             r   rC  z,DigitalHumanV2Handler._preview_digital_humanZ  sR   "$$S  g/C%DEEEF_$$R55 	FVV,--Ib1I1I
 	j!1!1!8!8!:!: 	ABB
EXEXEXXK!!##  --

##C'3J)KLLL*%%
OO%%-	%%'''*g~~||;3666)9555'222!!!#j//4(( 	.Aq$*---	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	.s   G==HHc                    |                                  }t                      }g }|                                D ]\  }}|                    dd          }|r	|r||k    r&|                    |d         |d         |                    dd          |                    dd          |                    dd	          |                    d
d          |                    dd          |                    dd          |                    dd          |                    dd          |d| d           |                    d d           |                     d|t          |          d           d S )Nr  r   r  rY  r)  r$  r  rI  r  rp   r   rq   rr   r  Tr   r:  )r  rY  r)  r  rI  rp   rq   rr   r  r   r  preview_urlc                     | d         S Nr  rL   r  s    r   <lambda>z<DigitalHumanV2Handler._list_digital_humans.<locals>.<lambda>  
    !L/ r   keyreverserD  )r"   count)r-  rM   r~  r;   r   sortr)  r   )r@  r0  rk  r~   dh_idr  r  s          r   r?  z*DigitalHumanV2Handler._list_digital_humans~  s|   &&(("$$ 	 	IE2FF7B''E E ex&7&7MMh6
66)Y77 ff\266&&733FF:q11++&&1--VVK66FF:r22GGG      	114@@@CFS[[!Q!QRRRRRr   c                 2   |                                  }t                      }g }i }|                                D ]b\  }}|                    dd          }|r	|r||k    r'|                    d          }|                    |||                    dd          |                    dd          |                    dd          |                    d	d
          |                    dd          |                    dd          |                    dd          |                    dd          ||                    dd          |                    dd          |                    dd          d           |r$||vrg ||<   ||                             |           d|                    d d           |                     d|d d         t          |          d t          |                                          d d         D             d           d S )Nr  r   batch_idbatch_indexr   batch_totalrm  r  rI  unknownr  r  rj   r  r  r@  r   )r\   r|  r}  r~  rm  rI  r  r  rj   r  r  r  r@  r   c                     | d         S rq  rL   rr  s    r   rs  z3DigitalHumanV2Handler._list_tasks.<locals>.<lambda>  rt  r   Tru  rD  r   c                     i | ]\  }}||	S rL   rL   )r  r  r  s      r   
<dictcomp>z5DigitalHumanV2Handler._list_tasks.<locals>.<dictcomp>  s    DDDA1DDDr   r   )r#   rx  batches)	r-  rY   r~  r;   r   ry  r)  r   r   )	r@  r0  r#   r~   r  tidtaskr  r|  s	            r   rA  z!DigitalHumanV2Handler._list_tasks  s$   &&(( 	. 	.ICHHWb))E E ex&7&7xx
++HMM$#xxq99#xxq9944((8Y77 HHZ3388Ir22,,"hh|R88"hh|R88!XXk266"hh|R88       .7**(*GH%!((---114@@@CDSD\[[DDgmmoo)>)>ss)CDDD"
 "
 	 	 	 	 	r   c                     t                      }||vr|                     dddi           d S ||         }|                     |d          sd S |                     d|           d S )Nr>  rD     任务不存在   任务rD  )rY   r)  r5  )r@  r\   r#   r  s       r   rB  zDigitalHumanV2Handler._get_task  sy    %g/@%ABBBFW~$$T844 	FC&&&&&r   c                 j   |                                  }t                      }g }|                                D ];\  }}|                    dd          }|r	|r||k    r&|                    |           <|                    d d           |                     d|t          |          d           d S )Nr  r   c                 .    |                      dd          S )Nr  r   )r;   rr  s    r   rs  z4DigitalHumanV2Handler._list_voices.<locals>.<lambda>  s    !%%b"9"9 r   Tru  rD  )r   rx  )r-  rT   r~  r;   r   ry  r)  r   )r@  r0  r   r~   r   r  r  s          r   rD  z"DigitalHumanV2Handler._list_voices  s    &&((%||~~ 	! 	!OHeIIgr**E E ex&7&7MM%    994HHHCFS[[!I!IJJJJJr   c                    |                                  }g }t                      }t                      }|                                D ]\  }}|                    dd          }|r	|r||k    r&|                    dd          }|rA|                    t          t          |                                                               t          t                              d          d d          D ][}	|	j                                        dvr	 |	                                }
|
j        d	z  }d
}d}|                                D ]Y\  }}|                    dd          }|t          |	          k    s	||	j        v r"|}|                    dd          d
d         } nZt          |	                                          }|r|r||vr|                    |	j        d|	j         d|	j         d|
j        t'          |d          t)          j        |
j                                                  ||d           L# t0          $ r Y Yw xY w|                     d|t5          |          d           d
S )u6   列出当前用户生成的视频，关联任务信息r  r   r   z*.*c                 4    |                                  j        S rJ   )r   st_mtimerr  s    r   rs  z4DigitalHumanV2Handler._list_videos.<locals>.<lambda>  s    affhh>O r   Tru  )r  r  i   Nrj   r   r  z?download=1r   )rl  r  download_urlr   size_mbr  r\   rj   rD  )videosrx  )r-  rY   r  r~  r;   r  r   r   resolver  r  r   r  r   r   r   stemr   rY  roundr   fromtimestampr  r  r-   r)  r   )r@  r0  r  r#   user_task_videosr  r  r  vpr0   r   file_size_mbrelated_task_idrelated_textvideo_path_strs                  r   rF  z"DigitalHumanV2Handler._list_videos  s   &&(( 55 	> 	>ICHHWb))E E ex&7&7,++B > $$Sb)9)9););%<%<===
..4O4OY]^^^ !	 !	Ax~~'888vvxx#|{;"&!!&  IC,33BSVV||qv*-'+xx';';CRC'@ )6 "%QYY[[!1!1  0 ^K[5[5[ !B!&BB$V16$V$V$V L$\155"*"8"G"G"Q"Q"S"S.(	 	 	 	 	 	    CFS[[!I!IJJJJJs   B9H>A0H>>
IIc                    |                     d          d         }d|v r|                     d          d         nd}i }|r:|                     d          D ]$}d|v r|                     dd          \  }}|||<   %|                    d          dk    }|                    d	d          }	d
|	v s|	s|                     d           dS t          |	z  }
|
                                s|                     d           dS t                      }t          |
                                          }|	                                D ]j\  }}|                    dd          }|rMt          t          |                                                    |k    r|                     |d          s dS  nk|
                                j        }|
j                                        }|dk    rdnd}|                     d           |                     d|           |                     d|           |                     dd           |r-ddlm}  ||	          }|                     dd| d|            |                                  |                                  t-          t          |
          d          5 }t/          j        || j                   ddd           dS # 1 swxY w Y   dS )u%   提供视频文件（预览/下载）r9  r   r   r   r  r  downloadr   r  ..  Nr>  r      视频r  rf  rg  rD  rT  r"  rh  ri  )r  zContent-Dispositionzattachment; filename="z"; filename*=UTF-8''rO  )rz   r;   r   rI  r  r)   rY   r   r  r~  r   r5  r   r   r  r   r%  r&  r  r  r+  r'  r*   r%  rj  r(  )r@  r.   raw_path	query_strquery_paramspairr  r  is_downloadrl  r   r#   r  r  r  tvpr  r  rm  r  safe_filenamer0   s                         r   rG  z"DigitalHumanV2Handler._serve_video
	  sP    ::c??1%*-++DJJsOOA&&2	 	(!,, ( ($;;::c1--DAq&'LO"&&z22c9##$BBGG88OOC   F(*
  "" 	OOC   F Z//1122 	 	IC((<,,C s499,,..//>AA,,T8<< FFOO%%-	%%'''*g~~||;3666)9555'222 	j******!E(OOM2hMhhYfhhj j j!!!#j//4(( 	.Aq$*---	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	.s   1KK Kc                 F   |                     dd                              d          d         }d|v s|s|                     d           dS t          |z  }|                                s|                     d           dS |                                j        }|j                                        }d	d
d
ddd}|	                    |d	          }| 
                    d           |                     d|           |                     d|           |                     dd           |                                  |                                  t          t          |          d          5 }t!          j        || j                   ddd           dS # 1 swxY w Y   dS )u   提供背景图片文件r=  r   r9  r   r  r  Nr>  z	image/pngz
image/jpegz
image/webpz	image/bmpr  z.jpgz.jpegz.webpz.bmprD  rT  r"  zCache-Controlzmax-age=86400rO  )r   rz   rI  BG_DIRr)   r   r   r  r   r;   r%  r&  r+  r'  r*   r   r%  rj  r(  )	r@  r.   rl  bg_pathr  r  content_type_maprm  r0   s	            r   rH  z%DigitalHumanV2Handler._serve_bg_image@	  s   << ;R@@FFsKKAN88OOC   F8#~~ 	OOC   FLLNN*	n""$$ !!
 
 (++C==3666)9555/:::!!!#g,,%% 	.q$*---	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	.s   .FFFc                 *   |                     dd                              d          d         }d|v r|                     d           d S |                    d          }|r|d         n|}t                      }||v r ||         }|                     |d          sd S t
          |z  }|                                sZt          |          d	k    rGt
          |z  d
z  }|                                r|}n#t
          |z  dz  }	|	                                r|	}|                                s|                     d           d S |                                j	        }
| 
                    d           |                     dd           |                     d|
           |                                  |                                  t          t          |          d          5 }t!          j        || j                   d d d            d S # 1 swxY w Y   d S )Nr;  r   r9  r   r  r  r
      声音r   preview.wavr  r>  rD  rT  z	audio/wavr"  rO  )r   rz   rI  rT   r5  r  r)   r   r   r   r%  r&  r+  r'  r*   r   r%  rj  r(  )r@  r.   voice_audio_idpartsr   r   r  r   preview_pathref_pathr  r0   s               r   rE  z(DigitalHumanV2Handler._serve_voice_audioa	  sa   &JBOOUUVYZZ[\]>!!OOC   F $$S))$8588. v8$E((99   .0
   "" 		*s5zzQ%0=@L""$$ *)

 &0?B??$$ *!)J  "" 	OOC   FOO%%-	3555)9555!!!#j//4(( 	.Aq$*---	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	.s    HHHc                    | j                             dd          }d|vr|                     dddi           d S |                    d          d                                         }t          | j                             d	d
                    }| j                            |          }|                    d|z             }|D ]}d|vr|                    d          }|dk    r$|d |         	                    dd          }||dz   d          }	|	
                    d          r
|	d d         }	d
d l}
|
                    d|          }|r|                    d          nd}dt          t          j                               }t          j                            |          d                                         pd}| | }t&          |z  }t)          t+          |          d          5 }|                    |	           d d d            n# 1 swxY w Y   |                     dd|t+          |          t+          |          |t/          |	          d            d S |                     dddi           d S )NrT  r   multipart/form-datar  rD     需要 multipart/form-data	boundary=r   r"  r   rP  	   filename=   

r  r&   ignoreerrorsr   rR  filename="(.+?)"z	video.mp4upload_r  ro  rD  T)r+  	upload_idr   r.   rl  r      未找到文件)rW  r;   r)  rz   rx  r   rfilerq  findrz  endswithr  searchgroupr|  rs  r.   splitextr   
UPLOAD_DIRr*   r   r  r   )r@  rm  r  content_lengthr  r  part
header_endheaders_raw	file_datar  filename_matchrl  r  r  	save_name	save_pathr0   s                     r   rL  z$DigitalHumanV2Handler._handle_upload	  s   |'';; 44g/K%LMMMF%%k2215<<>>T\--.>BBCCz~..

58+,, !	 !	D4'';//JR{
{+22782LLKZ\]]+I!!'** +%crcN	IIIYY':KHHN2@Q~++A...kH4#dikk"2"244I'""8,,Q/5577A6C$+c++I"Y.Ic)nnd++ #q	"""# # # # # # # # # # # # # # # &!)nnI$I& &    FFC'+<!=>>>>>s   .HH	H	c                 .   | j                             dd          }d|vr|                     dddi           dS |                    d          d	                                         }t          | j                             d
d                    }| j                            |          }|                    d|z             }|D ]}d|vr|                    d          }|dk    r$|d|         	                    dd          }||dz   d         }	|	
                    d          r
|	dd         }	ddl}
|
                    d|          }|r|                    d	          nd}dt          t          j                               dt          j                    j        dd          }t$          j                            |          d	                                         }|dvrd}| | }t,          |z  }t/          t1          |          d          5 }|                    |	           ddd           n# 1 swxY w Y   |                     dd|t1          |          d | |t5          |	          d!            dS |                     ddd"i           dS )#u:   上传背景图片（用于绿幕/透明数字人合成）rT  r   r  r  rD  r  Nr  r   r"  r   rP  r  r  r  r&   r  r  r   rR  r  r  zbg.pngbg_r  r  r  r  ro  rD  Tr=  )r+  bg_idr  bg_urlrl  r   u   未找到背景图片文件)rW  r;   r)  rz   rx  r   r  rq  r  rz  r  r  r  r  r|  ru  rv  rw  rs  r.   r  r   r  r*   r   r  r   )r@  rm  r  r  r  r  r  r  r  r  r  r  rl  r  r  r  r  r0   s                     r   rP  z'DigitalHumanV2Handler._handle_bg_upload	  s   |'';; 44g/K%LMMMF%%k2215<<>>T\--.>BBCCz~..

58+,, #	 #	D4'';//JR{
{+22782LLKZ\]]+I!!'** +%crcN	IIIYY':KHHN2@N~++A...hHC#dikk**CCTZ\\-=bqb-ACCE'""8,,Q/5577CDDD #I*Ic)nnd++ #q	"""# # # # # # # # # # # # # # # y>>AiAA$I& &    FFC'+H!IJJJJJs   H55H9	<H9	c           
         |                                  }|sd S t          | j                            dd                    }t	          j        | j                            |                    }|                    d          }|                    dd          }|                    dd          }|s|                     dd	d
i           d S t          |          
                                s|                     dd	d| i           d S t          t          j                              d d         }dt          t          j                               }|dddd|||t          j                                                    d	}	t%          ||	           |                     dd||dd           t'          j        t*          j        |||||fd|id                                           d S )Nr"  r   r   rY  u   未命名数字人r)  r$  r  rD  u   缺少 video_pathu   视频文件不存在: rb  dh_r  pendingu   等待训练...)	r\   rm  rI  r  r  r  rY  r  r  rD  Tstarted)r+  r\   r  rI  r  )r~  r  ra   r  )r1  r   rW  r;   r+   rx   r  rq  r)  r   r)   r   ru  rv  r|  r   r  r  r^   r9  r  rb  r  r  )
r@  r0  r  r  r   rY  r)  r\   r  r]   s
             r   rM  z#DigitalHumanV2Handler._handle_train	  s   %%'' 	FT\--.>BBCCz$*//.99::XXl++
xx 455((9i00 	g/B%CDDDFJ&&(( 	g/U/U/U%VWWWFdjll##BQB'-3ty{{++--
 ($",..2244

 

	 	7I&&&C$	"
 "
 	 	 	 	<:z4AX&		
 	
 	

 %'''''r   c                 n   |                                  }|sd S t          | j                            dd                    }| j                            |          }	 t          j        |          }n9# t          $ r, t          j        |	                    dd                    }Y nw xY w|                    d          }|                    d          }|                    d          }|                    d	d
          }|                    d          }	t          |                    dd                    }
|                    dd          }|r|s|                     dddi           d S t                      }|                    |i           }|r|                     |d          sd S |                    d|                    dd                    }|r>t                      }|                    |i           }|r|                     |d          sd S t          t!          j                              d d         }|dddd||t%          j                                                    d}t+          ||           |                     dd|dd           t,                              |||||||	|
|	  	         d S ) Nr"  r   gbkr   r  r  rj   r   r*  r  r4  r  r  r  r  r  rD  u   缺少 digital_id 或 textre  r)  r$  r  rb  r  r  u   等待生成...)r\   rm  rI  r  r  r  r  r  rD  Tr  )r+  r\   rI  )r1  r   rW  r;   r  rq  r+   rx   UnicodeDecodeErrorrz  r{   r)  rM   r5  rT   r   ru  rv  r   r  r  r^   rb  r  )r@  r0  r  raw_bodyr  r  rj   r   r*  r4  r  r  rk  r  r)  r   r  r\   r]   s                      r   rN  z&DigitalHumanV2Handler._handle_generate'
  s   %%'' 	FT\--.>BBCC:??>22	H:h''DD! 	H 	H 	H:hooeIoFFGGDDD	H XXl++
xx88J''88J	2211dhhw,,--hh}l;; 	 	g/K%LMMMF #$$WWZ$$ 	d++B<< 	F((9bffY	&B&BCC  	!^^FJJx,,E T225(CC djll##BQB'($",..2244	
 	
	 	7I&&&CTgQY!Z!Z[[[ 	T8WhP]_dfqrrrrrs   A1 13B'&B'c                    |                                  }|sdS t          | j                            dd                    }t	          j        | j                            |                    }|                    d          }|                    dg           }|                    d          }|                    dd          }|                    d	g           }t          |                    d
d                    }	|                    dd          }
|r|s| 	                    dddi           dS t                      }|                    |i           }|r|                     |d          sdS |                    d|                    dd                    }|r>t                      }|                    |i           }|r|                     |d          sdS |r|s| 	                    dddi           dS t          t          j                              dd         }|dd         }g }t!          |          D ]\  }}| d| }||dddd|dz    dt#          |           d||dd         ||dz   t#          |          t%          j                                                    d}t+          ||           |                    |           | 	                    d d!||t#          |          d"t#          |           d#d$           t!          t/          ||                    D ]G\  }\  }}|t#          |          k     r||         nd}t0                              ||||||||	|
	  	         HdS )%u9   批量生成：一次提交多条文案（串行执行）Nr"  r   r  textsr   r*  r  	bg_imagesr  r  r  r  r  rD  u   缺少 digital_id 或 textsre  r)  r$  r  rb  r   r  r  r  u   等待批量生成 (r   r
   r_  r   )r\   r|  rm  rI  r  r  r  rj   r  r}  r~  r  rD  Tr  u1    个任务已加入生成队列，将依次处理)r+  r|  task_idsrx  rI  r  )r1  r   rW  r;   r+   rx   r  rq  r{   r)  rM   r5  rT   r   ru  rv  r  r   r   r  r  r^   r   ziprb  r  )r@  r0  r  r  r  r  r   r*  r  r  r  rk  r  r)  r   r  r|  batch_textsr  r   rj   r\   r]   idxitem_bgs                            r   rO  z,DigitalHumanV2Handler._handle_generate_batch`
  s   %%'' 	FT\--.>BBCCz$*//.99::XXl++
"%%88J''88J	22HH["--	dhhw,,--hh}l;; 	 	g/L%MNNNF #$$WWZ$$ 	d++B<< 	F((9bffY	&B&BCC  	!^^FJJx,,E T225(CC  	 	g/L%MNNNFtz||$$RaR(CRCj -- 	% 	%GAt!''A''G"$"#N!A#NNK8H8HNNN(TcT
! 1u";//&lnn6688 I w	***OOG$$$$C  ]]h--ZZZ"
 "
 	 	 	 %.c(K.H.H$I$I 	K 	K C'4(+c)nn(<(<inn$GOOGZx"HgukK K K K	K 	Kr   c                    | j                             dd          }d|vr|                     dddi           dS |                    d          d	                                         }t          | j                             d
d                    }| j                            |          }|                    d|z             }|D ]}d|vr|                    d          }|dk    r$|d|         	                    dd          }||dz   d         }	|	
                    d          r
|	dd         }	ddl}
|
                    d|          }|r|                    d	          nd}dt          t          j                               }t          |z  }|                    dd           t"          j                            |          d	                                         pd}d| }||z  }t+          t-          |          d          5 }|                    |	           ddd           n# 1 swxY w Y   |dz  }t0          dd t-          |          d!d"d#d$d%d&t-          |          g}t3          j        |d'           |                     d(d|t-          |          t-          |          |t7          |	          d)            dS |                     ddd*i           dS )+u   上传音频文件到声音库rT  r   r  r  rD  r  Nr  r   r"  r   rP  r  r  r  r&   r  r  r   rR  r  r  z	audio.wav
vc_upload_Tr   rN  rawro  r  r   r   r   r   r   r   r   r   r  rD  )r+  r   r   r  rl  r   r  )rW  r;   r)  rz   rx  r   r  rq  r  rz  r  r  r  r  r|  r  r   rs  r.   r  r   r*   r   r  r   ru   rv   r   )r@  rm  r  r  r  r  r  r  r  r  r  r  rl  r  
upload_dirr  r  r  r0   r  r}   s                        r   rQ  z*DigitalHumanV2Handler._handle_voice_upload
  s8   |'';; 44g/K%LMMMF%%k2215<<>>T\--.>BBCCz~..

58+,, -	 -	D4'';//JR{
{+22782LLKZ\]]+I!!'** +%crcN	IIIYY':KHHN2@Q~++A...kH7S%5%577I#i/JTD999'""8,,Q/5577A6C#cI"Y.Ic)nnd++ #q	"""# # # # # # # # # # # # # # # "O3HT4Y;sE7HC
 N3t4444%!(mm	NN$I& &    FFC'+<!=>>>>>s   	H++H/	2H/	c                 	   |                                  sdS | j                            dd          }d|v r|                    d          d                                         }t          | j                            dd                    }| j                            |          }|                    d	|z             }d}d
d|D ]}d|vr|                    d          }|dk    r#|d|         	                    dd          }	||dz   d         }
|

                    d          r
|
dd         }
ddl}|                    d|	          }|s|                    d          }d|	v r|
}|dv r|
	                    dd          |dk    r|
	                    dd          |s|                     dddi           dS dt          t          j                               t           z                      dd           dz  t%          t'                    d           5 }|                    |           ddd           n# 1 swxY w Y   t'          t+          j                              dd!         d"d#dd$t/          j                                                    d%}t5          |           |                     d&dd'd(           fd)}t7          j        |d*                                           dS t          | j                            dd                    }t=          j        | j                            |                    }|                    d+          |                    d,          p|                    d-d
          |                    dd          r!tA                    !                                s|                     ddd.i           dS dt          t          j                               t           z  t'          t+          j                              dd!         t5          d"d#dd$t/          j                                                    d%           |                     d&dd'd(           fd/}t7          j        |d*                                           dS )0u   声音克隆训练NrT  r   r  r  r   r"  r   rP  u   未命名声音r  s   Content-Dispositionr  r  r&   r  r  r   rR  r  zname="(.+?)"z	filename=)r  rY  r  r  rD  u   未找到音频文件r  Tr   zraw_upload.wavro  rb  voice_trainrn  u   声音克隆训练中...)r\   rm  rI  r  r  r   r  r  rD  r  )r+  r   r\   rI  c            	      ~   	 t           j                            t                    
t                              \  } }t	                      }	|d<   |d<   ||	<   t          |           t          ddd           d S # t          $ r-}t          dd	t          |           
           Y d }~d S d }~ww xY wN)r  r\   r  r  rj  r   u   声音克隆完成！r  rm  u   声音克隆失败: r  rb  r  r  r   rT   rV   rb   r-   )v_idr  r   rG   r  raw_audio_pathr\   r0  r  r   r  s       r   do_trainz;DigitalHumanV2Handler._handle_voice_train.<locals>.do_train;  s
   d'-'8'D'DN++Z#&y>>7 (E ( ($D*
 *^^F'/Jt$*2Jw''1F8$ ((( s(?A A A A A A  d d d CbZ]^_Z`Z`CbCbccccccccccds   B B 
B<"B77B<r}  r   rY  r  u   音频文件不存在c            	      d   	 t           j                            
t                              \  } }	|d<   |d<   t	                      }||	<   t          |           t          ddd           d S # t          $ r-}t          dd	t          |           
           Y d }~d S d }~ww xY wr  r  )r  r  r   rG   r   r  r\   r0  r  r   r  s       r   do_train_jsonz@DigitalHumanV2Handler._handle_voice_train.<locals>.do_train_jsonr  s   d'-'8'D'D"J#&y>>7 (E ( ($D* (0Jt$*2Jw')^^F'1F8$ ((( s(?A A A A A A  d d d CbZ]^_Z`Z`CbCbccccccccccds   A3A8 8
B/"B**B/)"r1  rW  r;   rz   rx  r   r  rq  r  rz  r  r  r  r  r)  r|  r  r   r*   r   r  ru  rv  r   r  r  r^   r9  r  r  r+   rx   r   r)   )r@  rm  r  r  r  r  r  r  r  r  
field_datar  
name_match
field_namer0   r]   r  r  r   r  r  r\   r0  r  r   r  s                     @@@@@@@@r   rR  z)DigitalHumanV2Handler._handle_voice_train
  s   %%'' 	F|'';; L00#))+66q9@@BBH !1!12BA!F!FGGN:??>22DJJux/00EJ*JH K K)55!YY{33
##";J;/66wx6PP!*Q,--0
&&w// 1!+CRCJ			YYDD
! '--a00
+--!+JJ#999!+!2!278!2!L!LJJ:--)000JJH ##C'3J)KLLL 0S--//H"X-IOOD4O888&)99Nc.))400 $A
###$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $*,,''+G"%&5$!&lnn6688	 	I w	***$"#	& &   d d d d d d d d d d d$ HT:::@@BBBBB !!1!12BA!F!FGGN:djoon==>>D,//J&))VTXXlDU-V-VJxx
D11H T*%5%5%<%<%>%> ##C'3J)KLLL/S--//H"X-I$*,,''+Gw"%&5$!&lnn6688	! 	! 	 	 	 $"#	& &   d d d d d d d d d d d  M$???EEGGGGGs   3IIIc                    t          | j                            dd                    }t          j        | j                            |                    }|                    d          }|                    dd          }t          |                    dd                    }|r|s|                     dd	d
i           dS t                      }||vr|                     dd	di           dS ||         }| 
                    |d          sdS |                    dd          }|r!t          |                                          s|                     dd	di           dS t          j                                        s|                     dd	di           dS 	 dt!          j                    j        dd          }	t&          |z  }
|
                    dd           |
|	 dz  }t          j                            ||                    dd                    }t          j                            |||                    dd          |                    dd          ||                    d          |                    d          t/          |                     |                     ddd | d!|	 dt/          |          d"           dS # t0          $ r3}|                     d#d	d$t/          |           i           Y d}~dS d}~ww xY w)%u   使用克隆声音合成语音r"  r   r   rj   r   r  r  r  rD  u   缺少 voice_id 或 textNr>     声音不存在r  r  3   参考音频文件不存在，请重新训练声音i  u   GPT-SoVITS 服务不可用synth_rb  Tr   rN  rp   r  r  r  r  r  r  rD  r;  r
   )r+  rX  r.   r2  u   合成失败: )r   rW  r;   r+   rx   r  rq  r{   r)  rT   r5  r   r)   rb  r  rM  ru  rv  rw  r  r   r  r  r   r-   )r@  r  r  r   rj   r  r   r  ref_audio_src	output_idr  r   r  rG   s                 r   rS  z.DigitalHumanV2Handler._handle_voice_synthesize  sM   T\--.>BBCCz$*//.99::88J''xx##dhhw,,-- 	t 	g/I%JKKKF6!!g/@%ABBBFx $$UH55 	F 		+r22 	D$7$7$>$>$@$@ 	g/d%efffF 0022 	g/K%LMMMF	K7!1"1"!577I#h.JTD999$)'9'9'99K)<<uyyQ779 9I (((:r22:t44!IIm44$yy)9::,, ) 	 	 	 \(\\Y\\\K((& &     
  	K 	K 	Kg/HA/H/H%IJJJJJJJJJ	Ks   D0K 
L(LLc                    |                                  }|sdS t          | j                            dd                    }t	          j        | j                            |                    }|                    d          }|                    dd          }|s|                     ddd	i           dS t                      }||vr|                     d
ddi           dS ||         }| 
                    |d          sdS |                    dd          }|r!t          |                                          s|                     d
ddi           dS t          j                                        s |                     ddd| ddd           dS 	 t           |z  }	|	                    dd           |	dz  }
t          j                            ||                    dd                    }t          j                            |||                    dd          |                    dd          d|                    d          |                    d          t)          |
                     |                     ddd| d t)          |
          d!           dS # t*          $ r3}|                     d"dd#t)          |           i           Y d}~dS d}~ww xY w)$u$   声音试听（合成示例文本）Nr"  r   r   rj   u6   你好，这是我的克隆声音，效果怎么样？r  rD  u   缺少 voice_idr>  r  r  r  r   r  rD  Tr;  z/reference.wavu/   GPT-SoVITS 不可用，返回原始参考音频)r+  rX  noter   r  rp   r  r  r  r  r  r  r  z/preview.wav)r+  rX  r  r2  u   试听失败: )r1  r   rW  r;   r+   rx   r  rq  r)  rT   r5  r   r)   rb  r  rM  r  r   r  r  r   r-   )r@  r0  r  r  r   rj   r   r  r  preview_dirr  r  rG   s                r   rU  z+DigitalHumanV2Handler._handle_voice_preview  s:   %%'' 	FT\--.>BBCCz$*//.99::88J''xx XYY 	g/@%ABBBF6!!g/@%ABBBFx $$UH55 	F 		+r22 	D$7$7$>$>$@$@ 	g/d%efffF 0022 	Z(ZZZI& &   
 F	K$x/KdT:::&6L )<<uyyQ779 9I (((:r22:t44!IIm44$yy)9::-- ) 	 	 	 X(XXX #L 1 1& &     
  	K 	K 	Kg/HA/H/H%IJJJJJJJJJ	Ks   DJ 
K%(KKc                    t                      }||vr|                     dddi           d S ||         }|                     |d          sd S |                    |           t	          |           t          |                    dd                    }|                                r#t          j	        t          |          d           |                     d	d|d
           d S )Nr>  rD  rd  re  r  r   Tr  rD  r+  deleted)rM   r)  r5  poprQ   r   r;   r)   r%  r  r   )r@  r  rk  r  r  s        r   rX  z+DigitalHumanV2Handler._delete_digital_human  s    "$$S  g/C%DEEEF_$$R55 	F
S!!! R0011	 	>M#i..====CTj!I!IJJJJJr   c                    t                      }||vr|                     dddi           d S ||         }|                     |d          sd S |                    |           t	          |           t
          |z  }|                                r#t          j        t          |          d           |                     dd|d           d S )	Nr>  rD  r  r  Tr  rD  r  )
rT   r)  r5  r  rV   r  r)   r%  r  r   )r@  r   r   r  r  s        r   rY  z#DigitalHumanV2Handler._delete_voice  s    6!!g/@%ABBBFx $$UH55 	F

8V )	 	>M#i..====CTh!G!GHHHHHr   c                    t           |z  }|                                s|                     dddi           dS t          |                                          }t                      }g }|                                D ]d\  }}|                    dd          }|rGt          t          |                                                    |k    r|	                    |           e|D ]#}||         }| 
                    |d          s dS $|                                 |D ]	}||v r||= 
|rt          t          |d	           |                     d
d||d           dS )u0   删除生成的视频文件及关联任务记录r>  rD  u   视频不存在Nr   r   r  r#   rO   rD  T)r+  r   related_tasks)r  r)   r)  r   r  rY   r~  r;   r   r   r5  r>   rH   rX   )	r@  r\  r   r  r#   r  r  r  r  s	            r   rZ  z#DigitalHumanV2Handler._delete_video.  s     (*
  "" 	g/@%ABBBF Z//1122 	* 	*IC((<,,C *s499,,..//>AA$$S))) ! 	 	C:D((x88  	 ! 	 	Ce||#J 	=z5G<<<<C*"
 "
 	 	 	 	 	r   c                 N   t                               |           t                      }||vr|                     dddi           dS ||         }|                     |d          sdS d}|                    dd          }|rrt          |                                          rQ	 t          |                                           d	}n,# t          $ r}t          d
| d|            Y d}~nd}~ww xY wt          |z  }|                                r`	 t          j        t          |          d	           t          d|            n)# t          $ r}t          d|            Y d}~nd}~ww xY w||= t          t           |d           |                     dd	||d           dS )u9   删除任务记录（可选：同时删除关联视频）r>  rD  r  Nr  Fr   r   Tu   [删除视频] 失败: r8   r  u    [清理] 临时目录已删除: u#   [清理] 临时目录删除失败: r#   rO   rD  )r+  r   video_also_deleted)r{  r  rY   r)  r5  r;   r   r)   r>   r-   rA   r  r%  r  r   rH   rX   )r@  r\   r#   r  deleted_videor   rG   temp_dirs           r   r[  z"DigitalHumanV2Handler._delete_taskU  s"    	((111%g/@%ABBBFW~$$T844 	F XXlB//
 	C$z**1133 	CCZ  ''))) $ C C CA
AAaAABBBBBBBBC g%?? 	AAc(mm4@@@@CCCDDDD A A A?A??@@@@@@@@A 'N:u8888C"/"
 "
 	 	 	 	 	s0   ##C 
C0C++C05E 
E.E))E.c                    t                      }||vr|                     dddi           dS ||         }|                     |d          sdS |                    d          dvr1|                     ddd	|                    d           d
i           dS t                              |           t          |dd           t          |z  }|                                rN	 t          j
        t          |          d           n)# t          $ r}t          d|            Y d}~nd}~ww xY w|                     ddd|d           dS )u<   取消任务（POST /api/digital-human/v2/cancel/:task_id）r>  rD  r  Nr  rI  )rn  r  r  r  u   任务状态 u    不支持取消r  u   用户取消任务r  Tr  u#   [取消] 临时目录清理失败: rD  r  )r+  r  r\   )rY   r)  r5  r;   r{  r  rb   r  r)   r%  r  r   r-   rA   )r@  r\   r#   r  r  rG   s         r   rT  z)DigitalHumanV2Handler._handle_cancel_task  s   %g/@%ABBBFW~$$T844 	F 88H%HHHg/ctxx?Q?Q/c/c/c%deeeF 	((111W[:NOOOO g%?? 	AAc(mm4@@@@@ A A A?A??@@@@@@@@A 	CT>O\c!d!deeeees    #D 
D*D%%D*N)r2  )%r  r  r  r   r)  r+  r-  r1  r5  r7  rJ  rV  r]  r@  rC  r?  rA  rB  rD  rF  rG  rH  rE  rL  rP  rM  rN  rO  rQ  rR  rS  rU  rX  rY  rZ  r[  rT  rL   r   r   r  r    sZ           r r r
; ; ;       
! ! !8! ! !6! ! !(
) 
) 
)". ". ".HS S S4% % %N' ' 'K K K2K 2K 2Kh4. 4. 4.l. . .B-. -. -.b.? .? .?`1K 1K 1Kf0 0 0d7s 7s 7srLK LK LK\;? ;? ;?zWH WH WHr:K :K :KxBK BK BKLK K K(I I I(% % %N( ( (Tf f f f fr   r  __main__z<============================================================u<   数字人口播服务 v2.0 (Duix.Avatar + GPT-SoVITS + RMBG)u
     端口: u     工作目录: u!     服务依赖 (需单独启动):z.    Duix.Avatar:  http://127.0.0.1:8383 (WSL2)z/    Duix TTS:     http://127.0.0.1:18180 (WSL2)z'    GPT-SoVITS:   http://127.0.0.1:9880z'    ComfyUI RMBG: http://127.0.0.1:8188u     API 端点:u7       POST /api/digital-human/v2/upload    - 上传视频u:       POST /api/digital-human/v2/train     - 训练数字人u=       POST /api/digital-human/v2/generate  - 生成口播视频u9       POST /api/digital-human/v2/voice/train - 声音克隆z0.0.0.0u0   [启动] 数字人 v2.0 服务运行在 0.0.0.0:u   
[停止] 服务已停止rJ   )r   )r   r   )r   r   )NN)r  r  )r   r,  r   r-  r.  )r   r,  r   )Rr  rs  sysr+   ru  r|  r%  structwaveru   r9  r  r  r  rE  urllib.errorpathlibr   r   http.serverr   r   socketserverr   r   r?  rA  r  r  r=  r   rt   WORK_DIRr  r  r  r  r  
MODELS_DIRr  dr   rK   rS   rX   PORTr  
_threadingr:  r:   r1   rH   rM   rQ   rT   rV   rY   r^   rb   r   r   r   r   r   r  r  r+  r6  r9  r;  r  r=  r{  rb  r  r  r  rA   serverserve_foreverKeyboardInterruptr  rL   r   r   <module>r     s   B 
			 



                                        < < < < < < < < ' ' ' ' ' '   ,,*++;< 7889$
9$	9$
6!8#
8#
=(
iXz:v	V ) )AGGD4G((((!66 .-
 o 
    %jo''joZ_ 	 	 	 	1 1 1 14/ / /F F F' ' '6 6 6& & &5 5 5
9 9 9A A A&" " "" " " "( ( ( (X\& \& \& \&|   4" " " "H) ) ) )X IM365 5 5 5r OS   BY Y Y Y Y Y Y Y|C C C C C C C CP_N _N _N _N _N _N _N _NHS
 S
 S
 S
 S
 S
 S
 S
p 
			    .*   Kf Kf Kf Kf Kf4 Kf Kf Kf`& z	E(OOO	E
HIII	E(OOO	E
t

	E
'X
'
'(((	EGGG	E
-...	E
;<<<	E
<===	E
4555	E
4555	EGGG	E/	E
DEEE	E
GHHH	E
JKKK	E
FGGG	EGGG  )T!24IJJF	E
CT
C
CDDD   *+++3 s   	J $KK