Spaces:
Sleeping
Sleeping
UI改版 Phase 1:字級統一、Metadata標題拿掉跳號、footer精簡、對話框視覺調整
Browse files- 全站字級收斂為 --font-size-base token;Metadata表單標題拿掉數字編號;
footer 移除 Gradio 品牌連結;Metadata略過文案定稿
- 對話氣泡改回貼合文字內容、加大四邊留白、移除色條邊線改用淺灰底色,
並修正 Gradio Chatbot 元件內建的 message-row margin/max-width 限制,
讓 AI/使用者訊息都能貼近對話視窗邊緣
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- .gitignore +1 -0
- app_agent.py +55 -36
.gitignore
CHANGED
|
@@ -23,6 +23,7 @@ LLM_Analysis-*.txt
|
|
| 23 |
|
| 24 |
# Pics / design assets
|
| 25 |
00pic/
|
|
|
|
| 26 |
|
| 27 |
# Spec workflow
|
| 28 |
.spec-workflow/
|
|
|
|
| 23 |
|
| 24 |
# Pics / design assets
|
| 25 |
00pic/
|
| 26 |
+
docs/design/
|
| 27 |
|
| 28 |
# Spec workflow
|
| 29 |
.spec-workflow/
|
app_agent.py
CHANGED
|
@@ -1683,6 +1683,8 @@ _CUSTOM_CSS = """
|
|
| 1683 |
--c-scrollbar: #cbd5e1;
|
| 1684 |
--c-scrollbar-hover: #94a3b8;
|
| 1685 |
|
|
|
|
|
|
|
| 1686 |
--body-background-fill: var(--c-bg) !important;
|
| 1687 |
--background-fill-primary: var(--c-surface) !important;
|
| 1688 |
--background-fill-secondary: #eef2f7 !important;
|
|
@@ -2024,15 +2026,27 @@ div[role="log"][aria-label="chatbot conversation"],
|
|
| 2024 |
}
|
| 2025 |
|
| 2026 |
/* ── 通用訊息氣泡 ── */
|
| 2027 |
-
/*
|
| 2028 |
-
間距
|
| 2029 |
-
|
| 2030 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2031 |
.main-chat .message-row .message {
|
| 2032 |
border-radius: 10px !important;
|
| 2033 |
-
font-size:
|
| 2034 |
line-height: 1.7 !important;
|
| 2035 |
-
padding: .
|
|
|
|
| 2036 |
max-width: 90% !important;
|
| 2037 |
transition: box-shadow .2s !important;
|
| 2038 |
}
|
|
@@ -2046,45 +2060,42 @@ div[role="log"][aria-label="chatbot conversation"],
|
|
| 2046 |
max-width: 100% !important;
|
| 2047 |
}
|
| 2048 |
|
| 2049 |
-
/* 使用者訊息:
|
| 2050 |
-
|
| 2051 |
/* Gradio 實際輸出的內層元素同時帶 user/bot 與 message 兩個 class(非巢狀父子),
|
| 2052 |
用複合選擇器只命中該元素本身,避免命中內層 panel-full-width 造成雙重框線 */
|
| 2053 |
.main-chat .message-row.user .message,
|
| 2054 |
.main-chat .message-row.user-row .user.message {
|
| 2055 |
background: transparent !important;
|
| 2056 |
border: none !important;
|
| 2057 |
-
border-right: 3px solid var(--c-success) !important;
|
| 2058 |
border-radius: 0 !important;
|
| 2059 |
color: var(--c-text) !important;
|
| 2060 |
margin-left: auto !important;
|
| 2061 |
font-weight: 500 !important;
|
| 2062 |
box-shadow: none !important;
|
| 2063 |
-
padding: .4rem .8rem !important;
|
| 2064 |
-
width: fit-content !important;
|
| 2065 |
max-width: 80% !important;
|
|
|
|
| 2066 |
}
|
| 2067 |
.main-chat .message-row.user,
|
| 2068 |
.main-chat .message-row.user-row { margin-bottom: 1.1rem !important; }
|
| 2069 |
|
| 2070 |
-
/* AI 訊息(主對話視窗):
|
| 2071 |
-
視覺上更簡潔,融入對話視窗本身的背景 */
|
| 2072 |
.main-chat .message-row.bot .message,
|
| 2073 |
.main-chat .message-row.bot-row .bot.message {
|
| 2074 |
background: transparent !important;
|
| 2075 |
border: none !important;
|
| 2076 |
-
border-left: 3px solid var(--c-accent-strong) !important;
|
| 2077 |
border-radius: 0 !important;
|
| 2078 |
color: var(--c-text) !important;
|
| 2079 |
-
font-size:
|
| 2080 |
line-height: 1.7 !important;
|
| 2081 |
box-shadow: none !important;
|
|
|
|
| 2082 |
}
|
| 2083 |
/* Gradio 產生的 <p> 段落本身有自己的 font-size(實測為固定 16px),
|
| 2084 |
不會沿用上面設在外層容器的字級,且段落間距預設高達 16px,
|
| 2085 |
視覺上偏大又有明顯空行,這裡直接命中 <p> 覆寫 */
|
| 2086 |
.main-chat .message-row .message p {
|
| 2087 |
-
font-size:
|
| 2088 |
line-height: 1.6 !important;
|
| 2089 |
margin: 0 0 .5rem !important;
|
| 2090 |
}
|
|
@@ -2095,8 +2106,11 @@ div[role="log"][aria-label="chatbot conversation"],
|
|
| 2095 |
改成 block 並統一字級後,這段隱形空隙就會消失 */
|
| 2096 |
.main-chat .message-row .message .md {
|
| 2097 |
display: block !important;
|
| 2098 |
-
font-size:
|
| 2099 |
line-height: 1.6 !important;
|
|
|
|
|
|
|
|
|
|
| 2100 |
}
|
| 2101 |
.main-chat .message-row.bot .message strong,
|
| 2102 |
.main-chat .message-row.bot .message b,
|
|
@@ -2134,7 +2148,7 @@ div[role="log"][aria-label="chatbot conversation"],
|
|
| 2134 |
}
|
| 2135 |
#exec_log_accordion .label-wrap {
|
| 2136 |
color: var(--c-text-muted) !important;
|
| 2137 |
-
font-size:
|
| 2138 |
}
|
| 2139 |
|
| 2140 |
/* 執行視窗(簡易訊息顯示欄,非對話氣泡) */
|
|
@@ -2150,7 +2164,7 @@ div[role="log"][aria-label="chatbot conversation"],
|
|
| 2150 |
margin-top: 0 !important;
|
| 2151 |
}
|
| 2152 |
.exec-log p {
|
| 2153 |
-
font-size:
|
| 2154 |
line-height: 1.5 !important;
|
| 2155 |
margin: 0 0 .3rem !important;
|
| 2156 |
padding: 0 !important;
|
|
@@ -2164,13 +2178,13 @@ div[role="log"][aria-label="chatbot conversation"],
|
|
| 2164 |
background: none !important;
|
| 2165 |
color: var(--c-accent-strong) !important;
|
| 2166 |
padding: 0 .15rem 0 0 !important;
|
| 2167 |
-
font-size:
|
| 2168 |
}
|
| 2169 |
/* 跟對話視窗一樣:包住段落的 <span class="md"> 預設 inline 卻裝 block 的
|
| 2170 |
<p>,會在最前面產生依自己字級算出的隱形空隙,這裡一併改成 block 並統一字級 */
|
| 2171 |
.exec-log .md {
|
| 2172 |
display: block !important;
|
| 2173 |
-
font-size:
|
| 2174 |
}
|
| 2175 |
|
| 2176 |
/* ── 5b. COLUMN LAYOUT ─────────────────────────────────────────── */
|
|
@@ -2230,15 +2244,15 @@ div[role="log"][aria-label="chatbot conversation"],
|
|
| 2230 |
border-bottom: 1px solid rgba(var(--c-accent-rgb),.16) !important;
|
| 2231 |
padding: 0 0 .9rem !important;
|
| 2232 |
margin-bottom: .9rem !important;
|
| 2233 |
-
font-size:
|
| 2234 |
}
|
| 2235 |
-
.upload-hint p, .upload-hint li { font-size:
|
| 2236 |
.upload-hint strong { color: var(--c-accent-strong) !important; }
|
| 2237 |
/* 同陷阱 13 第 3 點:<span class="md"> 預設 inline 卻裝 block 的 <p>,
|
| 2238 |
會在最前面產生依自己字級算出的隱形空隙,這裡一併修正 */
|
| 2239 |
.upload-hint .md {
|
| 2240 |
display: block !important;
|
| 2241 |
-
font-size:
|
| 2242 |
}
|
| 2243 |
.upload-actions {
|
| 2244 |
margin-top: 1rem !important;
|
|
@@ -2303,7 +2317,7 @@ button.primary, button[data-testid="submit"] {
|
|
| 2303 |
border: none !important;
|
| 2304 |
border-radius: 9px !important;
|
| 2305 |
font-weight: 700 !important;
|
| 2306 |
-
font-size:
|
| 2307 |
color: #fff !important;
|
| 2308 |
box-shadow: 0 2px 12px rgba(2,132,199,.28) !important;
|
| 2309 |
transition: transform .18s ease, box-shadow .18s ease, opacity .18s !important;
|
|
@@ -2319,7 +2333,7 @@ button.secondary {
|
|
| 2319 |
color: var(--c-accent-strong) !important;
|
| 2320 |
border-radius: 9px !important;
|
| 2321 |
font-weight: 600 !important;
|
| 2322 |
-
font-size:
|
| 2323 |
cursor: pointer !important;
|
| 2324 |
transition: background .18s ease, border-color .18s ease !important;
|
| 2325 |
}
|
|
@@ -2365,7 +2379,7 @@ table thead th {
|
|
| 2365 |
table tbody td {
|
| 2366 |
background: var(--c-surface) !important;
|
| 2367 |
color: var(--c-text-soft) !important;
|
| 2368 |
-
font-size:
|
| 2369 |
border-color: rgba(var(--c-accent-rgb),.06) !important;
|
| 2370 |
font-family: 'JetBrains Mono', monospace !important;
|
| 2371 |
padding: 7px 12px !important;
|
|
@@ -2512,7 +2526,7 @@ a:hover { color: var(--c-link-hover); }
|
|
| 2512 |
}
|
| 2513 |
.legend-item {
|
| 2514 |
display: inline-flex; align-items: center; gap: .5rem;
|
| 2515 |
-
font-size:
|
| 2516 |
color: var(--c-text-subtle);
|
| 2517 |
}
|
| 2518 |
.legend-item .dot {
|
|
@@ -2773,7 +2787,7 @@ def create_app():
|
|
| 2773 |
with gr.Column(visible=False, elem_id="metadata_zone", elem_classes=["metadata-zone"]) as metadata_row:
|
| 2774 |
gr.Markdown("### 📑 語料 Metadata 說明\n請於正式分析前說明語料來源、範圍與比較結構,將寫入研究報告。")
|
| 2775 |
|
| 2776 |
-
gr.Markdown("**
|
| 2777 |
with gr.Row():
|
| 2778 |
meta_title = gr.Textbox(label="原文標題", scale=2)
|
| 2779 |
meta_author = gr.Textbox(label="作者", scale=2)
|
|
@@ -2784,7 +2798,7 @@ def create_app():
|
|
| 2784 |
|
| 2785 |
# 比較結構(僅情境 3、4 需要;情境 1、2 固定二群)
|
| 2786 |
with gr.Group(visible=False) as meta_compare_group:
|
| 2787 |
-
gr.Markdown("**
|
| 2788 |
with gr.Row():
|
| 2789 |
meta_ngroups = gr.Radio(
|
| 2790 |
["二群", "三群"], label="群組數量", value="二群", scale=1,
|
|
@@ -2794,7 +2808,7 @@ def create_app():
|
|
| 2794 |
value="群組間比較", scale=1,
|
| 2795 |
)
|
| 2796 |
|
| 2797 |
-
gr.Markdown("**
|
| 2798 |
meta_group_df = gr.Dataframe(
|
| 2799 |
headers=["群組標籤", "翻譯類型", "翻譯方向", "譯者背景", "目標讀者"],
|
| 2800 |
datatype=["str"] * 5,
|
|
@@ -2804,7 +2818,7 @@ def create_app():
|
|
| 2804 |
label="群組層",
|
| 2805 |
)
|
| 2806 |
|
| 2807 |
-
gr.Markdown("**
|
| 2808 |
meta_indiv_df = gr.Dataframe(
|
| 2809 |
headers=["檔案", "譯者/系統名稱", "出版年", "譯者母語", "後編輯程度", "重譯序位"],
|
| 2810 |
datatype=["str"] * 6,
|
|
@@ -2814,6 +2828,10 @@ def create_app():
|
|
| 2814 |
label="個體層",
|
| 2815 |
)
|
| 2816 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2817 |
with gr.Row(elem_classes=["upload-actions"]):
|
| 2818 |
meta_cancel_btn = gr.Button("略過", scale=1, variant="secondary")
|
| 2819 |
meta_confirm_btn = gr.Button("確認並開始分析", scale=2, variant="primary")
|
|
@@ -3245,24 +3263,24 @@ def create_app():
|
|
| 3245 |
ngroups, method, group_df, indiv_df):
|
| 3246 |
sc = state.get("scenario", "")
|
| 3247 |
L = ["## 語料 Metadata", "",
|
| 3248 |
-
"###
|
| 3249 |
f"- 原文標題:{title or '(未填)'}",
|
| 3250 |
f"- 作者:{author or '(未填)'}",
|
| 3251 |
f"- 語言:{lang or '(未填)'}",
|
| 3252 |
f"- 出版年:{pubyear or '(未填)'}",
|
| 3253 |
f"- 版本:{version or '(未填)'}", ""]
|
| 3254 |
if sc in ("3", "4"):
|
| 3255 |
-
L += ["###
|
| 3256 |
f"- 群組數量:{ngroups}",
|
| 3257 |
f"- 比較方式:{method}", ""]
|
| 3258 |
gh = ["群組標籤", "翻譯類型", "翻譯方向", "譯者背景", "目標讀者"]
|
| 3259 |
-
L += ["###
|
| 3260 |
for r in _df_rows(group_df):
|
| 3261 |
if not any(str(c).strip() for c in r):
|
| 3262 |
continue
|
| 3263 |
L.append("- " + ";".join(f"{h}:{str(v).strip()}" for h, v in zip(gh, r) if str(v).strip()))
|
| 3264 |
ih = ["檔案", "譯者/系統名稱", "出版年", "譯者母語", "後編輯程度", "重譯序位"]
|
| 3265 |
-
L += ["", "###
|
| 3266 |
for r in _df_rows(indiv_df):
|
| 3267 |
if not any(str(c).strip() for c in r):
|
| 3268 |
continue
|
|
@@ -3408,4 +3426,5 @@ if __name__ == "__main__":
|
|
| 3408 |
inbrowser=False,
|
| 3409 |
allowed_paths=[str(SESSIONS_DIR)],
|
| 3410 |
head=_APP_HEAD,
|
|
|
|
| 3411 |
)
|
|
|
|
| 1683 |
--c-scrollbar: #cbd5e1;
|
| 1684 |
--c-scrollbar-hover: #94a3b8;
|
| 1685 |
|
| 1686 |
+
--font-size-base: 0.875rem;
|
| 1687 |
+
|
| 1688 |
--body-background-fill: var(--c-bg) !important;
|
| 1689 |
--background-fill-primary: var(--c-surface) !important;
|
| 1690 |
--background-fill-secondary: #eef2f7 !important;
|
|
|
|
| 2026 |
}
|
| 2027 |
|
| 2028 |
/* ── 通用訊息氣泡 ── */
|
| 2029 |
+
/* 不同時間產生的訊息之間如果間距太小,會分不出是好幾則獨立訊息還是同一則,
|
| 2030 |
+
拉大訊息列間距讓每則訊息之間有清楚的留白斷開 */
|
| 2031 |
+
/* Gradio 預設給每個 message-row 左右各留 20px margin(原本應是保留給頭像用的
|
| 2032 |
+
空間,本專案沒有用頭像),導致 AI 訊息離左邊、使用者訊息離右邊都比預期遠,
|
| 2033 |
+
這裡歸零讓氣泡貼近對話視窗邊緣。另外 Gradio 還設了 max-width: calc(100% - 60px),
|
| 2034 |
+
AI 訊息貼左邊不受影響,但使用者訊息靠 margin-left:auto 貼右邊,這 60px
|
| 2035 |
+
缺口會整個落在最右側,一併覆寫掉 */
|
| 2036 |
+
.main-chat .message-row {
|
| 2037 |
+
margin-bottom: 1.1rem !important;
|
| 2038 |
+
margin-left: 0 !important;
|
| 2039 |
+
margin-right: 0 !important;
|
| 2040 |
+
width: 100% !important;
|
| 2041 |
+
max-width: 100% !important;
|
| 2042 |
+
align-self: stretch !important;
|
| 2043 |
+
}
|
| 2044 |
.main-chat .message-row .message {
|
| 2045 |
border-radius: 10px !important;
|
| 2046 |
+
font-size: var(--font-size-base) !important;
|
| 2047 |
line-height: 1.7 !important;
|
| 2048 |
+
padding: 0.75rem 1rem !important;
|
| 2049 |
+
width: fit-content !important;
|
| 2050 |
max-width: 90% !important;
|
| 2051 |
transition: box-shadow .2s !important;
|
| 2052 |
}
|
|
|
|
| 2060 |
max-width: 100% !important;
|
| 2061 |
}
|
| 2062 |
|
| 2063 |
+
/* 使用者訊息:淺灰底色跟白色頁面背景錯開,不用外框線,靠右對齊與置左的
|
| 2064 |
+
AI 訊息做區分 */
|
| 2065 |
/* Gradio 實際輸出的內層元素同時帶 user/bot 與 message 兩個 class(非巢狀父子),
|
| 2066 |
用複合選擇器只命中該元素本身,避免命中內層 panel-full-width 造成雙重框線 */
|
| 2067 |
.main-chat .message-row.user .message,
|
| 2068 |
.main-chat .message-row.user-row .user.message {
|
| 2069 |
background: transparent !important;
|
| 2070 |
border: none !important;
|
|
|
|
| 2071 |
border-radius: 0 !important;
|
| 2072 |
color: var(--c-text) !important;
|
| 2073 |
margin-left: auto !important;
|
| 2074 |
font-weight: 500 !important;
|
| 2075 |
box-shadow: none !important;
|
|
|
|
|
|
|
| 2076 |
max-width: 80% !important;
|
| 2077 |
+
text-align: right !important;
|
| 2078 |
}
|
| 2079 |
.main-chat .message-row.user,
|
| 2080 |
.main-chat .message-row.user-row { margin-bottom: 1.1rem !important; }
|
| 2081 |
|
| 2082 |
+
/* AI 訊息(主對話視窗):淺灰底色跟白色頁面背景錯開,不用外框線 */
|
|
|
|
| 2083 |
.main-chat .message-row.bot .message,
|
| 2084 |
.main-chat .message-row.bot-row .bot.message {
|
| 2085 |
background: transparent !important;
|
| 2086 |
border: none !important;
|
|
|
|
| 2087 |
border-radius: 0 !important;
|
| 2088 |
color: var(--c-text) !important;
|
| 2089 |
+
font-size: var(--font-size-base) !important;
|
| 2090 |
line-height: 1.7 !important;
|
| 2091 |
box-shadow: none !important;
|
| 2092 |
+
text-align: left !important;
|
| 2093 |
}
|
| 2094 |
/* Gradio 產生的 <p> 段落本身有自己的 font-size(實測為固定 16px),
|
| 2095 |
不會沿用上面設在外層容器的字級,且段落間距預設高達 16px,
|
| 2096 |
視覺上偏大又有明顯空行,這裡直接命中 <p> 覆寫 */
|
| 2097 |
.main-chat .message-row .message p {
|
| 2098 |
+
font-size: var(--font-size-base) !important;
|
| 2099 |
line-height: 1.6 !important;
|
| 2100 |
margin: 0 0 .5rem !important;
|
| 2101 |
}
|
|
|
|
| 2106 |
改成 block 並統一字級後,這段隱形空隙就會消失 */
|
| 2107 |
.main-chat .message-row .message .md {
|
| 2108 |
display: block !important;
|
| 2109 |
+
font-size: var(--font-size-base) !important;
|
| 2110 |
line-height: 1.6 !important;
|
| 2111 |
+
padding: 0.9rem 1.1rem !important;
|
| 2112 |
+
background: var(--c-surface2) !important;
|
| 2113 |
+
border-radius: 10px !important;
|
| 2114 |
}
|
| 2115 |
.main-chat .message-row.bot .message strong,
|
| 2116 |
.main-chat .message-row.bot .message b,
|
|
|
|
| 2148 |
}
|
| 2149 |
#exec_log_accordion .label-wrap {
|
| 2150 |
color: var(--c-text-muted) !important;
|
| 2151 |
+
font-size: var(--font-size-base) !important;
|
| 2152 |
}
|
| 2153 |
|
| 2154 |
/* 執行視窗(簡易訊息顯示欄,非對話氣泡) */
|
|
|
|
| 2164 |
margin-top: 0 !important;
|
| 2165 |
}
|
| 2166 |
.exec-log p {
|
| 2167 |
+
font-size: var(--font-size-base) !important;
|
| 2168 |
line-height: 1.5 !important;
|
| 2169 |
margin: 0 0 .3rem !important;
|
| 2170 |
padding: 0 !important;
|
|
|
|
| 2178 |
background: none !important;
|
| 2179 |
color: var(--c-accent-strong) !important;
|
| 2180 |
padding: 0 .15rem 0 0 !important;
|
| 2181 |
+
font-size: var(--font-size-base) !important;
|
| 2182 |
}
|
| 2183 |
/* 跟對話視窗一樣:包住段落的 <span class="md"> 預設 inline 卻裝 block 的
|
| 2184 |
<p>,會在最前面產生依自己字級算出的隱形空隙,這裡一併改成 block 並統一字級 */
|
| 2185 |
.exec-log .md {
|
| 2186 |
display: block !important;
|
| 2187 |
+
font-size: var(--font-size-base) !important;
|
| 2188 |
}
|
| 2189 |
|
| 2190 |
/* ── 5b. COLUMN LAYOUT ─────────────────────────────────────────── */
|
|
|
|
| 2244 |
border-bottom: 1px solid rgba(var(--c-accent-rgb),.16) !important;
|
| 2245 |
padding: 0 0 .9rem !important;
|
| 2246 |
margin-bottom: .9rem !important;
|
| 2247 |
+
font-size: var(--font-size-base) !important;
|
| 2248 |
}
|
| 2249 |
+
.upload-hint p, .upload-hint li { font-size: var(--font-size-base) !important; color: var(--c-text-soft) !important; }
|
| 2250 |
.upload-hint strong { color: var(--c-accent-strong) !important; }
|
| 2251 |
/* 同陷阱 13 第 3 點:<span class="md"> 預設 inline 卻裝 block 的 <p>,
|
| 2252 |
會在最前面產生依自己字級算出的隱形空隙,這裡一併修正 */
|
| 2253 |
.upload-hint .md {
|
| 2254 |
display: block !important;
|
| 2255 |
+
font-size: var(--font-size-base) !important;
|
| 2256 |
}
|
| 2257 |
.upload-actions {
|
| 2258 |
margin-top: 1rem !important;
|
|
|
|
| 2317 |
border: none !important;
|
| 2318 |
border-radius: 9px !important;
|
| 2319 |
font-weight: 700 !important;
|
| 2320 |
+
font-size: var(--font-size-base) !important;
|
| 2321 |
color: #fff !important;
|
| 2322 |
box-shadow: 0 2px 12px rgba(2,132,199,.28) !important;
|
| 2323 |
transition: transform .18s ease, box-shadow .18s ease, opacity .18s !important;
|
|
|
|
| 2333 |
color: var(--c-accent-strong) !important;
|
| 2334 |
border-radius: 9px !important;
|
| 2335 |
font-weight: 600 !important;
|
| 2336 |
+
font-size: var(--font-size-base) !important;
|
| 2337 |
cursor: pointer !important;
|
| 2338 |
transition: background .18s ease, border-color .18s ease !important;
|
| 2339 |
}
|
|
|
|
| 2379 |
table tbody td {
|
| 2380 |
background: var(--c-surface) !important;
|
| 2381 |
color: var(--c-text-soft) !important;
|
| 2382 |
+
font-size: var(--font-size-base) !important;
|
| 2383 |
border-color: rgba(var(--c-accent-rgb),.06) !important;
|
| 2384 |
font-family: 'JetBrains Mono', monospace !important;
|
| 2385 |
padding: 7px 12px !important;
|
|
|
|
| 2526 |
}
|
| 2527 |
.legend-item {
|
| 2528 |
display: inline-flex; align-items: center; gap: .5rem;
|
| 2529 |
+
font-size: var(--font-size-base);
|
| 2530 |
color: var(--c-text-subtle);
|
| 2531 |
}
|
| 2532 |
.legend-item .dot {
|
|
|
|
| 2787 |
with gr.Column(visible=False, elem_id="metadata_zone", elem_classes=["metadata-zone"]) as metadata_row:
|
| 2788 |
gr.Markdown("### 📑 語料 Metadata 說明\n請於正式分析前說明語料來源、範圍與比較結構,將寫入研究報告。")
|
| 2789 |
|
| 2790 |
+
gr.Markdown("**原文資訊**")
|
| 2791 |
with gr.Row():
|
| 2792 |
meta_title = gr.Textbox(label="原文標題", scale=2)
|
| 2793 |
meta_author = gr.Textbox(label="作者", scale=2)
|
|
|
|
| 2798 |
|
| 2799 |
# 比較結構(僅情境 3、4 需要;情境 1、2 固定二群)
|
| 2800 |
with gr.Group(visible=False) as meta_compare_group:
|
| 2801 |
+
gr.Markdown("**比較結構**")
|
| 2802 |
with gr.Row():
|
| 2803 |
meta_ngroups = gr.Radio(
|
| 2804 |
["二群", "三群"], label="群組數量", value="二群", scale=1,
|
|
|
|
| 2808 |
value="群組間比較", scale=1,
|
| 2809 |
)
|
| 2810 |
|
| 2811 |
+
gr.Markdown("**群組層資訊**(共通屬性)")
|
| 2812 |
meta_group_df = gr.Dataframe(
|
| 2813 |
headers=["群組標籤", "翻譯類型", "翻譯方向", "譯者背景", "目標讀者"],
|
| 2814 |
datatype=["str"] * 5,
|
|
|
|
| 2818 |
label="群組層",
|
| 2819 |
)
|
| 2820 |
|
| 2821 |
+
gr.Markdown("**個體層資訊**(每個譯本/檔案)")
|
| 2822 |
meta_indiv_df = gr.Dataframe(
|
| 2823 |
headers=["檔案", "譯者/系統名稱", "出版年", "譯者母語", "後編輯程度", "重譯序位"],
|
| 2824 |
datatype=["str"] * 6,
|
|
|
|
| 2828 |
label="個體層",
|
| 2829 |
)
|
| 2830 |
|
| 2831 |
+
gr.Markdown(
|
| 2832 |
+
"以下資訊會寫入報告開頭,您也可以先略過(略過後這次分析將不會用到這些補充說明)",
|
| 2833 |
+
elem_classes=["upload-hint"],
|
| 2834 |
+
)
|
| 2835 |
with gr.Row(elem_classes=["upload-actions"]):
|
| 2836 |
meta_cancel_btn = gr.Button("略過", scale=1, variant="secondary")
|
| 2837 |
meta_confirm_btn = gr.Button("確認並開始分析", scale=2, variant="primary")
|
|
|
|
| 3263 |
ngroups, method, group_df, indiv_df):
|
| 3264 |
sc = state.get("scenario", "")
|
| 3265 |
L = ["## 語料 Metadata", "",
|
| 3266 |
+
"### 原文資訊",
|
| 3267 |
f"- 原文標題:{title or '(未填)'}",
|
| 3268 |
f"- 作者:{author or '(未填)'}",
|
| 3269 |
f"- 語言:{lang or '(未填)'}",
|
| 3270 |
f"- 出版年:{pubyear or '(未填)'}",
|
| 3271 |
f"- 版本:{version or '(未填)'}", ""]
|
| 3272 |
if sc in ("3", "4"):
|
| 3273 |
+
L += ["### 比較結構",
|
| 3274 |
f"- 群組數量:{ngroups}",
|
| 3275 |
f"- 比較方式:{method}", ""]
|
| 3276 |
gh = ["群組標籤", "翻譯類型", "翻譯方向", "譯者背景", "目標讀者"]
|
| 3277 |
+
L += ["### 群組層資訊"]
|
| 3278 |
for r in _df_rows(group_df):
|
| 3279 |
if not any(str(c).strip() for c in r):
|
| 3280 |
continue
|
| 3281 |
L.append("- " + ";".join(f"{h}:{str(v).strip()}" for h, v in zip(gh, r) if str(v).strip()))
|
| 3282 |
ih = ["檔案", "譯者/系統名稱", "出版年", "譯者母語", "後編輯程度", "重譯序位"]
|
| 3283 |
+
L += ["", "### 個體層資訊"]
|
| 3284 |
for r in _df_rows(indiv_df):
|
| 3285 |
if not any(str(c).strip() for c in r):
|
| 3286 |
continue
|
|
|
|
| 3426 |
inbrowser=False,
|
| 3427 |
allowed_paths=[str(SESSIONS_DIR)],
|
| 3428 |
head=_APP_HEAD,
|
| 3429 |
+
footer_links=["api", "settings"],
|
| 3430 |
)
|