util.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. from autosub import DEFAULT_CONCURRENCY
  2. from autosub import DEFAULT_SUBTITLE_FORMAT
  3. from pytranscriber.control.ctr_main import Ctr_Main
  4. from pytranscriber.control.ctr_autosub import Ctr_Autosub
  5. import re,random, time
  6. from itertools import groupby
  7. from operator import itemgetter
  8. from rakeUtil.Rake import Rake
  9. import requests,rpyc
  10. from difflib import SequenceMatcher
  11. from PIL import Image,ImageDraw,ImageFont
  12. import openshot
  13. obj = Rake()
  14. stop_path = "rakedata/stoplist/中文停用词表(1208个).txt"
  15. conj_path = "rakedata/stoplist/中文分隔词词库.txt"
  16. obj.initializeFromPath(stop_path, conj_path)
  17. def trim_punctuation(s):
  18. pat_block = u'[^\u4e00-\u9fff0-9a-zA-Z]+';
  19. pattern = u'([0-9]+{0}[0-9]+)|{0}'.format(pat_block)
  20. res = re.sub(pattern, lambda x: x.group(1) if x.group(1) else u" " ,s)
  21. return res
  22. def txt2image(content, save_target,lang='zh'):
  23. unicode_text = trim_punctuation(content)
  24. content = content.replace(' ','')
  25. font = ''
  26. if lang=='zh':
  27. font = ImageFont.truetype(font="font/DFT_B7.ttc", size=38)
  28. else :
  29. font = ImageFont.truetype(font="font/arial.ttf", size=38)
  30. text_width, text_height = font.getsize(unicode_text)
  31. canvas = Image.new('RGBA', (700, 500), (255, 0, 0, 0) )
  32. draw = ImageDraw.Draw(canvas)
  33. text= unicode_text
  34. draw.text((5,5), text, (255, 255, 0), font)
  35. canvas.save(save_target, "PNG")
  36. def generate_subtitle_image_from_dict(cpath, sub_dict):
  37. for script in sub_dict:
  38. sv_path = cpath + '/' + str(script['index'])+'.png'
  39. sub = script['content']
  40. txt2image(sub,sv_path)
  41. def listener_progress(string, percent):
  42. True
  43. def transScript(cpath):
  44. Ctr_Autosub.init()
  45. Ctr_Autosub.generate_subtitles(cpath+"speech.mp3",'zh'
  46. ,listener_progress
  47. ,output=cpath+"script.txt"
  48. ,concurrency=DEFAULT_CONCURRENCY,subtitle_file_format=DEFAULT_SUBTITLE_FORMAT)
  49. def syllable_count(word):
  50. word = word.lower()
  51. count = 0
  52. vowels = "aeiouy"
  53. if word[0] in vowels:
  54. count += 1
  55. for index in range(1, len(word)):
  56. if word[index] in vowels and word[index - 1] not in vowels:
  57. count += 1
  58. if word.endswith("e"):
  59. count -= 1
  60. if count == 0:
  61. count += 1
  62. return count
  63. def getKeyword(inStr):
  64. re.findall(r'[\u4e00-\u9fff]+', inStr)
  65. zh_idx = []
  66. eng_idx= []
  67. for i in range(len(inStr)):
  68. if inStr[i] > u'\u4e00' and inStr[i] < u'\u9fff':
  69. zh_idx.append(i)
  70. else:
  71. eng_idx.append(i)
  72. kws = obj.extractKeywordFromString(inStr)
  73. engStr =''
  74. for idx in range(len(eng_idx)):
  75. if idx != len(eng_idx)-1:
  76. if eng_idx[idx]+1 == eng_idx[idx+1]:
  77. engStr+=inStr[eng_idx[idx]]
  78. else:
  79. engStr+=inStr[eng_idx[idx]]
  80. if len(engStr)>2:
  81. kws.append((engStr,10))
  82. engStr=''
  83. else:
  84. engStr+=inStr[eng_idx[idx]]
  85. if len(engStr)>2:
  86. kws.append((engStr,10))
  87. engStr=''
  88. return kws
  89. def getImgDict():
  90. return [{'kw':'podcast','id':'17j41rqsoWVzc-HD8jvdxb651pbHJhvH8'}
  91. ,{'kw':'podcast','id':'1wT3uIaoe3xD-wrAo-J9eZweHEuEfI22_'}
  92. ,{'kw':'podcast','id':'1uaP8_xtqMn_Zbx3DX78ALdCtFjUPYgKQ'}
  93. ,{'kw':'podcast','id':'1L1NMByTorcDBN8EpbwwUakTexdRAiF4w'}
  94. ,{'kw':'youtuber','id':'17vUM8xrMgI9y1aEbAoprOxKiK9OOkipE'}
  95. ,{'kw':'支持者','id':'1sb-DmU5X9YE7HZLva_UueEvzcXqrKoGk'}
  96. ,{'kw':'app','id':'1jxoZuFlUHyl1L7-WB2ejPKBEW38bsbR6'}]
  97. def savekeywordImage(kw,imgDict):
  98. highest_val = 0
  99. highest_d = None
  100. for d in imgDict:
  101. sim = SequenceMatcher(None, d['kw'], kw).ratio()
  102. #print(sim,d['kw'],kw)
  103. if sim>highest_val :
  104. highest_val = sim
  105. highest_d = d
  106. return highest_d
  107. def get_script(cPath):
  108. fpath = cPath+'script.txt'
  109. with open(fpath, 'r',encoding="utf-8") as f:
  110. raw_lines = [line.strip() for line in f]
  111. lines =[]
  112. for idx in range(int(len(raw_lines)/4+1)):
  113. line_content = raw_lines[idx*4+2]
  114. lines.append(line_content)
  115. return lines
  116. def rewriteScript(cPath,newlines):
  117. fpath = cPath+'script.txt'
  118. with open(fpath, 'r',encoding="utf-8") as f:
  119. raw_lines = [line.strip() for line in f]
  120. for idx in range(int(len(raw_lines)/4+1)):
  121. raw_lines[idx*4+2] = newlines[idx]
  122. f = open(fpath, 'w',encoding="utf-8")
  123. for l in raw_lines:
  124. f.write(l+'\n')
  125. f.close()
  126. def parse_script(file_path):
  127. imgDict = getImgDict()
  128. with open(file_path, 'r',encoding="utf-8") as f:
  129. raw_lines = [line.strip() for line in f]
  130. dict_list = []
  131. sScript_dicts = []
  132. scriptIdx = 0
  133. for idx in range(int(len(raw_lines)/4+1)):
  134. script={}
  135. line_content = raw_lines[idx*4+2]
  136. script['content'] = line_content
  137. time_raw = raw_lines[idx * 4 +1 ].split(' --> ')
  138. start = time_raw[0].split(':')
  139. stop = time_raw[1].split(':')
  140. script['start'] = float(start[0])*3600 + float(start[1])*60 + float(start[2].replace(',','.'))
  141. script['stop'] = float(stop[0])*3600 + float(stop[1])*60 + float(stop[2].replace(',','.'))
  142. script['duration'] = script['stop']-script['start']
  143. duration = script['duration']
  144. start = script['start']
  145. try:
  146. kw= getKeyword(script['content'])
  147. kw.sort(key=lambda tup: tup[1], reverse=True)
  148. if kw[0][1]>2:
  149. script['kw'] = kw[0][0]
  150. else:
  151. script['kw'] = ''
  152. except Exception as e:
  153. script['kw']=''
  154. kwd = savekeywordImage(script['kw'],imgDict)
  155. if kwd is not None:
  156. script['imgid'] = kwd['id']
  157. imgDict.remove(kwd)
  158. else:
  159. script['imgid'] = None
  160. dict_list.append(script)
  161. accumulated_duration = 0
  162. for sen in shorten(script['content'],15):
  163. #print(sen)
  164. sScript = {}
  165. sScript['content'] = sen['content']
  166. sScript['index'] = scriptIdx
  167. scriptIdx+=1
  168. sScript['start'] = accumulated_duration+script['start']
  169. sScript['duration'] = duration*sen['time_ratio']
  170. accumulated_duration+=duration*sen['time_ratio']
  171. sScript_dicts.append(sScript)
  172. img_dicts=[]
  173. found = False
  174. start = 0
  175. stop = 0
  176. imgid=''
  177. imgidx = 0
  178. for d in dict_list:
  179. if d['imgid'] is not None:
  180. if found :
  181. img_dicts.append({'index':imgidx,'imgid':imgid,'start':start,'duration':d['start']-start})
  182. imgidx+=1
  183. start = d['start']
  184. imgid = d['imgid']
  185. else:
  186. found=True
  187. start = d['start']
  188. imgid = d['imgid']
  189. if d['start']==dict_list[-1]['start']:
  190. if d['imgid'] is not None:
  191. img_dicts.append({'index':imgidx,'imgid':d['imgid'],'start':d['start'],'duration':d['duration']})
  192. else:
  193. img_dicts.append({'index':imgidx,'imgid':imgid,'start':start,'duration':d['stop']-start})
  194. imgidx+=1
  195. return sScript_dicts, img_dicts
  196. def shorten(in_str, maxLen):
  197. re.findall(r'[\u4e00-\u9fff]+', in_str)
  198. zh_idx = []
  199. eng_idx= []
  200. for i in range(len(in_str)):
  201. if in_str[i] > u'\u4e00' and in_str[i] < u'\u9fff':
  202. zh_idx.append(i)
  203. else:
  204. eng_idx.append(i)
  205. space_index = [m.start() for m in re.finditer(' ', in_str)]
  206. for idx in space_index:
  207. eng_idx.remove(idx)
  208. eng_range_list = []
  209. for k, g in groupby(enumerate(eng_idx), lambda ix : ix[0] - ix[1]):
  210. eng_range = list(map(itemgetter(1), g))
  211. eng_range_list.append(eng_range)
  212. total_syllable = 0
  213. for i in range(len(eng_range_list)):
  214. total_syllable += (syllable_count(in_str[eng_range_list[i][0]:eng_range_list[i][-1]+1])+0.5)
  215. for i in range(len(zh_idx)):
  216. total_syllable+=1
  217. #final chchchchchc[en][en][en]
  218. #[en] is a vocabulary dict with occurence of image
  219. zh_eng_idx_list = []
  220. i = 0
  221. while i < len(in_str):
  222. if in_str[i]==' ':
  223. i+=1
  224. if i in zh_idx:
  225. zh_eng_idx_list.append(i)
  226. i+=1
  227. if i in eng_idx:
  228. for ls in eng_range_list:
  229. if i in ls:
  230. zh_eng_idx_list.append(ls)
  231. i = ls[-1]+1
  232. break
  233. zh_eng_dict_list = [{'content':'','time_ratio':0}]
  234. idx = 0
  235. current_len = 0
  236. sen_idx = 0
  237. while idx < len(zh_eng_idx_list):
  238. str_from_idx = ''
  239. sylla_cnt = 1
  240. if type(zh_eng_idx_list[idx])==type([]):
  241. str_from_idx = in_str[zh_eng_idx_list[idx][0]:zh_eng_idx_list[idx][-1]+1]+' '
  242. sylla_cnt = syllable_count(str_from_idx)
  243. else:
  244. str_from_idx = in_str[zh_eng_idx_list[idx]]
  245. if len(zh_eng_dict_list[sen_idx]['content'])+sylla_cnt>=maxLen:
  246. zh_eng_dict_list[sen_idx]['time_ratio'] = current_len/total_syllable
  247. zh_eng_dict_list.append({'content':'','time_ratio':0})
  248. sen_idx+=1
  249. current_len = 0
  250. else:
  251. current_len += sylla_cnt
  252. zh_eng_dict_list[sen_idx]['content'] += str_from_idx
  253. idx+=1
  254. total_ratio = 0
  255. for obj in zh_eng_dict_list:
  256. total_ratio+=obj['time_ratio']
  257. zh_eng_dict_list[-1]['time_ratio'] = 1-total_ratio
  258. return zh_eng_dict_list
  259. def video_writer_init(path):
  260. w = openshot.FFmpegWriter(path)
  261. w.SetAudioOptions(True, "aac", 44100, 2, openshot.LAYOUT_STEREO, 3000000)
  262. w.SetVideoOptions(True, "libx264", openshot.Fraction(30000, 1000), 1280, 720,
  263. openshot.Fraction(1, 1), False, False, 3000000)
  264. return w
  265. def cKey(r,g,b,fuzz):
  266. col=openshot.Color()
  267. col.red=openshot.Keyframe(r)
  268. col.green=openshot.Keyframe(g)
  269. col.blue=openshot.Keyframe(b)
  270. return openshot.ChromaKey(col, openshot.Keyframe(fuzz))
  271. def video_photo_clip(vid=None,layer=None, position=None, end=None
  272. ,scale_x=1,scale_y=1,location_x=0,location_y=0,ck=None,audio=True):
  273. clip = openshot.Clip(vid)
  274. clip.Layer(layer)
  275. clip.Position(position)
  276. clip.End(end)
  277. clip.scale_x=openshot.Keyframe(scale_x)
  278. clip.scale_y=openshot.Keyframe(scale_y)
  279. clip.location_x=openshot.Keyframe(location_x)
  280. clip.location_y=openshot.Keyframe(location_y)
  281. if ck!=None:
  282. clip.AddEffect(ck)
  283. if audio==True:
  284. clip.has_audio=openshot.Keyframe(1)
  285. else:
  286. clip.has_audio=openshot.Keyframe(0)
  287. return clip
  288. def downloadFromDrive(cPath,fid,idx):
  289. download_file_from_google_drive(fid, cPath+str(idx)+'img.jpg')
  290. def download_file_from_google_drive(id, destination):
  291. URL = "https://docs.google.com/uc?export=download"
  292. session = requests.Session()
  293. response = session.get(URL, params = { 'id' : id }, stream = True)
  294. token = get_confirm_token(response)
  295. if token:
  296. params = { 'id' : id, 'confirm' : token }
  297. response = session.get(URL, params = params, stream = True)
  298. save_response_content(response, destination)
  299. def get_confirm_token(response):
  300. for key, value in response.cookies.items():
  301. if key.startswith('download_warning'):
  302. return value
  303. return None
  304. def save_response_content(response, destination):
  305. CHUNK_SIZE = 32768
  306. with open(destination, "wb") as f:
  307. for chunk in response.iter_content(CHUNK_SIZE):
  308. if chunk: # filter out keep-alive new chunks
  309. f.write(chunk)
  310. def call_anchor(fileName,avatar):
  311. conn = rpyc.classic.connect("192.168.1.111",18812)
  312. ros = conn.modules.os
  313. rsys = conn.modules.sys
  314. fr=open(fileName,'rb')# local svoice
  315. #warning!!! file my be replaced by other process
  316. fw=conn.builtins.open('/tmp/output.mp3','wb')# remote
  317. while True:
  318. b=fr.read(1024)
  319. if b:
  320. fw.write(b)
  321. else:
  322. break
  323. fr.close()
  324. fw.close()
  325. val=random.randint(1000000,9999999)
  326. ros.chdir('/home/jared/to_video')
  327. ros.system('./p'+str(avatar)+'.sh '+str(val)+' &')
  328. while True:
  329. print('waiting...')
  330. if ros.path.exists('/tmp/results/'+str(val)):
  331. break
  332. time.sleep(5)
  333. print('waiting...')
  334. fr=conn.builtins.open('/tmp/results/'+str(val)+'.mp4','rb')
  335. newfileName = fileName.replace('speech.mp3','speaker.mp4')
  336. fw=open(newfileName,'wb')#local anchor
  337. while True:
  338. b=fr.read(1024)
  339. if b:
  340. fw.write(b)
  341. else:
  342. break
  343. fr.close()
  344. fw.close()