Spaces:
Sleeping
Sleeping
| """Componentes de UI com suporte a tema escuro.""" | |
| from typing import Dict, Any | |
| from config.config import AppConfig | |
| from src.ui.theme_manager import theme_manager | |
| from src.utils.utils import ( | |
| NumberUtils, | |
| ConfidenceUtils, | |
| ActionUtils, | |
| SentimentUtils, | |
| FormatUtils | |
| ) | |
| class DarkThemeUIComponents: | |
| """Componentes da interface com suporte a tema escuro.""" | |
| def create_header() -> str: | |
| """Cria o cabeçalho da aplicação com tema escuro.""" | |
| theme = theme_manager.get_current_theme() | |
| colors = theme['colors'] | |
| return f""" | |
| <div style="text-align: center; padding: 25px; background: linear-gradient(135deg, {colors['gradient_start']} 0%, {colors['gradient_end']} 100%); border-radius: 15px; margin-bottom: 25px; box-shadow: 0 8px 32px {colors['shadow']};"> | |
| <h1 style="color: white; margin: 0; font-size: 2.8em; text-shadow: 2px 2px 8px rgba(0,0,0,0.5); font-weight: 700;"> | |
| 📈 {AppConfig.APP_TITLE} | |
| </h1> | |
| <p style="color: #f0f0f0; margin: 15px 0 0 0; font-size: 1.3em; opacity: 0.9;"> | |
| {AppConfig.APP_DESCRIPTION} | |
| </p> | |
| <div style="margin-top: 15px; padding: 8px 16px; background: rgba(255,255,255,0.1); border-radius: 20px; display: inline-block;"> | |
| <span style="color: white; font-size: 0.9em; font-weight: 500;">🌙 Tema Escuro Ativo</span> | |
| </div> | |
| </div> | |
| """ | |
| def format_harmonic_patterns(analysis_result: Dict[str, Any]) -> str: | |
| """Formata padrões harmônicos com tema escuro.""" | |
| theme = theme_manager.get_current_theme() | |
| colors = theme['colors'] | |
| harmonic_patterns = analysis_result.get('harmonic_patterns', []) | |
| if not harmonic_patterns: | |
| return f""" | |
| <div style="background: {colors['card_background']}; border-radius: 12px; padding: 25px; border: 1px solid {colors['border']}; box-shadow: 0 4px 12px {colors['shadow']};"> | |
| <h3 style="color: {colors['text_primary']}; margin-top: 0; font-size: 1.4em; font-weight: 600;">🎵 Padrões Harmônicos</h3> | |
| <div style="text-align: center; padding: 40px; color: {colors['text_muted']};"> | |
| <div style="font-size: 3em; margin-bottom: 15px; opacity: 0.6;">📊</div> | |
| <p style="font-size: 1.1em;">Nenhum padrão harmônico detectado</p> | |
| </div> | |
| </div> | |
| """ | |
| patterns_html = "" | |
| for pattern in harmonic_patterns: | |
| pattern_name = pattern.get('name', 'Desconhecido') | |
| confidence = pattern.get('confidence', 0) | |
| direction = pattern.get('direction', 'NEUTRO') | |
| direction_emoji = "📈" if direction == "ALTA" else "📉" if direction == "BAIXA" else "➡️" | |
| direction_color = colors['success'] if direction == "ALTA" else colors['error'] if direction == "BAIXA" else colors['warning'] | |
| patterns_html += f""" | |
| <div style="background: {colors['surface']}; border-radius: 10px; padding: 18px; margin-bottom: 12px; border-left: 4px solid {colors['info']}; transition: all 0.3s ease;"> | |
| <div style="display: flex; justify-content: space-between; align-items: center;"> | |
| <div> | |
| <strong style="color: {colors['text_primary']}; font-size: 1.1em;">{direction_emoji} {pattern_name}</strong> | |
| <div style="color: {direction_color}; font-size: 0.95em; margin-top: 4px; font-weight: 500;">Direção: {direction}</div> | |
| </div> | |
| <div style="text-align: right;"> | |
| <div style="font-weight: bold; color: {colors['info']}; font-size: 1.2em;">{confidence}%</div> | |
| <div style="color: {colors['text_secondary']}; font-size: 0.85em;">Confiança</div> | |
| </div> | |
| </div> | |
| </div> | |
| """ | |
| return f""" | |
| <div style="background: {colors['card_background']}; border-radius: 12px; padding: 25px; border: 1px solid {colors['border']}; box-shadow: 0 4px 12px {colors['shadow']};"> | |
| <h3 style="color: {colors['text_primary']}; margin-top: 0; border-bottom: 2px solid {colors['info']}; padding-bottom: 12px; font-size: 1.4em; font-weight: 600;"> | |
| 🎵 Padrões Harmônicos Detectados | |
| </h3> | |
| {patterns_html} | |
| </div> | |
| """ | |
| def format_fibonacci_alerts(analysis_result: Dict[str, Any]) -> str: | |
| """Formata alertas de Fibonacci com tema escuro.""" | |
| theme = theme_manager.get_current_theme() | |
| colors = theme['colors'] | |
| fibonacci_data = analysis_result.get('fibonacci_analysis', {}) | |
| levels = fibonacci_data.get('levels', []) | |
| if not levels: | |
| return f""" | |
| <div style="background: {colors['card_background']}; border-radius: 12px; padding: 25px; border: 1px solid {colors['border']}; box-shadow: 0 4px 12px {colors['shadow']};"> | |
| <h3 style="color: {colors['text_primary']}; margin-top: 0; font-size: 1.4em; font-weight: 600;">📐 Níveis de Fibonacci</h3> | |
| <div style="text-align: center; padding: 40px; color: {colors['text_muted']};"> | |
| <div style="font-size: 3em; margin-bottom: 15px; opacity: 0.6;">📊</div> | |
| <p style="font-size: 1.1em;">Nenhum nível de Fibonacci calculado</p> | |
| </div> | |
| </div> | |
| """ | |
| levels_html = "" | |
| for level in levels: | |
| level_value = level.get('level', 0) | |
| price = level.get('price', 0) | |
| status = level.get('status', 'NEUTRO') | |
| status_color = colors['success'] if status == 'SUPORTE' else colors['error'] if status == 'RESISTÊNCIA' else colors['text_secondary'] | |
| levels_html += f""" | |
| <div style="display: flex; justify-content: space-between; align-items: center; padding: 12px 0; border-bottom: 1px solid {colors['border']}; transition: all 0.3s ease;"> | |
| <span style="color: {colors['text_secondary']}; font-weight: 500;">{level_value}%</span> | |
| <span style="font-weight: bold; color: {colors['text_primary']}; font-size: 1.1em;">{NumberUtils.format_price(price)}</span> | |
| <span style="color: {status_color}; font-weight: 600; padding: 4px 12px; background: {status_color}20; border-radius: 20px; font-size: 0.9em;">{status}</span> | |
| </div> | |
| """ | |
| return f""" | |
| <div style="background: {colors['card_background']}; border-radius: 12px; padding: 25px; border: 1px solid {colors['border']}; box-shadow: 0 4px 12px {colors['shadow']};"> | |
| <h3 style="color: {colors['text_primary']}; margin-top: 0; border-bottom: 2px solid {colors['warning']}; padding-bottom: 12px; font-size: 1.4em; font-weight: 600;"> | |
| 📐 Níveis de Fibonacci | |
| </h3> | |
| <div style="background: {colors['surface']}; border-radius: 8px; padding: 15px;"> | |
| {levels_html} | |
| </div> | |
| </div> | |
| """ | |
| def format_main_result(analysis_result: Dict[str, Any]) -> str: | |
| """Formata resultado principal com tema escuro.""" | |
| theme = theme_manager.get_current_theme() | |
| colors = theme['colors'] | |
| action = analysis_result.get('action', 'AGUARDAR') | |
| confidence = analysis_result.get('confidence', 0) | |
| market_data = analysis_result.get('market_data', {}) | |
| price = market_data.get('price', 0) | |
| variation = market_data.get('variation', 0) | |
| # Formatação de preço e variação | |
| formatted_price = NumberUtils.format_price(price) | |
| formatted_variation = f"{variation:+.2f}%" if variation != 0 else "0.00%" | |
| variation_color = colors['success'] if variation > 0 else colors['error'] if variation < 0 else colors['text_secondary'] | |
| # Nível de confiança | |
| confidence_level = ConfidenceUtils.get_confidence_level(confidence) | |
| confidence_bar = ConfidenceUtils.get_confidence_bar(confidence) | |
| # Emojis e cores para ação | |
| action_emojis = { | |
| 'COMPRAR': {'emoji': '🟢', 'color': colors['success'], 'action': 'COMPRAR'}, | |
| 'VENDER': {'emoji': '🔴', 'color': colors['error'], 'action': 'VENDER'}, | |
| 'AGUARDAR': {'emoji': '🟡', 'color': colors['warning'], 'action': 'AGUARDAR'} | |
| } | |
| action_info = action_emojis.get(action, action_emojis['AGUARDAR']) | |
| return f""" | |
| <div style="background: {colors['card_background']}; border-radius: 15px; padding: 30px; border: 1px solid {colors['border']}; box-shadow: 0 8px 24px {colors['shadow']};"> | |
| <div style="text-align: center; margin-bottom: 25px;"> | |
| <div style="font-size: 4em; margin-bottom: 10px;">{action_info['emoji']}</div> | |
| <h2 style="color: {action_info['color']}; margin: 0; font-size: 2.2em; font-weight: 700; text-transform: uppercase; letter-spacing: 1px;"> | |
| {action_info['action']} | |
| </h2> | |
| </div> | |
| <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 25px; margin-bottom: 25px;"> | |
| <div style="text-align: center; padding: 20px; background: {colors['surface']}; border-radius: 12px; box-shadow: 0 4px 8px {colors['shadow']};"> | |
| <div style="font-size: 0.95em; color: {colors['text_secondary']}; margin-bottom: 8px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px;">PREÇO ATUAL</div> | |
| <div style="font-size: 2em; font-weight: bold; color: {colors['text_primary']}; margin-bottom: 5px;">{formatted_price}</div> | |
| <div style="font-size: 1.2em; color: {variation_color}; font-weight: 600; padding: 4px 12px; background: {variation_color}20; border-radius: 20px;">{formatted_variation}</div> | |
| </div> | |
| <div style="text-align: center; padding: 20px; background: {colors['surface']}; border-radius: 12px; box-shadow: 0 4px 8px {colors['shadow']};"> | |
| <div style="font-size: 0.95em; color: {colors['text_secondary']}; margin-bottom: 8px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px;">CONFIANÇA</div> | |
| <div style="font-size: 2em; font-weight: bold; color: {colors['text_primary']}; margin-bottom: 5px;">{confidence}%</div> | |
| <div style="font-size: 0.95em; color: {colors['text_secondary']}; padding: 4px 12px; background: {colors['info']}20; border-radius: 20px;">{confidence_level}</div> | |
| </div> | |
| </div> | |
| <div style="text-align: center; margin-top: 20px;"> | |
| <div style="font-size: 0.95em; color: {colors['text_secondary']}; margin-bottom: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px;">NÍVEL DE CONFIANÇA</div> | |
| <div style="font-family: monospace; font-size: 1.3em; letter-spacing: 3px; color: {colors['info']}; background: {colors['surface']}; padding: 8px 16px; border-radius: 8px; display: inline-block;">{confidence_bar}</div> | |
| </div> | |
| </div> | |
| """ | |
| def format_sentiment_analysis(analysis_result: Dict[str, Any]) -> str: | |
| """Formata análise de sentimento com tema escuro.""" | |
| theme = theme_manager.get_current_theme() | |
| colors = theme['colors'] | |
| sentiment_data = analysis_result.get('sentiment_analysis', {}) | |
| label = sentiment_data.get('label', 'NEUTRO') | |
| confidence = sentiment_data.get('confidence', 0) | |
| # Configurações de sentimento | |
| sentiment_config = SentimentUtils.get_sentiment_config(label) | |
| emoji = sentiment_config['emoji'] | |
| color = colors['success'] if label == 'POSITIVO' else colors['error'] if label == 'NEGATIVO' else colors['warning'] | |
| return f""" | |
| <div style="background: {colors['card_background']}; border-radius: 12px; padding: 25px; border: 1px solid {colors['border']}; box-shadow: 0 4px 12px {colors['shadow']};"> | |
| <h3 style="color: {colors['text_primary']}; margin-top: 0; border-bottom: 2px solid {colors['success']}; padding-bottom: 12px; font-size: 1.4em; font-weight: 600;"> | |
| 🧠 Análise de Sentimento | |
| </h3> | |
| <div style="text-align: center; padding: 25px;"> | |
| <div style="font-size: 4em; margin-bottom: 20px;">{emoji}</div> | |
| <h4 style="color: {color}; margin: 0; font-size: 1.8em; text-transform: uppercase; font-weight: 700; letter-spacing: 1px;">{label}</h4> | |
| <div style="margin-top: 15px; color: {colors['text_secondary']}; font-size: 1.1em; font-weight: 500;">Confiança: {confidence:.1f}%</div> | |
| </div> | |
| <div style="background: {colors['surface']}; padding: 20px; border-radius: 10px; margin-top: 20px;"> | |
| <h5 style="margin-top: 0; color: {colors['text_primary']}; font-size: 1.1em; font-weight: 600;">📝 Detalhes da Análise</h5> | |
| <p style="margin: 0; color: {colors['text_secondary']}; font-size: 1em; line-height: 1.6;"> | |
| O modelo de IA analisou o contexto do mercado e determinou um sentimento <strong style="color: {color};">{label.lower()}</strong> | |
| com <strong style="color: {colors['info']};">{confidence:.1f}%</strong> de confiança. | |
| </p> | |
| </div> | |
| </div> | |
| """ | |
| def format_recommendations(analysis_result: Dict[str, Any]) -> str: | |
| """Formata recomendações com tema escuro.""" | |
| theme = theme_manager.get_current_theme() | |
| colors = theme['colors'] | |
| action = analysis_result.get('action', 'AGUARDAR') | |
| market_data = analysis_result.get('market_data', {}) | |
| price = market_data.get('price', 0) | |
| # Recomendações de trading | |
| trading_recs = FormatUtils.format_trading_recommendations(action, price) | |
| # Direção de trading | |
| direction = ActionUtils.get_trading_direction(action) | |
| direction_emoji = "📈" if direction == "COMPRA" else "📉" if direction == "VENDA" else "⏸️" | |
| direction_color = colors['success'] if direction == "COMPRA" else colors['error'] if direction == "VENDA" else colors['warning'] | |
| return f""" | |
| <div style="background: {colors['card_background']}; border-radius: 12px; padding: 25px; border: 1px solid {colors['border']}; box-shadow: 0 4px 12px {colors['shadow']};"> | |
| <h3 style="color: {colors['text_primary']}; margin-top: 0; border-bottom: 2px solid {colors['warning']}; padding-bottom: 12px; font-size: 1.4em; font-weight: 600;"> | |
| 💡 Recomendações de Trading | |
| </h3> | |
| <div style="background: {colors['warning']}20; border: 1px solid {colors['warning']}; border-radius: 10px; padding: 20px; margin-bottom: 25px;"> | |
| <div style="display: flex; align-items: center; gap: 15px; margin-bottom: 12px;"> | |
| <span style="font-size: 2em;">{direction_emoji}</span> | |
| <strong style="color: {direction_color}; font-size: 1.3em; font-weight: 700;">Direção: {direction}</strong> | |
| </div> | |
| </div> | |
| <div style="background: {colors['surface']}; padding: 20px; border-radius: 10px; white-space: pre-line; font-family: 'Segoe UI', sans-serif; line-height: 1.6; color: {colors['text_primary']};"> | |
| {trading_recs} | |
| </div> | |
| <div style="background: {colors['info']}20; border: 1px solid {colors['info']}; border-radius: 10px; padding: 20px; margin-top: 20px;"> | |
| <h5 style="margin-top: 0; color: {colors['info']}; font-size: 1.1em; font-weight: 600;">⚠️ Aviso Importante</h5> | |
| <p style="margin: 0; color: {colors['text_secondary']}; font-size: 0.95em; line-height: 1.6;"> | |
| Esta análise é apenas para fins educacionais. Sempre faça sua própria pesquisa e | |
| considere consultar um consultor financeiro antes de tomar decisões de investimento. | |
| </p> | |
| </div> | |
| </div> | |
| """ | |
| def _get_ai_status_html(available: bool, model_description: str = "") -> str: | |
| """Gera HTML para status da IA com tema escuro.""" | |
| theme = theme_manager.get_current_theme() | |
| colors = theme['colors'] | |
| if available: | |
| return f""" | |
| <div style="background: {colors['success_background']}; border: 1px solid {colors['success_border']}; border-radius: 12px; padding: 15px; margin-bottom: 20px; box-shadow: 0 4px 12px {colors['shadow']};"> | |
| <div style="display: flex; align-items: center; gap: 12px;"> | |
| <span style="font-size: 1.3em;">🤖</span> | |
| <div> | |
| <strong style="color: {colors['success_text']}; font-size: 1.1em;">IA Ativa:</strong> | |
| <span style="color: {colors['success_text']}; margin-left: 8px;">{model_description}</span> | |
| </div> | |
| </div> | |
| </div> | |
| """ | |
| else: | |
| return f""" | |
| <div style="background: {colors['warning_background']}; border: 1px solid {colors['warning_border']}; border-radius: 12px; padding: 15px; margin-bottom: 20px; box-shadow: 0 4px 12px {colors['shadow']};"> | |
| <div style="display: flex; align-items: center; gap: 12px;"> | |
| <span style="font-size: 1.3em;">⚠️</span> | |
| <div> | |
| <strong style="color: {colors['warning_text']}; font-size: 1.1em;">IA Indisponível:</strong> | |
| <span style="color: {colors['warning_text']}; margin-left: 8px;">Executando apenas análise técnica</span> | |
| </div> | |
| </div> | |
| </div> | |
| """ | |
| def create_footer(model_info: Dict[str, Any]) -> str: | |
| """Cria rodapé com tema escuro.""" | |
| theme = theme_manager.get_current_theme() | |
| colors = theme['colors'] | |
| return f""" | |
| <div style="text-align: center; padding: 20px; margin-top: 30px; background: {colors['surface']}; border-radius: 12px; border: 1px solid {colors['border']};"> | |
| <p style="color: {colors['text_secondary']}; margin: 0; font-size: 0.9em;"> | |
| 🤖 Powered by <strong style="color: {colors['primary']};">FinBERT AI</strong> | | |
| 🌙 <strong style="color: {colors['text_primary']};">Tema Escuro</strong> | | |
| 📊 <strong style="color: {colors['info']};">Análise Financeira Avançada</strong> | |
| </p> | |
| </div> | |
| """ |