
    *-?jX$                       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	m
Z
 ddlmZ ddlmZmZ ddlmZ ddlmZ ddlZddlZddlZddlmc mZ ej                                        ry ej        d          Zej                            d          Z ej        !                    d          j"        d	z  Z# e$d
e  de#dd           ej        %                                Z&n! ej        d          ZdZ dZ#dZ& e$d           ddl'Z'ddl(Z(dZ)e)*                    dd          Z+ej,        -                    e)          rFej,        .                    e)          ej/        z   ej0        1                    dd          z   ej0        d<   d Z2d Z3 e
e4          j5        j5        dz  Z6e6dz  Z7e6dz  Z8e6dz  Z9e6dz  Z:e6dz  Z;e6dz  Z<e6dz  Z=e7e8e9e:e;fD ]Z>e>?                    d d !           d"d#d$d%d&d"d'd(d)d*d+d,d-d&d*d'd.d)d/d0d1d2d&d/d'd3d)d4d5d6d7d&d4d'd8d)d9d:d;d<d&d9d'd=d)gZ@d> ZAd? ZBd@ZC G dA dB          ZD eD            ZE G dC dDe          ZFdE ZGeHdFk    r eG             dS dS )Gu  
数字人口播服务 - MuseTalk GPU 加速版
RTX 5060 Ti (15.9GB VRAM) + CUDA 13.0

功能：绿幕视频上传、数字人训练、文案驱动口播生成

GPU 加速架构：
1. 绿幕抠图: PyTorch GPU (HSV转换 + Mask + 形态学)  
2. 语音合成: Edge-TTS (微软免费TTS，无需GPU)
3. 口型同步: MuseTalk (腾讯开源, 真实AI口型驱动, 独立Python 3.10进程)
4. 视频合成: FFmpeg (高质量编码)
    N)Path)datetime)
HTTPServerSimpleHTTPRequestHandler)ThreadingMixIn)urlparsecuda   @z[GPU]  (.1f	 GB VRAM)cpuCPUu+   [GPU] CUDA 不可用，回退到 CPU 模式$D:\AI-Ad-Agent\ffmpeg\bin\ffmpeg.exe
ffmpeg.exezffprobe.exePATH c                     t           ddddd| g}t          j        |dd          }|j        dk    r4t	          j        |j                  }t          |d	         d
                   S dS )u*   通过 ffprobe 获取音频时长（秒）-vquiet-print_formatjsonz-show_formatTcapture_outputtextr   formatduration)_FFPROBE_PATH
subprocessrun
returncoder   loadsstdoutfloat)filepathcmdresultinfos       digital_human_server.pyget_audio_durationr*   :   sh    $&.RZ
[C^C4@@@FAz&-((T(^J/0001    c                 f   t           j                            |           d                                         }|dk    rt	          j        | d          5 }|                                }|                                }|                                }|	                                }|
                    |          }ddd           n# 1 swxY w Y   |dk    r	d||z  z  }n|dk    r	d||z  z  }nd	||z  z  }t          j        t          j        ||          t          j        
          }	|dk    r*|	                    d|                              d          }	|	|fS | dz   }
t%          j        t(          dd| dddddd|
gd           t+          |
          \  }	}t          j        |
           |	|fS )uL   读取音频文件为 numpy 数组（支持 WAV/MP3 通过 ffmpeg 转 WAV）   .wavrbN   z<%dh   z<%diz<%dBdtype)axisz.tmp.wav-y-i-acodec	pcm_s16le-ac1-ar16000Tr   )ospathsplitextlowerwaveopengetnchannelsgetsampwidthgetframerate
getnframes
readframesnparraystructunpackfloat32reshapemeanr   r    _FFMPEG_PATHread_audio_samplesunlink)r%   extwf
n_channelssample_width	frameraten_framesrawfmtsampleswav_pathsrs               r)   rR   rR   C   s   
'

8
$
$Q
'
-
-
/
/C
f}}Yx&& 	*"**J??,,L))I}}H--))C	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 1Hz12CCQHz12CCHz12C(6=c22"*EEE>>oob*55:::BBG	!! *$HNdD(;sE7 	   
 %X..KGRIhB;s   A&CC
C
digital_humanuploadstrainedoutputstempvoiceszvoices.jsonz
tasks.jsonTparentsexist_okzh-CN-XiaoxiaoNeuralu   晓晓u   👩u"   温柔女声 - 适合带货/推荐system+0%uP   你好，欢迎使用AI智能广告工作台，我是你的语音助手晓晓。)idnameicondesctypevoicespeedsample_textzh-CN-YunxiNeuralu   云希u   👨u"   阳光男声 - 适合品牌/科技uP   你好，欢迎使用AI智能广告工作台，我是你的语音助手云希。zh-CN-XiaoyiNeuralu   晓依u   👧u"   活泼女声 - 适合潮流/娱乐uP   你好，欢迎使用AI智能广告工作台，我是你的语音助手晓依。zh-CN-YunjianNeuralu   云健u   👨‍💼u"   沉稳男声 - 适合新闻/专业uP   你好，欢迎使用AI智能广告工作台，我是你的语音助手云健。zzh-CN-XiaochenNeuralu   晓辰u   👩‍💼u"   亲切女声 - 适合教程/讲解uP   你好，欢迎使用AI智能广告工作台，我是你的语音助手晓辰。c                      g } t                                           rN	 t          t           dd          5 }t          j        |          } ddd           n# 1 swxY w Y   n	#  g } Y nxY wt
          | z   S )u<   加载语音风格列表（系统默认 + 用户自定义）rutf-8encodingN)VOICES_FILEexistsrD   r   loadDEFAULT_VOICES)customfs     r)   _load_voicesr      s    F 	k3999 &Q1& & & & & & & & & & & & & & &	FFFF""s.   A! A	A! AA! AA! !A'c                     t          t          dd          5 }t          j        | |dd           ddd           dS # 1 swxY w Y   dS )u!   保存用户自定义语音风格wrx   ry   Fr0   ensure_asciiindentN)rD   r{   r   dump)rd   r   s     r)   _save_custom_voicesr      s    	k3	1	1	1 ;Q	&!%::::; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;s   >AAi="  c                   &   e Zd ZdZ ej        g deej                  Z ej        g deej                  Z	dZ
d Zd Zd Zd	 Zd#dZed             Zed$d            Zd Zd Zd Zd%dZd Zd&dZd'dZd Z	 	 d(dZd)d Zd*d!Zd*d"ZdS )+DigitalHumanEngineu   数字人引擎 - GPU 加速版)#   2   r   )devicer3   )U      r   Fc                     |                                  | _        |                                 | _        t	          dt
           d| j                    d S )Nu"   [Engine] 初始化完成, 设备: z
, FFmpeg: )_load_taskstasks_find_ffmpegffmpeg_pathprintDEVICEselfs    r)   __init__zDigitalHumanEngine.__init__   sQ    %%''
,,..W6WWTEUWWXXXXXr+   c                     g d}|D ]9}t           j                            |          st          j        |          r|c S :dS )N)r   zC:\ffmpeg\bin\ffmpeg.exer   ffmpeg)r?   r@   r|   shutilwhich)r   pathsps      r)   r   zDigitalHumanEngine._find_ffmpeg   s\    
 
 

  	 	Aw~~a   FLOO xr+   c                     t                                           rCt          t           dd          5 }t          j        |          cd d d            S # 1 swxY w Y   i S )Nrw   rx   ry   )
TASKS_FILEr|   rD   r   r}   r   r   s     r)   r   zDigitalHumanEngine._load_tasks   s     	$j#888 $Ay||$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $	s   AAAc                     t          t          dd          5 }t          j        | j        |dd           d d d            d S # 1 swxY w Y   d S )Nr   rx   ry   Fr0   r   )rD   r   r   r   r   r   s     r)   _save_taskszDigitalHumanEngine._save_tasks   s    *cG444 	CIdj!%BBBB	C 	C 	C 	C 	C 	C 	C 	C 	C 	C 	C 	C 	C 	C 	C 	C 	C 	Cs   AA
Ar   r   Nc                     ||||t          j                                                    d| j        |<   |                                  d S )N)statusprogressmessager'   
updated_at)r   now	isoformatr   r   )r   task_idr   r   r   r'   s         r)   update_taskzDigitalHumanEngine.update_task   sP     ",..2244
 

7 	r+   c                    | d         dz  }| d         dz  }| d         dz  }t          j        | dddf         dz  d	          \  }}t          j        | dddf         dz  d	          \  }}||z
  }t          j        |          }	|d
k    |d
k    z  }
|dk    |d
k    z  }|dk    |d
k    z  }d||
         ||
         z
  ||
         z  dz  z  |	|
<   d||         ||         z
  ||         z  dz   z  |	|<   d||         ||         z
  ||         z  dz   z  |	|<   t          j        |          }||d
k             ||d
k             z  ||d
k    <   |}t          j        |	||gd	          S )u   
        GPU 加速 RGB -> HSV 转换
        rgb_tensor: [H, W, 3] 范围 [0, 255] on GPU
        返回: [H, W, 3] HSV 范围 H[0-360], S[0-1], V[0-1]
        .r        o@.r-   .r0   .N   r4   )dimr   r-   r0   g      N@   r1   )torchmaxmin
zeros_likestack)
rgb_tensorrw   gbmax_valmax_idxmin_val_deltahmask_rmask_gmask_bsvs                  r)   rgb_to_hsv_gpuz!DigitalHumanEngine.rgb_to_hsv_gpu   s    v&v&v& 9ZRaR%85%@bIIIYz#rr'2U:CCC
'! W%%Q,519-Q,519-Q,519-ai!F)3uV}DIJ&	ai!F)3uV}DIJ&	ai!F)3uV}DIJ&	 W%%w{+ggk.BB'A+ {Aq!9"----r+   r   r-   c                 @   |                                                      d                              d          }|dz  }|}t          |          D ]6}t          j        | |d|           }t          j        ||d|          }|}7|                                dk    S )ux   
        GPU 形态学开运算 + 闭运算 (使用卷积近似)
        mask: [H, W] bool/binary tensor on GPU
        r   r0   r-   )kernel_sizestridepadding      ?)r$   	unsqueezerangeF
max_pool2dsqueeze)	maskr   
iterations
mask_floatkernel_halfpadr   erodeddilateds	            r)   morphological_ops_gpuz(DigitalHumanEngine.morphological_ops_gpu  s     ZZ\\++A..88;;
 "Q&z"" 	! 	!AlJ;KPQ[^____Fl6{1VYZZZG JJ!!##c))r+   c                    t          |          | dz  }|                    dd           t          j        |          }|                                st          d|           |                    t          j                  }t          |                    t          j	                            }t          |                    t          j
                            }t          |                    t          j                            }	|dk    r||z  nd}
t          d| d| d|	 d	|d
d|
d
d           ||	z  dz  dz  }t          dt          dt          t          dz  dz  |z                                }t          d|            d}g }	 |                                \  }}|snt          j        |t          j                  }|                    ||f           t)          |          |k    s	||dz
  k    r|                     ||||	           g }|dz  }|dz  dk    s||k    r"||z  dz  }t          d| d| d|dd           |                                 ||||	|
t/          |          t1          j                                                    t6          j        dk    t:          d	}t          |          | dz  }t=          |dd           5 }t?          j         ||d!d"#           d$d$d$           n# 1 swxY w Y   |S )%u   
        GPU 加速绿幕抠图
        - 使用 PyTorch GPU 进行 HSV 转换和 mask 生成
        - 批量处理帧，充分利用 15.9GB VRAM
        - 返回: (帧序列目录, 元信息)
        _framesTre      无法打开视频: r   u   [GPU抠图]     帧, x, r   fps, r   r   r1   r-      g333333?r
   u   [GPU抠图] Batch size: r   d   u     [GPU抠图] /r   .0f%)r	   )	fpstotal_frameswidthheightr   
frames_dirprocessed_atgpu_acceleratedgpu_name
_meta.jsonr   rx   ry   Fr0   r   N)!r   mkdircv2VideoCaptureisOpened	ExceptiongetCAP_PROP_FPSintCAP_PROP_FRAME_COUNTCAP_PROP_FRAME_WIDTHCAP_PROP_FRAME_HEIGHTr   r   r   GPU_VRAMreadcvtColorCOLOR_BGR2RGBappendlen_process_batchreleasestrr   r   r   r   ro   GPU_NAMErD   r   r   )r   
input_path
output_dir
digital_idr   capr   r   r   r   r   bytes_per_frame	max_batch	frame_idxbatch_framesretframergbpctmeta	meta_pathr   s                         r)   process_green_screen_gpuz+DigitalHumanEngine.process_green_screen_gpu&  s    *%%:(>(>(>>
555z**||~~ 	A?:??@@@ggc&''3773#;<<==CGGC45566SWWS67788),q<#%%a`\``````3```QY````aaa  &.1,q03r3x#~'?/'Q#R#RSSTT	444555		PJC  ,uc&788CC 0111 <  I--lQ>N1N1N##L*eVLLL!NI2~""i<&?&?,.4NyNN<NN3NNNNOOO%	P( 	 % j//$LNN4466%{f4 

 

 $$*'@'@'@@	)S7333 	=qIdAE!<<<<	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= s   K??LLc                    d |D             }t          j        d |D                       }t          r$t          j                            t                    nt          j                    5  t          j        |                              t          t          j
                  }|                     |          }|d         }	|d         }
|d         }|	dk    |	dk    z  }|
d	k    }|d	k    }||z  |z  }| }t          t          |                    D ]&}||         }|                     |d
          }|||<   '|                                dz  }|                                                                                    t           j                  }|                                                                                    t           j                  }ddd           n# 1 swxY w Y   t)          |          D ]W\  }}||         }||         }t          j        ||g          }|d|ddz  }t-          j        t1          |          |           XdS )u   GPU 批量处理绿幕帧c                     g | ]\  }}|S  r  ).0idxr   s      r)   
<listcomp>z5DigitalHumanEngine._process_batch.<locals>.<listcomp>o  s    222633222r+   c                     g | ]\  }}|S r  r  )r  r   r  s      r)   r  z5DigitalHumanEngine._process_batch.<locals>.<listcomp>p  s    AAA5eAAAr+   r2   r   r   r   r   r   g?r   )r   r   Nframe_06d.png)rJ   r   CUDA_STREAMr   r	   streamno_grad
from_numpytor   rN   r   r   r  r   r$   r   numpyastypeuint8	enumeratedstackr   imwriter  )r   r  r   r   r   indices	frames_np
frames_gpuhsv_gpur   r   r   mask_hmask_smask_v
green_maskfg_maskimalphaframes_np_outalpha_npr  bgrabgraout_paths                              r)   r  z!DigitalHumanEngine._process_batchm  s}   22\222HAALAAABB	 0;OUZ{+++ 	< 	<))4477em7TTJ ))*55G AAA2g!r'*FWFWF&61J "kG 3|,,--  AJ..qa.@@

 MMOOe+E 'NN,,2244;;BHEEMyy{{((**11"(;;H=	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	<B  (( 	- 	-FAs"CA 9c1X&&D!$:S$:$:$:$::HKHt,,,,	- 	-s   )E*GG#&G#c                 F   t          |          | dz  }|                    dd           t          j        |          }|                                st          d|           |                    t          j                  }t          |                    t          j	                            }t          |                    t          j
                            }t          |                    t          j                            }	|dk    r||z  nd}
t          d| d| d|	 d	|d
d|
d
d           d}	 |                                \  }}|snt          j        |t          j                  }|d|ddz  }t          j        t#          |          t          j        |t          j                             |dz  }|dz  dk    s||k    r"||z  dz  }t          d| d| d|dd           |                                 ||||	|
t#          |          t)          j                                                    dt.          dd
}t          |          | dz  }t1          |dd          5 }t3          j        ||dd            d!d!d!           n# 1 swxY w Y   |S )"u   
        自然背景模式：直接提取视频帧为 PNG（保留原背景，不做绿幕抠图）
        返回 meta 信息
        r   Tre   r   r   u   [自然背景提取] r   r   r   r   r   r   r  r  r  r-   r   r   u     [帧提取] r   r   r   r   Fnatural)
r   r   r   r   r   r   r   r   r   bg_moder   r   rx   ry   r0   r   N)r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r)  r  COLOR_RGB2BGRr  r   r   r   r  rD   r   r   )r   r  r  r  r   r	  r   r   r   r   r   r  r  r  r  r;  r  r  r  r   s                       r)   _extract_frames_naturalz*DigitalHumanEngine._extract_frames_natural  s   
 *%%:(>(>(>>
555z**||~~ 	A?:??@@@ggc&''3773#;<<==CGGC45566SWWS67788),q<#%%ailii%ii&iiCiiiZbiiiijjj		PJC  ,uc&788C!$@Y$@$@$@$@@HKHs|C9J'K'KLLLNI2~""i<&?&?,.4NyNN<NN3NNNNOOO	P 	 % j//$LNN4466$  
 
 $$*'@'@'@@	)S7333 	=qIdAE!<<<<	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= s   1JJJrh   rj   c                 6  
 ddl }ddl
|                    dd          t          j        t          j                            |          rt          j                            |          ndd           
fd}	 |                                }|                    |           |	                    |
                     |            d	
                     |                                 nI# |j        $ r t          d          t          $ r$}t          dt          |                     d}~ww xY wt          j        t"          dddddddd|gddd          }	|	j        dk    rt          d|	j                   t          j                   |S )uN   使用 Edge-TTS 生成语音，输出标准 WAV 格式（增强稳定性版）r   Nr.   .mp3.T)rg   c                  r   K                                  } |                                d {V  d S )N)rate)Communicatesave)communicateedge_ttsmp3_pathrE  r   rp   s    r)   _genz0DigitalHumanEngine.generate_speech.<locals>._gen  sM      "..tU.FFK""8,,,,,,,,,,,r+   <   )timeoutuM   语音合成超时（60秒），请检查网络连接或尝试更短的文本   语音合成失败: r6   r7   r8   r9   r:   r;   r<   r=      r   r   rM  u   音频转换失败: )asynciorI  replacer?   makedirsr@   dirnamenew_event_loopset_event_looprun_until_completewait_forcloseTimeoutErrorr   r  r   r    rQ   r!   stderrrS   )r   r   output_pathrp   rE  rQ  rK  looper'   rI  rJ  s    ` ``     @@r)   generate_speechz"DigitalHumanEngine.generate_speech  s   &&vv66
BGOOK4P4PYBGOOK000VYdhiiii	- 	- 	- 	- 	- 	- 	- 	- 	-		=))++D""4(((##G$4$4TTVVR$4$H$HIIIJJLLLL# 	m 	m 	mklll 	= 	= 	=;3q66;;<<<	= $h{E3w!
 T2	7 7 7 !!B6=BBCCC 		(s   A/C2 2"D8D33D8c                    t          |          \  }}|                    t          j                  }t	          |dz            }|dz  }t          j        |                              t                    }t          |          |z
  |z  dz   }	t          j
        |	t                    }
t          dt          |          |z
  |          D ]@}||z  }||||z            }t          j        t          j        |dz                      |
|<   A|
                                dk    r|
|
                                z  }
|
                                                                }|d         }g }|D ]R}t	          ||z  dz            }t          |          |z  }|                    t%          ||z   |dz
                       S|S )uU   
        GPU 加速口型同步
        基于音频短时能量的帧映射
        g{Gz?r0   r-   )r   r   r   gQ?)rR   r%  rJ   rN   r   r   r"  r#  r   r  zerosr   sqrtrP   r   r   r$  r   r   )r   
audio_pathr  r  r\   sample_ratewindow_sizehop_sizesamples_gpunum_windowsenergyr3  r  window	energy_npr   	frame_mapr^  offset
base_frames                       r)   sync_lips_gpuz DigitalHumanEngine.sync_lips_gpu  s   
  2*==..,,+,--!# &w//226::7||k1h>B[888q#g,,4h?? 	> 	>Ax-C 1[=1F*UZ!%<%<==F3KK ::<<!fjjll*FJJLL&&((	 N+	 	K 	KA\)D011FY,6JS*v"5q8HIIJJJJr+   #00FF00c                 d   |d         }|d         }t           dz  }t          |d          5 }	|D ]u}
t          |          d|
ddz  }|                                rH|	                    d|                                 d	           |	                    d
d|z  dd           v	 ddd           n# 1 swxY w Y   | j        ddddddt          |          d|ddddddddddd| d t          |          g}t          j	        |d!d!"          }|j
        d#k    rt          d$|j                   |S )%u   FFmpeg 合成最终视频r   r   zframe_list.txtr   r  r  r  file ''
	duration r-   .6f
Nr6   -fconcat-safe0r7   -c:vlibx264-pix_fmtyuv420p-c:aaac-b:a128kz	-shortest-vfzfps=z,format=yuv420pTr   r   u   FFmpeg 合成失败: )TEMP_DIRrD   r   r|   writeas_posixr   r  r   r    r!   r   r[  )r   r  rc  rl  r\  bg_colorr   r   frame_list_pathr   r  
frame_filer&   r'   s                 r)   composite_videoz"DigitalHumanEngine.composite_video#  s   ,'
5k"%55/3'' 	71& 7 7	!*--0L0L0L0L0LL
$$&& 7GG?Z%8%8%:%:???@@@GG5#5555666	7	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 d(GS#o&&*Iz9E66.#...

 DtDDD!!CFMCCDDDs   A9B11B58B5green_screenc                    	 |dk    rdnd}|                      |ddd| d           t          | dz  }t          j        ||           d	}	|                      |dd
d           |                     t          |          ||          }	|dk    rX|                      |dddt           d           |                     t          |          t          t                    |          }
nN|                      |ddd           | 	                    t          |          t          t                    |          }
||
d<   |                      |ddd           t          |
d                   }t          |                    d                    }|r(t          | dz  }t          j        |d         |           |||
|d| t          j                                                    t          |	d	u|	r|	d         nd	d	}t          | dz  }t!          |dd          5 }t#          j        ||dd            d	d	d	           n# 1 swxY w Y   d!| d"t           d#}|	r|d$|	d%          z  }|                      |d&d'||||
d(         |
d)         |
d*         ||	d+           d	S # t&          $ r.}|                      |d,dd-t          |                       d	}~ww xY w).u   
        训练数字人 (GPU加速) + 自动提取语音风格
        
        Args:
            bg_mode: "green_screen" (绿幕抠图) 或 "natural" (保留自然背景)
            bg_color: 绿幕颜色 (仅 green_screen 模式有效)
        r  u   绿幕抠图   自然背景training
   u   正在分析视频 (u
   模式)....mp4N   u   检测视频音轨...   u   GPU抠图提取人像 ()...u'   提取视频帧 (保留自然背景)...r>  r   u   正在生成预览...r   zframe_*.png_preview.pngr   /api/digital-human/preview/rk   )	rk   rl   r  r>  preview
created_atgpu	has_voicevoice_id
_info.jsonr   rx   ry   Fr0   r   u   数字人训练完成！(u   模式, GPU: )u     | 已自动提取语音风格: rl   	completedr   r   r   r   )r  rl   r   r   framesr>  voice_stylefailedu   训练失败: )r   
UPLOAD_DIRr   copy_extract_voice_from_videor  r  r  	TRAIN_DIRr@  r   sortedglobr   r   r   rD   r   r   r   )r   r   
video_pathr  rl   r>  r  
mode_labeldestvoice_extractedr  r   first_framesr  r(   	info_pathr   
result_msgr^  s                      r)   trainzDigitalHumanEngine.trainB  s   >	+2n+D+D.JWj"6cZ6c6c6cddd: 3 3 33DK
D))) #OWj"6MNNN"<<SYY
TXYYO.((  *b:bT\:b:b:bccc44SYYIPZ[[  *b:cddd33CIIs9~~zZZ &DOWj"6MNNN d<011J!*//-"@"@AAL 6#&A&A&AALOW555 !"EEE&lnn6688,D85DNOD11$
 
D "z$=$=$==Iiw777 A1	$a@@@@A A A A A A A A A A A A A A A ZZYYhYYYJ [ZQWAXZZZ
Wk3
( ,E{~.".E E       	 	 	Wh3LCFF3L3LMMM	s=   HJ H9-J 9H==J  H=AJ 
K!)K

Kc                 N   	 t           ddddd|g}t          j        |ddd          }|j        d	k    rd
S t	          j        |j                  }d |                    dg           D             }|st          d           d
S d| t           dz  }t          dd|ddddddddt          |          g}	t          j        |	dd           |                                r|                                j        dk     rd
S t          t          |                    }
	 t!          t          |                    \  }}t#          |          d	k    r^t%          j        t$          j                            |d
t-          t#          |          |dz                                         }t$          j                            t-          t#          |          |dz            d|z            }t%          j        ||z            t%          j        |          dz   z  }t%          j        t%          j        |d
t-          t#          |          |d z                     d!z                      }|d"k     rd#}d$}d%}nA|d&k     rd'}d(}d)}n4|d*k     rd+}d,}d-}n'|d.k     rd/}d0}d)}n|d1k     rd2}d3}d4}nd5}d0}d6}nd7}d0}d)}n#  d7}d0}d)}Y nxY w| d8d9d:| d;|
d<d=d>||d?| d@d|t7          |
dA          |dB t9          j                                                    dC}dD t?                      D             }fdE|D             }|                     |           tC          |           t          dF|dG          d;| dH           |S # tD          $ r}t          dI|            Y d
}~d
S d
}~ww xY w)Ju   
        从视频中提取音轨并创建语音风格
        
        Returns:
            voice_info dict 或 None（如果视频无音轨）
        r   r   r   r   z-show_streamsTrO  rP  r   Nc                 D    g | ]}|                     d           dk    |S )
codec_typeaudior   )r  r   s     r)   r  z@DigitalHumanEngine._extract_voice_from_video.<locals>.<listcomp>  s/    bbb1155CVCVZaCaCaQCaCaCar+   streamsu4   [Voice Extract] 视频无音轨，跳过语音提取
extracted_r.   r6   r7   r8   r9   r:   r;   r<   r=   z-t30rL  )r   rM  i     g      ?g:0yE>r   r0     u   低沉雄厚zzh-CN-YunyangNeuralz-5%iX  u   温暖磁性ru   rj   i   u   阳光中音rs   z+5%i  u   温柔女声rh   i  u   明亮清晰rt   z+10%u   高亢清亮z+15%u   自然音色u	   的语音u   🎬u   从视频提取 - r   r   u   秒)r      你好，我是   ，这是我的语音风格。r-   /api/digital-human/voice/audio/)rk   rl   rm   rn   ro   rp   rq   rr   	has_audioextracted_fromaudio_durationtonepreview_urlr  c                 D    g | ]}|                     d           dk    |S ro   r   r  r  r   s     r)   r  z@DigitalHumanEngine._extract_voice_from_video.<locals>.<listcomp>  ,    MMMA155==H3L3La3L3L3Lr+   c                 ,    g | ]}|d          k    |S rk   r  r  r   r  s     r)   r  z@DigitalHumanEngine._extract_voice_from_video.<locals>.<listcomp>  s'    ???A1T7h+>+>a+>+>+>r+   u*   [Voice Extract] 成功提取语音风格: rl   r  u$   [Voice Extract] 语音提取失败: )#r   r   r    r!   r   r"   r#   r   r   
VOICES_DIRrQ   r  r|   statst_sizer*   rR   r  rJ   absfftrfftr   rfftfreqsumrb  rP   roundr   r   r   r   r   r   r   )r   r  r  digital_name	probe_cmdr'   r(   audio_streams	audio_wavextract_cmdr  r\   r^   spectrumfreqsspectral_centroidrms	tone_desc	tts_voice	tts_speedcustom_voicer   r^  r  s                          @r)   r  z,DigitalHumanEngine._extract_voice_from_video  sa   p	 tWovI  ^IdWYZZZF A%%t:fm,,DbbB(?(?bbbM  MNNNt 1J00H"%6%6%66I dD*;sE7dI	K N;tRHHHH##%% )9)9)AD)H)Ht 0I??N,"0Y@@w<<!##!vbfkk':T3s7||RRSV;T;T:T2U&V&VWWHFOOCGb1f,E,EsRxPPE(*ux/?(@(@BF8DTDTW[D[(\% '"''2L3s7||R!V3L3L2L*MQR*R"S"STTC
 )3..$2	$9	$)		*S00$2	$9	$)		*S00$2	$7	$)		*T11$2	$:	$)		*T11$2	$8	$*		$2	$:	$*		 .I 6I %I"*	2	!			 '222RYRR.RRRR ""]]]]!","'":":!KKK&lnn6688 L$ NMMMMF???????FMM,''''''c|F?SccW`cccddd 	 	 	<<<===44444	sD   1M= A
M= A;M= ?M= FJ4 3M= 4J><C M= =
N$NN$colorc	                 n
   	 t           j                                        rt           j                                         t           j                                         t           j                            d          j        t           j                            d          z
  }	|	dz  }
t          d|
ddd           |
dk     rRt          d	|
dd
d           t           j                                         t           j        	                                 | 
                    |ddd           t          | dz  }t          | dz  }|                                st          d| d          t          |dd          5 }t          j        |          }ddd           n# 1 swxY w Y   |dk    r|                                r	 t          |dd          5 }t          j        |          }ddd           n# 1 swxY w Y   |                    d          rpt%                      }t'          fd|D             d          }|rD|                    d|          }|                    d|          }t          d|d                     n#  Y nxY w| 
                    |ddd           t(          | dz  }|                     |t-          |          ||           | 
                    |dd d!           t/          |d"                   }t(          | d#z  }|                    d$d%          }|                     |t-          |          |d&         |d%k    '           | 
                    |dd(d)           t(          | d*z  }|                     t-          |          t-          |          t-          |          |+           t4          | d,| d-z  }|d.k    r0t7          j        t-          |          t-          |                     nP| 
                    |dd/d0| d1           |                     t-          |          t-          |          ||||           |                    d2           |                    d2           |                    d2           t?          t-          |                    }d3d4d5d6                    ||          }| 
                    |d7d8d9| d:d;| d,| d-||d<|d=           dS # t          $ r.}| 
                    |d>dd?t-          |                       d}~ww xY w)@un  
        生成口播视频 (MuseTalk AI口型驱动 + 自动语音风格匹配)
        
        Args:
            bg_mode: "natural" (保留原背景), "color" (纯色背景), "custom" (自定义背景图片)
            bg_color: 纯色背景颜色 (仅 color 模式有效)
            bg_image_path: 自定义背景图片路径 (仅 custom 模式有效)
        r   r
   u0   [Generate] GPU缓存已清理, 可用显存约: r   GBTflushg       @u   [Generate] ⚠️ 显存不足(u   GB)，尝试强制清理...
generatingr  u   正在加载数字人数据...r   r  u
   数字人 u
    未训练rw   rx   ry   Nrh   r  c              3   4   K   | ]}|d          k    |V  dS rk   Nr  )r  r   bound_voice_ids     r)   	<genexpr>z.DigitalHumanEngine.generate.<locals>.<genexpr>,  s1      +[+[!4NAZAZAAZAZAZAZ+[+[r+   rp   rq   u%   [Generate] 自动匹配语音风格: rl   r  u    正在生成语音 (Edge-TTS)...z
_audio.wavr  u   准备视频素材...r   z
_input.mp4r>  r  r   )fill_green_bgrO  u,   MuseTalk AI口型推理中 (约2-5分钟)...z_musetalk.mp4)r  rc  r\  r   r   r  r=  r   u   正在合成背景 (r  
missing_okr  u   纯色背景u   自定义背景)r=  r  r   r  r   u   口播视频生成完成！(u   , MuseTalk AI驱动)/api/digital-human/video/MuseTalk)	video_urlr   r   enginer>  r  u   生成失败: ) r   r	   is_availableempty_cachesynchronizeget_device_propertiestotal_memorymemory_reservedr   ipc_collectr   r  r|   r   rD   r   r}   r   r   nextr  r_  r  r   _frames_to_video_run_musetalk
OUTPUT_DIRr   r  _apply_backgroundrS   r*   )r   r   r  r   rp   r>  r  bg_image_pathrq   free_memfree_gbr  r  r   r  d_inford   bound_voicerc  r   temp_input_videotrain_bg_modemusetalk_rawr\  r  bg_labelr^  r  s                              @r)   generatezDigitalHumanEngine.generate  sB   b	z&&(( 	-
&&(((
&&((( :;;A>>KejNhNhijNkNkk"W,XXXXX`deeeeS==dGddddlpqqqqJ**,,,J**,,,WlA7WXXX!z$=$=$==I!z$=$=$==I##%% E CZ C C CDDDiw777 $1y||$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ ...93C3C3E3E.iw??? .1!%1. . . . . . . . . . . . . . .%+ZZ
%;%;N% a!-&*+[+[+[+[v+[+[+[]a&b&b& a$/OOGU$C$CE$/OOGU$C$CE!"_+V\J]"_"_```DWlB8Z[[[!w$:$:$::J  s:uEEEWlB8OPPP d<011J'W*@*@*@@ HHY??M!!*c2B.C.CT%[1>.1P " S S S WlB8fggg $&?&?&??L/00z??--	     %''D'DJ'D'D'DDK)##C--s;/?/?@@@@   ,<`SZ<`<`<`aaa&&%%s;'7'7'8]   ##t#4444000.../K0@0@AAN#1NVghhllmtv}~~HWk38uW_8u8u8uSSS:SSS*$"x x       	 	 	Wh3LCFF3L3LMMM	sz   E<S< ?F S<  F$$S< 'F$(S< J G9-J 9G==J  G=B
J S< JI,S< <
T4)T//T4c                 6   ddl t          fdt          j        |          D             fd          }|st	          d          |rddl}t          |                    t          d                    }t          d	t          |           d
d           |D ]H}t          |          |z  }	t          j        t          |	          t          j                  }
|
j        d         dk    r|
ddddddf         }|
ddddddf         dz  }t!          j        |          }d|dddddf<   |                    t           j                  |z  |                    t           j                  d|z
  z  z                       t           j                  }t          j        t          ||z            |           #t          j        t          ||z            |
           Jt          |          }t          dz  }t-          |d          5 }|D ]H}|                    dt          |          |z   d           |                    dd|z  dd           I	 ddd           n# 1 swxY w Y   t1          j        t4          ddddddt          |          d d!d"d#d$d%d&d'd(t          |          t          |          gdd)           |                    d*           |r5d+t9                      v r'ddl} |j        t          |          d,           dS dS dS )-u@  
        将帧序列合成为视频文件
        
        Args:
            fill_green_bg: 如果为 True，将 BGRA 帧的透明区域填充为纯绿色 (#00FF00)，
                          确保后续 FFmpeg colorkey 能正确抠图。
                          适用于绿幕训练模式的帧序列。
        r   Nc                 @    g | ]}                     d |          |S )zframe_\d+\.png)match)r  r   res     r)   r  z7DigitalHumanEngine._frames_to_video.<locals>.<listcomp>|  s-    QQQ1"((;La2P2PQQQQQr+   c                 p    t                              d|                               d                    S )Nz(\d+)r-   )r   searchgroup)r   r  s    r)   <lambda>z5DigitalHumanEngine._frames_to_video.<locals>.<lambda>}  s+    #bii!44::1==>> r+   )keyu   帧序列为空green_filled_)dirprefixu"   [帧合成] 填充绿色背景到 u    帧...Tr  r0   r1   r   r   r   r-   zconcat_list.txtr   rr  rs  rt  ru  rv  r6   rw  rx  ry  rz  r7   r{  r|  r}  r~  -presetfast-crf18z-r)r   checkr  green_filled_dir)ignore_errors)r  r  r?   listdirr   tempfiler   mkdtempr  r   r  r   imreadr  IMREAD_UNCHANGEDshaperJ   r   r%  rN   r&  r)  rD   r  r   r    rQ   rS   r  r   rmtree)r   r   r\  r   r  frame_filesr  r  ffsrcimgr8  r5  green_bgblendedconcat_listr   r   r  s                     @r)   r  z#DigitalHumanEngine._frames_to_videoq  s    				QQQQ
:..QQQ>>>>
 
 

  	/-... 	/OOO#H$4$4/$4$Z$Z[[Ps;7G7GPPPX\]]]]! A A:&&+jS3+?@@9Q<1$$aaaBQBh-C111ac	NU2E!}S11H(+HQQQ1W%"zz"*55=PRPZ@[@[_`ch_h@iiqqrtrz{{GK$4r$9 : :GDDDDK$4r$9 : :C@@@@-..J !22+s## 	3q! 3 3;j!1!1B!6;;;<<<1AcE111122223	3 	3 	3 	3 	3 	3 	3 	3 	3 	3 	3 	3 	3 	3 	3
 	$h#k""Iz9vvt#c((
 d	, 	, 	, 	, 	d+++ 	E/35588MMMFM#.//tDDDDDD	E 	E88s   AI))I-0I-c                    |                     dd          }|d         }|d         }	|d         }
|dk    rbd}|dk    rS|                    d          }| d	}t          d
d|dddd| d| d|	 d|
 d|ddddddddddddt          |          g}nS|rt          j                            |          s@d}| d	}t          d
d|dddd| d| d|	 d|
 d|ddddddddddddt          |          g}nt          d t          j                            |           z  }t          j
        t          d
d|d!d"| d#|	 d$| d#|	 d%	d&d't          |          g	d()           d*| d+}t          d
d|dt          |          d|ddddddddddddt          |          g}nL|dk    rM|                    d          }t          d
d|dddd| d| d|	 d|
 dd,ddddddddddddt          |          g}n|rt          j                            |          s:d}t          d
d|dddd| d| d|	 d|
 dd,ddddddddddddt          |          g}nt          d t          j                            |           z  }t          j
        t          d
d|d!d"| d#|	 d$| d#|	 d%	d&d't          |          g	d()           t          d
d|dt          |          dd-ddddddddddddt          |          g}t          j
        |d(d(.          }|j        d/k    rt          d0|j                   |d1k    rc|rct          j                            |          rFt          d t          j                            |           z  }|                    d(2           d3S d3S d3S d3S )4u  
        对 MuseTalk 输出视频应用背景处理
        
        绿幕模式策略（优化版）：
        1. colorkey 去除绿色背景 → 得到人物前景
        2. chromakey + despill 去除绿色溢出（消除鬼脸/绿边）
        3. 叠加目标背景（纯色/自定义图）
        
        Args:
            bg_mode: "color" 纯色 或 "custom" 自定义图片
            bg_color: 纯色值如 "#00FF00"
            bg_image_path: 自定义背景图路径（仅 custom 模式）
        r>  r  r   r   r   zC[0:v]colorkey=0x00FF00:0.4:0.02,despill=green:expand=1:brightness=0r  #z,[fg];[1:v][fg]overlay=format=auto:shortest=1r6   r7   rw  lavfiz
color=c=0xz:s=r   z:r=z-filter_complexr{  r|  r}  r~  r  r  r  r  r  slowerr  15FFFFFF
bg_scaled_r  zscale=:z*:force_original_aspect_ratio=decrease,pad=z:(ow-iw)/2:(oh-ih)/2z	-frames:vr;   Tr>   z[1:v]loop=-1:size=1[bg];z+[fg];[bg][fg]overlay=format=auto:shortest=1z([1:v][0:v]overlay=format=auto:shortest=1z?[1:v]loop=-1:size=1[bg];[bg][0:v]overlay=format=auto:shortest=1r   r   u   背景合成失败: r   r  N)r   lstriprQ   r  r?   r@   r|   r  basenamer   r    r!   r   r[  rS   )r   input_videor\  r  r>  r  r  r  r   r   r   colorkey_filter	hex_colorfilter_complexr&   	bg_scaledr'   s                    r)   r  z$DigitalHumanEngine._apply_background  se    N;;Wh5kN**6 
 '!!$OOC00	 ' ? ? ? 
 !$+'4)\i)\)\E)\)\F)\)\WZ)\)\%~Iz9E66x$$	 % &BGNN=,I,I & (I* C C C #
 %dkgt-`)-`-`-`-`PV-`-`[^-`-`)>	:yvv!8VTK((	CC !)+Y8H8H8W8W+Y+Y YIN$dD-   G   G   G   G   Gbg   G   Gjp   G   G   G#S#i..$ '+	, , , ,B*B B B # %dkc)nn)>	:yvv!8VTK((	CC '!!$OOC00	 $+'4)\i)\)\E)\)\F)\)\WZ)\)\%'QIz9E66x$$	 % BGNN=,I,I  (I$dkgt-`)-`-`-`-`PV-`-`[^-`-`)+U	:yvv!8VTK((	CC !)+Y8H8H8W8W+Y+Y YIN$dD-   G   G   G   G   Gbg   G   Gjp   G   G   G#S#i..$ '+	, , , , %dkc)nn)Z	:yvv!8VTK((
C DtDDD!!B6=BBCCC h=RW^^M5R5R #Q0@0@0O0O#Q#QQI----- r+   c                    d}t          t                    j        dz  }t          j                            |          st          d|           t          j                            |          st          d|           t          j                            |          dz  }t          j                            |          dz  }t          d| d|dd	d
           t          d| d|dd	d
           t          j
                                        rrt          j
                                         t          j
                                         t          dt          j
                            d          dz  ddd
           |t          |          d|d|d|dddddddg}	t          dd
           t          dd                    |	           d
           t"          dz  }
|
                    d
d
           |
|pd  d!z  }t'          |d"d#$          5 }t)          j        |	|t(          j        d
i t          j        d%d&i'          }d(d(d(           n# 1 swxY w Y   t1          j                    }d}t1          j                    }d)}d*}|                                t1          j        d+           |                                rx|                                j        }||k    rX|}t1          j                    }	 t'          |d,d#$          5 }|                                }|r|d-                                         }|r|rd.|v r	 |                    d.          d                                                                         d-         }tA          |          }d/tA          |d0z            z   }d1|v r-|                    d1          d-                                         nd2}| !                    |d3|d4| d| d5           n#  Y nxY wt          d6| d
           d(d(d(           n# 1 swxY w Y   n#  Y nxY wt1          j                    |z
  }t1          j                    |z
  |k    rK|"                                 |#                                 t          d7tA          |d8z             d9          ||k    rp|"                                 |#                                 t          j                            |          rt          d:d
           |S t          d;|d8z   d<          |                                |j$        }|                                r`t'          |d,d#$          5 }|%                                }d(d(d(           n# 1 swxY w Y   t          d=tM          |           d>d
           |dk    r\t          j                            |          r=t          j                            |          dz  }t          d?| d|dd	d
           |S d@| }|                                rit'          |d,d#$          5 }|                                dAd(         }|dBdC                    |          d(dD         z   z  }d(d(d(           n# 1 swxY w Y   t          dE| d
           t          dF|d(dD                    )Gui  
        调用 MuseTalk 推理（独立 Python 3.10 进程）- 非阻塞版本
        
        关键改进：
        1. 使用 Popen + 文件重定向（避免管道缓冲区阻塞）
        2. 实时读取日志输出到服务端日志文件
        3. 非阻塞轮询，支持进度更新
        4. 心跳检测：超时无输出则判定卡死
        z.D:\AI-Ad-Agent\musetalk_env\Scripts\python.exezmusetalk_inference.pyu   输入视频不存在: u   音频文件不存在: i   u   [MuseTalk] 视频: r   r   zMB)Tr  u   [MuseTalk] 音频: u.   [MuseTalk] GPU 缓存已清理, 可用显存: r   r
   r  z--videoz--audioz--outputz--bbox_shift5z--extra_margin10z--parsing_modejawz--use_float16u    [MuseTalk] 启动推理进程...u   [MuseTalk] 命令:  musetalk_logsre   musetalkz.logr   rx   ry   PYTHONUNBUFFEREDr;   )r#   r[  r   envNx   i  r0   rw   r4   %rO  r   r-  u   MuseTalk推理中r  z
MuseTalk: r   z[MuseTalk] u   MuseTalk 推理卡死：rL  uB   分钟无新输出。请检查GPU状态或尝试更短的文案。u2   [MuseTalk] 总超时但有部分输出，使用它u   MuseTalk 推理超时（超过u	   分钟）u   [MuseTalk] 完整日志 (u    字符)u   [MuseTalk] 推理成功: u
   返回码=iu   ; 最后输出: r     u   [MuseTalk] 推理失败: u   MuseTalk 推理失败: )'r   __file__parentr?   r@   r|   r   getsizer   r   r	   r  r  r  r  r  joinr  r   rD   r   PopenSTDOUTenvirontimepollsleepr  r  	readlinesstripsplitr   r   killwaitr!   r   r  ) r   r  rc  r\  r   MUSETALK_PYTHONMUSETALK_SCRIPTvideo_size_mbaudio_size_mbr&   log_dirlog_filelfproc
start_timelast_output_sizelast_heartbeatHEARTBEAT_TIMEOUTTOTAL_TIMEOUTcurrent_sizelines	last_linepct_strr  
mapped_pct	step_descelapsedr!   	final_logoutput_size_mberror_detailtails                                    r)   r  z DigitalHumanEngine._run_musetalk@  sc    Lx../2II w~~j)) 	DBjBBCCCw~~j)) 	DBjBBCCC
33{C
33{CHJHH-HHHHPTUUUUHJHH-HHHHPTUUUU :""$$ 	~J""$$$J""$$$p5:C]C]^_C`C`ahChppppx|}}}}   zzCde

 	1>>>>3CHHSMM334@@@@ _,dT222 5:;;;;(C'222 	b#!(;rz;#5s;;  D	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 Y[[
iikk!JqMMM    '}}6"222'3$%)Y[[N!(C'BBB Mb$&LLNNE$ M,1"IOO,=,=	#, !1 !1'*i'7'7)16?ooc6J6J16M6S6S6U6U6[6[6]6]^`6aG25g,,C9;c#)nn9LJ\_cl\l\l	8L8LR8P8V8V8X8X8X  sFI,0,<,<WlT^  aBmv  aB  aBz}  aB  aB  aB  -C  -C  -C  -C)1,0D %&?I&?&?t L L L L#M M M M M M M M M M M M M M M$ikkJ.Gy{{^+.???				  !Y3?PQS?S;T;T  !Y  !Y  !Y  Z  Z  Z &&				7>>+.. 'OW[\\\\&& ]PRAR ] ] ]^^^] iikk!b _
 ?? 	Thg666 &"GGII	& & & & & & & & & & & & & & &Fc)nnFFFdSSSS??rw~~k::?W__[99[INTkTT^TTTT\`aaaa4
44L   M(C'::: Mb<<>>#$$/D $6tt9L$LLLM M M M M M M M M M M M M M M <l<<DIIIIJl4C46HJJKKKs   4II!IQ  9P4B;PP4PP4(Q  4P88Q  ;P8<Q   Q:VV"VA Z!!Z%(Z%)r   r   N)r   r-   )rh   rj   )rp  )r  rp  )rh   r  rp  Nrj   )FN)__name__
__module____qualname____doc__r   tensorr   rN   GREEN_LOWERGREEN_UPPER_rgb_to_hsv_kernel_loadedr   r   r   r   r   staticmethodr   r   r  r  r@  r_  ro  r  r  r  r  r  r  r  r  r+   r)   r   r      s       )) %,|||F%-PPPK%,~~~fEMRRRK !&Y Y Y
	 	 	  C C C    . . \.B * * * \*,E E EN.- .- .-`7 7 7r$ $ $ $L% % %N   >F F F FPw w wr 9OPUl l l l\=E =E =E =E~N. N. N. N.`FL FL FL FL FL FLr+   r   c                        e Zd Z fdZ f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 xZS )DigitalHumanHandlerc           	           t                      j        |dt          t          t                    j                  i| d S )N	directory)superr   r  r   rA  rB  )r   argskwargs	__class__s      r)   r   zDigitalHumanHandler.__init__  s;    $O#d8nn.C*D*DOOOOOOr+   c                    t          | j                  }|j        }|dk    r|                                  d S |dk    r|                                  d S |dk    r|                                  d S |dk    r|                                  d S |dk    rc|                     dt          t          t          d          t          t                    t          j                                        d           d S |                    d	          r2|                    d
          d         }|                     |           d S |                    d          r|                     |           d S |                    d          r|                     |           d S |                    d          r|                     |           d S t+                                                       d S )Nz/api/digital-human/listz/api/digital-human/videosz/api/digital-human/voicesz/api/digital-human/tasksz/api/digital-human/statusrunningr-   )r   r  vram_gbr   cuda_availablez/api/digital-human/task/r   r4   r  r  r  )r   r@   _list_digitals_list_videos_list_voices_list_tasks_json_responser  r  r   r  r   r   r	   r  
startswithrM  	_get_task_serve_preview_serve_video_serve_voice_audiorv  do_GET)r   parsedr@   r   ry  s       r)   r  zDigitalHumanHandler.do_GET  s   $)$${,,,!!!!!000000///000# 1--f++"'*"9"9";";! !      __788 
	jjoob)GNN7#####__:;; 	%%%%%__899 	d#####__>?? 	##D)))))GGNNr+   c                 ~   t          | j                  }|j        }|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	          r|                     |           d S |                     d
           d S )Nz/api/digital-human/uploadz/api/digital-human/trainz/api/digital-human/generatez/api/digital-human/upload-bgz/api/digital-human/deletez/api/digital-human/voice/createz /api/digital-human/voice/previewz/api/digital-human/voice/delete /api/digital-human/video/delete/  )r   r@   _handle_upload_handle_train_handle_generate_handle_upload_bg_handle_delete_digital_handle_create_voice_handle_preview_voice_handle_delete_voicer  _handle_delete_video
send_error)r   r  r@   s      r)   do_POSTzDigitalHumanHandler.do_POST  s   $)$${...!!!!!///     222!!#####333""$$$$$000'')))))666%%'''''777&&(((((666%%'''''__?@@ 	!%%d+++++OOC     r+   c                     |                      d           |                                  |                     dd           |                                  d S )N   Access-Control-Allow-MethodsGET, POST, DELETE, OPTIONS)send_response_cors_headerssend_headerend_headersr   s    r)   
do_OPTIONSzDigitalHumanHandler.do_OPTIONS  sX    379UVVVr+   c                     |                      dd           |                      dd           |                      dd           d S )NzAccess-Control-Allow-Origin*r  r  zAccess-Control-Allow-HeadersContent-Type)r  r   s    r)   r  z!DigitalHumanHandler._cors_headers  sN    6<<<79UVVV7HHHHHr+   r  c                 .   |                      |           |                                  |                     dd           |                                  | j                            t          j        |d                              d                     d S )Nr  zapplication/json; charset=utf-8F)r   rx   )	r  r  r  r  wfiler  r   dumpsencode)r   datar   s      r)   r  z"DigitalHumanHandler._json_response  s    6""")JKKK
Du===DDWMMNNNNNr+   c                 0   g }t                               d          D ]S}t          |dd          5 }|                    t	          j        |                     d d d            n# 1 swxY w Y   T|                     |t          |          d           d S )Nz*_info.jsonrw   rx   ry   )digitalscount)r  r  rD   r   r   r}   r  r  )r   r  r   fhs       r)   r~  z"DigitalHumanHandler._list_digitals  s    .. 	/ 	/Aaw/// /2	".../ / / / / / / / / / / / / / /CMMJJKKKKKs   (A%%A)	,A)	c                 H    |                      dt          j        i           d S )Nr   )r  r  r   r   s    r)   r  zDigitalHumanHandler._list_tasks$  s#    Wfl344444r+   c                     t           j                            |          }|r|                     |           d S |                     ddid           d S )Nerroru   任务不存在r  )r  r   r   r  )r   r   tasks      r)   r  zDigitalHumanHandler._get_task'  s\    |(( 	C%%%%%*; <cBBBBBr+   c                    |                     dd          }t          | dz  }|                                r|                     d           |                                  |                     dd           |                                  t          |d          5 }| j        	                    |
                                           d d d            d S # 1 swxY w Y   d S |                     d           d S )	Nr  r   r  r  r  z	image/pngr/   r  )rR  r  r|   r  r  r  r  rD   r  r  r   r  )r   r@   r  preview_pathr   s        r)   r  z"DigitalHumanHandler._serve_preview.  s4   \\"?DD
 j#>#>#>>   	!s###   ^[999lD)) +Q
  ***+ + + + + + + + + + + + + + + + + + OOC     s   -CCCc                 F   |                     dd          }t          |z  }|                                r|                     d           |                                  |                     dd           |                     d|                                j                   |                                  t          |d          5 }| j
                            |                                           d d d            d S # 1 swxY w Y   d S |                     d           d S )	Nr  r   r  r  z	video/mp4Content-Lengthr/   r  )rR  r  r|   r  r  r  r  r  r  rD   r  r  r   r  )r   r@   filenamer  r   s        r)   r  z DigitalHumanHandler._serve_video;  sO   << ;R@@(*
 		!s###   ^[999-z/@/@/HIIIj$'' +1
  ***+ + + + + + + + + + + + + + + + + + OOC     s   -C??DDc                    g }t          t                              d          d d          D ]}|j        }|                    dd          d                             dd          }t          |          dk    r|d         nd	}|                                }|                    |d
| ||j	        t          |j	        dz  dz  d          t          j        |j                                                  t          t          t!          |                    d          d           |                     |t          |          d           dS )u   列出所有已生成的视频z*.mp4c                 4    |                                  j        S rh  )r  st_mtime)r   s    r)   r  z2DigitalHumanHandler._list_videos.<locals>.<lambda>L  s    @Q r+   T)r  reverserC  r-   r   r   unknownr  i   r0   )r  urlr  sizesize_mbr  r   )videosr  N)r  r  r  rl   rsplitrM  r  r  r   r  r  r   fromtimestampr  r   r*   r  r  )r   r  r   fnamepartsr  sts          r)   r  z DigitalHumanHandler._list_videosI  sC   
006Q6Q[_``` 	 	AFELLa((+11#q99E%(ZZ!^^qJBMM!:5::(
 d!2T!91==&4R[AAKKMM!"4SVV"<"<a@@      	vFDDEEEEEr+   c                    t          | j                            dd                    }t          j        | j                            |                    }|                    dd          }|s|                     ddid           dS g }g }| d	| d
| dg}|D ]}t          |z  }|	                                rf	 |
                                 |                    |j                   P# t          $ r)}	|                    |j         d|	            Y d}	~	~d}	~	ww xY wt          | dz  }
|
	                                rz|
                                rf	 t          j        |
           |                    |
j                   n6# t          $ r)}	|                    |
j         d|	            Y d}	~	nd}	~	ww xY wt"          | dz  }|	                                rf	 |
                                 |                    |j                   n6# t          $ r)}	|                    |j         d|	            Y d}	~	nd}	~	ww xY wd}t$                              d| d          D ]R}	 |
                                 |dz  }# t          $ r)}	|                    |j         d|	            Y d}	~	Kd}	~	ww xY w|                     t)          |          dk    |||d           dS )u   删除数字人及关联文件r  r   r  r   r  u   缺少 digital_idr  Nr  r   r  z: r   r  z*_r-   )successdeletedvideo_deletederrors)r   headersr   r   r"   rfiler   r  r  r|   rS   r   rl   r   is_dirr   r  r  r  r  r  )r   content_lengthbodyr  r  r  patternspatfpr^  r   upload_filer  vfs                 r)   r  z*DigitalHumanHandler._handle_delete_digital]  s   T\--.>BBCCz$*//.99::XXlB//
 	*= >DDDF %%%%%%'''

  	5 	5CSByy{{ 55IIKKKNN27++++  5 5 5MMRW"3"3"3"3444444445	5 J!7!7!77
 	9:#4#4#6#6 	99j)))z//// 9 9 977A77888888889 !j#6#6#66 	::""$$${/0000 : : :!188Q8899999999: //"7z"7"7"788 	1 	1B1		" 1 1 1//A//000000001 	6{{a'*	
 
 	 	 	 	 	s`   <.C++
D5DD.F 
F:F55F:.H 
IH<<I'J
J4J//J4c                    |                     dd          }t          |z  }|                    d          rd|v sd|v r|                     ddid           d	S |                                rl	 |                                 |                     d
|d           d	S # t          $ r0}|                     dt          |          id           Y d	}~d	S d	}~ww xY w|                     ddid           d	S )u   删除指定视频文件r  r   r  ..r   r  u   无效的文件名r  NT)r  r  r@  u   文件不存在r  )rR  r  endswithr  r|   rS   r   r  )r   r@   r  r  r^  s        r)   r  z(DigitalHumanHandler._handle_delete_video  s/   << BBGG(*
   (( 	DH,<,<x*> ?EEEF 	C<!!#####($K$KLLLLL < < <##Wc!ff$5s;;;;;;;;;< *; <cBBBBBs   -,B 
C%%CCc           	      N   | j                             dd          }d|v r|                    d          d                                         }t	          | j                             dd                    }| j                            |          }|                    d|z             }|D ]G}d	|v r?|                    d
          }|d |                             dd          }||dz   d          }	|		                    d          r
|	d d         }	dd l
}
|
                    d|          }|r|                    d          nd}t          t          j                              d d         }t           d| d| z  }t#          |d          5 }|                    |	           d d d            n# 1 swxY w Y   |                     ||t          |          t)          |	          d            d S I|                     ddid           d S |                     ddid           d S )Nr  r   multipart/form-data	boundary=r-   r  r      --	   filename=   

rx   ignorer  r1      
filename="(.+?)"z	video.mp4   upload_r   wb)r   r  r@   r  r     未找到文件r     需要 multipart/form-data)r  r   rM  r  r   r  r   finddecoder  r  r
  r  r  uuiduuid4r  rD   r  r  r  )r   content_typeboundaryr  r  r  part
header_endr  	file_datar  filename_matchr  r   	save_pathr   s                   r)   r  z"DigitalHumanHandler._handle_upload  s   |'';; L00#))+66q9@@BBH !1!12BA!F!FGGN:??>22DJJux/00E  4''!%;!7!7J";J;/66wx6PPG $Z\]] 3I ))'22 3$-crcN	III%'YY/BG%L%LN:HY~33A666kH!$*,,//3G *-Kw-K-K-K-K KIi.. +!	***+ + + + + + + + + + + + + + + ''#*$, #I #I	) )    FF- (0 *; <cBBBBB*F GMMMMMs   F//F3	6F3	c           	         t          | j                            dd                    }t          j        | j                            |                    }|                    dt          t          j	                              d d                   }|                    d          }|                    dd          }|                    dd	          }|                    d
d          }|s| 
                    ddid           d S dt          t          j                               }| 
                    ||dd           t          j        t          j        ||||||fd                                           d S )Nr  r   r   r  r  rl   u   未命名数字人r>  r  r  rp  r  u   缺少 video_pathr  dh_started)r   r  r   Ttargetrw  daemon)r   r  r   r   r"   r  r   r  r  r  r  rH  	threadingThreadr  r  start)	r   r  r  r   r  rl   r>  r  r  s	            r)   r  z!DigitalHumanHandler._handle_train  si   T\--.>BBCCz$*//.99::((9c$*,,&7&7&;<<XXl++
xx 455((9n5588J	22 	*= >DDDF-3ty{{++--
zU^__```GZUY[bdl3mvz{{{  	B  	B  	D  	D  	D  	D  	Dr+   c                    t          | j                            dd                    }t          j        | j                            |                    }t          t          j	                              d d         }|                    d          }|                    d          }|                    dd          }|                    dd	          }|                    d
d          }|                    dd           }	|                    dd          }
|r|s| 
                    ddid           d S | 
                    |dd           t          j        t          j        |||||||	|
fd                                           d S )Nr  r   r  r  r   rp   rh   r>  r  r  rp  r  rq   rj   r  u   缺少 digital_id 或 textr  r  )r   r   Tr  )r   r  r   r   r"   r  r   r  r  r  r  r  r  r  r  r  )r   r  r  r   r  r   rp   r>  r  r  rq   s              r)   r  z$DigitalHumanHandler._handle_generate  s   T\--.>BBCCz$*//.99::djll##BQB'XXl++
xx"899((9g..88J	22$77%(( 	 	*F GMMMF9EEFFFw
DRWY`bjly  |A  7B  KO  	P  	P  	P  	V  	V  	X  	X  	X  	X  	Xr+   c           
         | j                             dd          }d|v r%|                    d          d                                         }t	          | j                             dd                    }| j                            |          }|                    d|z             }|D ]}d	|v rx|                    d
          }|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                                         }|dvrd}| | }t$          |z  }t'          |d          5 }|                    |	           ddd           n# 1 swxY w Y   |                     d|t-          |          |t/          |	          d            dS |                     ddid           dS |                     ddid           dS )u   上传自定义背景图片r  r   r  r  r-   r  r   r  r  r  Nrx   r  r  r1   r  r  r  zbg.pngbg_)r  z.jpgz.jpegz.webpz.bmpr  r  T)r  bg_idr@   r  r  r  r  r  r  )r  r   rM  r  r   r  r   r  r  r  r  r
  r  rH  r?   r@   rA   rB   r  rD   r  r  r  r  )r   r  r  r  r  r  r  r  r  r  r  r  r  r  rT   	save_namer  r   s                     r)   r  z%DigitalHumanHandler._handle_upload_bg  s   |'';; L00#))+66q9@@BBH !1!12BA!F!FGGN:??>22DJJux/00E  4''!%;!7!7J";J;/66wx6PPG $Z\]] 3I ))'22 3$-crcN	III%'YY/BG%L%LN:HV~33A666hH4#dikk"2"244E'**844Q7==??C"LLL$#(#I (9 4Ii.. +!	***+ + + + + + + + + + + + + + + ''#'!& #I$, #I) )    FF7 (: *; <cBBBBB*F GMMMMMs   G''G+	.G+	c                 l    t                      }|                     |t          |          d           dS )u   列出所有语音风格)rd   r  N)r   r  r  )r   rd   s     r)   r  z DigitalHumanHandler._list_voices+  s3    vFDDEEEEEr+   c                    |                     dd                              d          d         }d|v sd|v r|                     d           dS t          | d	z  }|                                r|                     d
           |                                  |                     dd           |                     d|                                j	                   | 
                                 t          |d          5 }| j                            |                                           ddd           dS # 1 swxY w Y   dS |                     d           dS )u   提供语音试听音频文件r  r   ?r   r  r   r  Nr.   r  r  z	audio/wavr  r/   r  )rR  rM  r  r  r|   r  r  r  r  r  r  rD   r  r  r   )r   r@   r  rc  r   s        r)   r  z&DigitalHumanHandler._serve_voice_audio0  s   << A2FFLLSQQRST8shOOC   FX"3"3"33
 		!s###   ^[999-z/@/@/HIIIj$'' +1
  ***+ + + + + + + + + + + + + + + + + + OOC     s    -D::D>D>c                 n   | j                             dd          }d|v r|                    d          d                                         }t	          | j                             dd                    }| j                            |          }|                    d|z             }i }d	}d
}|D ]}	d|	vr|	                    d          }
|
dk     r$|	d	|
                             dd          }|	|
dz   d	         }|	                    d          r
|d	d         }|	                    d          r
|d	d         }dd	l
}|                    d|          }|                    d|          }|r|}|                    d          }|r-|                    dd          ||                    d          <   	|                    dd          }|                    dd          }|                    dd          }dt	          t          j                               }t          j                            |          d                                         }|dvrd}t$          | | z  }|rt'          |d          5 }|                    |           d	d	d	           n# 1 swxY w Y   |dk    rct$          | dz  }t+          j        t.          dd t1          |          d!d"d#d$d%d&t1          |          gd'(           |                    d')           |                    d*d+| d,          }t$          | d-z  }	 t4                              |t1          |          ||           n)# t8          $ r}t;          d.|            Y d	}~nd	}~ww xY w||d/d0| d1||||d	ud2| d3t=          j                                                     d4}d5 tC                      D             }|"                    |           tG          |           | $                    d'|d6           d	S | $                    d7d8id9           d	S ):u6   创建自定义语音风格：上传录音 + 元信息r  r   r  r  r-   r  r   r  Nzrecording.wavs   Content-Dispositionr  rx   r  r  r1   r  r  zname="(.+?)"r  rl   u   未命名风格rp   rh   rq   rj   custom_)r.   rB  .m4a.oggr.   r  r6   r7   r8   r9   r:   r;   r<   r=   Tr>   r  rr   r  r  _preview.wavu   [Voice] 试听生成失败: u   🎙️u   自定义 - r   r  _preview)rk   rl   rm   rn   ro   rp   rq   rr   r  r  r  c                 D    g | ]}|                     d           dk    |S r  r  r  s     r)   r  z<DigitalHumanHandler._handle_create_voice.<locals>.<listcomp>  r  r+   )r  rp   r  r  r  )%r  r   rM  r  r   r  r   r  r  r  r  r
  r  rH  r?   r@   rA   rB   r  rD   r  r   r    rQ   r  rS   r  r_  r   r   r   r   r   r   r   r   r  )r   r  r  r  r  r  fields
audio_dataaudio_filenamer  r  r  r  r  
name_matchr  rl   rp   rq   r  rT   rc  r   r]   rr   r  r^  r  r   s                                r)   r  z(DigitalHumanHandler._handle_create_voiceC  s   |'';; L00#))+66q9@@BBH !1!12BA!F!FGGN:??>22DJJux/00EFJ,N X X)55!YY{33
>>{
{+22782LLJNOO,==)) %9D=='' %9D			YY@@
!#+>!H!H! X!%J%3%9%9!%<%<NN X26++gh+2W2WF:++A../::f&788DJJw(>??EJJw..E3TY[[!1!133H '"">2215;;==C:::#&83&8&88J 7*d++ (qGGJ'''( ( ( ( ( ( ( ( ( ( ( ( ( ( ( &==)x,=,=,==HN$dD#j//!;sE7H$ '+	, , , ,
 %%%666 !**]4jd4j4j4jkkK%8(A(A(AAL:&&{C4E4EueTTTT : : :8Q8899999999: !.u.. *'t3SSSS&lnn6688 L NMMMMFMM,''''''D< H HIIIII*F GMMMMMs*   ;JJ!$J!9*M$ $
N
.NN
c                 ~  
 t          | j                            dd                    }t          j        | j                            |                    }|                    dd          
|                    dd          }
s|                     ddid           d	S t                      }t          
fd
|D             d	          }|s|                     ddid           d	S |                    dd          }|                    dd          }|s|                    dd          }t          
 dz  }	 t                              |t          |          ||           |                     dd
 d|d           d	S # t          $ r3}	|                     ddt          |	           id           Y d	}	~	d	S d	}	~	ww xY w)u   生成语音试听r  r   r  r   r   r     缺少 voice_idr  Nc              3   4   K   | ]}|d          k    |V  dS r  r  r  s     r)   r  z<DigitalHumanHandler._handle_preview_voice.<locals>.<genexpr>  s1      FF1!D'X2E2EQ2E2E2E2EFFr+   u   语音风格不存在r  rp   rh   rq   rj   rr   u   你好，这是语音试听。r  Tr  r  )r  r  r   rN  r@  )r   r  r   r   r"   r  r   r  r   r  r  r  r_  r  r   )r   r  r  r   rd   voice_configr  r  r  r^  r  s             @r)   r  z)DigitalHumanHandler._handle_preview_voice  s   T\--.>BBCCz$*//.99::88J++xx## 	*; <cBBBF FFFFFFFMM 	*A BCHHHF $$W.DEE	 $$We44	 	U##M3STTD!x$=$=$==	Q""4\):):IyQQQSSSS! !     
  	Q 	Q 	Q*IQ*I*I JCPPPPPPPPP	Qs   6AE? ?
F<	(F77F<c                    t          | j                            dd                    }t          j        | j                            |                    }|                    dd          s|                     ddid           dS d	 t          D             v r|                     dd
id           dS d t                      D             }fd|D             }t          |            d d d d dfD ]4}t          |z  }|                                r|                                 5|                     dd           dS )u   删除自定义语音风格r  r   r  r   r  r  r  Nc                     g | ]
}|d          S r  r  r  s     r)   r  z<DigitalHumanHandler._handle_delete_voice.<locals>.<listcomp>  s    888A$888r+   u   系统默认语音不可删除i  c                 D    g | ]}|                     d           dk    |S r  r  r  s     r)   r  z<DigitalHumanHandler._handle_delete_voice.<locals>.<listcomp>  s,    IIIquuV}}/H/H!/H/H/Hr+   c                 ,    g | ]}|d          k    |S r  r  r  s     r)   r  z<DigitalHumanHandler._handle_delete_voice.<locals>.<listcomp>  s'    ;;;qw(':':!':':':r+   r.   rB  r  r  r  T)r  r  )r   r  r   r   r"   r  r   r  r~   r   r   r  r|   rS   )r   r  r  r   patternr  r  s         @r)   r  z(DigitalHumanHandler._handle_delete_voice  s   T\--.>BBCCz$*//.99::88J++ 	*; <cBBBF 8888888*J KSQQQF JI\^^III;;;;V;;;F### $)))h+<+<+<>O>O>O#)))h+D+D+DF 	 	Gg%Byy{{ 		(CCDDDDDr+   c                 :    t          d|d          d           d S )Nz[DH-Server] r   Tr  )r   )r   r   rw  s      r)   log_messagezDigitalHumanHandler.log_message  s(    &T!W&&d333333r+   )r  )ri  rj  rk  r   r  r  r  r  r  r~  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  __classcell__)ry  s   @r)   rs  rs    s       P P P P P    @! ! !2  I I I
O O O OL L L5 5 5C C C! ! !! ! !F F F(< < <|C C C&$N $N $NLD D D(X X X**N *N *N\F F F
! ! !&]N ]N ]N~"Q "Q "QHE E E:4 4 4 4 4 4 4r+   rs  c                  x   t          ddz             t          d           t          dt           dt          dd           t          dt          j                                                    t          d	t                      t          d
t                      t          ddz             t          d           t          d           t          d           t          d           t          d           t          d           t          d            G d dt          t                    }  | dt          ft                    }t          dt                      t          d           	 |                                 d S # t          $ r' t          d           |                                 Y d S w xY w)N=7   u'     数字人口播服务 - GPU 加速版u
     设备: r   r   r   z  CUDA: u
     端口: u     工作目录: zAPI:u4     GET  /api/digital-human/list     - 列出数字人u/     GET  /api/digital-human/status   - GPU 状态u7     POST /api/digital-human/upload   - 上传绿幕视频u4     POST /api/digital-human/train    - 训练数字人u7     POST /api/digital-human/generate - 生成口播视频u7     GET  /api/digital-human/task/:id - 查询任务状态c                       e Zd ZdZdZdS )!main.<locals>.ThreadingHTTPServeru3   多线程 HTTP 服务器，支持并发请求处理TN)ri  rj  rk  rl  daemon_threadsr  r+   r)   ThreadingHTTPServerr    s        AAr+   r  z0.0.0.0u    
服务运行在 http://0.0.0.0:u"   模式: 多线程 (ThreadingMixIn)u   
数字人服务已停止)r   r  r   r   r	   r  PORTWORK_DIRr   r   rs  serve_foreverKeyboardInterruptshutdown)r  servers     r)   mainr&    s   	$)	
4555	
:x
:
:8
:
:
:
:;;;	
0UZ,,..
0
0111	
t

	
'X
'
'(((	$)	'NNN	
ABBB	
<===	
DEEE	
ABBB	
DEEE	
DEEE    nj    ! )T!24GHHF	
4d
4
4555	
/000   *+++s   2F -F98F9__main__)Irl  r?   sysr   r  rH  r   r   r  pathlibr   r   http.serverr   r   socketserverr   urllib.parser   r   r$  rJ   r   torch.nn.functionalnn
functionalr   r	   r  r   r   get_device_namer  r  r  r   r   Streamr  rC   rL   rQ   rR  r   r@   r|   rT  pathseprG  r   r*   rR   rA  rB  r!  r  r  r  r  r  r{   r   dr   r~   r   r   r   r   r  rs  r&  ri  r  r+   r)   <module>r4     s    
			 



                         < < < < < < < < ' ' ' ' ' ' ! ! ! ! ! ! 



               	: 9U\&!!Fz))!,,Hz//22?'IH	E
68
6
6x
6
6
6
6777*##%%KKU\%  FHHK	E
7888  6$$\=AA7>>, a66CbjnnU[]_F`F``BJv       F 4>> '/9	!
y 		!
f 
&$

iXz	B ) )AGGD4G((((
 %4'i	 	 "4$i	 	 #4%i	 	 $4&i	 	 %4'i	 	S3j	# 	# 	#; ; ;
 JL JL JL JL JL JL JL JL^  
			W4 W4 W4 W4 W42 W4 W4 W4t  @ zDFFFFF r+   