浏览代码

first arrange

ming 3 年之前
父节点
当前提交
b351bd2ccc
共有 6 个文件被更改,包括 463 次插入38 次删除
  1. 35 33
      api/main.py
  2. 1 0
      api/static/upload.js
  3. 0 0
      api/static/uploadAudio.html
  4. 408 0
      api/static/util.py
  5. 18 4
      composer/cService.py
  6. 1 1
      composer/util.py

+ 35 - 33
api/main.py

@@ -2,52 +2,45 @@ from typing import Optional
 from fastapi.staticfiles import StaticFiles
 from fastapi import FastAPI,File, UploadFile,Request,Response
 import util,os, math, time,queue,threading
-import openshot
 from pydantic import BaseModel
 from fastapi.templating import Jinja2Templates
+import rpyc
 
-class Item:
-    name ='str'
-    price = 90
+q = queue.Queue()
+app = FastAPI()
+templates = Jinja2Templates(directory="static")
+app.mount("/static", StaticFiles(directory="static"), name="static")
+
+class Cast_info:
+    sub_dict = None
+    img_dict = None
+    name_hash = None
+
+class updateScriptModel(BaseModel):
+    name_hash:str
+    scriptStr:str
 
 def tEntry():
     while q.qsize!=0:
-        it = q.get()
-        print(it.price)
-        for i in range(10):
-            print(i)
-            time.sleep(1)
-
+        ci = q.get()
+        c = rpyc.connect("localhost", 8838)
+        c._config['sync_request_timeout'] = None
+        remote_svc = c.root
+        result = remote_svc.gen_video(ci.name_hash,ci.sub_dict,ci.img_dict)
 
-q = queue.Queue()
 t1 = threading.Thread(target=tEntry)
 t1.start()
 
+rootPath = '../composer/'
 
-
-templates = Jinja2Templates(directory="static")
-app = FastAPI()
-
-app.mount("/static", StaticFiles(directory="static"), name="static")
-
-rootPath = '/app/components/'
-
-@app.get("/")
-def read_root(request: Request, response: Response):
+@app.get("/uploadAudio")
+def uploadAudio(request: Request, response: Response):
     return templates.TemplateResponse("uploadmp3.html", {"request": request, "response": response})
 
 @app.get("/modifyScript")
-def read_root(request: Request, response: Response):
+def modifyScript(request: Request, response: Response):
     return templates.TemplateResponse("modifyScript.html", {"request": request, "response": response})
 
-@app.get("/items/{item_id}")
-def read_item(item_id: int, q: Optional[str] = None):
-    return {"item_id": item_id, "q": q}
-
-class updateScriptModel(BaseModel):
-    name_hash:str
-    scriptStr:str
-    
 @app.post("/updateScript")
 def read_item(info : updateScriptModel):
     lines = info.scriptStr.split(',')
@@ -56,7 +49,17 @@ def read_item(info : updateScriptModel):
     util.rewriteScript(cPath,lines)
 
     sub_dict,img_dict=filePrepare(info.name_hash)
-    genVideo(info.name_hash,sub_dict,img_dict)
+
+    cinfo = Cast_info()
+    cinfo.name_hash = info.name_hash
+    cinfo.sub_dict
+    cinfo.img_dict
+    
+    item = Item()
+    q.put(item)
+    if not t1.is_alive():
+        t1 = threading.Thread(target=tEntry)
+        t1.start()
     
     return 'ok'
 
@@ -74,5 +77,4 @@ async def uploadmp3(file: UploadFile = File(...)):
     
     util.transScript(cPath)
     scripts = util.get_script(cPath)
-   
-    return name_hash, scripts
+    return name_hash

+ 1 - 0
api/static/upload.js

@@ -18,6 +18,7 @@ function prepareUpload(event) {
     url: 'uploadmp3',
     dataType: 'json',
     success: function (jsonData) {
+      
       window.location.href = "/modifyScript?p="+jsonData;
     },
     error: function (error) {

+ 0 - 0
api/static/uploadmp3.html → api/static/uploadAudio.html


+ 408 - 0
api/static/util.py

@@ -0,0 +1,408 @@
+
+
+from autosub import DEFAULT_CONCURRENCY
+from autosub import DEFAULT_SUBTITLE_FORMAT
+from pytranscriber.control.ctr_main import Ctr_Main
+from pytranscriber.control.ctr_autosub import Ctr_Autosub
+import re,random, time
+from itertools import groupby
+from operator import itemgetter
+from rakeUtil.Rake import Rake
+import requests,rpyc
+from difflib import SequenceMatcher
+from PIL import Image,ImageDraw,ImageFont
+import openshot
+obj = Rake()
+stop_path = "rakedata/stoplist/中文停用词表(1208个).txt"
+conj_path = "rakedata/stoplist/中文分隔词词库.txt"
+obj.initializeFromPath(stop_path, conj_path)
+
+def trim_punctuation(s):
+    pat_block = u'[^\u4e00-\u9fff0-9a-zA-Z]+';
+    pattern = u'([0-9]+{0}[0-9]+)|{0}'.format(pat_block)
+    res = re.sub(pattern, lambda x: x.group(1) if x.group(1) else u" " ,s)
+    return res
+
+def txt2image(content, save_target,lang='zh'):
+    unicode_text = trim_punctuation(content)
+    content = content.replace(' ','')
+    font = ''
+    if lang=='zh':
+        font = ImageFont.truetype(font="font/DFT_B7.ttc", size=38)
+    else :
+        font = ImageFont.truetype(font="font/arial.ttf", size=38)
+    text_width, text_height = font.getsize(unicode_text)
+    canvas = Image.new('RGBA', (700, 500), (255, 0, 0, 0) )
+    draw = ImageDraw.Draw(canvas)
+    text= unicode_text
+    draw.text((5,5), text, (255, 255, 0), font)
+    canvas.save(save_target, "PNG")
+
+def generate_subtitle_image_from_dict(cpath, sub_dict):
+    for script in sub_dict:
+        sv_path = cpath + '/' + str(script['index'])+'.png'
+        sub = script['content']
+        txt2image(sub,sv_path)
+
+def listener_progress(string, percent):
+    True
+
+def transScript(cpath):
+    Ctr_Autosub.init()
+    Ctr_Autosub.generate_subtitles(cpath+"speech.mp3",'zh'
+    ,listener_progress
+    ,output=cpath+"script.txt"
+    ,concurrency=DEFAULT_CONCURRENCY,subtitle_file_format=DEFAULT_SUBTITLE_FORMAT)
+
+def syllable_count(word):
+    word = word.lower()
+    count = 0
+    vowels = "aeiouy"
+    if word[0] in vowels:
+        count += 1
+    for index in range(1, len(word)):
+        if word[index] in vowels and word[index - 1] not in vowels:
+            count += 1
+
+    if word.endswith("e"):
+        count -= 1
+    if count == 0:
+        count += 1
+    return count
+
+def getKeyword(inStr):
+    re.findall(r'[\u4e00-\u9fff]+', inStr)
+
+    zh_idx = []
+    eng_idx= []
+    for i in range(len(inStr)):
+        if inStr[i] > u'\u4e00' and inStr[i] < u'\u9fff':
+            zh_idx.append(i)
+        else:
+            eng_idx.append(i)
+    kws = obj.extractKeywordFromString(inStr)
+
+    engStr =''
+    for idx in range(len(eng_idx)):
+        if idx != len(eng_idx)-1:
+            if eng_idx[idx]+1 == eng_idx[idx+1]:
+                engStr+=inStr[eng_idx[idx]]
+            else:
+                engStr+=inStr[eng_idx[idx]]
+                if len(engStr)>2:
+                    kws.append((engStr,10))
+                engStr=''
+        else:
+            engStr+=inStr[eng_idx[idx]]
+            if len(engStr)>2:
+                kws.append((engStr,10))
+            engStr=''
+    return kws
+
+
+def getImgDict():
+    return [{'kw':'podcast','id':'17j41rqsoWVzc-HD8jvdxb651pbHJhvH8'}
+    ,{'kw':'podcast','id':'1wT3uIaoe3xD-wrAo-J9eZweHEuEfI22_'}
+    ,{'kw':'podcast','id':'1uaP8_xtqMn_Zbx3DX78ALdCtFjUPYgKQ'}
+    ,{'kw':'podcast','id':'1L1NMByTorcDBN8EpbwwUakTexdRAiF4w'}
+    ,{'kw':'youtuber','id':'17vUM8xrMgI9y1aEbAoprOxKiK9OOkipE'}
+    ,{'kw':'支持者','id':'1sb-DmU5X9YE7HZLva_UueEvzcXqrKoGk'}
+    ,{'kw':'app','id':'1jxoZuFlUHyl1L7-WB2ejPKBEW38bsbR6'}]
+
+def savekeywordImage(kw,imgDict):
+    highest_val = 0
+    highest_d = None
+    for d in imgDict:
+        sim = SequenceMatcher(None, d['kw'], kw).ratio()
+        #print(sim,d['kw'],kw)
+        if sim>highest_val :
+            highest_val = sim
+            highest_d = d
+    return highest_d
+
+def get_script(cPath):
+    fpath = cPath+'script.txt'
+
+    with open(fpath, 'r',encoding="utf-8") as f:
+        raw_lines = [line.strip() for line in f]
+    lines =[]
+    for idx in range(int(len(raw_lines)/4+1)):
+        line_content = raw_lines[idx*4+2]
+        lines.append(line_content)
+    return lines
+
+def rewriteScript(cPath,newlines):
+    fpath = cPath+'script.txt'
+
+    with open(fpath, 'r',encoding="utf-8") as f:
+        raw_lines = [line.strip() for line in f]
+
+    for idx in range(int(len(raw_lines)/4+1)):
+        raw_lines[idx*4+2] = newlines[idx]
+    
+    
+    f = open(fpath, 'w',encoding="utf-8")
+    for l in raw_lines:
+        f.write(l+'\n')
+    f.close()
+
+def parse_script(file_path):
+    imgDict = getImgDict()
+    with open(file_path, 'r',encoding="utf-8") as f:
+        raw_lines = [line.strip() for line in f]
+
+    dict_list = []
+    sScript_dicts = []
+    scriptIdx = 0
+    for idx in range(int(len(raw_lines)/4+1)):
+        script={}
+        line_content = raw_lines[idx*4+2]
+        script['content'] = line_content
+
+        time_raw = raw_lines[idx * 4 +1 ].split(' --> ')
+        start = time_raw[0].split(':')
+        stop = time_raw[1].split(':')
+        script['start'] = float(start[0])*3600 + float(start[1])*60 + float(start[2].replace(',','.'))
+        script['stop'] = float(stop[0])*3600 + float(stop[1])*60 + float(stop[2].replace(',','.'))
+        script['duration'] = script['stop']-script['start']
+        duration = script['duration']
+        start = script['start']
+        try:
+            kw= getKeyword(script['content'])
+            kw.sort(key=lambda tup: tup[1], reverse=True)
+            if kw[0][1]>2:
+                script['kw'] = kw[0][0]
+            else:
+                script['kw'] = ''
+        except Exception as e:
+            script['kw']=''
+
+        kwd = savekeywordImage(script['kw'],imgDict)
+
+        
+        if kwd is not None:
+            script['imgid'] = kwd['id']
+            imgDict.remove(kwd)
+        else:
+            script['imgid'] = None
+   
+        dict_list.append(script)
+  
+        accumulated_duration = 0
+        for sen in shorten(script['content'],15):
+            #print(sen)
+            
+            sScript = {}
+            sScript['content'] = sen['content']
+            sScript['index'] = scriptIdx
+            scriptIdx+=1
+            sScript['start'] = accumulated_duration+script['start']
+            sScript['duration'] = duration*sen['time_ratio']
+            accumulated_duration+=duration*sen['time_ratio']
+            sScript_dicts.append(sScript)
+    img_dicts=[]
+    found = False
+    start = 0
+    stop = 0
+    imgid=''
+    imgidx = 0
+    for d in dict_list:
+        if d['imgid'] is not None:
+            
+            if found :
+                img_dicts.append({'index':imgidx,'imgid':imgid,'start':start,'duration':d['start']-start})
+                imgidx+=1
+                start = d['start']
+                imgid = d['imgid']
+            else:
+                found=True
+                start = d['start']
+                imgid = d['imgid']
+
+        if d['start']==dict_list[-1]['start']:
+            if d['imgid'] is not None:
+                img_dicts.append({'index':imgidx,'imgid':d['imgid'],'start':d['start'],'duration':d['duration']})
+            else:
+                img_dicts.append({'index':imgidx,'imgid':imgid,'start':start,'duration':d['stop']-start})
+                imgidx+=1
+            
+    return sScript_dicts, img_dicts
+
+def shorten(in_str, maxLen):
+    re.findall(r'[\u4e00-\u9fff]+', in_str)
+
+    zh_idx = []
+    eng_idx= []
+    for i in range(len(in_str)):
+        if in_str[i] > u'\u4e00' and in_str[i] < u'\u9fff':
+            zh_idx.append(i)
+        else:
+            eng_idx.append(i)
+
+    space_index = [m.start() for m in re.finditer(' ', in_str)]
+    for idx in space_index:
+        eng_idx.remove(idx)
+    
+    eng_range_list = []
+    for k, g in groupby(enumerate(eng_idx), lambda ix : ix[0] - ix[1]):
+        eng_range = list(map(itemgetter(1), g))
+        eng_range_list.append(eng_range)
+
+    total_syllable = 0
+    for i in range(len(eng_range_list)):
+        total_syllable += (syllable_count(in_str[eng_range_list[i][0]:eng_range_list[i][-1]+1])+0.5)
+    for i in range(len(zh_idx)):
+        total_syllable+=1
+    
+    #final chchchchchc[en][en][en]
+    #[en] is a vocabulary dict with  occurence of image
+    zh_eng_idx_list = []
+    i = 0
+    while i < len(in_str):
+        if in_str[i]==' ':
+            i+=1
+        if i in zh_idx:
+            zh_eng_idx_list.append(i)
+            i+=1
+        if i in eng_idx:
+            for ls in eng_range_list:
+                if i in ls:
+                    zh_eng_idx_list.append(ls)
+                    i = ls[-1]+1
+                    break
+            
+    zh_eng_dict_list = [{'content':'','time_ratio':0}]
+    idx = 0 
+    current_len = 0
+    sen_idx = 0
+    while idx < len(zh_eng_idx_list):
+        str_from_idx = ''
+        sylla_cnt = 1
+        if type(zh_eng_idx_list[idx])==type([]):
+            str_from_idx = in_str[zh_eng_idx_list[idx][0]:zh_eng_idx_list[idx][-1]+1]+' '
+            sylla_cnt = syllable_count(str_from_idx)
+        else:
+            str_from_idx = in_str[zh_eng_idx_list[idx]]
+    
+      
+        if len(zh_eng_dict_list[sen_idx]['content'])+sylla_cnt>=maxLen:
+            zh_eng_dict_list[sen_idx]['time_ratio'] = current_len/total_syllable
+           
+            zh_eng_dict_list.append({'content':'','time_ratio':0})
+            sen_idx+=1
+            current_len = 0
+        else:
+            current_len += sylla_cnt
+            zh_eng_dict_list[sen_idx]['content'] += str_from_idx
+            idx+=1
+        
+    total_ratio = 0
+    for obj in zh_eng_dict_list:
+        total_ratio+=obj['time_ratio']
+    zh_eng_dict_list[-1]['time_ratio'] = 1-total_ratio
+    return zh_eng_dict_list
+def video_writer_init(path):
+    w = openshot.FFmpegWriter(path)
+    w.SetAudioOptions(True, "aac", 44100, 2, openshot.LAYOUT_STEREO, 3000000)
+    w.SetVideoOptions(True, "libx264", openshot.Fraction(30000, 1000), 1280, 720,
+        openshot.Fraction(1, 1), False, False, 3000000)
+    return w
+def cKey(r,g,b,fuzz):
+    col=openshot.Color()
+    col.red=openshot.Keyframe(r)
+    col.green=openshot.Keyframe(g)
+    col.blue=openshot.Keyframe(b)
+    return openshot.ChromaKey(col, openshot.Keyframe(fuzz))
+
+def video_photo_clip(vid=None,layer=None, position=None, end=None
+    ,scale_x=1,scale_y=1,location_x=0,location_y=0,ck=None,audio=True):
+    clip = openshot.Clip(vid)
+    clip.Layer(layer)
+    clip.Position(position)
+    clip.End(end)
+    clip.scale_x=openshot.Keyframe(scale_x)
+    clip.scale_y=openshot.Keyframe(scale_y)
+    clip.location_x=openshot.Keyframe(location_x)
+    clip.location_y=openshot.Keyframe(location_y)
+    
+    if ck!=None:
+        clip.AddEffect(ck)
+    if audio==True:
+        clip.has_audio=openshot.Keyframe(1)
+    else:
+        clip.has_audio=openshot.Keyframe(0)
+    return clip
+
+def downloadFromDrive(cPath,fid,idx):
+    download_file_from_google_drive(fid, cPath+str(idx)+'img.jpg')
+
+def download_file_from_google_drive(id, destination):
+    URL = "https://docs.google.com/uc?export=download"
+
+    session = requests.Session()
+
+    response = session.get(URL, params = { 'id' : id }, stream = True)
+    token = get_confirm_token(response)
+
+    if token:
+        params = { 'id' : id, 'confirm' : token }
+        response = session.get(URL, params = params, stream = True)
+
+    save_response_content(response, destination)    
+
+def get_confirm_token(response):
+    for key, value in response.cookies.items():
+        if key.startswith('download_warning'):
+            return value
+
+    return None
+
+def save_response_content(response, destination):
+    CHUNK_SIZE = 32768
+
+    with open(destination, "wb") as f:
+        for chunk in response.iter_content(CHUNK_SIZE):
+            if chunk: # filter out keep-alive new chunks
+                f.write(chunk)
+
+def call_anchor(fileName,avatar):
+    conn = rpyc.classic.connect("192.168.1.111",18812)
+    ros = conn.modules.os 
+    rsys = conn.modules.sys 
+    fr=open(fileName,'rb')# local svoice
+    #warning!!!    file my be replaced by other process
+    fw=conn.builtins.open('/tmp/output.mp3','wb')# remote
+
+    while True:
+        b=fr.read(1024)
+        if b:
+            fw.write(b)
+        else:
+            break
+
+    fr.close()
+    fw.close()
+
+    val=random.randint(1000000,9999999)
+    ros.chdir('/home/jared/to_video')
+    ros.system('./p'+str(avatar)+'.sh '+str(val)+' &')
+
+    while True:
+        print('waiting...')
+        if ros.path.exists('/tmp/results/'+str(val)):
+            break
+        time.sleep(5)
+        print('waiting...')
+
+    fr=conn.builtins.open('/tmp/results/'+str(val)+'.mp4','rb')
+    newfileName = fileName.replace('speech.mp3','speaker.mp4')
+    fw=open(newfileName,'wb')#local anchor
+    while True:
+        b=fr.read(1024)
+        if b:
+            fw.write(b)
+        else:
+            break
+
+    fr.close()
+    fw.close()

+ 18 - 4
composer/cService.py

@@ -2,7 +2,7 @@
 import util,os, math, time,queue,threading
 import openshot
 
-rootPath = '/app/components/'
+rootPath = './'
 
 
 def filePrepare(name_hash):
@@ -17,7 +17,7 @@ def filePrepare(name_hash):
     for imgd in img_dict:
         print(imgd)
         util.downloadFromDrive(cPath,imgd['imgid'],imgd['index'])
-    
+
     util.call_anchor(cPath+'speech.mp3',7)
     return sub_dict,img_dict
 
@@ -84,11 +84,25 @@ def genVideo(name_hash,sub_dict,img_dict):
         img_list[idx].Close()
 
 
-    w = util.video_writer_init("myraw.mp4")
+    w = util.video_writer_init("output.mp4")
     w.Open()
     frames = int(t.info.fps)*int(main_timer)
     for n in range(frames):
         f=t.GetFrame(n)
         w.WriteFrame(f)
     t.Close()
-    w.Close()
+    w.Close()
+
+
+
+
+class podcast_service(rpyc.Service):
+    def exposed_gen_video(self,name_hash, sub_dict, img_dict):
+        genVideo(name_hash, sub_dict, img_dict)
+
+
+
+from rpyc.utils.server import ThreadedServer
+t = ThreadedServer(podcast_service, port=8838)
+print('service started')
+t.start()

+ 1 - 1
composer/util.py

@@ -69,6 +69,7 @@ def syllable_count(word):
     if count == 0:
         count += 1
     return count
+
 def getKeyword(inStr):
     re.findall(r'[\u4e00-\u9fff]+', inStr)
 
@@ -145,7 +146,6 @@ def rewriteScript(cPath,newlines):
         f.write(l+'\n')
     f.close()
 
-
 def parse_script(file_path):
     imgDict = getImgDict()
     with open(file_path, 'r',encoding="utf-8") as f: