Files
Document_translator/migrations/fix_translation_cache.py
2025-10-02 17:13:24 +08:00

194 lines
7.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
修復 dt_translation_cache 資料表結構
問題:資料表欄位名稱與模型定義不一致
- content_hash → source_text_hash
- source_lang → source_language
- target_lang → target_language
"""
import sys
from pathlib import Path
project_root = Path(__file__).parent.parent
sys.path.insert(0, str(project_root))
from app import create_app, db
from sqlalchemy import text
def run_migration():
app = create_app()
with app.app_context():
print("=" * 60)
print("修復 dt_translation_cache 資料表結構")
print("=" * 60)
try:
# 1. 檢查當前結構
print("\n[1/6] 檢查當前資料表結構...")
result = db.session.execute(text('SHOW COLUMNS FROM dt_translation_cache'))
current_columns = {row[0]: row for row in result}
print(f" ✓ 當前欄位: {', '.join(current_columns.keys())}")
# 2. 備份資料
print("\n[2/6] 備份現有資料...")
db.session.execute(text('''
CREATE TABLE IF NOT EXISTS dt_translation_cache_backup_20251001
AS SELECT * FROM dt_translation_cache
'''))
db.session.commit()
backup_count = db.session.execute(
text('SELECT COUNT(*) FROM dt_translation_cache_backup_20251001')
).scalar()
print(f" ✓ 已備份 {backup_count} 筆記錄")
# 3. 重新命名欄位content_hash → source_text_hash
if 'content_hash' in current_columns and 'source_text_hash' not in current_columns:
print("\n[3/6] 重新命名 content_hash → source_text_hash...")
db.session.execute(text('''
ALTER TABLE dt_translation_cache
CHANGE COLUMN content_hash source_text_hash VARCHAR(64) NOT NULL COMMENT '來源文字hash'
'''))
db.session.commit()
print(" ✓ 已重新命名")
else:
print("\n[3/6] 跳過(已經是 source_text_hash")
# 4. 重新命名欄位source_lang → source_language
if 'source_lang' in current_columns and 'source_language' not in current_columns:
print("\n[4/6] 重新命名 source_lang → source_language...")
db.session.execute(text('''
ALTER TABLE dt_translation_cache
CHANGE COLUMN source_lang source_language VARCHAR(50) NOT NULL COMMENT '來源語言'
'''))
db.session.commit()
print(" ✓ 已重新命名")
else:
print("\n[4/6] 跳過(已經是 source_language")
# 5. 重新命名欄位target_lang → target_language
if 'target_lang' in current_columns and 'target_language' not in current_columns:
print("\n[5/6] 重新命名 target_lang → target_language...")
db.session.execute(text('''
ALTER TABLE dt_translation_cache
CHANGE COLUMN target_lang target_language VARCHAR(50) NOT NULL COMMENT '目標語言'
'''))
db.session.commit()
print(" ✓ 已重新命名")
else:
print("\n[5/6] 跳過(已經是 target_language")
# 6. 刪除不需要的欄位
print("\n[6/6] 清理多餘欄位...")
# 檢查並刪除 quality_score
if 'quality_score' in current_columns:
db.session.execute(text('''
ALTER TABLE dt_translation_cache
DROP COLUMN quality_score
'''))
print(" ✓ 已刪除 quality_score")
# 檢查並刪除 hit_count
if 'hit_count' in current_columns:
db.session.execute(text('''
ALTER TABLE dt_translation_cache
DROP COLUMN hit_count
'''))
print(" ✓ 已刪除 hit_count")
# 檢查並刪除 last_used_at
if 'last_used_at' in current_columns:
db.session.execute(text('''
ALTER TABLE dt_translation_cache
DROP COLUMN last_used_at
'''))
print(" ✓ 已刪除 last_used_at")
db.session.commit()
# 7. 重建索引和約束
print("\n[7/7] 重建索引和約束...")
# 先刪除舊的唯一約束(如果存在)
try:
db.session.execute(text('''
ALTER TABLE dt_translation_cache
DROP INDEX idx_content_hash
'''))
print(" ✓ 已刪除舊索引 idx_content_hash")
except:
pass
try:
db.session.execute(text('''
ALTER TABLE dt_translation_cache
DROP INDEX idx_source_lang_target_lang
'''))
print(" ✓ 已刪除舊索引 idx_source_lang_target_lang")
except:
pass
# 建立新的唯一約束
try:
db.session.execute(text('''
ALTER TABLE dt_translation_cache
ADD UNIQUE KEY uk_cache (source_text_hash, source_language, target_language)
'''))
print(" ✓ 已建立唯一約束 uk_cache")
except Exception as e:
if 'Duplicate' not in str(e):
print(f" ⚠ 約束建立警告: {str(e)}")
# 建立語言索引
try:
db.session.execute(text('''
ALTER TABLE dt_translation_cache
ADD INDEX idx_languages (source_language, target_language)
'''))
print(" ✓ 已建立索引 idx_languages")
except Exception as e:
if 'Duplicate' not in str(e):
print(f" ⚠ 索引建立警告: {str(e)}")
db.session.commit()
# 驗證最終結構
print("\n" + "=" * 60)
print("驗證最終資料表結構")
print("=" * 60)
result = db.session.execute(text('SHOW COLUMNS FROM dt_translation_cache'))
final_columns = list(result)
print(f"\n最終欄位列表 (共 {len(final_columns)} 個):")
for col in final_columns:
print(f" - {col[0]:30} {col[1]:30} NULL={col[2]}")
# 顯示索引
print("\n索引:")
result = db.session.execute(text('SHOW INDEX FROM dt_translation_cache'))
for idx in result:
print(f" - {idx[2]:30} -> {idx[4]}")
print("\n" + "=" * 60)
print("✅ Migration 執行完成!")
print("=" * 60)
except Exception as e:
db.session.rollback()
print(f"\n❌ Migration 失敗: {str(e)}")
print("\n可以使用備份表還原資料:")
print(" DROP TABLE dt_translation_cache;")
print(" CREATE TABLE dt_translation_cache AS SELECT * FROM dt_translation_cache_backup_20251001;")
raise
if __name__ == '__main__':
run_migration()