ILRDF-AI-Translator / deep_analyzer.py
ILRDF-Lowking's picture
Update deep_analyzer.py
b45cad4 verified
Raw
History Blame Contribute Delete
14.9 kB
# deep_analyzer.py
import google.generativeai as genai
from supabase import create_client
import config
import json
import logging
import re
import requests # 👈 確保檔案最上面有 import requests
logger = logging.getLogger(__name__)
genai.configure(api_key=config.GEMINI_KEY)
supabase = create_client(config.SUPABASE_URL, config.SUPABASE_KEY)
# ----------------------------------------------------------------
# 📝 根據官方規範建立的資料庫全稱對齊映射(超前部署未來 15 族資料)
# ----------------------------------------------------------------
TRIBE_MAPPING = {
"阿美": "海岸阿美語",
"泰雅": "賽考利克泰雅語",
"賽夏": "賽夏語",
"邵": "邵語",
"賽德克": "德固達雅賽德克語",
"布農": "郡群布農語",
"排灣": "北排灣語",
"魯凱": "霧台魯凱語",
"太魯閣": "太魯閣語",
"噶瑪蘭": "噶瑪蘭語",
"鄒": "阿里山鄒語",
"卑南": "南王卑南語",
"雅美": "雅美語",
"撒奇萊雅": "撒奇萊雅語",
"卡那卡那富": "卡那卡那富語",
"拉阿魯哇": "拉阿魯哇語"
}
# ----------------------------------------------------------------
# 1. 滿血型 RAG 檢索邏輯 (智慧文字雷達版 - 速度極快且 100% 穩定)
# ----------------------------------------------------------------
def get_context(query, tribe):
try:
db_tribe_clean = tribe
db_tribe_full = TRIBE_MAPPING.get(tribe, tribe)
# 🎯 步驟 1:直接從 Supabase 撈取該族群的所有黃金語料 (不走 RPC 向量,改走純文字精準撈取)
response = supabase.table("lang_knowledge")\
.select("category, content")\
.in_("tribe", [db_tribe_clean, db_tribe_full])\
.execute()
records = response.data if response.data else []
if not records:
logger.info(f"[{tribe}語] 文字雷達:資料庫中目前無該族群的任何原始語料。")
return "尚無相關權威辭典與語法參考資料。"
# 🎯 步驟 2:核心文字雷達演算法(剝離標點符號,計算關鍵字元重疊比例)
clean_query = re.sub(r'[\s,。!?、??!\-_=\.<>]', '', query)
query_chars = set(clean_query)
scored_records = []
for item in records:
content = item.get('content', '')
# 計算使用者輸入的漢字/字元出現在此條語料中的數量
match_count = sum(1 for char in query_chars if char in content)
if match_count > 0:
score = match_count / len(query_chars) if query_chars else 0
scored_records.append((score, item))
# 依重疊分數從高到低進行語言學權重排序
scored_records.sort(key=lambda x: x[0], reverse=True)
# 僅篩選出重疊率大於 15% 的高價值精準小抄,最多取 10 筆
top_records = [item for score, item in scored_records if score >= 0.15][:10]
if not top_records:
logger.info(f"[{tribe}語] 文字雷達掃描完畢,但輸入語意與現存語料的特徵重疊度過低。")
return "尚無相關權威辭典與語法參考資料。"
academic_data = []
dictionary_data = []
for item in top_records:
cat = str(item.get('category', '')).strip()
content = item['content']
if "學術" in cat or "四行" in cat:
academic_data.append(f"【學術語法規範】: {content}")
else:
dictionary_data.append(f"【辭典詞彙參考】: {content}")
# 混合戰術:學術上限 5 句,剩餘由辭典補齊
final_context = academic_data[:5] + dictionary_data[:(10 - len(academic_data[:5]))]
logger.info(f"🎉 [文字雷達 RAG 大通車] 成功繞過 Google API,精擺打撈出 {len(final_context)} 筆核心對齊語料!")
return "\n\n".join(final_context)
except Exception as e:
logger.error(f"文字雷達 RAG 檢索徹底失敗: {e}")
return ""
# ----------------------------------------------------------------
# 2. 構詞語法分析引擎 (支援長短句智慧分流與 16 族文法隔離)
# ----------------------------------------------------------------
def get_structured_analysis(query, tribe):
context = get_context(query, tribe)
word_count = len(re.findall(r'\w+', query))
is_long = word_count > 15
# 💡 語言學防線分流:將太魯閣語特定的書寫規範進行隔離,避免干擾其他 15 族
if tribe == "太魯閣":
LINGUISTIC_RULES = """
【🛑 核心語言學與數詞規範】(最高優先級):
1. 構詞拆解:綴詞必須使用 '-' (例如 m-usa),代名詞連綴必須使用 '=' (例如 bubu=mu),完成貌必須使用 '<en>' (例如 q<en>pah)。
2. 數詞系統必須遵循族語習慣:40 必須為 mspatul,10 為 maxal。嚴禁使用生硬的拼湊(如 spac kmxalan)。
3. 遵守書寫規範 2.0 (單字中 o 轉 u)。
"""
else:
LINGUISTIC_RULES = f"""
【🛑 核心語言學與數詞規範】(最高優先級):
1. 構詞拆解:必須嚴格符合當前「{tribe}語」的官方現代構詞、標點與連字號書寫規範。
2. 語法結構分析與中文翻譯必須 100% 精準對齊「{tribe}語」的傳統生活語感與文化脈絡,絕對不准套用太魯閣語、泰雅語或其他無關族語的文法規則!
"""
if is_long:
# 長句模式:純文字標籤輸出(防 JSON 破碎)
model = genai.GenerativeModel('models/gemini-3.5-flash')
prompt = f"""
你是一位{tribe}語權威語言學家。請針對這段長難句進行深度解析。
原文:「{query}
【🛑 嚴格限制】:
1. 絕對禁止在說明中提到其他無關族語,一律以「{tribe}語」進行解析與說明。
2. 翻譯與分析必須絕對忠實,禁止修改原文語感。
3. 🛑【禁止擅自推翻小抄】進行深度解析時,語意核心「必須」與【參考資料】(小抄)完全一致!絕對禁止自行腦補出與原句核心題意(如:刺自己)毫不相干的華語解釋(如:獨立、現代等)!
{LINGUISTIC_RULES}
請嚴格按照以下標籤格式輸出:
【分析結果】:(這裡放條列式解釋,必須包含原文、構詞、語法、翻譯的分析)
【中文原文】:{query}
參考資料:
{context}
"""
try:
response = model.generate_content(prompt, generation_config={"temperature": 0.0})
text = response.text
explanation = text.split("【分析結果】:")[-1].split("【中文原文】:")[0].strip()
explanation = explanation.replace("**", "").replace("'", "")
return {"is_long": True, "explanation": explanation, "translation": query}
except:
return {"is_long": True, "explanation": "⚠️ 解析過於精密,請嘗試拆分句子。", "translation": query}
else:
model = genai.GenerativeModel(
'models/gemini-3.5-flash',
generation_config={"temperature": 0.0, "response_mime_type": "application/json"}
)
prompt = f"""
你是一位{tribe}語權威語言學家。針對使用者輸入產出符合學術「四行分析(Interlinear Glossing)」規範的精確 JSON。
使用者輸入:「{query}
【🛑 嚴格處理步驟與限制】:
1. 必須完全、唯一使用「{tribe}語」進行解析,回覆內容中絕對不准夾帶或提到其他族語。
2. 若輸入中文,請務必先將其精準翻譯為「{tribe}語」後再進行拆解。
3. 🛑【字義與解說防叛變鐵律】在拆解 line3(華語解釋)與填寫 explanation(綜合重點解說)時,所有字詞含意與意譯方向「必須」嚴格忠實於【參考資料】(小抄)的核心題意!絕對禁止自作聰明推翻小抄,或盲目腦補出與原句(如:刺自己)毫無關聯的離譜華語字面意思(如:獨立、現代、各做各的等)!
【🛑 四行分析欄位鋼鐵定義】:
- line1 (第一行):【族語書寫文字】。請填入該{tribe}語句子的單字原形拆解。
- line2 (第二行):【族語構詞語法分析 (仍為族語文字)】。請保留族語文字,並精準標出前綴、中綴、連字號等構詞結構。
- line3 (第三行):【構詞語法分析 (華語解釋)】。必須完全使用「繁體中文」說明該單字或綴詞的語法功能或字義(如:焦點標記、主格、過去貌、喜歡、家)。【絕對禁止出現英文或國際語言學縮寫(如 FOC, NOM, AF)】!
- translation (第四行):【句子華語翻譯】。請將整句話翻譯成最自然流暢的完整華語/中文句子。
3. 必須包含 'glossing' 結構,且 line1, line2, line3 必須是長度完全一致的陣列。
{LINGUISTIC_RULES}
【JSON 標準格式範例】:
{{
"is_long": false,
"glossing": {{
"line1": ["單字1", "單字2"],
"line2": ["構詞1", "構詞2"],
"line3": ["華語解釋1", "華語解釋2"]
}},
"explanation": "針對此句子語法的綜合重點解說內容",
"translation": "整句句子的華語完整翻譯"
}}
參考資料:
{context}
"""
try:
response = model.generate_content(prompt)
clean_text = response.text.replace("```json", "").replace("```", "").strip()
data = json.loads(clean_text)
if "glossing" not in data:
data["glossing"] = {
"line1": data.get("original", []),
"line2": data.get("morphemes", []),
"line3": data.get("gloss", [])
}
lines = ["line1", "line2", "line3"]
max_l = max([len(data["glossing"].get(l, [])) if isinstance(data["glossing"].get(l), list) else 0 for l in lines] + [1])
for l in lines:
if l not in data["glossing"] or not isinstance(data["glossing"][l], list):
data["glossing"][l] = []
while len(data["glossing"][l]) < max_l:
data["glossing"][l].append("")
if 'explanation' in data:
data['explanation'] = data['explanation'].replace("**", "").replace("'", "")
# 🎯【核心修正】如果使用者輸入的句子本身就包含華語(中文),強制將第四行校正為該中文!
# 這樣不論 Gemini 怎麼腦補,第四行都絕對會是整齊的華語翻譯。
if re.search(r'[\u4e00-\u9fff]', query):
data['translation'] = query
data['is_long'] = False
return data
except Exception as e:
logger.error(f"JSON 解析錯誤: {e}")
return {"is_long": True, "explanation": "自動轉為文字模式解析。", "translation": query}
# ----------------------------------------------------------------
# 3. 深度文化翻譯潤飾引擎 (經典三大防線 + 思考消音咒)
# ----------------------------------------------------------------
def deep_translation(source_text, target_text, tribe):
context = get_context(source_text + " " + target_text, tribe)
model = genai.GenerativeModel(
'models/gemini-3.5-flash',
generation_config={"temperature": 0.0, "max_output_tokens": 4000}
)
prompt = f"""
你是一位平易近人的{tribe}語翻譯專家。請參考資料對初稿進行深度潤飾與校正。
【🛑 第一防線:語意與防腦補絕對限制】(最高優先級)
1. 絕對忠實原文:翻譯內容必須 100% 貼合【原翻譯(華語)】的語意(如:這個學生自己刺自己)。原文沒有的主詞、時間或情境,【絕對禁止】自行添加!
2. 🚨【強制摧毀一般翻譯的詞彙幻覺】🚨:一般翻譯(初稿)極度不可靠,經常出現嚴重的字詞幻覺(例如將『刺』錯譯為『迷路 mataohtaoh』)。你「絕對不准」盲目保留一般翻譯的動詞結構!
3. 🚨【鋼鐵文法套用鐵律】🚨:你必須強制採用【參考資料】(小抄)中提供的高階權威反身文法骨架(如:Kis’anak’anak a ... a kislaupa)!請保持這個神級文法公式,僅根據使用者輸入的中文,將主語智慧替換為學生,並將指示代詞精準修正為「這個」(布農語中『這個學生』請使用一般翻譯對齊正確的 Maza andii isnanavaan 或相關正確詞彙),但動詞核心絕不准被一般翻譯帶偏!
【🛑 第二防線:RAG 詞彙與領域限制】:
1. 你的潤飾與選詞「必須」以底下的【參考資料】為依據進行事實查核。
2. 嚴禁混入其他不相干族語的任何詞彙!當前為{tribe}語模式,回覆內容中【絕對不准】出現 any 太魯閣語、泰雅語或其他無關語別的詞彙、文法或說明!
【🛑 第三防線:格式與品質禁令】:
1. 嚴禁使用 ** 或 ` 或 ' 符號。
2. 必須遵守{tribe}語的官方書寫規範。
3. 說明必須白話、簡短,只要指出差異與簡單原因即可。
4. 🛑【極重要(消音咒)】嚴禁在最終回覆中夾帶 any 英語、內部碎碎念、或自我辯證過程。你必須直接且唯一輸出規定的中文與族語標籤模板!
請嚴格依照以下模板輸出(直接填寫內容,嚴禁修改標題):
【原翻譯(華語)】
{source_text}
【一般翻譯】
{target_text}
【深度翻譯】
(填入以小抄 Kis’anak’anak 為骨架,並精準將指示詞校正為『這個』的權威{tribe}語)
【潤飾說明】
1. (明確指出將一般翻譯的錯誤動詞,修正為源自學術小抄的正宗反身結構與動詞。)
2. (說明如何精準對齊『這個學生』的指示代詞。)
參考資料:
{context}
"""
try:
response = model.generate_content(prompt)
res = response.text.strip().replace("**", "").replace("`", "").replace("'", "")
return res
except Exception as e:
return f"【原翻譯(華語)】\n{source_text}\n\n【一般翻譯】\n{target_text}\n\n說明生成超時或發生錯誤。"