File size: 3,796 Bytes
02ee0b7 a67abac 02ee0b7 a67abac 02ee0b7 a67abac ea1d31a aba0609 02ee0b7 aba0609 02ee0b7 175d049 02ee0b7 fea7e85 ea1d31a 02ee0b7 175d049 02ee0b7 da94ae5 02ee0b7 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | import os
import base64
import urllib.parse
from pathlib import Path
import gradio as gr
def _logo_data_uri() -> str:
"""logo.png を Base64 エンコードして data URI を返す。ファイルがなければ空文字。"""
logo_path = Path(__file__).parent / "logo.png"
if logo_path.exists():
data = base64.b64encode(logo_path.read_bytes()).decode()
return f"data:image/png;base64,{data}"
return ""
LOGO_SRC = _logo_data_uri()
# --- チャット(コメントアウト) ---
# # Level Bridge Chat の Space URL(環境変数で上書き可能)
# CHAT_SPACE_URL = os.environ.get(
# "LEVEL_BRIDGE_CHAT_URL",
# "https://dlpo-level-bridge-chat.hf.space",
# )
# # チャットiframeに転送するパラメータ名一覧
# FORWARD_PARAMS = ["url", "industry", "campaign_name", "cvr", "ctr", "cpa"]
#
#
# def build_chat_html(params: dict) -> str:
# """URLパラメータをチャットiframe srcに付与してHTML生成"""
# chat_params = {k: v for k, v in params.items() if k in FORWARD_PARAMS and v}
# if chat_params:
# src = CHAT_SPACE_URL + "?" + urllib.parse.urlencode(chat_params)
# else:
# src = CHAT_SPACE_URL
# return f"""
# <div style="
# border: 1px solid #e0e0e0;
# border-radius: 12px;
# overflow: hidden;
# height: 1000px;
# background: #fafafa;
# ">
# <iframe
# src="{src}"
# style="width:100%; height:100%; border:none;"
# allow="clipboard-write"
# ></iframe>
# </div>
# <p style="font-size:11px; color:#999; margin-top:4px; text-align:right;">
# Powered by Level Bridge Chat
# </p>
# """
def create_login_ui(handle_login_fn):
"""
Create Gradio login UI (チャットはコメントアウト済み).
Args:
handle_login_fn: Function to handle login (request, email, password) -> (form_update, status_update, token)
First argument must be gr.Request for source detection.
Returns:
Gradio Blocks UI for login
"""
with gr.Blocks(title="Login") as ui:
# --- 上段: ロゴ ---
gr.HTML(f'<img src="{LOGO_SRC}" alt="dlpo" style="height:48px;display:block;margin:16px 0 8px 0;">')
with gr.Column(visible=True) as login_form:
email_input = gr.Textbox(label="Email")
pass_input = gr.Textbox(label="Password", type="password")
login_btn = gr.Button("Login", variant="primary")
status_msg = gr.Markdown("")
# Hidden textbox to store token and trigger cookie setting via JS
token_storage = gr.Textbox(visible=False, elem_id="token_storage")
# External login handler (from app.py) is bound here.
# gr.Request は Gradio が第1引数に自動注入するため inputs に含めない。
login_btn.click(
handle_login_fn,
inputs=[email_input, pass_input],
outputs=[login_form, status_msg, token_storage],
)
# When token is set, use JavaScript to save cookie and redirect
token_storage.change(
None,
inputs=[token_storage],
js="""(token) => {
if (!token || token === "") return;
// Set cookie: max-age=3600 は Supabase JWT の標準有効期限に合わせた値。
// セッション延長には Supabase refresh_token による更新が必要(中長期対応候補)。
document.cookie = `sb_access_token=${token}; path=/; max-age=3600; SameSite=None; Secure;`;
console.log("Cookie set, redirecting...");
// Wait briefly then redirect
setTimeout(() => {
window.location.href = '/app/';
}, 200);
}""",
)
return ui
|