Sfoglia il codice sorgente

Merge remote-tracking branch 'origin/master' into front-dev

SyuanYu 1 anno fa
parent
commit
ebecec9188

+ 23 - 0
backend/app/app/aianchor/config.py

@@ -0,0 +1,23 @@
+from pathlib import Path
+videofile=[".mp4", ".avi", ".MOV", ".mov"]
+imagefile=[".png", ".jpg", ".PNG", ".JPG", ".jpeg"]
+outputfile = "output.mp4"
+voice_json = "voice.json"
+temp_dir = "temp"
+input_dir = "input"
+voice_dir = "voice"
+caption_dir = "caption"
+ai_character_dir = "ai_character"
+output_dir = "output"
+srt_dir = "srt"
+character = "character"
+user_upload = "user_upload"
+DEFAULT_AI_CHARACTER = "angela"
+STORAGE_PATH = Path(__file__).resolve().parent.parent.parent / "storage" 
+AI_CHARACTER_PATH = STORAGE_PATH / "character"
+STYLE_PATH = STORAGE_PATH / "style"
+DEFAULT_STYLE = "style1"
+HD = (1280, 720)
+FHD = (1920, 1080)
+QHD = (2560, 1440)
+UHD = (3840, 2160)

+ 124 - 18
backend/app/app/aianchor/utils2.py

@@ -1,8 +1,13 @@
+import shutil
 import pandas as pd
 from pathlib import Path
 import zipfile
 from io import BytesIO
 from chardet.universaldetector import UniversalDetector
+try:
+    from app.aianchor.config import *
+except ImportError:
+    from config import *
 
 DEFAULT_ENCODING = "utf-8"
 
@@ -25,9 +30,8 @@ def check_zip(zip_filepath:str):
   with zipfile.ZipFile(str(path)) as zf:
     filenames = [x for x in zf.namelist() if not x.endswith('/')]
     result = guess_codec(filenames)
-    true_filenames = [x.encode('cp437').decode(result) for x in zf.namelist() if not x.endswith('/')]
-    print(true_filenames)
-    scenarios_files = [(x, i) for i, x in enumerate(true_filenames) if Path(x).suffix in [".xlsx", ".csv"] and not Path(x).name.startswith("._") and Path(x).stem != "style"]
+    true_filepaths = [x.encode('cp437').decode(result) for x in zf.namelist() if not x.endswith('/')]
+    scenarios_files = [(Path(x).name, i) for i, x in enumerate(true_filepaths) if Path(x).suffix in [".xlsx", ".csv"] and not Path(x).name.startswith("._") and not Path(x).name.startswith("~$") and Path(x).stem != "style"]
     print(scenarios_files)
     
     if len(scenarios_files) == 0:
@@ -40,31 +44,133 @@ def check_zip(zip_filepath:str):
     elif Path(scenarios_files[0][0]).suffix == ".csv":
       table = pd.read_csv(BytesIO(f), dtype=object)
     table.reset_index(inplace=True)
-    print(table)
     
-    stems = [Path(x).stem for x in true_filenames]
+    true_filenames = [(Path(x).name, i) for i, x in enumerate(true_filepaths)]
+    true_stems = [(Path(x).stem, i) for i, x in enumerate(true_filepaths)]
     for i in range(len(table)):
       # excel 裡的圖檔跟zip裡的檔案要一致
       if not table.loc[i, ['素材']].isna().item():
         img =  table.loc[i, ['素材']].item()
-        print(img)
-
         img_files = [x.strip() for x in img.split(',')]
         for img in img_files:
-          print(img)
-          n = stems.count(img)
+          if Path(img).suffix:
+            n = len([x for x in true_filenames if x[0] == img])
+          else:
+            n = len([x for x in true_stems if x[0] == img])
           if n == 0:
-            raise VideoMakerError(f"{img}: no such media file in zip.")
+            raise VideoMakerError(f"{img}: no such img file in zip.")
           elif n > 1:
-            raise VideoMakerError(f'too many same name media files as {img} in zip')
-      
+            raise VideoMakerError(f'too many same name img files as {img} in zip')
+
+      # 需要tts文字或音檔
+      if '字幕' in table.columns and table.loc[i, ['字幕']].isna().item():
+        if '音檔' in table.columns and table.loc[i, ['音檔']].isna().item():
+          raise VideoMakerError(f'text or voice file is needed at scene {i+1}.')
+        voice_file = table.loc[i, ['音檔']].item()
+        if Path(voice_file).suffix:
+          n = len([x for x in true_filenames if x[0]==voice_file])
+        else:
+          n = true_stems.count(voice_file)
+        if n == 0:
+          raise VideoMakerError(f"{voice_file}: no such voice file in zip.")
+        elif n > 1:
+          raise VideoMakerError(f'too many same name voice files as {voice_file} in zip')
+  
+  return True
+
+def prepare_workingdir(work_dir_path:str):
+  work_dir_Path = Path(work_dir_path)
+  (work_dir_Path/voice_dir).mkdir(exist_ok=True)
+  (work_dir_Path/caption_dir).mkdir(exist_ok=True)
+  (work_dir_Path/input_dir).mkdir(exist_ok=True)
+  (work_dir_Path/output_dir).mkdir(exist_ok=True)
+  (work_dir_Path/srt_dir).mkdir(exist_ok=True)
+  (work_dir_Path/ai_character_dir).mkdir(exist_ok=True)
+
+def check_and_extract_zip(zip_filepath:str, working_dirpath:str):
+  working_dir_Path = Path(working_dirpath)
+  with zipfile.ZipFile(zip_filepath) as zf:
+    filenames = [x for x in zf.namelist() if not x.endswith('/')]
+    result = guess_codec(filenames)
+    true_filepaths = [x.encode('cp437').decode(result) for x in zf.namelist() if not x.endswith('/')]
+    scenarios_filenames = [(Path(x).name, i) for i, x in enumerate(true_filepaths) if Path(x).suffix in [".xlsx", ".csv"] and not Path(x).name.startswith("._") and not Path(x).name.startswith("~$") and Path(x).stem != "style" ]
+    media_filenames = [(Path(x).name, i) for i, x in enumerate(true_filepaths) if Path(x).suffix not in [".xlsx", ".csv"] and not Path(x).name.startswith("._") and not Path(x).name.startswith("~$")]
+    
+    if len(scenarios_filenames) == 0:
+      raise VideoMakerError("no excel or csv file in zip.")
+    if len(scenarios_filenames) > 1:
+      raise VideoMakerError("too many excel or csv file in zip.")
+    
+    save_filepath = working_dir_Path / input_dir / scenarios_filenames[0][0]
+    if not save_filepath.exists():
+      with open(save_filepath, 'wb') as output_file:  # 建立並開啟新檔案
+        with zf.open(filenames[scenarios_filenames[0][1]], 'r') as origin_file:  # 開啟原檔案
+          shutil.copyfileobj(origin_file, output_file)  # 將原檔案內容複製到新檔案 
+    else:
+      raise VideoMakerError(f"{scenarios_filenames[0]} already exists.")
+    
+    f = zf.read(filenames[scenarios_filenames[0][1]])
+    if Path(scenarios_filenames[0][0]).suffix == ".xlsx":
+      table = pd.read_excel(BytesIO(f), dtype=object)
+    elif Path(scenarios_filenames[0][0]).suffix == ".csv":
+      table = pd.read_csv(BytesIO(f), dtype=object)
+    table.reset_index(inplace=True)
+    
+    true_filenames = [(Path(x).name, i) for i, x in enumerate(true_filepaths)]
+    true_stems = [(Path(x).stem, i) for i, x in enumerate(true_filepaths)]
+    for i in range(len(table)):
+      # excel 裡的圖檔跟zip裡的檔案要一致
+      if not table.loc[i, ['素材']].isna().item():
+        img =  table.loc[i, ['素材']].item()
+        img_files = [x.strip() for x in img.split(',')]
+        for img in img_files:
+          if Path(img).suffix:
+            target_filenames = [x for x in true_filenames if x[0] == img]
+          else:
+            target_filenames = [x for x in true_stems if x[0] == img]
+          if len(target_filenames) == 0:
+            raise VideoMakerError(f"{img}: no such img file in zip.")
+          elif len(target_filenames) > 1:
+            raise VideoMakerError(f'too many same name img files as {img} in zip')
+          
+          save_filepath = working_dir_Path / input_dir / true_filenames[target_filenames[0][1]][0]
+          if not save_filepath.exists():
+            with open(save_filepath, 'wb') as output_file:  # 建立並開啟新檔案
+              with zf.open(filenames[target_filenames[0][1]], 'r') as origin_file:  # 開啟原檔案
+                shutil.copyfileobj(origin_file, output_file)  # 將原檔案內容複製到新檔案
+          else:
+            raise VideoMakerError(f"{target_filenames[0][0]} already exists.")
+        
       # 需要tts文字或音檔
-      if not table.loc[i, ['字幕']].isna().item():
-        if not '音檔' in table.columns or table.loc[i, ['音檔']].isna().item():
+      if '字幕' in table.columns and table.loc[i, ['字幕']].isna().item():
+        if '音檔' in table.columns and table.loc[i, ['音檔']].isna().item():
           raise VideoMakerError(f'text or voice file is needed at scene {i+1}.')
         voice_file = table.loc[i, ['音檔']].item()
-        n = stems.count(voice_file)
-        if n != 1:
-          raise VideoMakerError(f"voice file is can't find is zip at scene {i+1}.")
+        if Path(voice_file).suffix:
+          target_filenames = [x for x in true_filenames if x[0] == voice_file]
+        else:
+          target_filenames = [x for x in true_stems if x[0] == voice_file]
+        if len(target_filenames) == 0:
+          raise VideoMakerError(f"{voice_file}: no such voice file in zip.")
+        elif len(target_filenames) > 1:
+          raise VideoMakerError(f'too many same name voice files as {voice_file} in zip')
+        
+        save_filepath = working_dir_Path / input_dir / true_filenames[target_filenames[0][1]][0]
+        if not save_filepath.exists():
+          with open(save_filepath, 'wb') as output_file:  # 建立並開啟新檔案
+            with zf.open(filenames[target_filenames[0][1]], 'r') as origin_file:  # 開啟原檔案
+              shutil.copyfileobj(origin_file, output_file)  # 將原檔案內容複製到新檔案
+        else:
+          raise VideoMakerError(f"{target_filenames[0][0]} already exists.")
+        
+if __name__ == "__main__":
+  from fire import Fire
+  
+  def fire_check_zip(zip_filepath:str):
+    try:
+      if check_zip(zip_filepath):
+        print("passed check_zip")
+    except VideoMakerError as e:
+      print(e)
   
-  return True
+  Fire(fire_check_zip)

+ 1 - 3
backend/app/app/api/api_v1/endpoints/videos.py

@@ -101,8 +101,6 @@ def upload_plot(
       print(e)
       error_msg = {"accepted": False, "error_message":f'{e}'}
       return JSONResponse(error_msg)
-    
-    return_msg = {"accepted_message":"accepted"}
 
     '''
     zip_filename = video.stored_file_name+".zip"
@@ -115,7 +113,7 @@ def upload_plot(
   
     video_create = schemas.VideoCreate(title=title, progress_state="PENDING", stored_filename=filename)
     video = crud.video.create_with_owner(db=db, obj_in=video_create, owner_id=current_user.id)
-    return_msg = {"video_message":"accepted"}
+    return_msg = {"video_message":"accepted", "accepted":True}
     video_data = jsonable_encoder(video)
     video_data['membership_status'] = current_user.membership_status
     video_data['available_time'] = current_user.available_time

+ 6 - 1
frontend/src/api.ts

@@ -134,5 +134,10 @@ export const api = {
   },
   async getVideos(token: string) {
     return axios.get<Video[]>(`${apiUrl}/api/v1/videos/`, authHeaders(token));
-  }
+  },
+  async ecpayPaymentHTML(token: string, amount: number) {
+    const formData = new FormData();
+    formData.append("amount", amount.toString());
+    return axios.post<string>(`${apiUrl}/api/v1/payment/ecpayVideoCharge`, formData, authHeaders(token))
+  },
 };

+ 11 - 0
frontend/src/stores/main.ts

@@ -453,6 +453,17 @@ export const useMainStore = defineStore("MainStoreId", {
       } catch (error) {
         await mainStore.checkApiError(error);
       }
+    },
+    async ecpayPaymentHTML(amount:number) {
+      const mainStore = useMainStore();
+      try {
+        const response = await api.ecpayPaymentHTML(mainStore.token, amount)
+        if (response) {
+          return response.data;
+        } 
+      }catch (error) {
+        await mainStore.checkApiError(error);
+      }
     }
   }
 });

+ 32 - 4
frontend/src/views/main/admin/TestECPay.vue

@@ -12,19 +12,33 @@
       </v-card-actions>
     </v-card>
   </v-container>
+  <div id="pay-form"></div>
 </template>
 <script setup lang="ts">
-import { ref} from 'vue';
+import { ref } from 'vue';
 import { required } from '@/utils';
 import { useAdminStore } from '@/stores/admin';
 import axios from "axios"; 
+import { useMainStore } from "@/stores/main";
+
+const mainStore = useMainStore();
 
 async function ECPaySubmit() {
+  /*
+  const timestamp = Date.now()
+  const date = new Date(timestamp);
+  const year = date.getFullYear();
+  const month = date.getMonth() + 1;
+  const day = date.getDate();
+  const hour = date.getHours();
+  const minute = date.getMinutes();
+  const second = date.getSeconds();
+
   console.log("ECPay button pushed")
   const formData = new URLSearchParams();
-  formData.append("MerchantID", "3002607") //必填
+  formData.append("MerchantID", "3226141") //必填
   formData.append("MerchantTradeNo", "AAA000") //必填
-  formData.append("MerchantTradeDate", "2023/05/15 10:35:10") //必填
+  formData.append("MerchantTradeDate", `${year}/${month}/${day} ${hour}:${minute}:${second}`) //必填
   formData.append("PaymentType", "aio") //必填
   formData.append("TotalAmount", "600") //必填
   formData.append("TradeDesc", "choozmo SaaS") //必填
@@ -49,7 +63,21 @@ async function ECPaySubmit() {
   formData.append("CustomField4", "")
   formData.append("Language", "")
   return axios.post("https://payment-stage.ecpay.com.tw/Cashier/AioCheckOut/V5", formData)
-  
+  */
+  const originalHTML = await mainStore.ecpayPaymentHTML(500)
+  console.log(originalHTML)
+  let formHTML = originalHTML?.replace('<script type="text/javascript">document.getElementById("data_set").submit();</scr', '')
+  formHTML = formHTML?.replace('ipt>','')
+  console.log(formHTML)
+  const payFormElement = document.getElementById('pay-form');
+  payFormElement!.innerHTML = formHTML!
+  const ecpayForm:HTMLFormElement = <HTMLFormElement>document.getElementById('data_set')
+  console.log(ecpayForm)
+  ecpayForm.submit()
 
+    
+
+  
+  
 }
 </script>