tomoya 3 هفته پیش
والد
کامیت
a951b0ce61
1فایلهای تغییر یافته به همراه247 افزوده شده و 7 حذف شده
  1. 247 7
      backend/app/app/api/api_v1/endpoints/edm_saas_api.py

+ 247 - 7
backend/app/app/api/api_v1/endpoints/edm_saas_api.py

@@ -2,7 +2,10 @@ from fastapi import APIRouter,FastAPI, Depends, HTTPException, status
 from pydantic import BaseModel
 from supabase import create_client, Client
 from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
-from fastapi import UploadFile, File, Form
+from fastapi import UploadFile, File, Form, BackgroundTasks, WebSocket
+from fastapi.responses import FileResponse
+import os
+from pathlib import Path
 from jose import JWTError, jwt
 from passlib.context import CryptContext
 from datetime import datetime, timedelta
@@ -14,24 +17,39 @@ from email.mime.multipart import MIMEMultipart
 from email.mime.text import MIMEText
 from google.auth.transport.requests import Request
 import supabase
+import asyncio
+from edge_tts import VoicesManager
+from app.aianchor.utils2 import check_zip, VideoMakerError
+from app.core.video_utils import update_zip
+from typing import Any, List, Optional, Literal
+import app.schemas as schemas 
+from app.core.celery_app import celery_app
+from app.core.config import settings
+import requests
 
-
-
+BACKEND_ZIP_STORAGE = Path("/app").joinpath(settings.BACKEND_ZIP_STORAGE)
+LOCAL_ZIP_STORAGE = Path("/").joinpath(settings.LOCAL_ZIP_STORAGE)
 
 SUPABASE_URL = "http://172.105.241.163:8000/"
 SUPABASE_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q"
 EDM_SECRET_KEY = "EdmSaasUserSecretKey"
 USER_TABLE="EDM_SAAS_USER"
+VIDEO_TABLE="EDM_SAAS_VIDEO"
 ALGORITHM = "HS256"
 
+LINE_URL = 'https://notify-api.line.me/api/notify'
+LINE_TOKEN = 'o8dqdVL2k8aiWO4jy3pawZamBu53bbjoSh2u0GJ7F0j'
+
 supabase: Client = create_client(SUPABASE_URL, SUPABASE_KEY)
 router = APIRouter()
+video_clients = {}
 
 class User(BaseModel):
     username: str
     password: str
 
 class UserInDB(BaseModel):
+    id: int
     username: str
     hashed_password: str
     token :Optional[str]
@@ -39,8 +57,17 @@ class UserInDB(BaseModel):
     point : Optional[int]
     recharge : Optional[int]
     
+class VideoInDB(BaseModel):
+    id:int
+    stored_filename:str
+    progress_state:str
+    created_datetime:str
+    length:Optional[int]
+    owner_id:int
+
+    
 pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
-oauth2_scheme = OAuth2PasswordBearer(tokenUrl="https://crm.choozmo.com/auth/token")
+oauth2_scheme = OAuth2PasswordBearer(tokenUrl="https://cmm.ai:10001/auth/token")
 
 async def get_user(username: str):
     user_table: str = USER_TABLE
@@ -53,7 +80,8 @@ async def get_user(username: str):
 
 @router.post("/zip2video")
 async def update_detect_info(
-    token: str = Depends(oauth2_scheme),
+    background_tasks: BackgroundTasks,
+    token: str ,
     title: str=Form(...), 
     anchor: str=Form(...),
     style: str=Form(...),
@@ -67,6 +95,170 @@ async def update_detect_info(
         headers={"WWW-Authenticate": "Bearer"},
     )
     try:
+        print(token)
+        payload = jwt.decode(token, EDM_SECRET_KEY, algorithms=[ALGORITHM])
+        username: str = payload.get("sub")
+        print(username)
+        if username is None:
+            raise credentials_exception
+    except JWTError:
+        raise credentials_exception
+
+    user = await get_user(username)
+    if user is None:
+        raise credentials_exception
+    
+    filename = datetime.now().strftime("VIDEO%Y%m%d%H%M%S")
+    filepath = str(Path(BACKEND_ZIP_STORAGE).joinpath(filename+".zip"))
+    try:
+        with open(filepath, 'wb') as f:
+            while contents := upload_file.file.read(1024 * 1024):
+                f.write(contents)
+    except Exception as e:
+        print(e, type(e))
+        error_msg = {"error_message": str(e)}
+        return JSONResponse(error_msg)
+    finally:
+        upload_file.file.close()
+    try:
+      if check_zip(filepath):
+        print("passed check_zip")
+    except VideoMakerError as e:
+      print(e)
+      error_msg = {"accepted": False, "error_message":f'{e}'}
+      return JSONResponse(error_msg)
+  
+    #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)
+    video = {"stored_filename":filename, "progress_state":"PENDING", "owner_id":user.id}
+    response = supabase.table(VIDEO_TABLE).insert(video).execute()
+    return_msg = {"video_message":"accepted", "accepted":True}
+    video_data = response.data[0]
+    video_data['membership_status'] = "infinite" ##
+    video_data['available_time'] = 0 ##
+    video_data['video_id'] = video_data['id']
+    video_data['character'] = anchor
+    video_data['anchor'] = anchor
+    video_data['style'] = style
+    video_data['lang'] = lang
+    background_tasks.add_task(wait_finish, video_data)
+    
+async def wait_finish(video_data:dict): 
+    zip_filename = video_data['stored_filename']+".zip"
+    process = await asyncio.create_subprocess_exec("sshpass", "-p", "choozmo9", 
+                    "scp", "-P", "5722", "-o", "StrictHostKeyChecking=no", f"{str(BACKEND_ZIP_STORAGE/zip_filename)}", f"root@172.104.93.163:{str(LOCAL_ZIP_STORAGE)}")
+    await process.wait()
+
+    task = celery_app.send_task("app.worker.make_video", kwargs=video_data)
+    while True:
+       await asyncio.sleep(1)
+       if task.state != "PENDING":
+           break
+       
+    video = supabase.table(VIDEO_TABLE).update({"progress_state":"STARTED"}).eq('id', video_data['id']).execute()
+    msg_data = f"{video_data['stored_filename']}:STARTED"
+    await publish(msg_data)
+    headers = {
+        'Authorization': 'Bearer ' + LINE_TOKEN    
+    }
+    data = {
+        'message':f'cloud-choozmo-com\n \
+                    Video\n \
+                    user: {video_data["owner_id"]}\n \
+                    membership: {video_data["membership_status"]}\n \
+                    video: {video_data["id"]}\n \
+                    state: start'     
+    }
+    data = requests.post(LINE_URL, headers=headers, data=data) 
+    while True:
+        await asyncio.sleep(1)
+        if task.state != "STARTED":
+            break
+
+    if task.state == "SUCCESS":
+        video = supabase.table(VIDEO_TABLE).update({"progress_state":"SUCCESS"}).eq('id', video_data['id']).execute()
+        if time := task.result:
+            # user.available_time -= int(time) if int(time) <= user.available_time else 0
+            # video.length = int(time)
+            pass
+        msg_data = f"{video_data['stored_filename']}:SUCCESS:{int(time)}"
+        headers = {
+            'Authorization': 'Bearer ' + LINE_TOKEN    
+        }
+        data = {
+            'message':f'cloud-choozmo-com\n \
+                        Video\n \
+                        user: {video_data["owner_id"]}\n \
+                        membership: {video_data["membership_status"]}\n \
+                        video: {video_data["id"]}\n \
+                        state: success'    
+        }
+        data = requests.post(LINE_URL, headers=headers, data=data) 
+
+    elif task.state == "FAILURE":
+        video = supabase.table(VIDEO_TABLE).update({"progress_state":"FAILURE"}).eq('id', video_data['id']).execute()
+        msg_data = f"{video_data['stored_filename']}:FAILURE"
+
+        headers = {
+            'Authorization': 'Bearer ' + LINE_TOKEN   
+        }
+        data = {
+            'message':f'cloud-choozmo-com\n \
+                        Video\n \
+                        user: {video_data["owner_id"]}\n \
+                        membership: {video_data["membership_status"]}\n \
+                        video: {video_data["id"]}\n \
+                        state: failure'     
+        }
+        data = requests.post(LINE_URL, headers=headers, data=data) 
+
+    await publish(msg_data)
+
+async def publish(data):
+    for video_client in video_clients.values():
+        await video_client.send_text(f"{data}")
+        
+@router.websocket("")
+async def websocket_endpoint(websocket: WebSocket):
+    await websocket.accept()
+    key = websocket.headers.get('sec-websocket-key')
+    video_clients[key] = websocket
+    try:
+        while True:
+            data = await websocket.receive_text()
+            if not data.startswith("subscribe"):
+              del video_clients[key]
+              #for client in sr_clients.values():
+              #      await client.send_text(f"ID: {key} | Message: {data}")
+
+    except:
+        # 接続が切れた場合、当該クライアントを削除する
+        del video_clients[key]
+    
+async def get_videos(user_id: int):
+    user_table: str = VIDEO_TABLE
+    response = supabase.table(user_table).select('*').eq('user_id', user_id).execute()
+    videos = response.data
+    if videos:
+        videos = [VideoInDB(**video) for video in videos]
+        return videos
+    return None
+    
+@router.get("/zip2video")
+async def get_video_list(
+    token: str ,
+) -> Any:
+    """
+    Retrieve items.
+    """
+    # 驗證身分
+    credentials_exception = HTTPException(
+        status_code=status.HTTP_401_UNAUTHORIZED,
+        detail="Could not validate credentials",
+        headers={"WWW-Authenticate": "Bearer"},
+    )
+    try:
+        print(token)
         payload = jwt.decode(token, EDM_SECRET_KEY, algorithms=[ALGORITHM])
         username: str = payload.get("sub")
         print(username)
@@ -79,7 +271,55 @@ async def update_detect_info(
     if user is None:
         raise credentials_exception
     
-    video_data = {"title":title, "anchor":anchor, "lang_id":lang}
-    print(video_data)
+    videos = get_videos(user_id=user.id)
+    
+    return videos
+
+@router.post('/zip-translate')
+def zip_translate(
+    *,
+    background_tasks: BackgroundTasks,
+    upload_file: UploadFile=File(),
+    lang:str):
+
+    try:
+        with open(upload_file.filename, 'wb') as f:
+            while contents := upload_file.file.read(1024 * 1024):
+                f.write(contents)
+    except Exception as e:
+        print(e, type(e))
+        error_msg = {"error_message": str(e)}
+        return JSONResponse(error_msg)
+    finally:
+        upload_file.file.close()
+    try:
+      if check_zip(upload_file.filename):
+        print("passed check_zip")
+    except VideoMakerError as e:
+      print(e)
+      error_msg = {"accepted": False, "error_message":f'{e}'}
+      return JSONResponse(error_msg)
+    path = Path(upload_file.filename)
+    local = None
+    if "-" in lang:
+        local = lang
+        lang = lang.split("-")[0]
+    gender = 'Female'
+    voices = asyncio.run(VoicesManager.create())
+    if local:
+        voice = voices.find(Gender=gender, Language=lang, Locale=local)
+        update_zip(str(path), local, str(path.parent/(path.stem+f"_{lang}"+path.suffix)), voice[0]['ShortName'])
+    else:
+        voice = voices.find(Gender=gender, Language=lang)
+        update_zip(str(path), lang, str(path.parent/(path.stem+f"_{lang}"+path.suffix)), voice[0]['ShortName'])
+
+    def remove_zip():
+            if os.path.exists(str(path.parent/(path.stem+"_"+lang+path.suffix))):
+                os.remove(str(path.parent/(path.stem+"_"+lang+path.suffix)))
+    background_tasks.add_task(remove_zip)
+    return FileResponse(str(path.parent/(path.stem+"_"+lang+path.suffix)), media_type="application/zip")
+
+
+