Pārlūkot izejas kodu

Merge branch 'master' of http://git.choozmo.com:3000/choozmo/AI_Anchor_2 into master

jeter20131220 3 gadi atpakaļ
vecāks
revīzija
131b306350
49 mainītis faili ar 2441 papildinājumiem un 484 dzēšanām
  1. BIN
      api/__pycache__/gSlide.cpython-39.pyc
  2. BIN
      api/__pycache__/mailer.cpython-39.pyc
  3. BIN
      api/__pycache__/main.cpython-36.pyc
  4. BIN
      api/__pycache__/main.cpython-39.pyc
  5. BIN
      api/__pycache__/models.cpython-39.pyc
  6. 124 69
      api/main.py
  7. 34 0
      api/role_test.py
  8. 2 2
      api/static/gen_avatar.js
  9. BIN
      api/static/img/checked.png
  10. 6 27
      api/static/script_util.js
  11. 718 0
      api/static/script_util_copy.js
  12. BIN
      api/util/__pycache__/models.cpython-36.pyc
  13. BIN
      api/util/__pycache__/models.cpython-39.pyc
  14. BIN
      api/util/__pycache__/swap_face.cpython-39.pyc
  15. BIN
      api/util/__pycache__/user.cpython-36.pyc
  16. BIN
      api/util/__pycache__/user.cpython-39.pyc
  17. 0 0
      api/util/models.py
  18. 80 10
      api/util/user.py
  19. 2 2
      html/index.html
  20. 5 8
      html/index_eng.html
  21. 8 27
      html/login.html
  22. 24 1
      html/login.js
  23. 51 20
      html/make_video.html
  24. 32 13
      html/make_video_long.html
  25. 31 10
      html/make_video_slide.html
  26. 47 4
      html/pricing.html
  27. 8 5
      html/register.html
  28. 40 20
      html/register.js
  29. 7 7
      html/reset_pwd.html
  30. 21 1
      html/reset_pwd.js
  31. 8 8
      html/reset_pwd_email.html
  32. 37 2
      html/reset_pwd_email.js
  33. 4 3
      html/script_eng.js
  34. 626 0
      html/script_long.js
  35. 157 34
      html/script_profiles.js
  36. BIN
      html/static/img/checked (2).png
  37. BIN
      html/static/img/nina灰.webp
  38. BIN
      html/static/img/nina黑.webp
  39. BIN
      html/static/img/summer韓小夏.webp
  40. BIN
      html/static/img/undraw_well_done_i2wr.png
  41. 20 4
      html/static/lan.js
  42. 79 7
      html/static/script_slides.js
  43. 169 41
      html/static/script_util.js
  44. 15 5
      html/static/scss/style.css
  45. 0 0
      html/static/scss/style.css.map
  46. 14 5
      html/static/scss/style.scss
  47. 0 132
      html/user_profile.html
  48. 16 17
      html/user_profile2.html
  49. 56 0
      html/verify_email.html

BIN
api/__pycache__/gSlide.cpython-39.pyc


BIN
api/__pycache__/mailer.cpython-39.pyc


BIN
api/__pycache__/main.cpython-36.pyc


BIN
api/__pycache__/main.cpython-39.pyc


BIN
api/__pycache__/models.cpython-39.pyc


+ 124 - 69
api/main.py

@@ -34,7 +34,7 @@ from jose import JWTError, jwt
 from fastapi_jwt_auth import AuthJWT
 from fastapi_jwt_auth.exceptions import AuthJWTException
 from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
-import models
+import util.models
 import pymysql
 import mailer
 from moviepy.editor import VideoFileClip
@@ -47,7 +47,8 @@ import util.user
 pymysql.install_as_MySQLdb()
 
 app = FastAPI()
-
+db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/AI_anchor?charset=utf8mb4')
+print("db loaded")
 mode = 'run'
 app.add_middleware(
     CORSMiddleware,
@@ -157,7 +158,7 @@ async def make_video_slide(request: Request, response: Response, Authorize: Auth
 
 @app.post('/user_profile', response_class=HTMLResponse)
 async def user_profile(token: str = Depends(oauth2_scheme)):
-    db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/AI_anchor?charset=utf8mb4')
+    db_check()
     user_id = get_user_id(token)
     user_obj = first(db.query('SELECT * FROM users where id ="'+str(user_id)+'"'))
 
@@ -180,8 +181,8 @@ async def user_profile(token: str = Depends(oauth2_scheme)):
     return str_return
 
 @app.post('/edit_profile')
-async def edit_profile(userModel : models.UserProfile ,token: str = Depends(oauth2_scheme)):
-    db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/AI_anchor?charset=utf8mb4')
+async def edit_profile(userModel : util.models.UserProfile ,token: str = Depends(oauth2_scheme)):
+    db_check()
     print(token)
     user_id = get_user_id(token)
     print(user_id)
@@ -197,7 +198,7 @@ async def get_login_and_register_page(request: Request):
 
 @app.post("/login")
 async def login_for_access_token(request: Request, form_data: OAuth2PasswordRequestForm = Depends(), Authorize: AuthJWT = Depends()):
-    db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/AI_anchor?charset=utf8mb4')
+    db_check()
     user = authenticate_user(form_data.username, form_data.password)
     if not user:
         raise HTTPException(
@@ -221,12 +222,14 @@ async def login_for_access_token(request: Request, form_data: OAuth2PasswordRequ
     if util.user.email_veri_pass(form_data.username):
         return {"access_token": access_token, "token_type": "bearer",'veri':'ok'}
     else:
+        veri_obj = first(db.query('SELECT * FROM register_veri_code where user_id ="'+str(user_dict['id'])+'"'))
+        mailer.register_verify('請至點擊網址驗證 : https://www.choozmo.com:8887/verify_email?code='+veri_obj['code'], user.email)
         return {"access_token": access_token, "token_type": "bearer",'veri':'fail'}
 
 
 @app.post("/token")
 async def access_token(form_data: OAuth2PasswordRequestForm = Depends(), Authorize: AuthJWT = Depends()):
-    db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/AI_anchor?charset=utf8mb4')
+     
     user = authenticate_user(form_data.username, form_data.password)
     if not user:
         raise HTTPException(
@@ -243,50 +246,73 @@ async def access_token(form_data: OAuth2PasswordRequestForm = Depends(), Authori
 #前後端分離完全實現後拔除
 @app.post("/register_old")
 async def register_old(request: Request):
-    db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/AI_anchor?charset=utf8mb4')
-    user = models.User(**await request.form())
+    db_check()
+    user = util.models.User(**await request.form())
     user_obj = first(db.query('SELECT * FROM users where username ="'+str(user.username)+'"'))
     if user_obj == None:
         id = user_register(user)
+        result = util.user.add_to_basic_role(id)
+        print(result)
         if type(id) is int:
             code = str(time.time()).replace('.','')
             db['register_veri_code'].insert({'code':code,'user_id':id})
             mailer.register_verify('請至點擊網址驗證 : https://www.choozmo.com:8887/verify_email?code='+code, user.email)
             return {'msg':{'eng':'Register success! Please login at previous page','zh':'註冊成功! 請回到上頁登入帳號'}}
         else :
-            return {'msg':'error'}
+            return {'msg':{'eng':'error','zh':'error'}}
         #return templates.TemplateResponse("make_video.html", {"request": request, "success": True},status_code=status.HTTP_302_FOUND)
         #return templates.TemplateResponse("login.html", {'request': request,"success": True}, status_code=status.HTTP_302_FOUND)
     else:
         return {'msg':{'eng':user.username+' is duplicated user name try another','zh':user.username+'重複,請更改'}}
 
 @app.post("/register")
-async def register(request: models.register_req):
-    db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/AI_anchor?charset=utf8mb4')
+async def register(request: util.models.register_req):
+    db_check()
     user_obj = first(db.query('SELECT * FROM users where username ="'+str(request.username)+'"'))
     
     if user_obj == None:
         id = user_register(request)
+        result = util.user.add_to_basic_role(id)
+        print(result)
         if type(id) is int:
             code = str(time.time()).replace('.','')
             db['register_veri_code'].insert({'code':code,'user_id':id})
             mailer.register_verify('請至點擊網址驗證 : https://www.choozmo.com:8887/verify_email?code='+code, request.email)
             return {'msg':{'eng':'Register success! Please login at previous page','zh':'註冊成功! 請回到上頁登入帳號'}}
         else :
-            return {'msg':'error'}
+            return {'msg':{'eng':'error','zh':'error'}}
     else:
         return {'msg':{'eng':user.username+' is duplicated user name try another','zh':user.username+'重複,請更改'}}
 
-
 @app.get('/logout')
 def logout(request: Request, Authorize: AuthJWT = Depends()):
     Authorize.jwt_required()
     Authorize.unset_jwt_cookies()
     return {"msg": "ok"}
 
+@app.post('/get_role')
+async def get_role(token: str = Depends(oauth2_scheme)):
+     
+    user_id = util.user.get_user_id(token)
+    roles = util.user.get_user_role(user_id)
+    return roles
+
+@app.post('/create_role')
+async def get_role(token: str = Depends(oauth2_scheme)):
+     
+    user_id = get_user_id(token)
+
+    return user_id
+
+@app.post('/get_avatar_by_role')
+async def get_role(token: str = Depends(oauth2_scheme)):
+    user_id = util.user.get_user_id(token)
+    avatar_info = util.user.get_avatar_by_role(user_id)
+    return avatar_info
+
 @app.get('/verify_email')
 async def verify_email(code):
-    db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/AI_anchor?charset=utf8mb4')
+    db_check()
     veri_obj = first(db.query('SELECT * FROM register_veri_code where code ="'+str(code)+'"'))
     if veri_obj != None:
         db['register_veri_code'].delete(code=code)
@@ -302,8 +328,9 @@ async def reset_pwd_page():
 
 @app.get('/send_reset_pwd')
 async def send_reset_pwd(user_id,email):
+    db_check()
     code = str(time.time()).replace('.','')
-    db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/AI_anchor?charset=utf8mb4')
+     
     db['reset_pw_code'].insert({'code':code,'user_id':user_id,'email':email})
     msg = '請至點擊網址以重設密碼 : https://www.choozmo.com:8887/reset_pwd_page    通行碼為 '+ code
     print(msg)
@@ -322,8 +349,8 @@ async def send_reset_pwd(user_id,email):
     return {'msg':'ok'}
 
 @app.post('/reset_pwd')
-async def reset_password(req :models.reset_pwd):
-    db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/AI_anchor?charset=utf8mb4')
+async def reset_password(req :util.models.reset_pwd):
+    db_check()
     print(req.code)
     veri_obj = next(iter(db.query('SELECT * FROM reset_pw_code where code ="'+str(req.code)+'"')))
     print(veri_obj['user_id'])
@@ -340,14 +367,14 @@ async def avatar():
     return FileResponse('static/gen_avatar.html')
 
 @app.post("/swapFace")
-async def swapFace(req:models.swap_req):
+async def swapFace(req:util.models.swap_req):
     if 'http' not in req.imgurl:
         req.imgurl= 'http://'+req.imgurl
     try:
         im = Image.open(requests.get(req.imgurl, stream=True).raw)
         im= im.convert("RGB")
     except:
-        return {'msg':"無法辨別圖片網址"+req.imgurl}
+        return {'msg':{'eng':req.imgurl+'cant be proccessed','zh':"無法辨別圖片網址"+req.imgurl}}
     name_hash = str(time.time()).replace('.','')
     
     x = threading.Thread(target=gen_avatar, args=(name_hash,req.imgurl))
@@ -371,13 +398,13 @@ async def create_upload_file(file: UploadFile = File(...)):
             return {"msg": resource_server+tmp_img_sub_folder+img_name+'.jpg'}
     except Exception as e:
         logging.error(traceback.format_exc())
-        return {'msg':'檔案無法使用'}
+        return {'msg':{'eng':'file cant be prossessed','zh':'檔案無法使用'}}
 
 @app.post("/upload_pttx/")
 async def upload_pttx(file: UploadFile = File(...)):
     try:
         if "_" in file.filename:
-            return {'msg':'檔案無法使用檔名不能含有"_"符號'}
+            return {'msg':{'eng':'symbol"_" is not allowed in file name','zh':'檔案無法使用檔名不能含有"_"符號'}}
         else:
             pttx_name = file.filename+'_'+str(time.time()).replace('.','')
             with open(pttx_dest+pttx_name, "wb+") as file_object:
@@ -385,18 +412,18 @@ async def upload_pttx(file: UploadFile = File(...)):
             return {"msg": resource_server+pttx_sub_folder+pttx_name}
     except Exception as e:
         logging.error(traceback.format_exc())
-        return {'msg':'檔案無法使用'}
+        return {'msg':{'eng':'file cant be prossessed','zh':'檔案無法使用'}}
 
 
 @app.post("/make_anchor_video_gSlide")
-async def make_anchor_video_gSlide(req:models.gSlide_req,token: str = Depends(oauth2_scheme)):
+async def make_anchor_video_gSlide(req:util.models.gSlide_req,token: str = Depends(oauth2_scheme)):
     if req.url_type == 0:
         name, text_content, image_urls = gSlide.parse_slide_url(req.slide_url,eng=False)
     else :
         filename = req.slide_url.replace(resource_server+pttx_sub_folder,resource_folder+pttx_sub_folder)
         name, text_content, image_urls = gSlide.parse_pttx_url(filename,img_upload_folder,resource_server+tmp_img_sub_folder,eng=False)
     if len(image_urls) != len(text_content):
-        return {'msg':'副標題數量、圖片(影片)數量以及台詞數量必須一致'}
+        return {'msg':{'eng':'number of subtitles and images(videos) should be the same','zh':'副標題數量、圖片(影片)數量以及台詞數量必須一致'}}
     for idx in range(len(image_urls)):
         if 'http' not in image_urls[idx]:
             image_urls[idx] = 'http://'+image_urls[idx]
@@ -404,10 +431,10 @@ async def make_anchor_video_gSlide(req:models.gSlide_req,token: str = Depends(oa
         for txt in text_content:
             if re.search('[a-zA-Z]', txt) !=None:
                 print('語言錯誤')
-                return {'msg':'輸入字串不能包含英文字!'}
+                return {'msg':{'eng':'English is not allowed in subtitles','zh':'輸入字串不能包含英文字!'}}
             if re.search(',', txt) !=None:
                 print('包含非法符號')
-                return {'msg':'輸入不能含有,符號'}
+                return {'msg':{'eng':'symbol "," is not allowede','zh':'輸入不能含有","符號'}}
     name_hash = str(time.time()).replace('.','')
     for imgu in image_urls:
         try:
@@ -417,9 +444,9 @@ async def make_anchor_video_gSlide(req:models.gSlide_req,token: str = Depends(oa
                 im = Image.open(requests.get(imgu, stream=True).raw)
                 im= im.convert("RGB")
         except:
-            return {'msg':"無法辨別圖片網址"+imgu}
+            return {'msg':{'eng':req.imgurl+'cant be proccessed','zh':"無法辨別圖片網址"+req.imgurl}}
     user_id = get_user_id(token)
-    proto_req = models.request_normal()
+    proto_req = util.models.request_normal()
     proto_req.text_content = text_content
     proto_req.name = name
     proto_req.image_urls = image_urls
@@ -428,13 +455,14 @@ async def make_anchor_video_gSlide(req:models.gSlide_req,token: str = Depends(oa
     video_id = save_history(proto_req,name_hash,user_id)
     x = threading.Thread(target=gen_video_queue, args=(name_hash,name, text_content, image_urls,int(req.avatar),req.multiLang,video_id,user_id))
     x.start()
-    return {"msg":"製作影片需要時間,請您耐心等候,成果會傳送至LINE群組中"} 
+    return {"msg":"ok"} 
 
 @app.post("/make_anchor_video_long")
-async def make_anchor_video_long(req:models.request,token: str = Depends(oauth2_scheme)):
+async def make_anchor_video_long(req:util.models.request,token: str = Depends(oauth2_scheme)):
+    db_check()
     left_tag = [m.start() for m in re.finditer('{', req.text_content[0])]
     if len(req.image_urls) != len(left_tag):
-        return {'msg':'副標題數量、圖片(影片)數量以及台詞數量必須一致'}
+        return {'msg':{'eng':'number of subtitles and images(videos) should be the same','zh':'副標題數量、圖片(影片)數量以及台詞數量必須一致'}}
     for idx in range(len(req.image_urls)):
         if 'http' not in req.image_urls[idx]:
             req.image_urls[idx] = 'http://'+req.image_urls[idx]
@@ -442,10 +470,10 @@ async def make_anchor_video_long(req:models.request,token: str = Depends(oauth2_
         for txt in req.text_content:
             if re.search('[a-zA-Z]', txt) !=None:
                 print('語言錯誤')
-                return {'msg':'輸入字串不能包含英文字!'}
+                return {'msg':{'eng':'English is not allowed in subtitles','zh':'輸入字串不能包含英文字!'}}
             if re.search(',', txt) !=None:
                 print('包含非法符號')
-                return {'msg':'輸入不能含有,符號'}
+                return {'msg':{'eng':'symbol "," is not allowede','zh':'輸入不能含有","符號'}}
     name_hash = str(time.time()).replace('.','')
     for imgu in req.image_urls:
         try:
@@ -455,17 +483,25 @@ async def make_anchor_video_long(req:models.request,token: str = Depends(oauth2_
                 im = Image.open(requests.get(imgu, stream=True).raw)
                 im= im.convert("RGB")
         except:
-            return {'msg':"無法辨別圖片網址"+imgu}
+            return {'msg':{'eng':req.imgurl+'cant be proccessed','zh':"無法辨別圖片網址"+req.imgurl}}
     user_id = get_user_id(token)
     video_id = save_history(req,name_hash,user_id)
     x = threading.Thread(target=gen_video_long_queue, args=(name_hash,req.name, req.text_content, req.image_urls,int(req.avatar),req.multiLang,video_id,user_id))
     x.start()
-    return {"msg":"ok"} 
+     
+    returnMsg = ''
+    if first(db.query('SELECT COUNT(1) FROM video_queue'))['COUNT(1)'] >= 3:
+        returnMsg =  {'msg':{'eng':'There are many videos have been processing, please wait.','zh':'目前有多部影片處理中,煩請耐心等候'}}
+    else:
+        returnMsg =  {'msg':{'eng':'Processing video requires a few minutes, please wait for notification','zh':'影片處理需要數分鐘,請等待通知'}}
+    return returnMsg
+
 
 @app.post("/make_anchor_video")
-async def make_anchor_video(req:models.request,token: str = Depends(oauth2_scheme)):
+async def make_anchor_video(req:util.models.request,token: str = Depends(oauth2_scheme)):
+    db_check()
     if len(req.image_urls) != len(req.text_content):
-        return {'msg':'副標題數量、圖片(影片)數量以及台詞數量必須一致'}
+        return {'msg':{'eng':'number of subtitles and images(videos) should be the same','zh':'副標題數量、圖片(影片)數量以及台詞數量必須一致'}}
     for idx in range(len(req.image_urls)):
         if 'http' not in req.image_urls[idx]:
             req.image_urls[idx] = 'http://'+req.image_urls[idx]
@@ -473,10 +509,10 @@ async def make_anchor_video(req:models.request,token: str = Depends(oauth2_schem
         for txt in req.text_content:
             if re.search('[a-zA-Z]', txt) !=None:
                 print('語言錯誤')
-                return {'msg':'輸入字串不能包含英文字!'}
+                return {'msg':{'eng':'English is not allowed in subtitles','zh':'輸入字串不能包含英文字!'}}
             if re.search(',', txt) !=None:
                 print('包含非法符號')
-                return {'msg':'輸入不能含有,符號'}
+                return {'msg':{'eng':'symbol "," is not allowede','zh':'輸入不能含有","符號'}}
     name_hash = str(time.time()).replace('.','')
     for imgu in req.image_urls:
         try:
@@ -486,17 +522,23 @@ async def make_anchor_video(req:models.request,token: str = Depends(oauth2_schem
                 im = Image.open(requests.get(imgu, stream=True).raw)
                 im= im.convert("RGB")
         except:
-            return {'msg':"無法辨別圖片網址"+imgu}
+            return {'msg':{'eng':req.imgurl+'cant be proccessed','zh':"無法辨別圖片網址"+req.imgurl}}
     user_id = get_user_id(token)
     video_id = save_history(req,name_hash,user_id)
     x = threading.Thread(target=gen_video_queue, args=(name_hash,req.name, req.text_content, req.image_urls,int(req.avatar),req.multiLang,video_id,user_id))
     x.start()
+     
+    if first(db.query('SELECT COUNT(1) FROM video_queue'))['COUNT(1)'] >= 3:
+        return {'msg':{'eng':'There are many videos have been processing, please wait.','zh':'目前有多部影片處理中,煩請耐心等候'}}
+    else:
+        return {'msg':{'eng':'Processing video requires a few minutes, please wait for notification','zh':'影片處理需要數分鐘,請等待通知'}}
     return {'msg':'ok'}
 
 @app.post("/make_anchor_video_eng")
-async def make_anchor_video_eng(req:models.request_eng,token: str = Depends(oauth2_scheme)):
+async def make_anchor_video_eng(req:util.models.request_eng,token: str = Depends(oauth2_scheme)):
+    db_check()
     if len(req.image_urls) != len(req.sub_titles) or len(req.sub_titles) != len(req.text_content):
-        return {'msg':'副標題數量、圖片(影片)數量以及台詞數量必須一致'}
+        return {'msg':{'eng':'number of subtitles and images(videos) should be the same','zh':'副標題數量、圖片(影片)數量以及台詞數量必須一致'}}
     for idx in range(len(req.image_urls)):
         if 'http' not in req.image_urls[idx]:
             req.image_urls[idx] = 'http://'+req.image_urls[idx]
@@ -509,16 +551,21 @@ async def make_anchor_video_eng(req:models.request_eng,token: str = Depends(oaut
                 im = Image.open(requests.get(imgu, stream=True).raw)
                 im= im.convert("RGB")
         except:
-            return {'msg':"無法辨別圖片網址"+imgu}
+            return {'msg':{'eng':req.imgurl+'cant be proccessed','zh':"無法辨別圖片網址"+req.imgurl}}
     user_id = get_user_id(token)
     video_id = save_history(req,name_hash, user_id)
     x = threading.Thread(target=gen_video_queue_eng, args=(name_hash,req.name, req.text_content, req.image_urls,req.sub_titles,int(req.avatar),video_id))
     x.start()
+     
+    if first(db.query('SELECT COUNT(1) FROM video_queue'))['COUNT(1)'] >= 3:
+        return {'msg':{'eng':'There are many videos have been processing, please wait.','zh':'目前有多部影片處理中,煩請耐心等候'}}
+    else:
+        return {'msg':{'eng':'Processing video requires a few minutes, please wait for notification','zh':'影片處理需要數分鐘,請等待通知'}}
     return {"msg":"ok"} 
 
 @app.post("/save_draft")
-async def save_draft(req:models.video_draft,token: str = Depends(oauth2_scheme)):
-    db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/AI_anchor?charset=utf8mb4')
+async def save_draft(req:util.models.video_draft,token: str = Depends(oauth2_scheme)):
+    db_check()
     user_id = get_user_id(token)
     
     txt_content_seperate_by_dot = ''
@@ -544,7 +591,7 @@ async def save_draft(req:models.video_draft,token: str = Depends(oauth2_scheme))
 
 @app.post('/draft_list')
 async def draft_list(token: str = Depends(oauth2_scheme)):
-    db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/AI_anchor?charset=utf8mb4')
+    db_check()
     user_id = get_user_id(token)
     statement = 'SELECT * FROM draft WHERE user_id='+str(user_id)+' ORDER BY time_stamp DESC LIMIT 50'
     logs = []
@@ -554,12 +601,12 @@ async def draft_list(token: str = Depends(oauth2_scheme)):
     return logs
 
 @app.post('/del_draft')
-async def del_draft(id_obj:models.id_obj,token: str = Depends(oauth2_scheme)):
-    db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/AI_anchor?charset=utf8mb4')
+async def del_draft(id_obj:util.models.id_obj,token: str = Depends(oauth2_scheme)):
+    db_check()
     user_id = get_user_id(token)
     statement = 'SELECT * FROM draft WHERE user_id="'+str(user_id)+'" and id ="'+str(id_obj.id)+'"'
     if first(db.query(statement)) is not None:
-        db['draft'].delete(id=id)
+        db['draft'].delete(id=id_obj.id)
     else:
         return {'msg':'wrong id'}
     
@@ -569,10 +616,11 @@ async def del_draft(id_obj:models.id_obj,token: str = Depends(oauth2_scheme)):
 
 @app.get("/history_input_old")
 async def history_input_old(request: Request, Authorize: AuthJWT = Depends()):
+    db_check()
     Authorize.jwt_required()
     current_user = Authorize.get_jwt_subject()
 
-    db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/AI_anchor?charset=utf8mb4')
+     
     user_id = first(db.query('SELECT * FROM users where username="' + current_user +'"'))['id']
     statement = 'SELECT * FROM history_input WHERE user_id="'+str(user_id)+'" ORDER BY timestamp DESC LIMIT 50'
 
@@ -584,21 +632,21 @@ async def history_input_old(request: Request, Authorize: AuthJWT = Depends()):
 
 @app.post("/history_input")
 async def history_input(token: str = Depends(oauth2_scheme)):
-    db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/AI_anchor?charset=utf8mb4')
+    db_check()
     user_id = get_user_id(token)
     user_obj = first(db.query('SELECT * FROM users where id ="'+str(user_id)+'"'))
     statement = 'SELECT * FROM history_input WHERE user_id="'+str(user_id)+'" ORDER BY timestamp DESC LIMIT 50'
 
     logs = []
     for row in db.query(statement):
-        logs.append({'id':row['id'],'name':row['name'],'text_content':row['text_content'].split(','),'link':row['link'],'image_urls':row['image_urls'].split(',')})
+        logs.append({'id':row['id'],'name':row['name'],'avatar':row['avatar'],'text_content':row['text_content'].split(','),'link':row['link'],'image_urls':row['image_urls'].split(',')})
     return logs
 
 
 
 @AuthJWT.load_config
 def get_config():
-    return models.Settings()
+    return util.models.Settings()
 
 @app.exception_handler(AuthJWTException)
 def authjwt_exception_handler(request: Request, exc: AuthJWTException):
@@ -608,7 +656,7 @@ def authjwt_exception_handler(request: Request, exc: AuthJWTException):
     )
 
 def get_user_id(token):
-    db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/AI_anchor?charset=utf8mb4')
+    db_check()
     credentials_exception = HTTPException(
         status_code=status.HTTP_401_UNAUTHORIZED,
         detail="Could not validate credentials",
@@ -619,7 +667,7 @@ def get_user_id(token):
         username: str = payload.get("sub")
         if username is None:
             raise credentials_exception
-        token_data = models.TokenData(username=username)
+        token_data = util.models.TokenData(username=username)
     except JWTError:
         raise credentials_exception
     user = get_user(username=token_data.username)
@@ -629,23 +677,23 @@ def get_user_id(token):
     return user_id
 
 def check_user_exists(username):
-    db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/AI_anchor?charset=utf8mb4')
+    db_check()
     if int(next(iter(db.query('SELECT COUNT(*) FROM AI_anchor.users WHERE username = "'+username+'"')))['COUNT(*)']) > 0:
         return True
     else:
         return False
 
 def get_user(username: str):
-    db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/AI_anchor?charset=utf8mb4')
+     
     if not check_user_exists(username):  # if user don't exist
         return False
     user_dict = next(
         iter(db.query('SELECT * FROM AI_anchor.users where username ="'+username+'"')))
-    user = models.User(**user_dict)
+    user = util.models.User(**user_dict)
     return user
     
 def user_register(user):
-    db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/AI_anchor?charset=utf8mb4')
+    db_check()
     table = db['users']
     user.password = get_password_hash(user.password)
     id = table.insert(dict(user))
@@ -656,11 +704,11 @@ def get_password_hash(password):
 def verify_password(plain_password, hashed_password):
     return pwd_context.verify(plain_password, hashed_password)
 def authenticate_user(username: str, password: str):
-    db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/AI_anchor?charset=utf8mb4')
+    db_check()
     if not check_user_exists(username):  # if user don't exist
         return False
     user_dict = next(iter(db.query('SELECT * FROM AI_anchor.users where username ="'+username+'"')))
-    user = models.User(**user_dict)
+    user = util.models.User(**user_dict)
     if not verify_password(password, user.password):
         return False
     return user
@@ -674,7 +722,7 @@ def create_access_token(data: dict, expires_delta):
     return encoded_jwt
 
 def save_history(req,name_hash,user_id):
-    db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/AI_anchor?charset=utf8mb4')
+    db_check()
     log_table = db['history_input']
     txt_content_seperate_by_dot = ''
     for txt in req.text_content:
@@ -687,7 +735,7 @@ def save_history(req,name_hash,user_id):
     time_stamp = datetime.fromtimestamp(time.time())
     time_stamp = time_stamp.strftime("%Y-%m-%d %H:%M:%S")
     pk = log_table.insert({'name':req.name,'text_content':txt_content_seperate_by_dot,'image_urls':img_urls_seperate_by_dot
-    ,'user_id':user_id,'link':'www.choozmo.com:8168/'+video_sub_folder+name_hash+'.mp4','timestamp':time_stamp})
+    ,'user_id':user_id,'link':'www.choozmo.com:8168/'+video_sub_folder+name_hash+'.mp4','avatar':req.avatar,'timestamp':time_stamp})
     return pk
     
 def get_url_type(url):
@@ -705,7 +753,7 @@ def notify_group(msg):
 
 
 def gen_video_long_queue(name_hash,name,text_content, image_urls,avatar,multiLang,video_id,user_id):
-    db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/AI_anchor?charset=utf8mb4')
+    db_check()
     time_stamp = datetime.fromtimestamp(time.time()).strftime("%Y-%m-%d %H:%M:%S")
     txt_content_seperate_by_dot = ''
     for txt in text_content:
@@ -763,7 +811,7 @@ def gen_video_long_queue(name_hash,name,text_content, image_urls,avatar,multiLan
         db['video_queue'].delete(id=top1['id'])
         db.query('UPDATE video_queue_status SET status = 0')
 def gen_video_queue(name_hash,name,text_content, image_urls,avatar,multiLang,video_id,user_id):
-    db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/AI_anchor?charset=utf8mb4')
+    db_check()
     time_stamp = datetime.fromtimestamp(time.time()).strftime("%Y-%m-%d %H:%M:%S")
     txt_content_seperate_by_dot = ''
     for txt in text_content:
@@ -822,7 +870,7 @@ def gen_video_queue(name_hash,name,text_content, image_urls,avatar,multiLang,vid
         db.query('UPDATE video_queue_status SET status = 0')
 
 def gen_video_queue_eng(name_hash,name,text_content, image_urls,sub_titles,avatar,video_id):
-    db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/AI_anchor?charset=utf8mb4')
+    db_check()
     time_stamp = datetime.fromtimestamp(time.time()).strftime("%Y-%m-%d %H:%M:%S")
     txt_content_seperate_by_dot = ''
     for txt in text_content:
@@ -861,7 +909,7 @@ def gen_video_queue_eng(name_hash,name,text_content, image_urls,sub_titles,avata
         db.query('UPDATE video_queue_status SET status = 0')
 
 def gen_avatar(name_hash, imgurl):
-    db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/AI_anchor?charset=utf8mb4')
+    db_check()
     db['avatar_queue'].insert({'name_hash':name_hash,'imgurl':imgurl})
     while True:
         statement = 'SELECT * FROM avatar_service_status'#only one row in this table, which is the id 1 one
@@ -917,7 +965,14 @@ async def make_voice(in_text:text_in):
     x = threading.Thread(target=call_voice, args=(in_text.text,))
     x.start()
     
-        
+def db_check():
+    global db
+    try:
+        db.tables
+    except:
+        print("database down")
+        db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/AI_anchor?charset=utf8mb4')
+
 
     
       

+ 34 - 0
api/role_test.py

@@ -0,0 +1,34 @@
+from fastapi import FastAPI,Cookie, Depends, Query, status,File, UploadFile,Request,Response,HTTPException
+import threading
+import rpyc
+import random
+import time
+import math
+import hashlib
+import re
+from fastapi.middleware.cors import CORSMiddleware
+import dataset
+from datetime import datetime, timedelta
+from util.swap_face import swap_face
+from fastapi.staticfiles import StaticFiles
+import io
+from first import first
+import models
+import pymysql
+import traceback
+import logging
+import util.user
+
+
+mode = 'run'
+app.add_middleware(
+    CORSMiddleware,
+    allow_origins=["*"],
+    allow_credentials=True,
+    allow_methods=["*"],
+    allow_headers=["*"],
+)
+
+pymysql.install_as_MySQLdb()
+
+app = FastAPI()

+ 2 - 2
api/static/gen_avatar.js

@@ -61,7 +61,7 @@ $(".next").click(function () {
   console.log(dataOBJ)
   //alert('資料已送出! 請耐心等候')
   $.ajax({
-    url: '192.168.1.106:8887/make_anchor_video_v2',
+    url: '/make_anchor_video_v2',
     //url: 'http://www.choozmo.com:8888/qqreq',
     dataType : 'json', // 預期從server接收的資料型態
     contentType : 'application/json; charset=utf-8', // 要送到server的資料型態
@@ -90,7 +90,7 @@ $(".gen_avatar").click(function () {
   console.log(dataOBJ)
   //alert('資料已送出! 請耐心等候')
   $.ajax({
-    url: '192.168.1.106:8887/swapFace',
+    url: '/swapFace',
     dataType: 'json', // 預期從server接收的資料型態
     contentType: 'application/json; charset=utf-8', // 要送到server的資料型態
     type: 'post',

BIN
api/static/img/checked.png


+ 6 - 27
api/static/script_util.js

@@ -5,10 +5,13 @@ var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
 });
 var myModal = new bootstrap.Modal(document.getElementById('history'), {
   keyboard: false
-})
+});
 var avatarModal = new bootstrap.Modal(document.getElementById('avatarmega'), {
   keyboard: false
-})
+});
+
+let lang = localStorage.getItem('lan');
+
 var modalImg = document.querySelector("#avatarmega .modal-img");
 var modalTitle = document.querySelector("#avatarmega .modal-title");
 var avatarSelector = document.getElementById("avatar");
@@ -480,28 +483,4 @@ function renderimgBlock(i) {
   imguploadlabel.textContent = '上傳檔案';
   imgInputs.appendChild(imguploadlabel);
   $('.img_uploader').on('change', prepareUpload);
-}
-
-
-$('.owl-carousel').owlCarousel({
-  loop: true,
-  margin: 10,
-  nav: false,
-  mouseDrag: true,
-  touchDrag: true,
-  smartSpeed: 1000,
-  autoplay: true,
-  autoplayTimeout: 8000,
-  autoplayHoverPause: false,
-  responsive: {
-    0: {
-      items: 1
-    },
-    600: {
-      items: 2
-    },
-    1000: {
-      items: 4
-    }
-  }
-})
+}

+ 718 - 0
api/static/script_util_copy.js

@@ -0,0 +1,718 @@
+checkRoute();
+
+let userBasics = JSON.parse(localStorage.getItem('user_profile')) || [];
+if(userBasics !== []){
+  $('.userName').html(`<h2 class="user-name text-white mt-4 fw-bold">Hi ${userBasics.user_info.userName}</h2>`);
+}
+
+function checkRoute() {
+  let jwt_token = get_jwt_token();
+  if(jwt_token == undefined) {
+    window.location.replace("login.html");
+  }
+  axios({
+    method: 'post',
+    url: 'https://www.choozmo.com:8887/user_profile',
+    headers: { 
+        'accept': 'text/html',
+        'Authorization': `Bearer ${jwt_token}`
+     }
+  }).then(res => {
+    console.log(res.data);
+    if(res.status !== 200) {
+      window.location.replace("login.html");
+    }
+    var userName='';
+    userName+=' <h2 class="user-name text-white mt-4 fw-bold">Hi '+res.data.user_info.userName+'</h2>';
+    $('.userName').html(userName);
+  }).catch(err => {
+    console.log(err);
+  });
+}
+
+const btnLoginPage = document.querySelector('.btn-login');
+const btnUserProfile = document.querySelector('.btn-userProfile');
+const btnLogout = document.querySelector('.btn-logout');
+function loginControl() {
+  btnLoginPage.style.display = 'none';
+  btnLogout.style.display = 'block';
+  btnUserProfile.style.display = 'block';
+}
+
+loginControl();
+
+var client_id = Date.now()
+var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
+var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
+  return new bootstrap.Tooltip(tooltipTriggerEl)
+});
+var myModal = new bootstrap.Modal(document.getElementById('history'), {
+  keyboard: false
+})
+var avatarModal = new bootstrap.Modal(document.getElementById('avatarmega'), {
+  keyboard: false
+})
+var modalImg = document.querySelector("#avatarmega .modal-img");
+var modalTitle = document.querySelector("#avatarmega .modal-title");
+var avatarSelector = document.getElementById("avatar");
+var card = document.getElementsByClassName('card');
+card = [...card];
+avatarSelector.addEventListener('change', avatarChange);
+avatarChange();
+
+function addCardListener() {
+  for (let i = 0; i < card.length; i++) {
+    card[i].addEventListener('click', openavatarModel);
+  }
+}
+
+addCardListener();
+
+function avatarChange() {
+  var value = avatarSelector.options[avatarSelector.selectedIndex].text;
+  $('.owl-carousel').trigger('to.owl.carousel', avatarSelector.selectedIndex);
+  for (let i = 0; i < card.length; i++) {
+    card[i].classList.remove('active');
+    if (card[i].dataset.avatar == value) {
+      card[i].classList.add('active');
+    }
+  }
+}
+
+function openavatarModel() {
+  console.log(this.dataset.img);
+  modalImg.setAttribute("src", `static/img/${this.dataset.img}.webp`);
+  modalTitle.textContent = `${this.dataset.avatar}`;
+  avatarModal.show();
+}
+
+$('input[type=file]').on('change', prepareUpload);
+function prepareUpload(event) {
+  files = event.target.files;
+  var data = new FormData();
+  //data.append('file', $('.img_up1').prop('files')[0]);
+  data.append('file', files[0]);
+  // append other variables to data if you want: data.append('field_name_x', field_value_x);
+  $(this).next().text('');
+  $(this).next().html('<img src="static/img/Spinner-1s-181px.gif">');
+  $.ajax({
+    type: 'POST',
+    processData: false, // important
+    contentType: false, // important
+    data: data,
+    url: 'https://www.choozmo.com:8887/uploadfile',
+    dataType: 'json',
+    success: function (jsonData) {
+      event.target.previousSibling.value = jsonData.msg;
+      console.log(event.target.previousSibling.value);
+      event.target.nextSibling.innerHTML = '';
+      event.target.nextSibling.textContent = '上傳檔案';
+      //console.log($(this).next());
+      //$(this).next().html('上傳檔案');
+      //$(this).next().text('上傳檔案');
+    },
+    error: function (error) {
+      event.target.nextSibling.innerHTML = '';
+      event.target.nextSibling.textContent = '上傳檔案';
+      alert('圖片錯誤');
+    }
+  });
+}
+const button = document.querySelector('.next');
+
+$(".next").click(function () {
+  button.setAttribute('disabled', '');
+  setTimeout(function () {
+    button.removeAttribute('disabled')
+  }, 4000);
+  avatar = $('.avatar').val();
+  name_title = $('.title_new').val();
+  txtARR = [];
+  imgARR = [];
+  var step;
+  let contentIdx = document.querySelectorAll(".txtsrc").length;
+  for (let i = 1; i < (contentIdx + 1); i++) {
+    if ($(`.txtsrc${i}`).val() != "") {
+      txtARR.push($(`.txtsrc${i}`).val())
+    }
+  }
+  let imgIdx = document.querySelectorAll(".imgsrc").length;
+  for (let i = 1; i < (imgIdx + 1); i++) {
+    if ($(`.imgsrc${i}`).val() != "") {
+      imgARR.push($(`.imgsrc${i}`).val())
+    }
+  }
+  multiLang = 0
+  if ($('#multiLang').prop("checked")) {multiLang = 1;}
+  dataOBJ = { "name": name_title, "text_content": txtARR, "image_urls": imgARR, "avatar": avatar,"multiLang":multiLang, "client_id": client_id }
+  objstr = JSON.stringify(dataOBJ);
+  console.log(dataOBJ)
+  jwt_token =  get_jwt_token()
+  var xhr = new XMLHttpRequest();
+  xhr.open("POST", "https://www.choozmo.com:8887/make_anchor_video");
+  xhr.setRequestHeader("accept", "application/json");
+  xhr.setRequestHeader("Authorization","Bearer "+jwt_token)
+  xhr.setRequestHeader("Content-Type", "application/json");
+  xhr.onreadystatechange = function () {
+    if (xhr.readyState === 4) {
+      responseOBJ = JSON.parse(xhr.responseText)
+      if (responseOBJ.msg=='ok')
+      {
+        Swal.fire({
+          title: "資料已送出",
+          icon: 'success',
+          text: '資料已傳送,請耐心等候',
+          confirmButtonColor: '#3085d6',
+        });
+      }
+      else{
+        Swal.fire({
+          title: "發生錯誤",
+          icon: 'error',
+          text: responseOBJ.msg,
+          confirmButtonColor: '#3085d6',
+        });
+      }
+      
+    }
+  };
+  var data = renderXHR_data(dataOBJ)
+  console.log(data)
+  result = xhr.send(objstr);
+});
+const buttonSend = document.querySelector('#sendBTN');
+$("#sendBTN").click(function () {
+  buttonSend.setAttribute('disabled', '');
+  setTimeout(function () {
+    buttonSend.removeAttribute('disabled')
+  }, 4000);
+  avatar = $('.avatar').val();
+  name_title = $('.title_new').val();
+  txtARR = [];
+  imgARR = [];
+  var step;
+  let contentIdx = document.querySelectorAll(".txtsrc").length;
+  for (let i = 1; i < (contentIdx + 1); i++) {
+    if ($(`.txtsrc${i}`).val() != "") {
+      txtARR.push($(`.txtsrc${i}`).val())
+    }
+  }
+  let imgIdx = document.querySelectorAll(".imgsrc").length;
+  for (let i = 1; i < (imgIdx + 1); i++) {
+    if ($(`.imgsrc${i}`).val() != "") {
+      imgARR.push($(`.imgsrc${i}`).val())
+    }
+  }
+  multiLang = 0
+  if ($('#multiLang').prop("checked")) {multiLang = 1;}
+  dataOBJ = { "name": name_title, "text_content": txtARR, "image_urls": imgARR, "avatar": avatar,"multiLang":multiLang, "client_id": client_id }
+  objstr = JSON.stringify(dataOBJ);
+  console.log(dataOBJ)
+  jwt_token =  get_jwt_token()
+  var xhr = new XMLHttpRequest();
+  xhr.open("POST", "https://www.choozmo.com:8887/make_anchor_video_long");
+  xhr.setRequestHeader("accept", "application/json");
+  xhr.setRequestHeader("Authorization","Bearer "+jwt_token)
+  xhr.setRequestHeader("Content-Type", "application/json");
+  xhr.onreadystatechange = function () {
+    if (xhr.readyState === 4) {
+      responseOBJ = JSON.parse(xhr.responseText)
+      if (responseOBJ.msg=='ok')
+      {
+        Swal.fire({
+          title: "資料已送出",
+          icon: 'success',
+          text: '資料已傳送,請耐心等候',
+          confirmButtonColor: '#3085d6',
+        });
+      }
+      else{
+        Swal.fire({
+          title: "發生錯誤",
+          icon: 'error',
+          text: responseOBJ.msg,
+          confirmButtonColor: '#3085d6',
+        });
+      }
+      
+    }
+  };
+  var data = renderXHR_data(dataOBJ)
+  console.log(data)
+  result = xhr.send(objstr);
+});
+
+const slide_button = document.querySelector('#send_slide');
+$("#send_slide").click(function () {
+  slide_button.setAttribute('disabled', '');
+  setTimeout(function () {
+    slide_button.removeAttribute('disabled')
+  }, 4000);
+  avatar = $('.avatar').val();
+  var step;
+  multiLang = 0
+  if ($('#multiLang').prop("checked")) {multiLang = 1;}
+  dataOBJ = {'slide_url':$('#slide_raw_url').val(),"avatar": avatar,"multiLang":multiLang, "client_id": client_id }
+  objstr = JSON.stringify(dataOBJ);
+  jwt_token =  get_jwt_token()
+  var xhr = new XMLHttpRequest();
+  xhr.open("POST", "https://www.choozmo.com:8887/make_anchor_video_gSlide");
+  xhr.setRequestHeader("accept", "application/json");
+  xhr.setRequestHeader("Authorization","Bearer "+jwt_token);
+  xhr.setRequestHeader("Content-Type", "application/json");
+  xhr.onreadystatechange = function () {
+    if (xhr.readyState === 4) {
+      Swal.fire({
+        title: "資料已送出",
+        icon: 'success',
+        text: '資料已傳送,請耐心等候',
+        confirmButtonColor: '#3085d6',
+      });
+    }
+  };
+  var data = renderXHR_data(dataOBJ)
+  console.log(data)
+  result = xhr.send(objstr);
+});
+
+$(".gen_avatar").click(function () {
+  dataOBJ = { "imgurl": $('.img_src').val() }
+  objstr = JSON.stringify(dataOBJ);
+  console.log(dataOBJ)
+  //alert('資料已送出! 請耐心等候')
+  $.ajax({
+    url: 'https://www.choozmo.com:8887/swapFace',
+    dataType: 'json', // 預期從server接收的資料型態
+    contentType: 'application/json; charset=utf-8', // 要送到server的資料型態
+    type: 'post',
+    data: objstr,
+    success: function (suc_data) {
+      alert(suc_data.msg)
+    },
+    //data:JSON.stringify({n1:"12",n2:"22"}),
+    error: function (error) {
+      console.error(error)
+    }
+  });
+});
+
+var loaded_data = ''
+function openNav() {
+  document.getElementById("mySidenav").style.width = "250px";
+  document.querySelector('.loader').style.display = "block";
+  let jwt_token = get_jwt_token();
+  axios({
+    method: 'post',
+    url: 'https://www.choozmo.com:8887/history_input',
+    headers: { 
+        'accept': 'application/json',
+        'Authorization': `Bearer ${jwt_token}`
+     }
+  }).then(res => {
+    console.log(res.data);
+    loaded_data = res.data;
+    for (var obj of loaded_data) {
+      var historyList = document.querySelector('.historyList');
+      var list = document.createElement('li');
+      list.id = obj.id;
+      // div-imgfr
+      var divImgfr = document.createElement('div');
+      divImgfr.classList.add('item_imgfr');
+      var img = document.createElement('img');
+      img.setAttribute('src', obj['image_urls'][0]);
+      divImgfr.appendChild(img);
+      // div-content
+      var contentBox = document.createElement('div');
+      contentBox.classList.add('content-box');
+      var boxTitle = document.createElement('p');
+      boxTitle.classList.add('box-title');
+      boxTitle.textContent = obj.name;
+      boxTitle.id = obj.id;
+      console.log(loaded_data);
+      boxTitle.setAttribute('onclick', `direct(${obj.id})`);
+
+      var boxLink = document.createElement('span');
+      boxLink.classList.add('box-link');
+      boxLink.setAttribute("data-url", obj.link);
+      boxLink.setAttribute('onclick', 'view()');
+      boxLink.innerHTML = '<i class="fas fa-play-circle me-1"></i>觀看影片';
+      contentBox.appendChild(boxTitle);
+      contentBox.appendChild(boxLink);
+      list.classList.add("historyList-item");
+      list.setAttribute('onclick', `direct(${obj.id})`);
+      list.appendChild(divImgfr);
+      list.appendChild(contentBox);
+      historyList.appendChild(list);
+    }
+    document.querySelector('.loader').style.display = "none";
+  
+  }).catch(err => {
+    console.log(err);
+  });
+}
+function closeNav() {
+  document.getElementById("mySidenav").style.width = "250px";
+}
+
+function view() {
+  event.stopPropagation();
+  console.log(event.target);
+  if (event.target.nodeName === 'I') {
+    return;
+  } else {
+    window.open(`http://${event.target.dataset.url}`, '_blank');
+  }
+}
+
+function renderXHR_data(jsonObj) {
+  XHRstring = ''
+  for (const [key, value] of Object.entries(jsonObj)) {
+    console.log(value)
+    if (typeof (value) == "object") {
+      XHRstring += (key+'=['+value.join(',')+']&')
+    }
+    else {
+      XHRstring += (key + '=' + value + '&')
+    }
+  }
+  XHRstring = XHRstring.substring(0, XHRstring.length - 1);
+  return XHRstring
+}
+
+function get_jwt_token(){
+  jwt_raw = document.cookie.split(';').filter(s=>s.includes('jwt_token'))[0];
+  if(!jwt_raw) {return}
+  return jwt_raw.split('=')[1];
+}
+
+function direct(id) {
+  location.href = `make_video.html?id=${id}`;
+}
+
+
+function load_data(tid, loaded_data, draft = false) {
+  if(!tid) {
+    return;
+  }
+  var title = document.getElementById("title");
+  var linker = document.getElementById("linker");
+  myModal.hide();
+  if(!draft) {
+    linker.setAttribute('href', `http://${loaded_data.find(item => item.id == tid).link}`)
+    linker.setAttribute('target', '_blank')
+    $("#linker").html(`http://${loaded_data.find(item => item.id == tid).link}`)
+    $("#linker").show();
+    $(".linker__box").show();
+  }
+  console.log(loaded_data);
+  let historyItem = loaded_data.filter(item => item.id == tid)[0];
+  console.log(historyItem.title);
+  if(draft) {
+    $(".title_new").val(historyItem.title);
+    $("#avatar").val(historyItem.avatar);
+  } else {
+    $(".title_new").val(loaded_data.find(item => item.id == tid).name);
+    //$("#avatar").val(historyItem.avatar);
+  }
+
+  let txtlength = historyItem.text_content.length;
+  let imglength = historyItem.image_urls.length;
+
+  subtitleInputs.innerHTML = '';
+  imgInputs.innerHTML = '';
+  for (let i = 0; i < txtlength; i++) {
+    var txtinput = document.createElement("input");
+    txtinput.setAttribute('type', 'text');
+    txtinput.setAttribute('name', `t${i + 1}`);
+    txtinput.value = historyItem.text_content[i];
+    txtinput.setAttribute('placeholder', `${i + 1}`);
+    txtinput.classList.add('txtsrc', `txtsrc${i + 1}`)
+    subtitleInputs.appendChild(txtinput);
+  }
+  for (let i = 0; i < imglength; i++) {
+    var imginput = document.createElement("input");
+    imginput.setAttribute('type', 'text');
+    imginput.setAttribute('name', `m${i + 1}`);
+    imginput.classList.add('imgsrc', `imgsrc${i + 1}`);
+    imginput.value = historyItem.image_urls[i];
+    imginput.setAttribute('placeholder', `${i + 1}`);
+    imgInputs.appendChild(imginput);
+
+    var imgupload = document.createElement("input");
+    imgupload.setAttribute('id', `img${i + 1}`);
+    imgupload.setAttribute('type', `file`);
+    imgupload.classList.add('img_uploader', 'img_up');
+    imgInputs.appendChild(imgupload);
+    var imguploadlabel = document.createElement("label");
+    imguploadlabel.setAttribute('for', `img${i + 1}`);
+    imguploadlabel.classList.add('upload-btn');
+    imguploadlabel.textContent = '上傳檔案';
+    imguploadlabel.setAttribute('set-lan', `html:upload_file`);
+    imgInputs.appendChild(imguploadlabel);
+  }
+   setTimeout(() => {
+    JsLoadingOverlay.hide();
+  }, 0);
+}
+
+getpathId();
+
+function getMode() {
+  let id = window.location.search.split('?').pop();
+  let mode = id.split('=')[0];
+  if(mode == 'draftid') {
+    JsLoadingOverlay.show({
+      "overlayBackgroundColor": "#FFFFFF",
+      "overlayOpacity": "0.9",
+      "spinnerIcon": "ball-circus",
+      "spinnerColor": "#B9DDF3",
+      "spinnerSize": "2x",
+      "overlayIDName": "overlay",
+      "spinnerIDName": "spinner",
+      "offsetX": 0,
+      "offsetY": 0,
+      "containerID": null,
+      "lockScroll": false,
+      "overlayZIndex": 9998,
+      "spinnerZIndex": 9999
+    });
+    getDraftData();
+  } else if(mode == 'id') {
+    JsLoadingOverlay.show({
+      "overlayBackgroundColor": "#FFFFFF",
+      "overlayOpacity": "0.9",
+      "spinnerIcon": "ball-circus",
+      "spinnerColor": "#B9DDF3",
+      "spinnerSize": "2x",
+      "overlayIDName": "overlay",
+      "spinnerIDName": "spinner",
+      "offsetX": 0,
+      "offsetY": 0,
+      "containerID": null,
+      "lockScroll": false,
+      "overlayZIndex": 9998,
+      "spinnerZIndex": 9999
+    });
+    getData();
+  }
+  return id.split('=')[1];
+  //load_data(id);
+}
+
+getMode();
+
+function getpathId(){
+  let id = window.location.search.split('?').pop();
+  return id.split('=')[1];
+}
+
+function getData() {
+  let jwt_token = get_jwt_token();
+  axios({
+    method: 'post',
+    url: 'https://www.choozmo.com:8887/history_input',
+    headers: { 
+        'accept': 'application/json',
+        'Authorization': `Bearer ${jwt_token}`
+     }
+  }).then(res => {
+    loaded_data = res.data;
+    console.log(loaded_data);
+    const id = getpathId();
+    load_data(id, loaded_data);
+  }).catch(err => {
+    console.log(err);
+  });
+} 
+
+var subtitleInputs = document.querySelector(".subtitle-inputs");
+var imgInputs = document.querySelector(".img-inputs");
+let length = 5;
+function initial() {
+  for (let i = 0; i < length; i++) {
+    rendertxtBlock(i + 1);
+    //renderimgBlock(i + 1);
+  }
+  console.log(document.querySelectorAll(".txtsrc").length + 1);
+}
+
+initial();
+
+var addbtn = document.querySelector(".add");
+var addimgbtn = document.querySelector(".addimg");
+
+addbtn.addEventListener('click', addtxtBlock);
+addimgbtn.addEventListener('click', addimgBlock);
+
+function addtxtBlock() {
+  let newIdx = document.querySelectorAll(".txtsrc").length + 1;
+  rendertxtBlock(newIdx);
+}
+
+function addimgBlock() {
+  let newimgIdx = document.querySelectorAll(".imgsrc").length + 1;
+  renderimgBlock(newimgIdx);
+}
+
+function rendertxtBlock(i) {
+  var txtinput = document.createElement("input");
+  txtinput.setAttribute('type', 'text');
+  txtinput.setAttribute('name', `t${i}`);
+  txtinput.value = "";
+  txtinput.setAttribute('placeholder', `${i}`);
+  txtinput.classList.add('txtsrc', `txtsrc${i}`)
+  subtitleInputs.appendChild(txtinput);
+}
+
+function renderimgBlock(i) {
+  var imginput = document.createElement("input");
+  imginput.setAttribute('type', 'text');
+  imginput.setAttribute('name', `m${i}`);
+  imginput.classList.add('imgsrc', `imgsrc${i}`);
+  imginput.value = "";
+  imginput.setAttribute('placeholder', `${i}`);
+  imgInputs.appendChild(imginput);
+
+  var imgupload = document.createElement("input");
+  imgupload.setAttribute('id', `img${i}`);
+  imgupload.setAttribute('type', `file`);
+  imgupload.classList.add('img_uploader', 'img_up');
+  imgInputs.appendChild(imgupload);
+  var imguploadlabel = document.createElement("label");
+  imguploadlabel.setAttribute('for', `img${i}`);
+  imguploadlabel.classList.add('upload-btn');
+  imguploadlabel.textContent = '上傳檔案';
+  imguploadlabel.setAttribute('set-lan', `html:upload_file`);
+  imgInputs.appendChild(imguploadlabel);
+  $('input[type=file]').on('change', prepareUpload);
+}
+
+
+$('.owl-carousel').owlCarousel({
+  loop: true,
+  margin: 10,
+  nav: false,
+  mouseDrag: true,
+  touchDrag: true,
+  smartSpeed: 1000,
+  autoplay: true,
+  autoplayTimeout: 8000,
+  autoplayHoverPause: false,
+  responsive: {
+    0: {
+      items: 1
+    },
+    600: {
+      items: 2
+    },
+    1000: {
+      items: 4
+    }
+  }
+});
+
+$('.draft-btn').click(() => {
+  $('.draft-btn').text('Loading...');
+  let jwt_token = get_jwt_token();
+  let avatar = $('.avatar').val();
+  let name_title = $('.title_new').val();
+  let txtARR = [];
+  let imgARR = [];
+  var step;
+  let contentIdx = document.querySelectorAll(".txtsrc").length;
+  for (let i = 1; i < (contentIdx + 1); i++) {
+    if ($(`.txtsrc${i}`).val() != "") {
+      txtARR.push($(`.txtsrc${i}`).val())
+    }
+  }
+  let imgIdx = document.querySelectorAll(".imgsrc").length;
+  for (let i = 1; i < (imgIdx + 1); i++) {
+    if ($(`.imgsrc${i}`).val() != "") {
+      imgARR.push($(`.imgsrc${i}`).val())
+    }
+  }
+  let multiLang = 0
+  if ($('#multiLang').prop("checked")) {multiLang = 1;}
+  let id = window.location.search.split('?').pop();
+  let mode = id.split('=')[0];
+  if(mode == 'draftid') {
+    id = Number(id.split('=')[1]);
+  } else {
+    id = -1;
+  }
+  let dataOBJ = { "id": id, "title": name_title, "text_content": txtARR, "image_urls": imgARR, "avatar": avatar,"multiLang":multiLang }
+  console.log(dataOBJ);
+  axios({
+    method: 'post',
+    url: 'https://www.choozmo.com:8887/save_draft',
+    headers: { 
+        'accept': 'application/json',
+        'Authorization': `Bearer ${jwt_token}`,
+        'Content-Type': 'application/json',
+     },
+    data: dataOBJ
+  }).then(res => {
+    console.log(res.data);
+    $('.draft-btn').text('存為草稿');
+    Swal.fire({
+      title: "儲存完成",
+      icon: 'success',
+      confirmButtonColor: '#3085d6',
+    }); 
+  }).catch(err => {
+    console.log(err);
+  });
+
+});
+
+function getDraftData() {
+  let token = get_jwt_token();
+  axios({
+    method: 'post',
+    url: 'https://www.choozmo.com:8887/draft_list',
+    headers: { 
+        'accept': 'application/json',
+        'Authorization': `Bearer ${token}`
+     }
+  }).then(res => {
+    console.log(res.data);
+    let result = [...res.data];
+    let id = getpathId();
+    load_data(id, result, true);
+  }).catch(err => {
+    console.log(err);
+  });
+
+}
+
+$(".copy").click(function(){
+  const copyStr = $(this).next().text();
+  copyToClipboard(copyStr);
+});
+
+const copyToClipboard = str => {
+  const el = document.createElement('textarea');
+  el.value = str;
+  el.setAttribute('readonly', '');
+  el.style.position = 'absolute';
+  el.style.left = '-9999px';
+  document.body.appendChild(el);
+  el.select();
+  document.execCommand('copy');
+  document.body.removeChild(el);
+  Swal.fire({
+    toast: true,
+    icon: 'success',
+    position: 'top-end',
+    title: 'Link copied!',
+    timerProgressBar: true,
+    showConfirmButton: false,
+    timer: 1000,
+    backdrop: false
+  })
+};
+
+$('.img-toggle').click(function(){
+  $('.img-box').toggle(100);
+})
+

BIN
api/util/__pycache__/models.cpython-36.pyc


BIN
api/util/__pycache__/models.cpython-39.pyc


BIN
api/util/__pycache__/swap_face.cpython-39.pyc


BIN
api/util/__pycache__/user.cpython-36.pyc


BIN
api/util/__pycache__/user.cpython-39.pyc


+ 0 - 0
api/models.py → api/util/models.py


+ 80 - 10
api/util/user.py

@@ -1,5 +1,16 @@
 import dataset
+from fastapi import FastAPI,Cookie, Depends, Query, status,File, UploadFile,Request,Response,HTTPException
 from first import first
+from jose import JWTError, jwt
+from fastapi_jwt_auth import AuthJWT
+from fastapi_jwt_auth.exceptions import AuthJWTException
+from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
+import util.models
+from passlib.context import CryptContext
+SECRET_KEY = "df2f77bd544240801a048bd4293afd8eeb7fff3cb7050e42c791db4b83ebadcd"
+ALGORITHM = "HS256"
+ACCESS_TOKEN_EXPIRE_DAYS = 5
+pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
 def get_user_id(token):
     db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/AI_anchor?charset=utf8mb4')
     credentials_exception = HTTPException(
@@ -12,20 +23,23 @@ def get_user_id(token):
         username: str = payload.get("sub")
         if username is None:
             raise credentials_exception
-        token_data = models.TokenData(username=username)
+        token_data = uitl.models.TokenData(username=username)
     except JWTError:
         raise credentials_exception
     user = get_user(username=token_data.username)
     if user is None:
         raise credentials_exception
     user_id = first(db.query('SELECT * FROM users where username="' + user.username+'"'))['id']
+    db.close()
     return user_id
 
 def check_user_exists( username):
     db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/AI_anchor?charset=utf8mb4')
     if int(next(iter(db.query('SELECT COUNT(*) FROM AI_anchor.users WHERE username = "'+username+'"')))['COUNT(*)']) > 0:
+        db.close()
         return True
     else:
+        db.close()
         return False
 
 def get_user( username: str):
@@ -34,7 +48,8 @@ def get_user( username: str):
         return False
     user_dict = next(
         iter(db.query('SELECT * FROM users where username ="'+username+'"')))
-    user = models.User(**user_dict)
+    user = util.models.User(**user_dict)
+    db.close()
     return user
     
 def user_register( user):
@@ -42,51 +57,106 @@ def user_register( user):
     table = db['users']
     user.password = get_password_hash(user.password)
     table.insert(dict(user))
+    db.close()
 
 def get_password_hash( password):
     return pwd_context.hash(password)
+
 def verify_password( plain_password, hashed_password):
     return pwd_context.verify(plain_password, hashed_password)
+
 def authenticate_user( username: str, password: str):
     db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/AI_anchor?charset=utf8mb4')
     if not check_user_exists(username):  # if user don't exist
+        db.close()
         return False
     user_dict = next(iter(db.query('SELECT * FROM AI_anchor.users where username ="'+username+'"')))
-    user = models.User(**user_dict)
+    user = util.models.User(**user_dict)
     if not verify_password(password, user.password):
+        db.close()
         return False
     return user
 
-def get_roles( username):
+def get_user_role(id):
     db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/AI_anchor?charset=utf8mb4')
     state = 'SELECT * FROM user_role '\
-    'INNER JOIN users on user_role.user_id= users.id'\
+    'INNER JOIN users on user_role.user_id= users.id '\
     'INNER JOIN role on user_role.role_id = role.id '\
-    'WHERE username=username'
+    'WHERE users.id='+str(id)
     role_list = []
-    for row in db.query(statement):
+    for row in db.query(state):
         role_list.append({'id':row['role_id'],'name':row['name']})
+    db.close()
+    return role_list
+
+def get_avatar_by_role(id):
+    db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/AI_anchor?charset=utf8mb4')
+    state = 'select role_avatar.role_id, avatar_id, avatar.name,num from role_avatar '\
+            'INNER JOIN '\
+            '(SELECT role_id FROM user_role '\
+            'INNER JOIN users on user_role.user_id= users.id '\
+            'INNER JOIN role on user_role.role_id = role.id '\
+            'WHERE users.id='+str(id)+') a '\
+            'on role_avatar.role_id = a.role_id '\
+            'INNER JOIN avatar on role_avatar.avatar_id = avatar.id;'
+    role_list = []
+    for row in db.query(state):
+        role_list.append({'role_id':row['role_id'],'avatar_id':row['avatar_id'],'name':row['name'],'num':row['num']})
+    db.close()
     return role_list
-    
 #def add_role( username,role_id):
     #db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/AI_anchor?charset=utf8mb4')
     #user_role_table = db['user_role']
     #user_role_table.insert({'user_id':,'role_id':role_id})
 
-def get_user_id( username):
+def add_to_basic_role(id):
     db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/AI_anchor?charset=utf8mb4')
-    return str(first(db.query('SELECT COUNT(*) FROM history_input WHERE user_id ='+str(user_obj['id'])))['COUNT(*)'])
+    state ='insert into user_role (user_id,role_id) values('+str(id)+',5) '
+    print(state)
+    code = 'ok'
+    try :
+        db.query(state)
+    except:
+        code = 'not ok'
+    return code
+
+def get_user_id(token):
+    db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/AI_anchor?charset=utf8mb4')
+    credentials_exception = HTTPException(
+        status_code=status.HTTP_401_UNAUTHORIZED,
+        detail="Could not validate credentials",
+        headers={"WWW-Authenticate": "Bearer"},
+    )
+    try:
+        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
+        username: str = payload.get("sub")
+        if username is None:
+            raise credentials_exception
+        token_data = util.models.TokenData(username=username)
+    except JWTError:
+        db.close()
+        raise credentials_exception
+    user = get_user(username=token_data.username)
+    if user is None:
+        db.close()
+        raise credentials_exception
+    user_id = first(db.query('SELECT * FROM users where username="' + user.username+'"'))['id']
+    db.close()
+    return user_id
     
 def get_id_by_email(email):
     db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/AI_anchor?charset=utf8mb4')
     user_dict = next(iter(db.query('SELECT * FROM users where email ="'+email+'"')))
+    db.close()
     return user_dict['id']
 
 def email_veri_pass(name):
     db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/AI_anchor?charset=utf8mb4')
     user_dict = next(iter(db.query('SELECT * FROM users where username ="'+name+'"')))
     user_obj = first(db.query('SELECT * FROM register_veri_code where user_id ="'+str(user_dict['id'])+'"'))
+    db.close()
     if user_obj == None:
         return True
     else:
         return False
+

+ 2 - 2
html/index.html

@@ -98,7 +98,7 @@
                             </ul>
                     </div>
                     <div class="col-12 col-lg-4">
-                        <a href="./pricing.html"><img style="width: 128px;" src="./static/img//transfer.png" alt=""></a>                    
+                        <a href="./pricing.html"><img style="width: 128px;" src="./static/img/transfer.png" alt=""></a>                    
                         <h2 set-lan="html:pricing_content">畫面素材支援: 圖檔 | 影檔 | 簡報</h2>
                         <ul class="price-text ms-1">
                             <li set-lan="html:index_li3_1">可上傳圖片或是影片作為背景</li>
@@ -109,7 +109,7 @@
              
                 <!-- <h1 class="mt-5 d-inline pe-5">$1200/7min</h1> -->
                 <p class="mt-5" set-lan="html:index_action">想要快速製作影音內容?立即註冊,開始創作!</p>
-                <a href="./pricing.html"><button class="get-started my-3" set-lan="html:pricing_checkout">立即查看</button></a>
+                <a href="./register.html"><button class="get-started my-3" set-lan="html:pricing_checkout">立即查看</button></a>
             </div>
         </div>
     </div>

+ 5 - 8
html/index_eng.html

@@ -31,13 +31,13 @@
         <div class="collapse navbar-collapse" id="navbarSupportedContent">
             <ul class="navbar-nav ms-auto mb-2 mb-lg-0">
                 <li class="nav-item">
-                    <a class="nav-link active" aria-current="page" href="pricing.html">Early Bird Plan</a>
+                    <a class="nav-link active" aria-current="page" href="pricing.html">Pricing</a>
                 </li>
                 <li class="nav-item">
                     <a class="nav-link active btn-login" aria-current="page" href="login.html">Login</a>
                 </li>
                 <li class="nav-item">
-                    <a class="nav-link btn-userProfile" aria-current="page" href="user_profile.html">User Profile</a>
+                    <a class="nav-link btn-userProfile" aria-current="page" href="user_profile2.html">User Profile</a>
                 </li>
                 <li class="nav-item">
                     <a class="nav-link btn-logout" aria-current="page">Log Out</a>
@@ -50,14 +50,13 @@
     <div id="mySidenav" class="sidenav">
       <!-- <a href="javascript:void(0)" class="closebtn" onclick="closeNav()">&times;</a> -->
       <div class="text-start mt-3">
-          <a href="index.html"><img class="img-fluid w-50 ps-1" src="./static/img/contactus/CMM_LOGO.png" alt=""></a>
           <h2 class="fw-bold ps-0" href="index.html"><a class="nav-link active ps-1" aria-current="page" href="index.html">AI Spokesgirl</a></h2>
       </div>
       <div class="userName"></div> 
-      <img class="user img-fluid rounded-circle" src="./static/img/contactus/man.jpg" alt="">
+      <img class="user img-fluid rounded-circle" src="./static/img/userprofile/userimg.png" alt="">
       <p class="text-white my-3 text-center">Create something today!</p>
       <div class="navbar-nav mb-2 mb-lg-0 px-3 pe-4">
-          <a class="nav-link btn-gocreate text-white col-6" aria-current="page" href="./make_video.html">Make <br>Videos</a>
+          <a class="nav-link btn-gocreate text-white col-6" aria-current="page" href="./index_eng.html">Make English<br>Videos</a>
           <a class="nav-link btn-gocreate text-white col-6" aria-current="page" href="./make_video_slide.html">Make Videos <br>By Slides</a>
       </div>
       <hr>
@@ -224,12 +223,10 @@
   <div class="modal" tabindex="-1"  id="avatarmega" aria-labelledby="history" aria-hidden="true">
     <div class="modal-dialog modal-dialog-centered">
       <div class="modal-content text-center">
-        <div class="modal-header">
-         
-        </div>
         <div class="modal-body">
           <img class="modal-img" src="" alt="">
           <h5 class="modal-title mt-2"></h5>
+          <button type="button" class="btn btn-secondary btn-dismiss" data-bs-dismiss="modal" set-lan="html:close">Close</button>
         </div>
       </div>
     </div>

+ 8 - 27
html/login.html

@@ -109,7 +109,7 @@
                 <div class="login-content">
                     <!-- 已登入 {% if success %} -->
                   <!-- 未登入 {% endif %} -->
-                    <h2 class="my-3 title">LOGIN</h2>
+                    <h2 class="my-3 title" set-lan="html:login">LOGIN</h2>
                     <div class="tab-content" id="myTabContent">
                         <div class="tab-pane fade p-lg-3 show active" id="login" role="tabpanel" aria-labelledby="login-tab">
                             
@@ -123,36 +123,17 @@
                                 </div>
                                 <div class="d-flex justify-content-center">
                                     <p set-lan="html:newHere">還沒有帳號?</p>
-                                    <a class="ms-1" set-lan="html:goRegister" href="register.html">註冊</a>
+                                    <a class="ms-2" set-lan="html:goRegister" href="register.html">註冊</a> 
+                                    <p class="mx-2"> / </p>
+                                    <a set-lan="html:forgotPsd" href="reset_pwd_email.html">忘記密碼</a>
                                 </div>
                                 <div class="d-flex justify-content-center">
-                                    <button id="btn_login" class="">Login</button>
+                                    <button id="btn_login" set-lan="html:login_link">立即登入</button>
                                 </div>
-                        </div>
-                        <!-- <div class="tab-pane fade p-lg-3" id="register" role="tabpanel" aria-labelledby="register-tab">
-                            <form>
-                                <div class="form-floating mb-3">
-                                    <input type="text" class="form-control" id="username" name="username" placeholder="User name" required>
-                                    <label for="username"><i class="fas fa-user me-2"></i>User name</label>
-                                </div>
-                                <div class="form-floating mb-3">
-                                    <input type="email" class="form-control" id="email" name="email" placeholder="name@example.com" required>
-                                    <label for="email"><i class="fas fa-envelope me-2"></i>Email address</label>
-                                </div>
-                                <div class="form-floating mb-3">
-                                    <input type="password" class="form-control" id="password" name="password"  placeholder="Password" required>
-                                    <label for="password"><i class="fas fa-lock me-2"></i>Password</label>
-                                </div>
-                                <div class="mb-3">
-                                    <input type="checkbox" id="privacy" name="privacy" checked required>
-                                    <label for="privacy"><a href="privacy.html" class="link_privacy" target="_blank" set-lan="html:privacy_term">同意隱私政策及使用條款</a></label>
+                                <div class="mt-3 d-flex justify-content-center">
+                                    
                                 </div>
-                                <div class="d-flex justify-content-center">
-                                    <button type="button" class="btn btn-primary align-items-center btn-register">Register</button>
-                                </div>
-        
-                            </form>
-                        </div> -->
+                        </div>
                     </div>
                 </div>
             </div>

+ 24 - 1
html/login.js

@@ -67,7 +67,30 @@ function login(){
         }
     };
     
-    var data = "grant_type=&username=" + $('#username').val() + "&password="+$('#password').val()+"&scope=&client_id=&client_secret=";
+    var username = $('#username').val();
+    var password = $('#password').val();
+
+    // 登入資料檢查
+    if (username == '' || password == '') {
+        let title = "登入失敗";
+        let text = "請先輸入您的帳號/密碼";
+
+        if (lang == 'en') { 
+            title = "Login Failed!";
+            text = "Please enter your username and password";
+        }
+
+        Swal.fire({
+            title: title,
+            icon: 'error',
+            text: text,
+            confirmButtonColor: '#3085d6',
+        });
+
+        return;
+    }
+
+    var data = "grant_type=&username=" + username + "&password="+password+"&scope=&client_id=&client_secret=";
     result = xhr.send(data);
     console.log(result);
 }

+ 51 - 20
html/make_video.html

@@ -80,19 +80,18 @@
             <div id="mySidenav" class="sidenav">
                 <!-- <a href="javascript:void(0)" class="closebtn" onclick="closeNav()">&times;</a> -->
                 <div class="text-start mt-3">
-                    <a href="index.html"><img class="img-fluid w-50 ps-1" src="./static/img/contactus/CMM_LOGO.png" alt=""></a>
                     <h2 class="fw-bold ps-0" href="index.html"><a class="nav-link active ps-1" aria-current="page" href="index.html">AI Spokesgirl</a></h2>
                 </div>
                 <div class="userName"></div> 
-                <img class="user img-fluid rounded-circle" src="./static/img/contactus/man.jpg" alt="">
+                <img class="user img-fluid rounded-circle" src="./static/img/userprofile/userimg.png" alt="">
                 <p class="text-white my-3 text-center" set-lan="html:Createsthtoday">今天要做甚麼影片呢?</p>
                 <div class="navbar-nav mb-2 mb-lg-0 px-3 pe-4">
-                    <a class="nav-link btn-gocreate text-white col-6" aria-current="page" href="./make_video.html" set-lan="html:make_video">影片製作</a>
-                    <a class="nav-link btn-gocreate text-white col-6" aria-current="page" href="./make_video_slide.html" set-lan="html:make_slides">投影影片製作</a>
+                    <a class="nav-link btn-gocreate text-white col-6 btn-makev" aria-current="page" href="./make_video.html" set-lan="html:make_video">影片製作</a>
+                    <a class="nav-link btn-gocreate text-white col-6 btn-makelong" aria-current="page" href="./make_video_long.html" set-lan="html:make_video_long">長影片製作</a>
                 </div>
                 <div class="navbar-nav mb-2 mb-lg-0 px-3 pe-4">
-                    <a class="nav-link btn-gocreate text-white col-6" aria-current="page" href="./index_eng.html" set-lan="html:make_video_eng">英文影片製作</a>
-                    <a class="nav-link btn-gocreate text-white col-6" aria-current="page" href="./make_video_long.html" set-lan="html:make_video_long">長影片製作</a>
+                    <a class="nav-link btn-gocreate text-white col-6 btn-makeppt" aria-current="page" href="./make_video_slide.html" set-lan="html:make_slides">投影片影片製作</a>
+                    <a class="nav-link btn-gocreate text-white col-6 btn-makeen" aria-current="page" href="./index_eng.html" set-lan="html:make_video_eng">純英文影片製作</a>
                 </div>
                 <hr>
                 <ul class="nav-list ps-0">
@@ -153,49 +152,49 @@
                             <option value="12">Jocelyn</option>
                             <option value="13">Angela</option>
                         </select>
-                        <div class="owl-carousel owl-theme">
-                            <div class="card item" data-avatar="Peggy" data-img="peggy">
+                        <div class="owl-carousel owl-theme d-flex row">
+                            <!-- <div class="card item col" data-avatar="Peggy" data-img="peggy">
                                 <div class="imgfr"><img src="static/img/peggy.webp" class="card-img-top" alt="..."></div>
                                 <div class="card-body">
                                     <h5 class="card-title">Peggy</h5>
                                 </div>
                             </div>
-                            <div class="card item" data-avatar="Stacy" data-img="stacy">
+                            <div class="card item col" data-avatar="Stacy" data-img="stacy">
                                 <div class="imgfr"><img src="static/img/stacy.webp" class="card-img-top" alt="..."></div>
                                 <div class="card-body">
                                     <h5 class="card-title">Stacy</h5>
                                 </div>
                             </div>
-                            <div class="card item" data-avatar="Nina黑" data-img="ninablack">
+                            <div class="card item col" data-avatar="Nina黑" data-img="ninablack">
                                 <div class="imgfr"><img src="static/img/ninablack.webp" class="card-img-top" alt="..."></div>
                                 <div class="card-body">
                                     <h5 class="card-title">Nina黑</h5>
                                 </div>
                             </div>
-                            <div class="card item" data-avatar="Nina灰" data-img="ninawhite">
+                            <div class="card item col" data-avatar="Nina灰" data-img="ninawhite">
                                 <div class="imgfr"><img src="static/img/ninawhite.webp" class="card-img-top" alt="..."></div>
                                 <div class="card-body">
                                     <h5 class="card-title">Nina灰</h5>
                                 </div>
                             </div>
-                            <div class="card item" data-avatar="Summer韓小夏" data-img="summer">
+                            <div class="card item col" data-avatar="Summer韓小夏" data-img="summer">
                                 <div class="imgfr"><img src="static/img/summer.webp" class="card-img-top" alt="..."></div>
                                 <div class="card-body">
                                     <h5 class="card-title">Summer韓小夏</h5>
                                 </div>
                             </div>
-                            <div class="card item" data-avatar="Jocelyn" data-img="Jocelyn">
+                            <div class="card item col" data-avatar="Jocelyn" data-img="Jocelyn">
                                 <div class="imgfr"><img src="static/img/Jocelyn.webp" class="card-img-top" alt="..."></div>
                                 <div class="card-body">
                                     <h5 class="card-title">Jocelyn</h5>
                                 </div>
                             </div>
-                            <div class="card item" data-avatar="Angela" data-img="Angela">
+                            <div class="card item col" data-avatar="Angela" data-img="Angela">
                                 <div class="imgfr"><img src="static/img/Angela.webp" class="card-img-top" alt="..."></div>
                                 <div class="card-body">
                                     <h5 class="card-title">Angela</h5>
                                 </div>
-                            </div>
+                            </div> -->
                         </div>
                     </fieldset>
                     <fieldset>
@@ -210,6 +209,15 @@
                     <fieldset id='imgSrc'>
                         <h3 class="fs-subtitle" style="display: inline-block;"><lan set-lan="html:img_link">影像連結</lan><img class="ms-1" src="static/img/question.png" alt="" data-bs-toggle="tooltip" data-bs-placement="right" title="僅接受png, jpg, mp4格式 Support File Formats: png, jpg, mp4"></h3><br/>
                         <div class="img-inputs">
+                            <!-- <div>
+                                <input type="text" name="t1" placeholder="1" class="txtsrc txtsrc1" style="width:calc(100% - 7rem);">
+                                <span class="img-toggle" style="width:6rem"><i class="fas fa-images"></i></span>
+                                <div class="img-box">
+                                    <input type="text" name="m1" class="imgsrc imgsrc1" placeholder="1">
+                                    <input id="img1" type="file" class="img_uploader img_up" style="display: none;">
+                                    <label for="img1" class="upload-btn" set-lan="html:upload_file">上傳檔案</label>
+                                </div>
+                            </div> -->
                         </div>
                         <span class="addimg">+</span>
                         <input id="checker" type="button" name="next" class="next action-button" set-lan="value:submit" value="送出" />
@@ -262,12 +270,10 @@
             <div class="modal" tabindex="-1"  id="avatarmega" aria-labelledby="history" aria-hidden="true">
                 <div class="modal-dialog modal-dialog-centered">
                     <div class="modal-content text-center">
-                        <div class="modal-header">
-                           
-                        </div>
                         <div class="modal-body">
                             <img class="modal-img" src="" alt="">
                             <h5 class="modal-title mt-2"></h5>
+                            <button type="button" class="btn btn-secondary btn-dismiss" data-bs-dismiss="modal" set-lan="html:close">Close</button>
                         </div>
                     </div>
                 </div>
@@ -281,7 +287,7 @@
     <!-- footer -->
     <footer class="fixed-bottom text-center py-2">
 
-    </footer>
+    </footer> 
     <!-- ================================================================= -->
   
     <script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script>
@@ -290,9 +296,34 @@
     <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/js/bootstrap.min.js" integrity="sha384-Atwg2Pkwv9vp0ygtn1JAojH0nYbwNJLPhwyoVbhoPwBhjQPR5VtM2+xf0Uwh9KtT" crossorigin="anonymous"></script> 
     <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11.0.18/dist/sweetalert2.all.min.js"></script>
     <script src="static/owl.carousel.min.js"></script>
-    <script src="static/script_util.js"></script>
+    <script src="static/loading-overlay.js"></script>
     <script type="text/javascript" src="static/lan.js"></script>
+    <script src="static/script_util.js"></script>
     <script src="static/common.js"></script>
+<script>
+$('.owl-carousel').owlCarousel({
+  loop: true,
+  margin: 10,
+  nav: false,
+  mouseDrag: true,
+  touchDrag: true,
+  smartSpeed: 1000,
+  autoplay: true,
+  autoplayTimeout: 8000,
+  autoplayHoverPause: false,
+  responsive: {
+    0: {
+      items: 1
+    },
+    600: {
+      items: 2
+    },
+    1000: {
+      items: 4
+    }
+  }
+});
+</script>
 </body>
 
 </html>

+ 32 - 13
html/make_video_long.html

@@ -80,19 +80,18 @@
             <div id="mySidenav" class="sidenav">
                 <!-- <a href="javascript:void(0)" class="closebtn" onclick="closeNav()">&times;</a> -->
                 <div class="text-start mt-3">
-                    <a href="index.html"><img class="img-fluid w-50 ps-1" src="./static/img/contactus/CMM_LOGO.png" alt=""></a>
                     <h2 class="fw-bold ps-0" href="index.html"><a class="nav-link active ps-1" aria-current="page" href="index.html">AI Spokesgirl</a></h2>
                 </div>
                 <div class="userName"></div>            
-                <img class="user img-fluid rounded-circle" src="./static/img/contactus/man.jpg" alt="">
+                <img class="user img-fluid rounded-circle" src="./static/img/userprofile/userimg.png" alt="">
                 <p class="text-white my-3 text-center" set-lan="html:Createsthtoday">今天要做甚麼影片呢?</p>
                 <div class="navbar-nav mb-2 mb-lg-0 px-3 pe-4">
-                    <a class="nav-link btn-gocreate text-white col-6" aria-current="page" href="./make_video.html" set-lan="html:make_video">影片製作</a>
-                    <a class="nav-link btn-gocreate text-white col-6" aria-current="page" href="./make_video_slide.html" set-lan="html:make_slides">投影片影片製作</a>
+                    <a class="nav-link btn-gocreate text-white col-6 btn-makev" aria-current="page" href="./make_video.html" set-lan="html:make_video">影片製作</a>
+                    <a class="nav-link btn-gocreate text-white col-6 btn-makelong" aria-current="page" href="./make_video_long.html" set-lan="html:make_video_long">長影片製作</a>
                 </div>
                 <div class="navbar-nav mb-2 mb-lg-0 px-3 pe-4">
-                    <a class="nav-link btn-gocreate text-white col-6" aria-current="page" href="./index_eng.html" set-lan="html:make_video_eng">英文影片製作</a>
-                    <a class="nav-link btn-gocreate text-white col-6" aria-current="page" href="./make_video_long.html" set-lan="html:make_video_long">長影片製作</a>
+                    <a class="nav-link btn-gocreate text-white col-6 btn-makeppt" aria-current="page" href="./make_video_slide.html" set-lan="html:make_slides">投影片影片製作</a>
+                    <a class="nav-link btn-gocreate text-white col-6 btn-makeen" aria-current="page" href="./index_eng.html" set-lan="html:make_video_eng">純英文影片製作</a>
                 </div>
                 <hr>
                 <ul class="nav-list ps-0">
@@ -202,10 +201,8 @@
                     <h3 class="fs-subtitle" set-lan="html:lines">台詞</h3>
                     <label for="myCheck" set-lan="html:add_eng">加入英文:</label> 
                     <input type="checkbox" id="multiLang" > <br/>
-                    <div class="subtitle-inputs">
+                    <textarea name="" id="" cols="100" rows="15" class="fs-txtarea"></textarea>
                     
-                    </div>
-                    <span class="add">+</span>
                 </fieldset>
                 <fieldset id='imgSrc'>
                     <h3 class="fs-subtitle" style="display: inline-block;"><lan set-lan="html:img_link">影像連結</lan><img class="ms-1" src="static/img/question.png" alt="" data-bs-toggle="tooltip" data-bs-placement="right" title="僅接受png, jpg, mp4格式"></h3><br/>
@@ -261,12 +258,10 @@
         <div class="modal" tabindex="-1"  id="avatarmega" aria-labelledby="history" aria-hidden="true">
             <div class="modal-dialog modal-dialog-centered">
                 <div class="modal-content text-center">
-                    <div class="modal-header">
-                    <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"><img src="static/img/close.svg" alt=""></button>
-                    </div>
                     <div class="modal-body">
                     <img class="modal-img" src="" alt="">
                     <h5 class="modal-title mt-2"></h5>
+                    <button type="button" class="btn btn-secondary btn-dismiss" data-bs-dismiss="modal" set-lan="html:close">Close</button>
                     </div>
                 </div>
                 </div>
@@ -289,9 +284,33 @@
     <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/js/bootstrap.min.js" integrity="sha384-Atwg2Pkwv9vp0ygtn1JAojH0nYbwNJLPhwyoVbhoPwBhjQPR5VtM2+xf0Uwh9KtT" crossorigin="anonymous"></script> 
     <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11.0.18/dist/sweetalert2.all.min.js"></script>
     <script src="static/owl.carousel.min.js"></script>
-    <script src="static/script_util.js"></script>
+    <script src="./script_long.js"></script>
     <script type="text/javascript" src="static/lan.js"></script>
     <script src="static/common.js"></script>
+<script>
+$('.owl-carousel').owlCarousel({
+    loop: true,
+    margin: 10,
+    nav: false,
+    mouseDrag: true,
+    touchDrag: true,
+    smartSpeed: 1000,
+    autoplay: true,
+    autoplayTimeout: 8000,
+    autoplayHoverPause: false,
+    responsive: {
+        0: {
+            items: 1
+        },
+        600: {
+            items: 2
+        },
+        1000: {
+            items: 4
+        }
+    }
+});
+</script>
 </body>
 
 </html>

+ 31 - 10
html/make_video_slide.html

@@ -80,19 +80,18 @@
             <div id="mySidenav" class="sidenav">
                 <!-- <a href="javascript:void(0)" class="closebtn" onclick="closeNav()">&times;</a> -->
                 <div class="text-start mt-3">
-                    <a href="index.html"><img class="img-fluid w-50 ps-1" src="./static/img/contactus/CMM_LOGO.png" alt=""></a>
                     <h2 class="fw-bold ps-0" href="index.html"><a class="nav-link active ps-1" aria-current="page" href="index.html">AI Spokesgirl</a></h2>
                 </div>
                 <div class="userName"></div> 
-                <img class="user img-fluid rounded-circle" src="./static/img/contactus/man.jpg" alt="">
+                <img class="user img-fluid rounded-circle" src="./static/img/userprofile/userimg.png" alt="">
                 <p class="text-white my-3 text-center" set-lan="html:Createsthtoday">今天要做甚麼影片呢?</p>
                 <div class="navbar-nav mb-2 mb-lg-0 px-3 pe-4">
-                    <a class="nav-link btn-gocreate text-white col-6" aria-current="page" href="./make_video.html" set-lan="html:make_video">影片製作</a>
-                    <a class="nav-link btn-gocreate text-white col-6" aria-current="page" href="./make_video_slide.html" set-lan="html:make_slides">投影片影片製作</a>
+                    <a class="nav-link btn-gocreate text-white col-6 btn-makev" aria-current="page" href="./make_video.html" set-lan="html:make_video">影片製作</a>
+                    <a class="nav-link btn-gocreate text-white col-6 btn-makelong" aria-current="page" href="./make_video_long.html" set-lan="html:make_video_long">長影片製作</a>
                 </div>
                 <div class="navbar-nav mb-2 mb-lg-0 px-3 pe-4">
-                    <a class="nav-link btn-gocreate text-white col-6" aria-current="page" href="./index_eng.html" set-lan="html:make_video_eng">英文影片製作</a>
-                    <a class="nav-link btn-gocreate text-white col-6" aria-current="page" href="./make_video_long.html" set-lan="html:make_video_long">長影片製作</a>
+                    <a class="nav-link btn-gocreate text-white col-6 btn-makeppt" aria-current="page" href="./make_video_slide.html" set-lan="html:make_slides">投影片影片製作</a>
+                    <a class="nav-link btn-gocreate text-white col-6 btn-makeen" aria-current="page" href="./index_eng.html" set-lan="html:make_video_eng">純英文影片製作</a>
                 </div>
                 <hr>
                 <ul class="nav-list ps-0">
@@ -154,7 +153,7 @@
                             <option value="12">Jocelyn</option>
                             <option value="12">Angela</option>
                         </select>
-                        <div class="owl-carousel owl-theme">
+                        <div class="owl-carousel owl-theme d-flex row">
                             <div class="card item" data-avatar="Peggy" data-img="peggy">
                                 <div class="imgfr"><img src="static/img/peggy.webp" class="card-img-top" alt="..."></div>
                                 <div class="card-body">
@@ -243,12 +242,10 @@
             <div class="modal" tabindex="-1"  id="avatarmega" aria-labelledby="history" aria-hidden="true">
                 <div class="modal-dialog modal-dialog-centered">
                     <div class="modal-content text-center">
-                        <div class="modal-header">
-                            <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"><img src="static/img/close.svg" alt=""></button>
-                        </div>
                         <div class="modal-body">
                             <img class="modal-img" src="" alt="">
                             <h5 class="modal-title mt-2"></h5>
+                            <button type="button" class="btn btn-secondary btn-dismiss" data-bs-dismiss="modal" set-lan="html:close">Close</button>
                         </div>
                     </div>
                 </div>
@@ -274,6 +271,30 @@
     <script src="static/script_slides.js"></script>
     <script type="text/javascript" src="static/lan.js"></script>
     <script src="static/common.js"></script>
+<script>
+$('.owl-carousel').owlCarousel({
+    loop: true,
+    margin: 10,
+    nav: false,
+    mouseDrag: true,
+    touchDrag: true,
+    smartSpeed: 1000,
+    autoplay: true,
+    autoplayTimeout: 8000,
+    autoplayHoverPause: false,
+    responsive: {
+        0: {
+            items: 1
+        },
+        600: {
+            items: 2
+        },
+        1000: {
+            items: 4
+        }
+    }
+});
+</script>
 </body>
 
 </html>

+ 47 - 4
html/pricing.html

@@ -51,14 +51,12 @@
                     <li class="nav-item">
                         <a class="nav-link active btn-login" aria-current="page" href="login.html" set-lan="html:login">登入</a>
                     </li>
-                    <!-- 
                     <li class="nav-item">
-                        <a class="nav-link btn-userProfile" aria-current="page" href="user_profile.html" set-lan="html:user_profile">會員資料</a>
+                        <a class="nav-link btn-userProfile" aria-current="page" href="user_profile2.html" set-lan="html:user_profile">會員資料</a>
                     </li>
                     <li class="nav-item">
                         <a class="nav-link btn-logout" aria-current="page" set-lan="html:logout">登出</a>
                     </li>
-                    -->
                 </ul>
             </div>
         </div>
@@ -103,7 +101,7 @@
                 <div class="col-4">
                     <div class="pricingTable">
                         <div class="pricingTable-header">
-                            <h3 class="title">早鳥方案</h3>
+                            <div class="title" set-lan="html:launch_special" style="font-size:2rem;">早鳥方案</div>
                         </div>
                         <ul class="pricing-content">
                             <li set-lan="html:pricing_lan">語言選擇: 中文 | 英文</li>
@@ -156,6 +154,51 @@
     <script src="static/owl.carousel.min.js"></script>
     <script type="text/javascript" src="static/lan.js"></script>
     <script src="static/common.js"></script>
+    <script>
+        const btnLoginPage = document.querySelector('.btn-login');
+        const btnUserProfile = document.querySelector('.btn-userProfile');
+        const btnLogout = document.querySelector('.btn-logout');
+        btnLoginPage.style.display = 'none';
+        btnLogout.style.display = 'none';
+        btnUserProfile.style.display = 'none';
+        function get_jwt_token(){
+            if(!document.cookie) {
+                return
+            }
+            jwt_raw = document.cookie.split(';').filter(s=>s.includes('jwt_token'))[0]
+            return jwt_raw.split('=')[1]
+        }
+        function checkRoute() {
+            let jwt_token = get_jwt_token();
+            if(jwt_token == undefined) {
+                btnLoginPage.style.display = 'block';
+                btnLogout.style.display = 'none';
+                btnUserProfile.style.display = 'none';
+                return;
+            }
+            axios({
+                method: 'post',
+                url: 'https://www.choozmo.com:8887/user_profile',
+                headers: { 
+                    'accept': 'text/html',
+                    'Authorization': `Bearer ${jwt_token}`
+                }
+            }).then(res => {
+                console.log(res.data);
+                if(res.status !== 200) {
+                    btnLoginPage.style.display = 'block';
+                    btnLogout.style.display = 'none';
+                    btnUserProfile.style.display = 'none';
+                }
+                btnLoginPage.style.display = 'none';
+                btnLogout.style.display = 'block';
+                btnUserProfile.style.display = 'block';
+            }).catch(err => {
+                console.log(err);
+            });
+        }
+        checkRoute();
+    </script>
 </body>
 
 </html>

+ 8 - 5
html/register.html

@@ -108,7 +108,7 @@
                 <div class="login-content">
                     <!-- 已登入 {% if success %} -->
                   <!-- 未登入 {% endif %} -->
-                    <h2 class="my-3 title">REGISTER</h2>
+                    <h2 class="my-3 title" set-lan="html:goRegister">REGISTER</h2>
                     <div class="tab-content" id="myTabContent">
                         <div class="tab-pane fade p-lg-3 show active" id="register" role="tabpanel" aria-labelledby="register-tab">
                             <form>
@@ -124,14 +124,17 @@
                                     <input type="password" class="form-control" id="password" name="password"  placeholder="Password" required>
                                     <label for="password"><i class="fas fa-lock me-2"></i>Password</label>
                                 </div>
-                                <div class="mb-3">
+                                <!-- <div class="mb-3">
                                     <input type="checkbox" id="privacy" name="privacy" checked required>
                                     <label for="privacy"><a href="privacy.html" class="link_privacy" target="_blank" set-lan="html:privacy_term">同意隱私政策及使用條款</a></label>
-                                </div>
+                                </div> -->
                                 <div class="d-flex justify-content-center">
-                                    <button type="button" class="btn btn-primary align-items-center btn-register">Register</button>
+                                    <p set-lan="html:oldHere">已經有帳號?</p>
+                                    <a class="ms-1" href="login.html" set-lan="html:login">登入</a>
+                                </div>
+                                <div class="mb-3 d-flex justify-content-center">
+                                    <button type="button" class="btn btn-primary align-items-center btn-register" set-lan="html:goRegister_link">立即註冊</button>
                                 </div>
-        
                             </form>
                         </div>
                     </div>

+ 40 - 20
html/register.js

@@ -23,7 +23,13 @@ function validateEmail(email) {
     if(re.test(String(email).toLowerCase()) === false) {
         $('#register [name = "email"]').addClass('error');
         if( !$('.error-text').length ) {
-            $('input.error').after('<p class="error-text" set-lan="html:errorEmail">請輸入正確E-mail</p>');
+            let msg = '請輸入正確E-mail';
+
+            if (lang == 'en') { 
+                msg = 'Please enter valid Email format.';
+            }
+
+            $('input.error').after('<p class="error-text" set-lan="html:errorEmail">' + msg + '</p>');
         } 
     } else {
         $('#register [name = "email"]').removeClass('error');
@@ -48,9 +54,30 @@ function validatePassword(psd) {
 }
 
 function register() {
-    const userName = $('#register [name = "username"]').val();
-    const email = $('#register [name = "email"]').val();
-    const password = $('#register [name = "password"]').val();
+    let userName = $('#register [name = "username"]').val();
+    let email = $('#register [name = "email"]').val();
+    let password = $('#register [name = "password"]').val();
+
+    // 註冊資料檢查
+    if (username == '' || password == '') {
+        let title = "註冊失敗";
+        let text = "請先輸入您的帳號/密碼";
+
+        if (lang == 'en') { 
+            title = "Login Failed!";
+            text = "Please enter your username and password";
+        }
+
+        Swal.fire({
+            title: title,
+            icon: 'error',
+            text: text,
+            confirmButtonColor: '#3085d6',
+        });
+
+        return;
+    }
+
     if(userName && validateEmail(email) && validatePassword(password)) {
         let userObj = {
             username: userName,
@@ -69,24 +96,17 @@ function register() {
             data: userObj
         }).then(res => {
             console.log(res.data.msg);
-            if(res.data.msg == 'ok') {
-                Swal.fire({
-                    title: "註冊成功",
-                    icon: 'success',
-                    text: res.data.msg,
-                    confirmButtonColor: '#3085d6',
-                });
-                window.setTimeout(() => {
-                    window.location.href = 'login.html';
-                }, 2000);
+            let text;
+            if (lang == 'en') { 
+                text = res.data.msg.eng;
             } else {
-                Swal.fire({
-                    title: "註冊失敗",
-                    icon: 'error',
-                    text: res.data.msg,
-                    confirmButtonColor: '#3085d6',
-                });
+                text = res.data.msg.zh;
             }
+            Swal.fire({
+                icon: 'info',
+                text: text,
+                confirmButtonColor: '#3085d6',
+            });
         }).catch(err => {
             console.log(err);
         })

+ 7 - 7
html/reset_pwd.html

@@ -62,16 +62,16 @@
           <h2 class="fw-bold ps-0" href="index.html"><a class="nav-link active ps-1" aria-current="page" href="index.html">AI Spokesgirl</a></h2>
       </div>
       <div class="userName"></div> 
-      <img class="user img-fluid rounded-circle" src="./static/img/contactus/man.jpg" alt="">
+      <img class="user img-fluid rounded-circle" src="./static/img/userprofile/userimg.png" alt="">
       <p class="text-white my-3 text-center" set-lan="html:Createsthtoday">今天要做甚麼影片呢?</p>
       <div class="navbar-nav mb-2 mb-lg-0 px-3 pe-4">
-          <a class="nav-link btn-gocreate text-white col-6" aria-current="page" href="./make_video.html" set-lan="html:make_video">影片製作</a>
-          <a class="nav-link btn-gocreate text-white col-6" aria-current="page" href="./make_video_slide.html" set-lan="html:make_slides">投影片影片製作</a>
-      </div>
+        <a class="nav-link btn-gocreate text-white col-6 btn-makev" aria-current="page" href="./make_video.html" set-lan="html:make_video">影片製作</a>
+        <a class="nav-link btn-gocreate text-white col-6 btn-makelong" aria-current="page" href="./make_video_long.html" set-lan="html:make_video_long">長影片製作</a>
+    </div>
       <div class="navbar-nav mb-2 mb-lg-0 px-3 pe-4">
-        <a class="nav-link btn-gocreate text-white col-6" aria-current="page" href="./index_eng.html" set-lan="html:make_video_eng">英文影片製作</a>
-        <a class="nav-link btn-gocreate text-white col-6" aria-current="page" href="./make_video_long.html" set-lan="html:make_video_long">長影片製作</a>
-        </div>
+        <a class="nav-link btn-gocreate text-white col-6 btn-makeppt" aria-current="page" href="./make_video_slide.html" set-lan="html:make_slides">投影片影片製作</a>
+        <a class="nav-link btn-gocreate text-white col-6 btn-makeen" aria-current="page" href="./index_eng.html" set-lan="html:make_video_eng">純英文影片製作</a>
+    </div>
       <hr>
       <ul class="nav-list ps-0">
           <li class="nav-list-item pb-1 mb-3" data-bs-toggle="modal" data-bs-target="#howto"><i

+ 21 - 1
html/reset_pwd.js

@@ -23,6 +23,25 @@ function renderXHR_data(jsonObj) {
    return XHRstring
  }
 
+ let lan = localStorage.getItem('lan');
+
+$('.dropdown-toggle').click(() => {
+  lan = localStorage.getItem('lan');
+  checkLan();
+});
+
+checkLan();
+
+function checkLan() {
+  if(lan == 'en') {
+    $('.btn-makev').css('display', 'none');
+    $('.btn-makelong').css('display', 'none');
+  } else {
+    $('.btn-makev').css('display', 'block');
+    $('.btn-makelong').css('display', 'block');
+  }
+}
+
 $(".sender").click(function () {
 
   var pwd = $("#in_pwd").val();
@@ -62,8 +81,9 @@ function openNav() {
   }).then(res => {
     console.log(res.data);
     loaded_data = res.data;
+    var historyList = document.querySelector('.historyList');
+    historyList.innerHTML = '';
     for (var obj of loaded_data) {
-      var historyList = document.querySelector('.historyList');
       var list = document.createElement('li');
       list.id = obj.id;
       // div-imgfr

+ 8 - 8
html/reset_pwd_email.html

@@ -62,16 +62,16 @@
           <h2 class="fw-bold ps-0" href="index.html"><a class="nav-link active ps-1" aria-current="page" href="index.html">AI Spokesgirl</a></h2>
       </div>
       <div class="userName"></div> 
-      <img class="user img-fluid rounded-circle" src="./static/img/contactus/man.jpg" alt="">
+      <img class="user img-fluid rounded-circle" src="./static/img/userprofile/userimg.png" alt="">
       <p class="text-white my-3 text-center" set-lan="html:Createsthtoday">今天要做甚麼影片呢?</p>
       <div class="navbar-nav mb-2 mb-lg-0 px-3 pe-4">
-          <a class="nav-link btn-gocreate text-white col-6" aria-current="page" href="./make_video.html" set-lan="html:make_video">影片製作</a>
-          <a class="nav-link btn-gocreate text-white col-6" aria-current="page" href="./make_video_slide.html" set-lan="html:make_slides">投影片影片製作</a>
-      </div>
+        <a class="nav-link btn-gocreate text-white col-6 btn-makev" aria-current="page" href="./make_video.html" set-lan="html:make_video">影片製作</a>
+        <a class="nav-link btn-gocreate text-white col-6 btn-makelong" aria-current="page" href="./make_video_long.html" set-lan="html:make_video_long">長影片製作</a>
+    </div>
       <div class="navbar-nav mb-2 mb-lg-0 px-3 pe-4">
-        <a class="nav-link btn-gocreate text-white col-6" aria-current="page" href="./index_eng.html" set-lan="html:make_video_eng">英文影片製作</a>
-        <a class="nav-link btn-gocreate text-white col-6" aria-current="page" href="./make_video_long.html" set-lan="html:make_video_long">長影片製作</a>
-        </div>
+        <a class="nav-link btn-gocreate text-white col-6 btn-makeppt" aria-current="page" href="./make_video_slide.html" set-lan="html:make_slides">投影片影片製作</a>
+        <a class="nav-link btn-gocreate text-white col-6 btn-makeen" aria-current="page" href="./index_eng.html" set-lan="html:make_video_eng">純英文影片製作</a>
+    </div>
       <hr>
       <ul class="nav-list ps-0">
           <li class="nav-list-item pb-1 mb-3" data-bs-toggle="modal" data-bs-target="#howto"><i
@@ -110,7 +110,7 @@
     <div class="content ms-auto">
       <form id="msform">
         <fieldset id='imgSrc'>
-          <h3 class="fs-subtitle" style="display: inline-block;">email</h3><br/>
+          <h3 class="fs-subtitle" style="display: inline-block;">Email</h3><br/>
           <input type="text" id='in_email' name='m1' class='imgsrc imgsrc1' value="" placeholder="" /><br/>
         
           <input id="checker" type="button" class="sender action-button" value="送出" set-lan="value:submit" />

+ 37 - 2
html/reset_pwd_email.js

@@ -10,6 +10,21 @@ function loginControl() {
 
 loginControl();
 
+function get_jwt_token(){
+  jwt_raw = document.cookie.split(';').filter(s=>s.includes('jwt_token'))[0];
+  if(!jwt_raw) {return}
+  return jwt_raw.split('=')[1];
+}
+
+function checkToken() {
+  let jwt_token = get_jwt_token();
+  if(jwt_token == undefined) {
+    window.location.replace("login.html");
+  }
+}
+
+checkToken();
+
 $(".sender").click(function () {
 
   var email = $("#in_email").val()
@@ -29,6 +44,25 @@ xhr.send();
 
 });
 
+let lan = localStorage.getItem('lan');
+
+$('.dropdown-toggle').click(() => {
+  lan = localStorage.getItem('lan');
+  checkLan();
+});
+
+checkLan();
+
+function checkLan() {
+  if(lan == 'en') {
+    $('.btn-makev').css('display', 'none');
+    $('.btn-makelong').css('display', 'none');
+  } else {
+    $('.btn-makev').css('display', 'block');
+    $('.btn-makelong').css('display', 'block');
+  }
+}
+
 var loaded_data = ''
 function openNav() {
   document.getElementById("mySidenav").style.width = "250px";
@@ -44,8 +78,9 @@ function openNav() {
   }).then(res => {
     console.log(res.data);
     loaded_data = res.data;
+    var historyList = document.querySelector('.historyList');
+    historyList.innerHTML = '';
     for (var obj of loaded_data) {
-      var historyList = document.querySelector('.historyList');
       var list = document.createElement('li');
       list.id = obj.id;
       // div-imgfr
@@ -95,4 +130,4 @@ function view() {
     } else {
       window.open(`http://${event.target.dataset.url}`, '_blank');
     }
-  }
+}

+ 4 - 3
html/script_eng.js

@@ -2,7 +2,7 @@ checkRoute();
 
 let userBasics = JSON.parse(localStorage.getItem('user_profile')) || [];
 if(userBasics !== []){
-  $('.userName').html(`<h2 class="user-name text-white mt-4 fw-bold">Hello,${userBasics.user_info.userName}</h2>`);
+  $('.userName').html(`<h2 class="user-name text-white mt-4 fw-bold">Hi ${userBasics.user_info.userName}</h2>`);
 }
 
 
@@ -24,7 +24,7 @@ function checkRoute() {
       window.location.replace("login.html");
     }
     var userName='';
-    userName+=' <h2 class="user-name text-white mt-4 fw-bold">Hello,'+res.data.user_info.userName+'</h2>';
+    userName+=' <h2 class="user-name text-white mt-4 fw-bold">Hi '+res.data.user_info.userName+'</h2>';
     $('.userName').html(userName);
   }).catch(err => {
     console.log(err);
@@ -205,8 +205,9 @@ function openNav() {
   }).then(res => {
     console.log(res.data);
     loaded_data = res.data;
+    var historyList = document.querySelector('.historyList');
+    historyList.innerHTML = '';
     for (var obj of loaded_data) {
-      var historyList = document.querySelector('.historyList');
       var list = document.createElement('li');
       list.id = obj.id;
       // div-imgfr

+ 626 - 0
html/script_long.js

@@ -0,0 +1,626 @@
+ checkRoute();
+
+let userBasics = JSON.parse(localStorage.getItem('user_profile')) || [];
+
+(function() {
+    if(userBasics !== []){
+        $('.userName').html(`<h2 class="user-name text-white mt-4 fw-bold">Hi ${userBasics.user_info.userName}</h2>`);
+    }
+})();
+
+
+function checkRoute() {
+  let jwt_token = get_jwt_token();
+  if(jwt_token == undefined) {
+    window.location.replace("login.html");
+  }
+  axios({
+    method: 'post',
+    url: 'https://www.choozmo.com:8887/user_profile',
+    headers: { 
+        'accept': 'text/html',
+        'Authorization': `Bearer ${jwt_token}`
+     }
+  }).then(res => {
+    console.log(res.data);
+    if(res.status !== 200) {
+      window.location.replace("login.html");
+    }
+    var userName='';
+    userName+=`<h2 class="user-name text-white mt-4 fw-bold">Hi ${res.data.user_info.userName}</h2>`;
+    $('.userName').html(userName);
+  }).catch(err => {
+    console.log(err);
+  });
+}
+
+const btnLoginPage = document.querySelector('.btn-login');
+const btnUserProfile = document.querySelector('.btn-userProfile');
+const btnLogout = document.querySelector('.btn-logout');
+function loginControl() {
+  btnLoginPage.style.display = 'none';
+  btnLogout.style.display = 'block';
+  btnUserProfile.style.display = 'block';
+}
+
+loginControl();
+
+let lan = localStorage.getItem('lan');
+
+$('.dropdown-toggle').click(() => {
+  lan = localStorage.getItem('lan');
+  checkLan();
+});
+
+checkLan();
+
+function checkLan() {
+  if(lan == 'en') {
+    $('.btn-makev').css('display', 'none');
+    $('.btn-makelong').css('display', 'none');
+  } else {
+    $('.btn-makev').css('display', 'block');
+    $('.btn-makelong').css('display', 'block');
+  }
+}
+
+var client_id = Date.now()
+var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
+var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
+  return new bootstrap.Tooltip(tooltipTriggerEl)
+});
+var myModal = new bootstrap.Modal(document.getElementById('history'), {
+  keyboard: false
+})
+var avatarModal = new bootstrap.Modal(document.getElementById('avatarmega'), {
+  keyboard: false
+})
+var modalImg = document.querySelector("#avatarmega .modal-img");
+var modalTitle = document.querySelector("#avatarmega .modal-title");
+var avatarSelector = document.getElementById("avatar");
+var card = document.getElementsByClassName('card');
+card = [...card];
+avatarSelector.addEventListener('change', avatarChange);
+avatarChange();
+
+function addCardListener() {
+  for (let i = 0; i < card.length; i++) {
+    card[i].addEventListener('click', openavatarModel);
+  }
+}
+
+addCardListener();
+
+function avatarChange() {
+  var value = avatarSelector.options[avatarSelector.selectedIndex].text;
+  $('.owl-carousel').trigger('to.owl.carousel', avatarSelector.selectedIndex);
+  for (let i = 0; i < card.length; i++) {
+    card[i].classList.remove('active');
+    if (card[i].dataset.avatar == value) {
+      card[i].classList.add('active');
+    }
+  }
+}
+
+function openavatarModel() {
+  console.log(this.dataset.img);
+  modalImg.setAttribute("src", `static/img/${this.dataset.img}.webp`);
+  modalTitle.textContent = `${this.dataset.avatar}`;
+  avatarModal.show();
+}
+
+$('input[type=file]').on('change', prepareUpload);
+function prepareUpload(event) {
+  files = event.target.files;
+  var data = new FormData();
+  //data.append('file', $('.img_up1').prop('files')[0]);
+  data.append('file', files[0]);
+  // append other variables to data if you want: data.append('field_name_x', field_value_x);
+  $(this).next().text('');
+  $(this).next().html('<img src="static/img/Spinner-1s-181px.gif">');
+  $.ajax({
+    type: 'POST',
+    processData: false, // important
+    contentType: false, // important
+    data: data,
+    url: 'https://www.choozmo.com:8887/uploadfile',
+    dataType: 'json',
+    success: function (jsonData) {
+      event.target.previousSibling.value = jsonData.msg;
+      $(this).prev().val(jsonData.msg);
+      event.target.nextSibling.innerHTML = '';
+      event.target.nextSibling.textContent = '上傳檔案';
+      //console.log($(this).next());
+      //$(this).next().html('上傳檔案');
+      //$(this).next().text('上傳檔案');
+    },
+    error: function (error) {
+      event.target.nextSibling.innerHTML = '';
+      event.target.nextSibling.textContent = '上傳檔案';
+      alert('圖片錯誤');
+    }
+  });
+}
+const button = document.querySelector('.next');
+
+const buttonSend = document.querySelector('#sendBTN');
+$("#sendBTN").click(function () {
+  buttonSend.setAttribute('disabled', '');
+  setTimeout(function () {
+    buttonSend.removeAttribute('disabled')
+  }, 4000);
+  avatar = $('.avatar').val();
+  name_title = $('.title_new').val();
+  imgARR = [];
+  txtARR = [];
+  var step;
+  txtARR.push($('.fs-txtarea').val());
+  let imgIdx = document.querySelectorAll(".imgsrc").length;
+  for (let i = 1; i < (imgIdx + 1); i++) {
+    if ($(`.imgsrc${i}`).val() != "") {
+      imgARR.push($(`.imgsrc${i}`).val())
+    }
+  }
+  multiLang = 0
+  if ($('#multiLang').prop("checked")) {multiLang = 1;}
+  dataOBJ = { "name": name_title, "text_content": txtARR, "image_urls": imgARR, "avatar": avatar,"multiLang":multiLang, "client_id": client_id }
+  objstr = JSON.stringify(dataOBJ);
+  console.log(dataOBJ)
+  jwt_token =  get_jwt_token()
+  var xhr = new XMLHttpRequest();
+  xhr.open("POST", "https://www.choozmo.com:8887/make_anchor_video_long");
+  xhr.setRequestHeader("accept", "application/json");
+  xhr.setRequestHeader("Authorization","Bearer "+jwt_token)
+  xhr.setRequestHeader("Content-Type", "application/json");
+  xhr.onreadystatechange = function () {
+    if (xhr.readyState === 4) {
+      responseOBJ = JSON.parse(xhr.responseText)
+      if (responseOBJ.msg=='ok'){
+        let title = "資料已送出";
+        let text = '資料已傳送,請耐心等候';
+        if (lan == 'en') { // 英文版訊息
+          title = "Submitted Successfully!";
+          text = 'We are working on your video. You will get notfication in line group when your video is done.';
+        }
+        Swal.fire({
+          title: title,
+          icon: 'success',
+          text: text,
+          confirmButtonColor: '#3085d6',
+        });
+      } else {
+        let title = '發生錯誤';
+        let text;
+        if(lan == 'en') {
+          title = 'Error';
+          text = responseOBJ.msg.eng;
+        } else {
+          text = responseOBJ.msg.zh;
+        }
+        Swal.fire({
+          title: title,
+          icon: 'error',
+          text: text,
+          confirmButtonColor: '#3085d6',
+        });
+      }
+      
+    }
+  };
+  var data = renderXHR_data(dataOBJ)
+  console.log(data)
+  result = xhr.send(objstr);
+});
+
+
+var loaded_data = ''
+function openNav() {
+  document.getElementById("mySidenav").style.width = "250px";
+  document.querySelector('.loader').style.display = "block";
+  let jwt_token = get_jwt_token();
+  axios({
+    method: 'post',
+    url: 'https://www.choozmo.com:8887/history_input',
+    headers: { 
+        'accept': 'application/json',
+        'Authorization': `Bearer ${jwt_token}`
+     }
+  }).then(res => {
+    console.log(res.data);
+    loaded_data = res.data;
+    var historyList = document.querySelector('.historyList');
+    historyList.innerHTML = '';
+    for (var obj of loaded_data) {
+      var list = document.createElement('li');
+      list.id = obj.id;
+      // div-imgfr
+      var divImgfr = document.createElement('div');
+      divImgfr.classList.add('item_imgfr');
+      var img = document.createElement('img');
+      img.setAttribute('src', obj['image_urls'][0]);
+      divImgfr.appendChild(img);
+      // div-content
+      var contentBox = document.createElement('div');
+      contentBox.classList.add('content-box');
+      var boxTitle = document.createElement('p');
+      boxTitle.classList.add('box-title');
+      boxTitle.textContent = obj.name;
+      boxTitle.id = obj.id;
+      console.log(loaded_data);
+      boxTitle.setAttribute('onclick', `direct(${obj.id})`);
+
+      var boxLink = document.createElement('span');
+      boxLink.classList.add('box-link');
+      boxLink.setAttribute("data-url", obj.link);
+      boxLink.setAttribute('onclick', 'view()');
+      boxLink.innerHTML = '<i class="fas fa-play-circle me-1"></i>觀看影片';
+      contentBox.appendChild(boxTitle);
+      contentBox.appendChild(boxLink);
+      list.classList.add("historyList-item");
+      list.setAttribute('onclick', `direct(${obj.id})`);
+      list.appendChild(divImgfr);
+      list.appendChild(contentBox);
+      historyList.appendChild(list);
+    }
+    document.querySelector('.loader').style.display = "none";
+  
+  }).catch(err => {
+    console.log(err);
+  });
+}
+function closeNav() {
+  document.getElementById("mySidenav").style.width = "250px";
+}
+
+function view() {
+  event.stopPropagation();
+  console.log(event.target);
+  if (event.target.nodeName === 'I') {
+    return;
+  } else {
+    window.open(`http://${event.target.dataset.url}`, '_blank');
+  }
+}
+
+function renderXHR_data(jsonObj) {
+  XHRstring = ''
+  for (const [key, value] of Object.entries(jsonObj)) {
+    console.log(value)
+    if (typeof (value) == "object") {
+      XHRstring += (key+'=['+value.join(',')+']&')
+    }
+    else {
+      XHRstring += (key + '=' + value + '&')
+    }
+  }
+  XHRstring = XHRstring.substring(0, XHRstring.length - 1);
+  return XHRstring
+}
+
+function get_jwt_token(){
+  jwt_raw = document.cookie.split(';').filter(s=>s.includes('jwt_token'))[0];
+  if(!jwt_raw) {return}
+  return jwt_raw.split('=')[1];
+}
+
+function direct(id) {
+  location.href = `make_video.html?id=${id}`;
+}
+
+
+function load_data(tid, loaded_data, draft = false) {
+  if(!tid) {
+    return;
+  }
+  var title = document.getElementById("title");
+  var linker = document.getElementById("linker");
+  myModal.hide();
+  if(!draft) {
+    linker.setAttribute('href', `http://${loaded_data.find(item => item.id == tid).link}`)
+    linker.setAttribute('target', '_blank')
+    $("#linker").html(`http://${loaded_data.find(item => item.id == tid).link}`)
+    $("#linker").show();
+    $(".linker__box").show();
+  }
+  console.log(loaded_data);
+  let historyItem = loaded_data.filter(item => item.id == tid)[0];
+  console.log(historyItem.title);
+  if(draft) {
+    $(".title_new").val(historyItem.title);
+    $("#avatar").val(historyItem.avatar);
+  } else {
+    $(".title_new").val(loaded_data.find(item => item.id == tid).name);
+    $("#avatar").val(historyItem.avatar);
+  }
+
+  let txtlength = historyItem.text_content.length;
+  let imglength = historyItem.image_urls.length;
+
+  //subtitleInputs.innerHTML = '';
+  imgInputs.innerHTML = '';
+  
+  for (let i = 0; i < imglength; i++) {
+    var imginput = document.createElement("input");
+    imginput.setAttribute('type', 'text');
+    imginput.setAttribute('name', `m${i + 1}`);
+    imginput.classList.add('imgsrc', `imgsrc${i + 1}`);
+    imginput.value = historyItem.image_urls[i];
+    imginput.setAttribute('placeholder', `${i + 1}`);
+    imgInputs.appendChild(imginput);
+
+    var imgupload = document.createElement("input");
+    imgupload.setAttribute('id', `img${i + 1}`);
+    imgupload.setAttribute('type', `file`);
+    imgupload.classList.add('img_uploader', 'img_up');
+    imgInputs.appendChild(imgupload);
+    var imguploadlabel = document.createElement("label");
+    imguploadlabel.setAttribute('for', `img${i + 1}`);
+    imguploadlabel.classList.add('upload-btn');
+    imguploadlabel.textContent = '上傳檔案';
+    if(lan == 'en') {
+      imguploadlabel.textContent = 'Upload';
+    }
+    imguploadlabel.setAttribute('set-lan', `html:upload_file`);
+    imgInputs.appendChild(imguploadlabel);
+  }
+   setTimeout(() => {
+    JsLoadingOverlay.hide();
+  }, 0);
+}
+
+getpathId();
+
+function getMode() {
+  let id = window.location.search.split('?').pop();
+  let mode = id.split('=')[0];
+  if(mode == 'draftid') {
+    /* JsLoadingOverlay.show({
+      "overlayBackgroundColor": "#FFFFFF",
+      "overlayOpacity": "0.9",
+      "spinnerIcon": "ball-circus",
+      "spinnerColor": "#B9DDF3",
+      "spinnerSize": "2x",
+      "overlayIDName": "overlay",
+      "spinnerIDName": "spinner",
+      "offsetX": 0,
+      "offsetY": 0,
+      "containerID": null,
+      "lockScroll": false,
+      "overlayZIndex": 9998,
+      "spinnerZIndex": 9999
+    }); */
+    getDraftData();
+  } else if(mode == 'id') {
+    /* JsLoadingOverlay.show({
+      "overlayBackgroundColor": "#FFFFFF",
+      "overlayOpacity": "0.9",
+      "spinnerIcon": "ball-circus",
+      "spinnerColor": "#B9DDF3",
+      "spinnerSize": "2x",
+      "overlayIDName": "overlay",
+      "spinnerIDName": "spinner",
+      "offsetX": 0,
+      "offsetY": 0,
+      "containerID": null,
+      "lockScroll": false,
+      "overlayZIndex": 9998,
+      "spinnerZIndex": 9999
+    }); */
+    getData();
+  }
+  return id.split('=')[1];
+  //load_data(id);
+}
+
+getMode();
+
+function getpathId(){
+  let id = window.location.search.split('?').pop();
+  return id.split('=')[1];
+}
+
+function getData() {
+  let jwt_token = get_jwt_token();
+  axios({
+    method: 'post',
+    url: 'https://www.choozmo.com:8887/history_input',
+    headers: { 
+        'accept': 'application/json',
+        'Authorization': `Bearer ${jwt_token}`
+     }
+  }).then(res => {
+    loaded_data = res.data;
+    console.log(loaded_data);
+    const id = getpathId();
+    load_data(id, loaded_data);
+  }).catch(err => {
+    console.log(err);
+  });
+} 
+
+//var subtitleInputs = document.querySelector(".subtitle-inputs");
+var imgInputs = document.querySelector(".img-inputs");
+let length = 5;
+function initial() {
+  for (let i = 0; i < length; i++) {
+    //rendertxtBlock(i + 1);
+    renderimgBlock(i + 1);
+  }
+}
+
+initial();
+
+
+var addimgbtn = document.querySelector(".addimg");
+
+
+addimgbtn.addEventListener('click', addimgBlock);
+
+
+function addimgBlock() {
+  let newimgIdx = document.querySelectorAll(".imgsrc").length + 1;
+  renderimgBlock(newimgIdx);
+}
+
+function renderimgBlock(i) {
+  var imginput = document.createElement("input");
+  imginput.setAttribute('type', 'text');
+  imginput.setAttribute('name', `m${i}`);
+  imginput.classList.add('imgsrc', `imgsrc${i}`);
+  imginput.value = "";
+  imginput.setAttribute('placeholder', `${i}`);
+  imgInputs.appendChild(imginput);
+
+  var imgupload = document.createElement("input");
+  imgupload.setAttribute('id', `img${i}`);
+  imgupload.setAttribute('type', `file`);
+  imgupload.classList.add('img_uploader', 'img_up');
+  imgInputs.appendChild(imgupload);
+  var imguploadlabel = document.createElement("label");
+  imguploadlabel.setAttribute('for', `img${i}`);
+  imguploadlabel.classList.add('upload-btn');
+  imguploadlabel.textContent = '上傳檔案';
+  if(lan == 'en') {
+    imguploadlabel.textContent = 'Upload';
+  }
+  imguploadlabel.setAttribute('set-lan', `html:upload_file`);
+  imgInputs.appendChild(imguploadlabel);
+  $('input[type=file]').on('change', prepareUpload);
+}
+
+
+$('.owl-carousel').owlCarousel({
+  loop: true,
+  margin: 10,
+  nav: false,
+  mouseDrag: true,
+  touchDrag: true,
+  smartSpeed: 1000,
+  autoplay: true,
+  autoplayTimeout: 8000,
+  autoplayHoverPause: false,
+  responsive: {
+    0: {
+      items: 1
+    },
+    600: {
+      items: 2
+    },
+    1000: {
+      items: 4
+    }
+  }
+});
+
+$('.draft-btn').click(() => {
+  let text = '儲存中...';
+
+  if (lan == 'en') {
+    text = 'Saving...';
+  }
+
+  $('.draft-btn').text(text);
+
+  let jwt_token = get_jwt_token();
+  let avatar = $('.avatar').val();
+  let name_title = $('.title_new').val();
+  let txtARR = [];
+  let imgARR = [];
+  var step;
+  let contentIdx = document.querySelectorAll(".txtsrc").length;
+  for (let i = 1; i < (contentIdx + 1); i++) {
+    if ($(`.txtsrc${i}`).val() != "") {
+      txtARR.push($(`.txtsrc${i}`).val())
+    }
+  }
+  let imgIdx = document.querySelectorAll(".imgsrc").length;
+  for (let i = 1; i < (imgIdx + 1); i++) {
+    if ($(`.imgsrc${i}`).val() != "") {
+      imgARR.push($(`.imgsrc${i}`).val())
+    }
+  }
+  let multiLang = 0
+  if ($('#multiLang').prop("checked")) {multiLang = 1;}
+  let id = window.location.search.split('?').pop();
+  let mode = id.split('=')[0];
+  if(mode == 'draftid') {
+    id = Number(id.split('=')[1]);
+  } else {
+    id = -1;
+  }
+  let dataOBJ = { "id": id, "title": name_title, "text_content": txtARR, "image_urls": imgARR, "avatar": avatar,"multiLang":multiLang }
+  console.log(dataOBJ);
+  axios({
+    method: 'post',
+    url: 'https://www.choozmo.com:8887/save_draft',
+    headers: { 
+        'accept': 'application/json',
+        'Authorization': `Bearer ${jwt_token}`,
+        'Content-Type': 'application/json',
+     },
+    data: dataOBJ
+  }).then(res => {
+    console.log(res.data);
+    $('.draft-btn').text('存為草稿');
+    let title = "儲存完成";
+    if(lan == 'en') {
+      title = 'Saved!'
+      $('.draft-btn').text('Save as Draft');
+    }
+    Swal.fire({
+      title: title,
+      icon: 'success',
+      confirmButtonColor: '#3085d6',
+    }); 
+  }).catch(err => {
+    console.log(err);
+  });
+});
+
+function getDraftData() {
+  let token = get_jwt_token();
+  axios({
+    method: 'post',
+    url: 'https://www.choozmo.com:8887/draft_list',
+    headers: { 
+        'accept': 'application/json',
+        'Authorization': `Bearer ${token}`
+     }
+  }).then(res => {
+    console.log(res.data);
+    let result = [...res.data];
+    let id = getpathId();
+    load_data(id, result, true);
+  }).catch(err => {
+    console.log(err);
+  });
+
+}
+
+$(".copy").click(function(){
+  const copyStr = $(this).next().text();
+  copyToClipboard(copyStr);
+});
+
+const copyToClipboard = str => {
+  const el = document.createElement('textarea');
+  el.value = str;
+  el.setAttribute('readonly', '');
+  el.style.position = 'absolute';
+  el.style.left = '-9999px';
+  document.body.appendChild(el);
+  el.select();
+  document.execCommand('copy');
+  document.body.removeChild(el);
+  Swal.fire({
+    toast: true,
+    icon: 'success',
+    position: 'top-end',
+    title: 'Link copied!',
+    timerProgressBar: true,
+    showConfirmButton: false,
+    timer: 1000,
+    backdrop: false
+  })
+};
+

+ 157 - 34
html/script_profiles.js

@@ -2,28 +2,45 @@ const btnLoginPage = document.querySelector('.btn-login');
 const btnUserProfile = document.querySelector('.btn-userProfile');
 const btnLogout = document.querySelector('.btn-logout');
 
+let lan = localStorage.getItem('lan');
+
 function getCookie(name) {
     const value = `; ${document.cookie}`;
     const parts = value.split(`; ${name}=`);
     if (parts.length === 2) return parts.pop().split(';').shift();
-  }
+}
 
 let userBasics = JSON.parse(localStorage.getItem('user_profile')) || [];
 
 function checkLocal() {
   if(userBasics.length == 0){ return };
-  $('.userName').html(`<h2 class="user-name text-white mt-4 fw-bold">Hello,${userBasics.user_info.userName}</h2>`);
+  $('.userName').html(`<h2 class="user-name text-white mt-4 fw-bold">Hi ${userBasics.user_info.userName}</h2>`);
 }
 
-checkLocal()
+$('.dropdown-toggle').click(() => {
+  lan = localStorage.getItem('lan');
+  checkLan();
+});
+
+checkLocal();
 
+function checkLan() {
+  if(lan == 'en') {
+    $('.btn-makev').css('display', 'none');
+    $('.btn-makelong').css('display', 'none');
+  } else {
+    $('.btn-makev').css('display', 'block');
+    $('.btn-makelong').css('display', 'block');
+  }
+}
+
+checkLan();
 
 function renderView() {
     let token = getCookie('jwt_token');
     if(!token) {
         return;
      }
-    // axios.defaults.withCredentials = false;
     axios({
         method: 'post',
         url: 'https://www.choozmo.com:8887/user_profile',
@@ -36,34 +53,29 @@ function renderView() {
         const userInfo = res.data;
         localStorage.setItem('user_profile', JSON.stringify(res.data));
           if(userInfo.user_info.left_sec < 20){
+            let title = "剩餘秒數不足";
+            let text = '您的影片額度即將不足,加值以持續使用';
+            let confirmButtonText = '加值';
+                    if (lan == 'en') { 
+                        title = "Insufficient seconds left!";
+                        text = 'Your seconds left is less than 20 seconds, refill to continue making videos.';
+                        confirmButtonText = 'Refill';
+                    }
             Swal.fire({
-                title: "剩餘秒數不足",
-                text: '您的影片額度即將不足,加值以持續使用',
+                title,
+                text,
                 icon: 'warning',
                 showCancelButton: true,
                 cancelButtonText: 'Cancel',
                 confirmButtonColor: '#3085d6',
-                confirmButtonText: '加值'
+                confirmButtonText
             }).then(result => {
               if (result.isConfirmed) {
                 location.href = "pricing.html";
               }
             });
           }
-        // const str = `<img src="static/img/undraw_male_avatar_323b.svg" alt="">
-        //     <p class="card-profile-txt">User Profile</p>
-        //     <p class="card-profile-cnt">${userInfo.user_info.userName}</p>
-        //     <p class="card-profile-cnt">${userInfo.user_info.email}</p>
-        //     <div class="d-flex justify-content-around">
-        //         <div>
-        //             <p set-lan="html:used">已使用</p>
-        //             <p><strong>${userInfo.user_info.total_sec}</strong><span set-lan="html:sec">秒</span></p>
-        //         </div>
-        //         <div>
-        //             <p set-lan="html:left">未使用</p>
-        //             <p><strong>${userInfo.user_info.left_sec}</strong><span set-lan="html:sec">秒</span></p>
-        //         </div>
-        //     </div>`;
+        
         const str = `<img src="static/img/undraw_male_avatar_323b.svg" alt="">
         <p class="card-profile-txt">User Profile</p>
         <p class="card-profile-cnt">${userInfo.user_info.userName}</p>
@@ -78,26 +90,52 @@ function renderView() {
                 <p><strong>${userInfo.user_info.left_sec}</strong><span set-lan="html:sec">秒</span></p>
             </div>
         </div>`;
+        let totalSec = (userInfo.user_info.total_sec == "None") ? 0 : userInfo.user_info.total_sec;
+        let leftSec = (userInfo.user_info.left_sec == null)? 0 : userInfo.user_info.left_sec;
         // 使用者名稱
-        const userName = `<h2 class="user-name text-white mt-4 fw-bold">Hello,${userInfo.user_info.userName}</h2>`;
+        let userName = `<h2 class="user-name text-white mt-4 fw-bold">Hi ${userInfo.user_info.userName}</h2>`;
         // 已使用
-        const usedtime=`<h1 class="text-center">${userInfo.user_info.total_sec}&ensp;<span style="font-size:15px;" set-lan="html:sec">秒</span></h1>`;
+        let usedtime=`<h1 class="text-center">${totalSec}&ensp;<span style="font-size:15px;" set-lan="html:sec">秒</span></h1>`;
+        if(lang == 'en') {
+          usedtime=`<h1 class="text-center">${totalSec}&ensp;<span style="font-size:15px;" set-lan="html:sec">Sec</span></h1>`;
+        }
         // 未使用
-        const NotUsedTime=`<h1  class="text-center">${userInfo.user_info.left_sec}&ensp;<span style="font-size:15px;" set-lan="html:sec">秒</span></h1>`;
+        let NotUsedTime=`<h1  class="text-center">${leftSec}&ensp;<span style="font-size:15px;" set-lan="html:sec">秒</span></h1>`;
+        if(lang == 'en') {
+          NotUsedTime=`<h1  class="text-center">${leftSec}&ensp;<span style="font-size:15px;" set-lan="html:sec">Sec</span></h1>`;
+        }
         // user資訊
-        const infContent=`
+        let infContent=`
         <div class="inf-content">
             <p>${userInfo.user_info.userName}</p>
             <p>***************&nbsp;<a href="./reset_pwd_email.html" set-lan="html:resetPsd">更改密碼</a></p>
             <p>${userInfo.user_info.email}</p>
         </div>`;
+        if(lang == 'en') {
+          infContent=`
+            <div class="inf-content">
+                <p>${userInfo.user_info.userName}</p>
+                <p>***************&nbsp;<a href="./reset_pwd_email.html" set-lan="html:resetPsd">Reset Password</a></p>
+                <p>${userInfo.user_info.email}</p>
+            </div>`;
+        }
         // 歷史紀錄
         // const historicalrecord 
-        var  historicalrecord=''
+        var  historicalrecord='';
         for (var i = 0; i < userInfo.video_info.length; i++) {
+          let formatted = userInfo.video_info[i].time_stamp;
+          if (lan == 'zh') {
+            const timeStamp = userInfo.video_info[i].time_stamp;
+            const year = timeStamp.split(',')[0].split('/')[2];
+            const arr = timeStamp.split(',')[0].split('/');
+            arr.pop();
+            arr.unshift(year);
+            const fomatDate = [arr.join('/')];
+            formatted = fomatDate.concat(timeStamp.split(',')[1]).join('');
+          }
             historicalrecord+='\
             <tr>\
-            <td class="px-0">'+userInfo.video_info[i].time_stamp+'</td>\
+            <td class="px-0">'+formatted+'</td>\
             <td class="px-0">'+userInfo.video_info[i].title+'</td>\
             <td class="px-0 w-25">'+userInfo.video_info[i].duration+'</td>\
           </tr>`\
@@ -123,7 +161,7 @@ renderView();
 function getDraft() {
   JsLoadingOverlay.show({
     "overlayBackgroundColor": "#FFFFFF",
-    "overlayOpacity": "0.1",
+    "overlayOpacity": "1",
     "spinnerIcon": "ball-circus",
     "spinnerColor": "#B9DDF3",
     "spinnerSize": "1x",
@@ -157,17 +195,25 @@ function getDraft() {
                   <span class="me-3 draft-content-icon" id="${result[i].id}" onclick="gotoDraft(${result[i].id})">
                     <i class="fas fa-edit"></i>
                     </span>
-                    <span class="ms-3 draft-content-icon" id="${result[i].id}" onclick="deleteDraft(${result[i].id})">
+                    <span class="ms-3 draft-content-icon draft-content-delete" id="${result[i].id}" onclick="deleteDraft(${result[i].id})">
                     <i class="fas fa-trash-alt"></i>
                     </span>
                     </td>
                 </tr>`
       }
+      let titleTxt = '標題';
+      let editTxt = '編輯';
+      let nodraftTxt = '目前沒有草稿喔';
+      if(lan == 'en') {
+        titleTxt = 'Video Title';
+        editTxt = 'Edit';
+        nodraftTxt = 'no_draft';
+      }
       str = `<table class="table text-center">
       <thead>
         <tr>
-          <th scope="col" set-lan="html:video_title">標題</th>
-          <th class="px-0" scope="col" set-lan="html:draft_edit">編輯</th>
+          <th scope="col" set-lan="html:video_title">${titleTxt}</th>
+          <th class="px-0" scope="col" set-lan="html:draft_edit">${editTxt}</th>
         </tr>
       </thead>
       <tbody class="draft-content">${draftStr}</tbody>
@@ -176,7 +222,7 @@ function getDraft() {
       JsLoadingOverlay.hide();
     } else {
       str = `<div>
-              <h5 set-lan="html:no_draft">目前沒有草稿喔</h5>
+              <h5 set-lan="html:no_draft">${nodraftTxt}</h5>
               <img src="static/img/undraw_void_3ggu.svg" width="80">
             </div>`;
       $('.draft-table .card').html(str); 
@@ -233,8 +279,9 @@ function openNav() {
   }).then(res => {
     console.log(res.data);
     loaded_data = res.data;
+    var historyList = document.querySelector('.historyList');
+    historyList.innerHTML = '';
     for (var obj of loaded_data) {
-      var historyList = document.querySelector('.historyList');
       var list = document.createElement('li');
       list.id = obj.id;
       // div-imgfr
@@ -291,6 +338,21 @@ function gotoDraft (id) {
 }
 function deleteDraft(id) {
   let token = getCookie('jwt_token');
+  JsLoadingOverlay.show({
+    "overlayBackgroundColor": "#FFFFFF",
+    "overlayOpacity": "1",
+    "spinnerIcon": "ball-circus",
+    "spinnerColor": "#B9DDF3",
+    "spinnerSize": "1x",
+    "overlayIDName": "overlay",
+    "spinnerIDName": "spinner",
+    "offsetX": 0,
+    "offsetY": 0,
+    "containerID": "draft-table",
+    "lockScroll": false,
+    "overlayZIndex": 9998,
+    "spinnerZIndex": 9999
+  });
   axios({
     method: 'post',
     url: 'https://www.choozmo.com:8887/del_draft',
@@ -302,6 +364,8 @@ function deleteDraft(id) {
     data: { "id": id }
   }).then(res => {
     console.log(res.data);
+    //$('.draft-content-delete').html('<i class="fas fa-trash-alt"></i>');
+    JsLoadingOverlay.hide();
     getDraft();
   }).catch(err => {
     console.log(err);
@@ -314,4 +378,63 @@ $('.share-email').click(function() {
   &body=${encodeURIComponent('I just created a video in 5 minutes, check out this amazing video making tool. https://video.choozmo.com/')}`;
     
     window.location.href = link;
-})
+});
+
+function trialStart() {
+  let title = "歡迎使用AiSpokesgirl!將你的生活、創作 、宣傳做成影片。";
+  let html = `<p>您有  <b> 2 </b>  分鐘影片製作額度。</p><br>
+              <p>您可以使用:</p>
+              <ul>
+                <li>1. 短影片製作</li>
+                <li>2. 個人歷史紀錄儲存</li>
+                <li>3. 影片下載(Mp4)</li>
+              </ul>
+              <p>欲使用其他功能請升級為Premium方案</p>`;
+  let confirmButtonText = '我知道了!';
+  if (lan == 'en') { 
+    title = "Welcome to AiSpokesgirl! Make your first video for promotion, creation and life today!";
+    html = `<p>You get<b>2</b>minutes of video</p><br>
+            <p>Here are several features you can try,</p>
+            <ul>
+              <li>1. Short video creation</li>
+              <li>2. Personal video history</li>
+              <li>3. Downloadable format (MP4)</li>
+            </ul>
+            <p>Want to access more features? Follow the link below to upgrade to a paid plan today.</p>`;
+    confirmButtonText = 'OK';
+  }
+  Swal.fire({
+    title,
+    html,
+    icon: 'success',
+    confirmButtonColor: '#3085d6',
+    confirmButtonText
+  });
+}
+
+function trialEnd() {
+  let title = "您的試用即將結束!好的idea值得延續,透過影片將你的idea完整呈現。";
+  let html = `<p>前往網站以升級為Premium方案,或是聯絡我們以洽詢細節。</p>`;
+  let confirmButtonText = '立即升級';
+  if (lan == 'en') { 
+    title = "Your trial is gonna over soon. Your idea worth spreading.";
+    html = `<p>All good things don't have to come to an end.</p><br>
+            <h5>Show your idea through video</h5><br>
+            <p>Want to access more features? Follow the link below to upgrade 
+            to a paid plan today or contact us get further details.</p>`;
+    confirmButtonText = 'Upgrade Now';
+  }
+  Swal.fire({
+    title,
+    html,
+    icon: 'success',
+    confirmButtonColor: '#3085d6',
+    confirmButtonText
+  }).then(result => {
+    if (result.isConfirmed) {
+      location.href = "pricing.html";
+    }
+  });;
+}
+
+

BIN
html/static/img/checked (2).png


BIN
html/static/img/nina灰.webp


BIN
html/static/img/nina黑.webp


BIN
html/static/img/summer韓小夏.webp


BIN
html/static/img/undraw_well_done_i2wr.png


+ 20 - 4
html/static/lan.js

@@ -52,8 +52,9 @@ var zh = {
     "make_video" : "影片製作",
     "make_slides" : "投影影片製作",
     "make_video_long": "長影片製作",
-    "make_video_eng": "英文影片製作",
+    "make_video_eng": "英文影片製作",
     "login" : "登入",
+    "login_link" : "立即登入",
     "user_profile": "會員資料",
     "logout": "登出",
     "en": "English",
@@ -76,7 +77,9 @@ var zh = {
     "submit": "送出",
     "privacy_term": "同意隱私政策及使用條款",
     "newHere": "還沒有帳號?",
+    "oldHere": "已經有帳號?",
     "goRegister": "註冊",
+    "goRegister_link": "立即註冊",
     "pricing" : "早鳥方案",
     "errorEmail": "請輸入正確E-mail",
     "errorPsd": "密碼至少為4個字元",
@@ -86,6 +89,7 @@ var zh = {
     "username": "帳號/用戶名稱",
     "password": "密碼",
     "resetPsd": "更改密碼",
+    "forgotPsd": "忘記密碼",
     "details": "查看詳情",
     "refill": "我要加值",
     "Createsthtoday": "今天要做甚麼影片呢?",
@@ -119,7 +123,11 @@ var zh = {
     "save_draft_btn": "存為草稿",
     "upload_file": "上傳檔案",
     "intro_img": "static/img/intro2.jpg",
-    "no_draft": "目前沒有草稿喔"
+    "no_draft": "目前沒有草稿喔",
+    "trial_title": "想要免費獲得更多時間額度?",
+    "trial_txt": "透過社群分享專屬連結,邀請好友註冊 AI Spokesgirl,凡是好友透過連結註冊成功,您可以免費獲得2分鐘製作額度。",
+    "share": "分享:",
+    "close": "關閉"
 };
 
 var en = {
@@ -130,6 +138,7 @@ var en = {
     "make_video_long": "Make Long Videos",
     "make_video_eng": "Make English Video",
     "login" : "Login",
+    "login_link" : "Login",
     "user_profile": "User Profile",
     "logout": "Logout",
     "en": "English",
@@ -152,7 +161,9 @@ var en = {
     "submit": "Submit",
     "privacy_term": "I Agree to privacy policy and terms of use.",
     "newHere": "New here?",
+    "oldHere": "Already have an account?",
     "goRegister": "REGISTER",
+    "goRegister_link": "REGISTER",
     "pricing" : "Pricing",
     "errorEmail": "Please enter valid Email format.",
     "errorPsd": "Passwords must be at least 4 characters long.",
@@ -160,8 +171,9 @@ var en = {
     "left": "Left",
     "sec": "Sec",
     "username": "User Name",
-    "password": "password",
+    "password": "Password",
     "resetPsd": "Reset Password",
+    "forgotPsd": "Forgot Password",
     "details": "Details",
     "refill": "Refill",
     "Createsthtoday": "Create something today!",
@@ -195,7 +207,11 @@ var en = {
     "save_draft_btn": "Save as Draft",
     "upload_file": "Upload",
     "intro_img": "static/img/intro_en.png",
-    "no_draft": "No drafts yet."
+    "no_draft": "No drafts yet.",
+    "trial_title": "Want to get more minutes?",
+    "trial_txt": "Invite your friends to AI Spokesgirl and for each eligible one that signs up from your referral, we'll give you 2 more minutes free!",
+    "share": "Share:",
+    "close": "Close"
 };
 
 function switchLanContent(val){

+ 79 - 7
html/static/script_slides.js

@@ -1,5 +1,10 @@
 checkRoute();
 
+let userBasics = JSON.parse(localStorage.getItem('user_profile')) || [];
+if(userBasics !== []){
+  $('.userName').html(`<h2 class="user-name text-white mt-4 fw-bold">Hi ${userBasics.user_info.userName}</h2>`);
+}
+
 function checkRoute() {
   let jwt_token = get_jwt_token();
   if(jwt_token == undefined) {
@@ -18,13 +23,32 @@ function checkRoute() {
       window.location.replace("login.html");
     }
     var userName='';
-    userName+=' <h2 class="user-name text-white mt-4 fw-bold">Hello,'+res.data.user_info.userName+'</h2>';
+    userName+=' <h2 class="user-name text-white mt-4 fw-bold">Hi '+res.data.user_info.userName+'</h2>';
     $('.userName').html(userName);
   }).catch(err => {
     console.log(err);
   });
 }
 
+let lan = localStorage.getItem('lan');
+
+$('.dropdown-toggle').click(() => {
+  lan = localStorage.getItem('lan');
+  checkLan();
+});
+
+checkLan();
+
+function checkLan() {
+  if(lan == 'en') {
+    $('.btn-makev').css('display', 'none');
+    $('.btn-makelong').css('display', 'none');
+  } else {
+    $('.btn-makev').css('display', 'block');
+    $('.btn-makelong').css('display', 'block');
+  }
+}
+
 const btnLoginPage = document.querySelector('.btn-login');
 const btnUserProfile = document.querySelector('.btn-userProfile');
 const btnLogout = document.querySelector('.btn-logout');
@@ -36,6 +60,47 @@ function loginControl() {
 
 loginControl();
 
+
+function getAvatar() {
+  let jwt_token = get_jwt_token();
+  if(jwt_token == undefined) {
+    window.location.replace("login.html");
+  }
+  axios({
+    method: 'post',
+    url: 'https://www.choozmo.com:8887/get_avatar_by_role',
+    headers: { 
+        'accept': 'text/html',
+        'Authorization': `Bearer ${jwt_token}`
+     }
+  }).then(res => {
+    console.log(res.data);
+    let result = [...res.data];
+    let str = '';
+    let carStr = '';
+    for(let i = 0; i < result.length; i++) {
+      str += `<option value="${result[i].num}">${result[i].name}</option>`
+    }
+    for(let i = 0; i < result.length; i++) {
+      carStr += `<div class="card item col" data-avatar="${result[i].name}" data-img="${result[i].name.toLowerCase()}">
+                    <div class="imgfr"><img src="static/img/${result[i].name.toLowerCase()}.webp" class="card-img-top" alt="..."></div>
+                    <div class="card-body">
+                        <h5 class="card-title">${result[i].name.toLowerCase()}</h5>
+                    </div>
+                </div>`;
+    }
+    $('#avatar').html(`<option set-lan="html:p_choose_character" value="請選擇人物" selected="selected" disabled>>請選擇人物</option>${str}`);
+    $('.owl-carousel').html(carStr);
+    card = document.getElementsByClassName('card');
+    console.log(card);
+    addCardListener(card);
+  }).catch(err => {
+    console.log(err);
+  });
+}
+
+getAvatar();
+
 var client_id = Date.now()
 var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
 var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
@@ -50,14 +115,14 @@ var avatarModal = new bootstrap.Modal(document.getElementById('avatarmega'), {
 var modalImg = document.querySelector("#avatarmega .modal-img");
 var modalTitle = document.querySelector("#avatarmega .modal-title");
 var avatarSelector = document.getElementById("avatar");
-var card = document.getElementsByClassName('card');
-card = [...card];
+var card = '';
+
 avatarSelector.addEventListener('change', avatarChange);
 avatarChange();
 
-function addCardListener() {
-  for (let i = 0; i < card.length; i++) {
-    card[i].addEventListener('click', openavatarModel);
+function addCardListener(arr) {
+  for (let i = 0; i < arr.length; i++) {
+    arr[i].addEventListener('click', openavatarModel);
   }
 }
 
@@ -162,8 +227,9 @@ function openNav() {
   }).then(res => {
     console.log(res.data);
     loaded_data = res.data;
+    var historyList = document.querySelector('.historyList');
+    historyList.innerHTML = '';
     for (var obj of loaded_data) {
-      var historyList = document.querySelector('.historyList');
       var list = document.createElement('li');
       list.id = obj.id;
       // div-imgfr
@@ -179,6 +245,7 @@ function openNav() {
       boxTitle.classList.add('box-title');
       boxTitle.textContent = obj.name;
       boxTitle.id = obj.id;
+      boxTitle.setAttribute('onclick', `direct(${obj.id})`);
 
       var boxLink = document.createElement('span');
       boxLink.classList.add('box-link');
@@ -198,6 +265,11 @@ function openNav() {
     console.log(err);
   });
 }
+
+function direct(id) {
+  location.href = `make_video.html?id=${id}`;
+}
+
 function closeNav() {
   document.getElementById("mySidenav").style.width = "250px";
 }

+ 169 - 41
html/static/script_util.js

@@ -1,10 +1,13 @@
 checkRoute();
 
 let userBasics = JSON.parse(localStorage.getItem('user_profile')) || [];
+
+
 if(userBasics !== []){
-  $('.userName').html(`<h2 class="user-name text-white mt-4 fw-bold">Hello,${userBasics.user_info.userName}</h2>`);
+  $('.userName').html(`<h2 class="user-name text-white mt-4 fw-bold">Hi ${userBasics.user_info.userName}</h2>`);
 }
 
+
 function checkRoute() {
   let jwt_token = get_jwt_token();
   if(jwt_token == undefined) {
@@ -23,7 +26,7 @@ function checkRoute() {
       window.location.replace("login.html");
     }
     var userName='';
-    userName+=' <h2 class="user-name text-white mt-4 fw-bold">Hello,'+res.data.user_info.userName+'</h2>';
+    userName+=`<h2 class="user-name text-white mt-4 fw-bold">Hi ${res.data.user_info.userName}</h2>`;
     $('.userName').html(userName);
   }).catch(err => {
     console.log(err);
@@ -41,6 +44,65 @@ function loginControl() {
 
 loginControl();
 
+let lan = localStorage.getItem('lan');
+
+$('.dropdown-toggle').click(() => {
+  lan = localStorage.getItem('lan');
+  checkLan();
+});
+
+checkLan();
+
+function checkLan() {
+  if(lan == 'en') {
+    $('.btn-makev').css('display', 'none');
+    $('.btn-makelong').css('display', 'none');
+  } else {
+    $('.btn-makev').css('display', 'block');
+    $('.btn-makelong').css('display', 'block');
+  }
+}
+
+function getAvatar() {
+  let jwt_token = get_jwt_token();
+  if(jwt_token == undefined) {
+    window.location.replace("login.html");
+  }
+  axios({
+    method: 'post',
+    url: 'https://www.choozmo.com:8887/get_avatar_by_role',
+    headers: { 
+        'accept': 'text/html',
+        'Authorization': `Bearer ${jwt_token}`
+     }
+  }).then(res => {
+    console.log(res.data);
+    let result = [...res.data];
+    let str = '';
+    let carStr = '';
+    for(let i = 0; i < result.length; i++) {
+      str += `<option value="${result[i].num}">${result[i].name}</option>`
+    }
+    for(let i = 0; i < result.length; i++) {
+      carStr += `<div class="card item col" data-avatar="${result[i].name}" data-img="${result[i].name.toLowerCase()}">
+                    <div class="imgfr"><img src="static/img/${result[i].name.toLowerCase()}.webp" class="card-img-top" alt="..."></div>
+                    <div class="card-body">
+                        <h5 class="card-title">${result[i].name.toLowerCase()}</h5>
+                    </div>
+                </div>`;
+    }
+    $('#avatar').html(`<option set-lan="html:p_choose_character" value="請選擇人物" selected="selected" disabled>>請選擇人物</option>${str}`);
+    $('.owl-carousel').html(carStr);
+    card = document.getElementsByClassName('card');
+    console.log(card);
+    addCardListener(card);
+  }).catch(err => {
+    console.log(err);
+  });
+}
+
+getAvatar();
+
 var client_id = Date.now()
 var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
 var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
@@ -55,18 +117,17 @@ var avatarModal = new bootstrap.Modal(document.getElementById('avatarmega'), {
 var modalImg = document.querySelector("#avatarmega .modal-img");
 var modalTitle = document.querySelector("#avatarmega .modal-title");
 var avatarSelector = document.getElementById("avatar");
-var card = document.getElementsByClassName('card');
-card = [...card];
+var card = '';
+
 avatarSelector.addEventListener('change', avatarChange);
 avatarChange();
 
-function addCardListener() {
-  for (let i = 0; i < card.length; i++) {
-    card[i].addEventListener('click', openavatarModel);
+function addCardListener(arr) {
+  for (let i = 0; i < arr.length; i++) {
+    arr[i].addEventListener('click', openavatarModel);
   }
 }
 
-addCardListener();
 
 function avatarChange() {
   var value = avatarSelector.options[avatarSelector.selectedIndex].text;
@@ -124,7 +185,7 @@ $(".next").click(function () {
   button.setAttribute('disabled', '');
   setTimeout(function () {
     button.removeAttribute('disabled')
-  }, 4000);
+  }, 10000);
   avatar = $('.avatar').val();
   name_title = $('.title_new').val();
   txtARR = [];
@@ -142,7 +203,7 @@ $(".next").click(function () {
       imgARR.push($(`.imgsrc${i}`).val())
     }
   }
-  multiLang = 0
+  multiLang = 0;
   if ($('#multiLang').prop("checked")) {multiLang = 1;}
   dataOBJ = { "name": name_title, "text_content": txtARR, "image_urls": imgARR, "avatar": avatar,"multiLang":multiLang, "client_id": client_id }
   objstr = JSON.stringify(dataOBJ);
@@ -156,23 +217,21 @@ $(".next").click(function () {
   xhr.onreadystatechange = function () {
     if (xhr.readyState === 4) {
       responseOBJ = JSON.parse(xhr.responseText)
-      if (responseOBJ.msg=='ok')
-      {
+      console.log(responseOBJ.msg);
+        //let title = "資料已送出";
+        let text;
+        if(lan == 'en') {
+          //title = 'Submitted Successfully!';
+          text = responseOBJ.msg.eng;
+        } else {
+          text = responseOBJ.msg.zh;
+        }
         Swal.fire({
-          title: "資料已送出",
-          icon: 'success',
-          text: '資料已傳送,請耐心等候',
-          confirmButtonColor: '#3085d6',
-        });
-      }
-      else{
-        Swal.fire({
-          title: "發生錯誤",
-          icon: 'error',
-          text: responseOBJ.msg,
+         // title: title,
+          icon: 'info',
+          text: text,
           confirmButtonColor: '#3085d6',
         });
-      }
       
     }
   };
@@ -217,20 +276,32 @@ $("#sendBTN").click(function () {
   xhr.onreadystatechange = function () {
     if (xhr.readyState === 4) {
       responseOBJ = JSON.parse(xhr.responseText)
-      if (responseOBJ.msg=='ok')
-      {
+      if (responseOBJ.msg=='ok'){
+        let title = "資料已送出";
+        let text = '資料已傳送,請耐心等候';
+        if (lan == 'en') { // 英文版訊息
+          title = "Submitted Successfully!";
+          text = 'We are working on your video. You will get notfication in line group when your video is done.';
+        }
         Swal.fire({
-          title: "資料已送出",
+          title: title,
           icon: 'success',
-          text: '資料已傳送,請耐心等候',
+          text: text,
           confirmButtonColor: '#3085d6',
         });
-      }
-      else{
+      } else {
+        let title = '發生錯誤';
+        let text;
+        if(lan == 'en') {
+          title = 'Error';
+          text = responseOBJ.msg.eng;
+        } else {
+          text = responseOBJ.msg.zh;
+        }
         Swal.fire({
-          title: "發生錯誤",
+          title: title,
           icon: 'error',
-          text: responseOBJ.msg,
+          text: text,
           confirmButtonColor: '#3085d6',
         });
       }
@@ -262,10 +333,16 @@ $("#send_slide").click(function () {
   xhr.setRequestHeader("Content-Type", "application/json");
   xhr.onreadystatechange = function () {
     if (xhr.readyState === 4) {
+      let title = "資料已送出";
+      let text = '資料已傳送,請耐心等候';
+      if (lan == 'en') { // 英文版訊息
+        title = "Submitted Successfully!";
+        text = 'We are working on your video. You will get notfication in line group when your video is done.';
+      }
       Swal.fire({
-        title: "資料已送出",
+        title: title,
         icon: 'success',
-        text: '資料已傳送,請耐心等候',
+        text: text,
         confirmButtonColor: '#3085d6',
       });
     }
@@ -311,8 +388,9 @@ function openNav() {
   }).then(res => {
     console.log(res.data);
     loaded_data = res.data;
+    var historyList = document.querySelector('.historyList');
+    historyList.innerHTML = '';
     for (var obj of loaded_data) {
-      var historyList = document.querySelector('.historyList');
       var list = document.createElement('li');
       list.id = obj.id;
       // div-imgfr
@@ -412,6 +490,7 @@ function load_data(tid, loaded_data, draft = false) {
     $("#avatar").val(historyItem.avatar);
   } else {
     $(".title_new").val(loaded_data.find(item => item.id == tid).name);
+    $("#avatar").val(historyItem.avatar);
   }
 
   let txtlength = historyItem.text_content.length;
@@ -446,21 +525,56 @@ function load_data(tid, loaded_data, draft = false) {
     imguploadlabel.setAttribute('for', `img${i + 1}`);
     imguploadlabel.classList.add('upload-btn');
     imguploadlabel.textContent = '上傳檔案';
+    if(lan == 'en') {
+      imguploadlabel.textContent = 'Upload';
+    }
     imguploadlabel.setAttribute('set-lan', `html:upload_file`);
     imgInputs.appendChild(imguploadlabel);
   }
-
+   setTimeout(() => {
+    JsLoadingOverlay.hide();
+  }, 0);
 }
 
- getpathId();
+getpathId();
 
 function getMode() {
   let id = window.location.search.split('?').pop();
   let mode = id.split('=')[0];
   if(mode == 'draftid') {
+    /* JsLoadingOverlay.show({
+      "overlayBackgroundColor": "#FFFFFF",
+      "overlayOpacity": "0.9",
+      "spinnerIcon": "ball-circus",
+      "spinnerColor": "#B9DDF3",
+      "spinnerSize": "2x",
+      "overlayIDName": "overlay",
+      "spinnerIDName": "spinner",
+      "offsetX": 0,
+      "offsetY": 0,
+      "containerID": null,
+      "lockScroll": false,
+      "overlayZIndex": 9998,
+      "spinnerZIndex": 9999
+    }); */
     getDraftData();
   } else if(mode == 'id') {
-    getData()
+    /* JsLoadingOverlay.show({
+      "overlayBackgroundColor": "#FFFFFF",
+      "overlayOpacity": "0.9",
+      "spinnerIcon": "ball-circus",
+      "spinnerColor": "#B9DDF3",
+      "spinnerSize": "2x",
+      "overlayIDName": "overlay",
+      "spinnerIDName": "spinner",
+      "offsetX": 0,
+      "offsetY": 0,
+      "containerID": null,
+      "lockScroll": false,
+      "overlayZIndex": 9998,
+      "spinnerZIndex": 9999
+    }); */
+    getData();
   }
   return id.split('=')[1];
   //load_data(id);
@@ -549,6 +663,9 @@ function renderimgBlock(i) {
   imguploadlabel.setAttribute('for', `img${i}`);
   imguploadlabel.classList.add('upload-btn');
   imguploadlabel.textContent = '上傳檔案';
+  if(lan == 'en') {
+    imguploadlabel.textContent = 'Upload';
+  }
   imguploadlabel.setAttribute('set-lan', `html:upload_file`);
   imgInputs.appendChild(imguploadlabel);
   $('input[type=file]').on('change', prepareUpload);
@@ -579,7 +696,14 @@ $('.owl-carousel').owlCarousel({
 });
 
 $('.draft-btn').click(() => {
-  $('.draft-btn').text('Loading...');
+  let text = '儲存中...';
+
+  if (lan == 'en') {
+    text = 'Saving...';
+  }
+
+  $('.draft-btn').text(text);
+
   let jwt_token = get_jwt_token();
   let avatar = $('.avatar').val();
   let name_title = $('.title_new').val();
@@ -621,15 +745,19 @@ $('.draft-btn').click(() => {
   }).then(res => {
     console.log(res.data);
     $('.draft-btn').text('存為草稿');
+    let title = "儲存完成";
+    if(lan == 'en') {
+      title = 'Saved!'
+      $('.draft-btn').text('Save as Draft');
+    }
     Swal.fire({
-      title: "儲存完成",
+      title: title,
       icon: 'success',
       confirmButtonColor: '#3085d6',
     }); 
   }).catch(err => {
     console.log(err);
   });
-
 });
 
 function getDraftData() {

+ 15 - 5
html/static/scss/style.css

@@ -140,7 +140,7 @@ body {
 
 .nav-list {
   color: white;
-  margin-top: 3rem;
+  margin-top: 1.5rem;
 }
 
 .nav-list-item {
@@ -182,6 +182,7 @@ body {
 
 .card-title {
   font-family: "Montserrat", sans-serif;
+  font-size: 1rem;
 }
 
 .strong {
@@ -662,6 +663,19 @@ footer {
   border-bottom: none;
 }
 
+.btn-dismiss {
+  background: -webkit-gradient(linear, left top, right top, from(#0162c8), to(#55e7fc));
+  background: linear-gradient(90deg, #0162c8, #55e7fc);
+  font-weight: bold;
+  color: white;
+  border: 0 none;
+  border-radius: 20px;
+  cursor: pointer;
+  padding: 10px 35px;
+  margin: 10px auto;
+  display: block;
+}
+
 #avatarmega .modal-content {
   background-color: transparent;
   border: none;
@@ -671,10 +685,6 @@ footer {
   color: white;
 }
 
-#avatarmega .btn-close {
-  background: none;
-}
-
 #avatarmega .modal-header {
   position: absolute;
   top: -0.5rem;

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
html/static/scss/style.css.map


+ 14 - 5
html/static/scss/style.scss

@@ -133,7 +133,7 @@ body {
 
 .nav-list {
 	color: white;
-	margin-top: 3rem;
+	margin-top: 1.5rem;
 }
 
 .nav-list-item {
@@ -174,6 +174,7 @@ body {
 
 .card-title {
 	font-family: "Montserrat", sans-serif;
+	font-size: 1rem;
 }
 
 .strong {
@@ -622,6 +623,18 @@ footer {
 	border-bottom: none;
 }
 
+.btn-dismiss {
+	background: linear-gradient(90deg, #0162c8, #55e7fc);
+	font-weight: bold;
+	color: white;
+	border: 0 none;
+	border-radius: 20px;
+	cursor: pointer;
+	padding: 10px 35px;
+	margin: 10px auto;
+	display: block;
+}
+
 #avatarmega .modal-content {
 	background-color: transparent;
 	border: none;
@@ -631,10 +644,6 @@ footer {
 	color: white;
 }
 
-#avatarmega .btn-close {
-	background: none;
-}
-
 #avatarmega .modal-header {
 	position: absolute;
 	top: -0.5rem;

+ 0 - 132
html/user_profile.html

@@ -1,132 +0,0 @@
-<!DOCTYPE html>
-<html lang="zh-TW">
-
-<head>
-    <meta charset="UTF-8">
-    <meta name="viewport" content="width=device-width, initial-scale=1.0">
-    <title>AI Spokesgirl</title>
-    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css">
-    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.13/css/all.css" integrity="sha384-DNOHZ68U8hZfKXOrtjWvjxusGo9WQnrNx2sqG0tfsghAvtVlRW3tvkXWZh58N9jp"
-      crossorigin="anonymous">
-    <link rel="stylesheet"
-      href="https://use.fontawesome.com/releases/v5.1.0/css/all.css" integrity="sha384-lKuwvrZot6UHsBSfcMvOkWwlCMgc0TaWr+30HWe3a4ltaBwTZhyTEggF5tJv8tbt"
-      crossorigin="anonymous">
-    <link rel="preconnect" href="https://fonts.googleapis.com">
-    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
-    <link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;500;600;700&display=swap" rel="stylesheet"> 
-    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-+0n0xVW2eSR5OomGNYDnhzAbDsOXxcvSN1TPprVMTNDbiYZCxYbOOl7+AMvyTG2x" crossorigin="anonymous">
-    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sweetalert2@11.0.18/dist/sweetalert2.min.css">
-    <link rel="stylesheet" href="static/owl.carousel.min.css">
-    <link rel="stylesheet" href="static/owl.theme.default.min.css">
-    <link rel="stylesheet" href="static/scss/style.css">
-    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
-    <title>AI Spokesgirl</title>
-</head>
-
-<body>
-    <!-- ================================================================= -->
-    <!-- navbar -->
-    <nav class="navbar navbar-expand-lg navbar-light">
-        <div class="container-fluid">
-            <a class="navbar-brand" href="index.html">AI Spokesgirl</a>
-            <button class="navbar-toggler" type="button" data-bs-toggle="collapse"
-                data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false"
-                aria-label="Toggle navigation">
-                <span class="navbar-toggler-icon"></span>
-            </button>
-            <div class="collapse navbar-collapse" id="navbarSupportedContent">
-                <ul class="navbar-nav me-auto mb-2 mb-lg-0">
-                    <li class="nav-item">
-                        <a class="nav-link active btn-gocreate text-white me-2" aria-current="page" href="make_video.html" set-lan="html:make_video">製作影片</a>
-                    </li>
-                    <li class="nav-item">
-                        <a class="nav-link active btn-gocreate text-white" aria-current="page" href="make_video_slide.html" set-lan="html:make_slides">SLIDE製作影片</a>                        
-                    </li>
-                    <li class="nav-item">
-                        <a class="nav-link active btn-gocreate text-white" aria-current="page" href="make_video_long.html" set-lan="html:make_video_long">製作長影片</a>                        
-                    </li>
-                </ul>
-                
-                <ul class="navbar-nav mb-2 mb-lg-0">
-                    <li class="nav-item">
-                        <a class="nav-link active" aria-current="page" href="pricing.html" set-lan="html:pricing">早鳥方案</a>
-                    </li>
-                    <li class="nav-item dropdown">
-                        <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
-                            中/En
-                        </a>
-                        <ul class="dropdown-menu" aria-labelledby="navbarDropdown">
-                            <li><button class="nav-link lan-swtich" aria-current="page" set-lan="html:en" onclick="changeLan(this)" value="en">English</button></li>
-                            <li><button class="nav-link lan-switch" aria-current="page" set-lan="html:zh" onclick="changeLan(this)" value="zh">中文</button></li>
-                        </ul>
-                    </li>
-                    <li class="nav-item">
-                        <a class="nav-link active btn-login" aria-current="page" href="login.html" set-lan="html:login">登入</a>
-                    </li>
-                    <li class="nav-item">
-                        <a class="nav-link btn-userProfile" aria-current="page" href="user_profile.html" set-lan="html:user_profile">會員資料</a>
-                    </li>
-                    <li class="nav-item">
-                        <a class="nav-link btn-logout" aria-current="page" set-lan="html:logout">登出</a>
-                    </li>
-                </ul>
-            </div>
-        </div>
-    </nav>
-    <!-- ================================================================= -->
-
-
-    <!-- ================================================================= -->
-    <!-- content -->
-    <div class="container px-0">
-        <div class="row">
-            <div class="col-xs-12 col-md-4">
-                <div class="container-profile">
-                    <img class="img-wave img-wave-profile" src="static/img/wave.png" alt="">
-                    <img class="container-bg" src="static/img/undraw_mobile_user_7oqo.svg" alt="">
-                    <div class="card card-profile">
-                        <img src="static/img/undraw_male_avatar_323b.svg" alt="">
-                        <p class="card-profile-txt">User Profile</p>
-                        <p class="card-profile-cnt"></p>
-                        <p class="card-profile-cnt"></p>
-                        <div class="d-flex justify-content-around">
-                            <div>
-                                <p set-lan="html:used">已使用</p>
-                                <p><strong></strong><span set-lan="html:sec">秒</span></p>
-                            </div>
-                            <div>
-                                <p set-lan="html:left">未使用</p>
-                                <p><strong></strong><span set-lan="html:sec">秒</span></p>
-                            </div>
-                        </div>
-                    </div>
-                </div> 
-            </div>
-            <div class="col-xs-12 col-md-8">
-                
-            </div>
-        </div>
-               
-    </div>
-    <!-- ================================================================= -->
-
-
-    <!-- ================================================================= -->
-    <!-- footer -->
-    <footer class="fixed-bottom text-center py-2">
-
-    </footer>
-    <!-- ================================================================= -->
-  
-    <script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script>
-    <script src='https://cdnjs.cloudflare.com/ajax/libs/jquery-easing/1.3/jquery.easing.min.js'></script>
-    <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.2/dist/umd/popper.min.js" integrity="sha384-IQsoLXl5PILFhosVNubq5LC7Qb9DXgDA9i+tQ8Zj3iwWAwPtgFTxbJ8NT4GN1R8p" crossorigin="anonymous"></script>
-    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/js/bootstrap.min.js" integrity="sha384-Atwg2Pkwv9vp0ygtn1JAojH0nYbwNJLPhwyoVbhoPwBhjQPR5VtM2+xf0Uwh9KtT" crossorigin="anonymous"></script> 
-    <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11.0.18/dist/sweetalert2.all.min.js"></script>
-    <script src="static/owl.carousel.min.js"></script>
-    <!-- <script src="script_profiles.js"></script> -->
-    <script type="text/javascript" src="static/lan.js"></script>
-    <script src="static/common.js"></script>
-</body>
-
-</html>

+ 16 - 17
html/user_profile2.html

@@ -53,10 +53,10 @@
                                 </ul>
                             </li>
                             <li class="nav-item">
-                                <a class="nav-link active btn-login text-white" aria-current="page" href="login.html" set-lan="html:login">登入</a>
+                                <a class="nav-link btn-userProfile text-white" aria-current="page" href="user_profile2.html" set-lan="html:user_profile">會員資料</a>
                             </li>
                             <li class="nav-item">
-                                <a class="nav-link btn-userProfile text-white" aria-current="page" href="user_profile.html" set-lan="html:user_profile">會員資料</a>
+                                <a class="nav-link active btn-login text-white" aria-current="page" href="login.html" set-lan="html:login">登入</a>
                             </li>
                             <li class="nav-item text-white">
                                 <a class="nav-link btn-logout text-white" aria-current="page" set-lan="html:logout">登出</a>
@@ -75,20 +75,20 @@
     <div class="container-fluid px-0">
         <div id="mySidenav" class="sidenav">
             <div class="text-start mt-3">
-                <a href="index.html"><img class="img-fluid w-50 ps-1" src="./static/img/contactus/CMM_LOGO.png" alt=""></a>
                 <h2 class="fw-bold ps-0" href="index.html"><a class="nav-link active ps-1" aria-current="page" href="index.html">AI Spokesgirl</a></h2>
             </div>
             <div class="userName"></div> 
-            <img class="user img-fluid rounded-circle" src="./static/img/contactus/man.jpg" alt="">
+            <img class="user img-fluid rounded-circle" src="./static/img/userprofile/userimg.png" alt="">
             <p class="text-white my-3 text-center" set-lan="html:Createsthtoday">今天要做甚麼影片呢?</p>
             <div class="navbar-nav mb-2 mb-lg-0 px-3 pe-4">
-                <a class="nav-link btn-gocreate text-white col-6" aria-current="page" href="./make_video.html" set-lan="html:make_video">影片製作</a>
-                <a class="nav-link btn-gocreate text-white col-6" aria-current="page" href="./make_video_slide.html" set-lan="html:make_slides">投影片影片製作</a>
+                <a class="nav-link btn-gocreate text-white col-6 btn-makev" aria-current="page" href="./make_video.html" set-lan="html:make_video">影片製作</a>
+                <a class="nav-link btn-gocreate text-white col-6 btn-makelong" aria-current="page" href="./make_video_long.html" set-lan="html:make_video_long">長影片製作</a>
             </div>
             <div class="navbar-nav mb-2 mb-lg-0 px-3 pe-4">
-                <a class="nav-link btn-gocreate text-white col-6" aria-current="page" href="./index_eng.html" set-lan="html:make_video_eng">英文影片製作</a>
-                <a class="nav-link btn-gocreate text-white col-6" aria-current="page" href="./make_video_long.html" set-lan="html:make_video_long">長影片製作</a>
+                <a class="nav-link btn-gocreate text-white col-6 btn-makeppt" aria-current="page" href="./make_video_slide.html" set-lan="html:make_slides">投影片影片製作</a>
+                <a class="nav-link btn-gocreate text-white col-6 btn-makeen" aria-current="page" href="./index_eng.html" set-lan="html:make_video_eng">純英文影片製作</a>
             </div>
+            
             <hr>
             <ul class="nav-list ps-0">
                 <li class="nav-list-item pb-1 mb-3" data-bs-toggle="modal" data-bs-target="#howto"><i
@@ -132,8 +132,8 @@
                     <div class="information">
                         <div class="row px-0 mx-0 mt-4">
                             <div style="letter-spacing: 3px;" class="col-lg-4">
-                                <p class="text-end" set-lan="html:username">帳號/用戶名稱:</p>
-                                <P class="text-end" set-lan="html:password">密碼:</P>
+                                <p class="text-end"><span set-lan="html:username">帳號/用戶名稱</span> : </p>
+                                <P class="text-end"><span set-lan="html:password">密碼</span> : </P>
                                 <p class="text-end">Email:</p>
                             </div>
                             <div class="userinf col-lg-8">
@@ -227,12 +227,11 @@
                                 </div>
                                 <div class="share col-lg-12">
                                     <div class="card p-4">
-                                        <h3>Want to get more minutes?</h3>
-                                       <p class="mb-0">Invite your friends to AI Spokesgirl and for each eligible one that </p>
-                                       <p>signs up from your referral, we'll give you 3 more minutes free!</p>
-                                       <div>
-                                           <p style="color:#183790; font-size: 20px;" class="d-inline fw-bold">Share:</p>
-                                           <div class="fb-share-button" data-href="https://video.choozmo.com/" data-layout="button" data-size="large"><a target="_blank" href="https://www.facebook.com/sharer/sharer.php?u=http%3A%2F%2Flocalhost%3A8080%2Fhtml%2Findex.html&amp;src=sdkpreparse" class="fb-xfbml-parse-ignore">分享</a></div>
+                                        <h3 set-lan="html:trial_title">Want to get more minutes?</h3>
+                                       <p class="mb-2" set-lan="html:trial_txt">Invite your friends to AI Spokesgirl and for each eligible one that signs up from your referral, we'll give you 3 more minutes free!</p>
+                                       <div class="d-flex">
+                                           <p style="color:#183790; font-size: 20px;" class="d-inline fw-bold" set-lan="html:share" >Share:</p>
+                                           <div class="fb-share-button mx-4" data-href="https://video.choozmo.com/" data-layout="button" data-size="large"><a target="_blank" href="https://www.facebook.com/sharer/sharer.php?u=http%3A%2F%2Flocalhost%3A8080%2Fhtml%2Findex.html&amp;src=sdkpreparse" class="fb-xfbml-parse-ignore">Facebook</a></div>
                                             <a class="mx-4" href="https://twitter.com/intent/tweet?text=I%20just%20created%20a%20video%20in%205%20minutes.%20Check%20it%20out%20%F0%9F%91%89%20https%3A%2F%2Fvideo.choozmo.com/&related=ai_cmm" target="_blank"><img width="28" class="me-2" src="./static/img/userprofile/Icon awesome-twitter-square.png" alt="">Twitter</a>
                                             <a class="mx-4 share-email"><img width="28" class="me-2" src="./static/img/userprofile/Icon material-email.png" alt="">Email</a>                                         
                                        </div>
@@ -305,8 +304,8 @@
     <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11.0.18/dist/sweetalert2.all.min.js"></script>
     <script src="static/owl.carousel.min.js"></script>
     <script src="static/loading-overlay.js"></script>
-    <script src="./script_profiles.js"></script>
     <script type="text/javascript" src="static/lan.js"></script>
+    <script src="./script_profiles.js"></script>
     <script src="static/common.js"></script>
 </body>
 

+ 56 - 0
html/verify_email.html

@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html lang="en" >
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>驗證信箱</title>
+    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css">
+    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.13/css/all.css" integrity="sha384-DNOHZ68U8hZfKXOrtjWvjxusGo9WQnrNx2sqG0tfsghAvtVlRW3tvkXWZh58N9jp"
+        crossorigin="anonymous">
+    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-+0n0xVW2eSR5OomGNYDnhzAbDsOXxcvSN1TPprVMTNDbiYZCxYbOOl7+AMvyTG2x" crossorigin="anonymous">
+    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
+    <style>
+    .h2 {
+        text-align: center;
+        font-size: 2rem;
+        font-weight: 500;
+        margin-top: 2rem;
+    }
+    .imgfr {
+      width: 70%;
+      max-width: 800px;
+      min-width: 300px;
+    }
+    .imgfr img {
+      width: 100%;
+    }
+    .pl-0 {
+        padding-left: 0;
+    }
+    .link {
+      text-decoration: none;
+    }
+    </style>
+</head>
+<body>
+    <div class="container">
+      <main>
+        <div class="m-auto text-center">
+          <h2 class="h2"><img src="../html/static/img/checked (2).png" width="36" class="me-2">驗證成功</h2>
+          <p>立即導頁至<a href="./login.html" class="link">登入頁</a>,以繼續使用服務</p>
+          <div><img src="../html/static/img/Spinner-1s-181px.gif" width="36" alt=""></div>
+          <div class="imgfr mx-auto">
+            <img src="../html/static/img/undraw_well_done_i2wr.png" alt="">
+          </div>
+          
+        </div>
+      </main>
+        
+    </div>
+    <script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script>
+    <script src='https://cdnjs.cloudflare.com/ajax/libs/jquery-easing/1.3/jquery.easing.min.js'></script>
+    <script>
+      
+    </script>
+</body>
+</html>

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels