This commit is contained in:
parent
2065323a59
commit
44705c79a7
|
|
@ -21,83 +21,82 @@ import markdown
|
||||||
class PDFGenerator:
|
class PDFGenerator:
|
||||||
"""Generate PDF reports from markdown content"""
|
"""Generate PDF reports from markdown content"""
|
||||||
|
|
||||||
# Emoji to Unicode symbol mapping for PDF compatibility
|
# Emoji to safe ASCII character mapping for PDF compatibility
|
||||||
# Emojis don't render well in PDFs, so we replace them with Unicode text symbols
|
# STSong-Light font has issues with certain Unicode symbols
|
||||||
# NOTE: Use ASCII brackets [] not full-width [] for better font compatibility
|
# Using ONLY ASCII characters to ensure perfect rendering
|
||||||
# NOTE: Avoid [文字] formats - use pure symbols only
|
|
||||||
EMOJI_TO_UNICODE = {
|
EMOJI_TO_UNICODE = {
|
||||||
# Status & Indicators
|
# Status & Indicators - ASCII only
|
||||||
'✅': '✓',
|
'✅': '[OK]',
|
||||||
'❌': '✗',
|
'❌': '[X]',
|
||||||
'⚠️': '⚠',
|
'⚠️': '[!]',
|
||||||
'⚡': '⚡',
|
'⚡': '*',
|
||||||
'🔔': '◉',
|
'🔔': 'o',
|
||||||
|
|
||||||
# Rating & Quality
|
# Rating & Quality - ASCII only
|
||||||
'⭐': '★',
|
'⭐': '*',
|
||||||
'🌟': '☆',
|
'🌟': '*',
|
||||||
'💎': '◆',
|
'💎': '+',
|
||||||
'🏆': '◈',
|
'🏆': '#',
|
||||||
|
|
||||||
# Charts & Analytics - pure symbols only
|
# Charts & Analytics - ASCII or empty
|
||||||
'📊': '▓',
|
'📊': '',
|
||||||
'📈': '↑',
|
'📈': '^',
|
||||||
'📉': '↓',
|
'📉': 'v',
|
||||||
'📋': '▪',
|
'📋': '-',
|
||||||
'📌': '◆',
|
'📌': '*',
|
||||||
|
|
||||||
# Money & Business - symbols only
|
# Money & Business - ASCII currency letters
|
||||||
'💰': '$',
|
'💰': '$',
|
||||||
'💵': '$',
|
'💵': '$',
|
||||||
'💴': '¥',
|
'💴': 'Y', # 日元
|
||||||
'💶': '€',
|
'💶': 'E', # 歐元
|
||||||
'💷': '£',
|
'💷': 'P', # 英鎊
|
||||||
'💸': '$',
|
'💸': '$',
|
||||||
'💹': '↑',
|
'💹': '^',
|
||||||
|
|
||||||
# Direction & Movement
|
# Direction & Movement - ASCII arrows
|
||||||
'🚀': '↑↑',
|
'🚀': '^^',
|
||||||
'⬆️': '↑',
|
'⬆️': '^',
|
||||||
'⬇️': '↓',
|
'⬇️': 'v',
|
||||||
'➡️': '→',
|
'➡️': '>',
|
||||||
'⬅️': '←',
|
'⬅️': '<',
|
||||||
'🔼': '▲',
|
'🔼': '^',
|
||||||
'🔽': '▼',
|
'🔽': 'v',
|
||||||
|
|
||||||
# Symbols
|
# Symbols - ASCII only
|
||||||
'🎯': '◎',
|
'🎯': 'o',
|
||||||
'🔥': '※',
|
'🔥': '*',
|
||||||
'💡': '◐',
|
'💡': '*',
|
||||||
'⚙️': '⚙',
|
'⚙️': '*',
|
||||||
'🔧': '►',
|
'🔧': '>',
|
||||||
'🔨': '►',
|
'🔨': '>',
|
||||||
|
|
||||||
# AI & Tech - symbols only
|
# AI & Tech - remove or simple ASCII
|
||||||
'🤖': '▣',
|
'🤖': '',
|
||||||
'💻': '▣',
|
'💻': '',
|
||||||
'📱': '▣',
|
'📱': '',
|
||||||
'🖥️': '▣',
|
'🖥️': '',
|
||||||
|
|
||||||
# People & Roles - symbols only
|
# People & Roles - remove
|
||||||
'👤': '◇',
|
'👤': '',
|
||||||
'👥': '◇◇',
|
'👥': '',
|
||||||
'🔬': '◈',
|
'🔬': '',
|
||||||
'📚': '▪',
|
'📚': '',
|
||||||
|
|
||||||
# Time - symbols only
|
# Time - simple ASCII
|
||||||
'⏰': '◷',
|
'⏰': 'o',
|
||||||
'📅': '▪',
|
'📅': '-',
|
||||||
'⏱️': '◷',
|
'⏱️': 'o',
|
||||||
|
|
||||||
# Other common emojis - symbols only
|
# Other common emojis - ASCII or remove
|
||||||
'✨': '‧',
|
'✨': '*',
|
||||||
'🎨': '◈',
|
'🎨': '',
|
||||||
'📝': '▪',
|
'📝': '-',
|
||||||
'📄': '▪',
|
'📄': '-',
|
||||||
'🗂️': '▪',
|
'🗂️': '=',
|
||||||
'🌐': '◎',
|
'🌐': 'o',
|
||||||
'🔗': '∞',
|
'🔗': '~',
|
||||||
'💼': '▣',
|
'💼': '',
|
||||||
}
|
}
|
||||||
"""Generate PDF reports from markdown content"""
|
"""Generate PDF reports from markdown content"""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,93 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
最簡單的解決方案:完全移除可能導致問題的 Unicode 符號
|
||||||
|
改用最安全的 ASCII 和基本中文字符
|
||||||
|
"""
|
||||||
|
|
||||||
|
# 問題分析:
|
||||||
|
# STSong-Light 對某些 Unicode 符號的支持不完整
|
||||||
|
# 可能將某些符號(如 ★ ※ ◈ 等)錯誤渲染為「煉」
|
||||||
|
|
||||||
|
# 解決方案:
|
||||||
|
# 1. 完全移除這些 Unicode 符號
|
||||||
|
# 2. 改用 ASCII 字符或簡單的中文文字
|
||||||
|
# 3. 如果必須使用符號,只使用最基本的 ASCII 符號
|
||||||
|
|
||||||
|
SAFE_EMOJI_MAPPING = {
|
||||||
|
# Status - 使用 ASCII
|
||||||
|
'✅': '[OK]',
|
||||||
|
'❌': '[X]',
|
||||||
|
'⚠️': '[!]',
|
||||||
|
'⚡': '*',
|
||||||
|
'🔔': 'o',
|
||||||
|
|
||||||
|
# Rating - 使用 ASCII
|
||||||
|
'⭐': '*',
|
||||||
|
'🌟': '*',
|
||||||
|
'💎': '+',
|
||||||
|
'🏆': '#',
|
||||||
|
|
||||||
|
# Charts - 使用簡單文字
|
||||||
|
'📊': '', # 完全移除
|
||||||
|
'📈': '^', # 向上
|
||||||
|
'📉': 'v', # 向下
|
||||||
|
'📋': '-',
|
||||||
|
'📌': '*',
|
||||||
|
|
||||||
|
# Money - 保留貨幣符號(這些是安全的)
|
||||||
|
'💰': '$',
|
||||||
|
'💵': '$',
|
||||||
|
'💴': 'Y', # 改用 ASCII Y 代替 ¥
|
||||||
|
'💶': 'E', # 改用 ASCII E 代替 €
|
||||||
|
'💷': 'P', # 改用 ASCII P 代替 £
|
||||||
|
'💸': '$',
|
||||||
|
'💹': '^',
|
||||||
|
|
||||||
|
# Direction - 使用 ASCII
|
||||||
|
'🚀': '^^',
|
||||||
|
'⬆️': '^',
|
||||||
|
'⬇️': 'v',
|
||||||
|
'➡️': '>',
|
||||||
|
'⬅️': '<',
|
||||||
|
'🔼': '^',
|
||||||
|
'🔽': 'v',
|
||||||
|
|
||||||
|
# Symbols - 純 ASCII
|
||||||
|
'🎯': 'o',
|
||||||
|
'🔥': '*',
|
||||||
|
'💡': '*',
|
||||||
|
'⚙️': '*',
|
||||||
|
'🔧': '>',
|
||||||
|
'🔨': '>',
|
||||||
|
|
||||||
|
# Tech - 全部移除或改 ASCII
|
||||||
|
'🤖': '',
|
||||||
|
'💻': '',
|
||||||
|
'📱': '',
|
||||||
|
'🖥️': '',
|
||||||
|
|
||||||
|
# People - 全部移除
|
||||||
|
'👤': '',
|
||||||
|
'👥': '',
|
||||||
|
'🔬': '',
|
||||||
|
'📚': '',
|
||||||
|
|
||||||
|
# Time - 純 ASCII
|
||||||
|
'⏰': 'o',
|
||||||
|
'📅': '-',
|
||||||
|
'⏱️': 'o',
|
||||||
|
|
||||||
|
# Other - 純 ASCII 或移除
|
||||||
|
'✨': '*',
|
||||||
|
'🎨': '',
|
||||||
|
'📝': '-',
|
||||||
|
'📄': '-',
|
||||||
|
'🗂️': '=',
|
||||||
|
'🌐': 'o',
|
||||||
|
'🔗': '~',
|
||||||
|
'💼': '',
|
||||||
|
}
|
||||||
|
|
||||||
|
print("安全的 Emoji 映射(只使用 ASCII 和基本字符):")
|
||||||
|
print(SAFE_EMOJI_MAPPING)
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import sys
|
||||||
|
sys.path.insert(0, '/Users/yaolo/Desktop/TradingAgentsX')
|
||||||
|
|
||||||
|
from backend.app.services.pdf_generator import PDFGenerator
|
||||||
|
|
||||||
|
# 測試包含各種符號的內容
|
||||||
|
test_content = '''# 測試報告
|
||||||
|
|
||||||
|
## 市場分析
|
||||||
|
- 上漲趨勢 ^
|
||||||
|
- 技術指標 *
|
||||||
|
- 支撐位 o
|
||||||
|
|
||||||
|
## 風險評估
|
||||||
|
- 警告標記 [!]
|
||||||
|
- 確認標記 [OK]
|
||||||
|
- 否定標記 [X]
|
||||||
|
|
||||||
|
## 結論
|
||||||
|
純文字和 ASCII 符號測試,不應該出現「煉」字
|
||||||
|
'''
|
||||||
|
|
||||||
|
pdf_gen = PDFGenerator()
|
||||||
|
pdf_bytes = pdf_gen.generate_analyst_report_pdf(
|
||||||
|
analyst_name='ASCII 符號測試',
|
||||||
|
ticker='TEST',
|
||||||
|
analysis_date='2025-11-27',
|
||||||
|
report_content=test_content
|
||||||
|
)
|
||||||
|
|
||||||
|
with open('/tmp/test_ascii_only.pdf', 'wb') as f:
|
||||||
|
f.write(pdf_bytes)
|
||||||
|
|
||||||
|
print('✓ 已生成測試 PDF: /tmp/test_ascii_only.pdf')
|
||||||
|
print('請檢查 PDF 中是否還有「煉」字出現')
|
||||||
|
print('如果沒有「煉」,說明 ASCII-only 方案成功解決問題')
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
測試找出哪個字符在 STSong-Light 中被渲染為「煉」
|
||||||
|
"""
|
||||||
|
import sys
|
||||||
|
sys.path.insert(0, '/Users/yaolo/Desktop/TradingAgentsX')
|
||||||
|
|
||||||
|
from backend.app.services.pdf_generator import PDFGenerator
|
||||||
|
import io
|
||||||
|
|
||||||
|
# 測試內容 - 包含我們使用的所有符號
|
||||||
|
test_symbols = {
|
||||||
|
'星號': '★',
|
||||||
|
'菱形': '◆',
|
||||||
|
'方塊': '▓',
|
||||||
|
'小方': '▪',
|
||||||
|
'雙菱': '◈',
|
||||||
|
'空菱': '◇',
|
||||||
|
'雙圓': '◎',
|
||||||
|
'米字': '※',
|
||||||
|
'時鐘': '◷',
|
||||||
|
'點': '‧',
|
||||||
|
'無限': '∞',
|
||||||
|
'粗方': '▣',
|
||||||
|
'對號': '✓',
|
||||||
|
'叉號': '✗',
|
||||||
|
'警告': '⚠',
|
||||||
|
'閃電': '⚡',
|
||||||
|
}
|
||||||
|
|
||||||
|
print("測試每個符號在 PDF 中的渲染...\n")
|
||||||
|
|
||||||
|
pdf_gen = PDFGenerator()
|
||||||
|
|
||||||
|
for name, symbol in test_symbols.items():
|
||||||
|
test_content = f"測試{name}符號: {symbol}"
|
||||||
|
|
||||||
|
try:
|
||||||
|
pdf_bytes = pdf_gen.generate_analyst_report_pdf(
|
||||||
|
analyst_name=f"測試: {symbol}",
|
||||||
|
ticker="TEST",
|
||||||
|
analysis_date="2025-11-27",
|
||||||
|
report_content=test_content
|
||||||
|
)
|
||||||
|
|
||||||
|
# 保存測試 PDF
|
||||||
|
filename = f"/tmp/test_symbol_{name}.pdf"
|
||||||
|
with open(filename, 'wb') as f:
|
||||||
|
f.write(pdf_bytes)
|
||||||
|
|
||||||
|
print(f"✓ {name} ({symbol}) - U+{ord(symbol):04X} - 已生成: {filename}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ {name} ({symbol}) - 錯誤: {e}")
|
||||||
|
|
||||||
|
print("\n請手動檢查 /tmp/test_symbol_*.pdf 文件,看看哪個符號顯示為「煉」")
|
||||||
Loading…
Reference in New Issue