This commit is contained in:
parent
2065323a59
commit
44705c79a7
|
|
@ -21,83 +21,82 @@ import markdown
|
|||
class PDFGenerator:
|
||||
"""Generate PDF reports from markdown content"""
|
||||
|
||||
# Emoji to Unicode symbol mapping for PDF compatibility
|
||||
# Emojis don't render well in PDFs, so we replace them with Unicode text symbols
|
||||
# NOTE: Use ASCII brackets [] not full-width [] for better font compatibility
|
||||
# NOTE: Avoid [文字] formats - use pure symbols only
|
||||
# Emoji to safe ASCII character mapping for PDF compatibility
|
||||
# STSong-Light font has issues with certain Unicode symbols
|
||||
# Using ONLY ASCII characters to ensure perfect rendering
|
||||
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"""
|
||||
|
||||
|
|
|
|||
|
|
@ -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