File size: 7,895 Bytes
a1bf219
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
"""Phase configuration component for Gradio UI."""

from typing import List, Tuple

import gradio as gr

from config.default_config import DEFAULT_CONFIG
from config.models import AnalysisPhase, PhaseConfiguration

# Phase display information
PHASE_INFO = {
    AnalysisPhase.TECHNICAL.value: {
        "label": "Technical Analysis",
        "description": "Indicators, patterns, trends (~15-20s)",
        "agents": "IndicatorAgent, PatternAgent, TrendAgent",
    },
    AnalysisPhase.FUNDAMENTAL.value: {
        "label": "Fundamental Analysis",
        "description": "Financial metrics, valuation (~30-40s)",
        "agents": "FundamentalsAgent",
    },
    AnalysisPhase.SENTIMENT.value: {
        "label": "Sentiment Analysis",
        "description": "Social & news sentiment (~20-30s)",
        "agents": "SentimentAgent, NewsAgent",
    },
    AnalysisPhase.RESEARCH_SYNTHESIS.value: {
        "label": "Research Synthesis",
        "description": "Integrated perspective (~15-20s)",
        "agents": "TechnicalAnalystAgent",
    },
    AnalysisPhase.RISK.value: {
        "label": "Risk Assessment",
        "description": "Risk scores, volatility (~15-20s)",
        "agents": "RiskManagerAgent",
    },
    AnalysisPhase.DECISION.value: {
        "label": "Portfolio Decision",
        "description": "Final BUY/SELL/HOLD (~15-20s)",
        "agents": "PortfolioManagerAgent, DecisionAgent",
    },
}


def create_phase_configuration():
    """Create phase configuration UI component.

    Returns:
        tuple: (checkboxgroup, preset dropdown, validation message, estimated time)
    """
    with gr.Group():
        gr.Markdown("### Workflow Phases")
        gr.Markdown(
            "Select which analysis phases to execute. You can use presets or customize:"
        )

        # Preset selector
        preset_choices = [
            ("Quick Technical Check (~15-20s)", "quick_technical"),
            ("Investment Research (~90s)", "investment_research"),
            ("Full Analysis (~2min)", "full_analysis"),
            ("Custom", "custom"),
        ]

        preset_dropdown = gr.Dropdown(
            choices=preset_choices,
            value="full_analysis",
            label="Analysis Preset",
            info="Choose a preset or select 'Custom' to manually choose phases",
        )

        # Phase checkboxes
        phase_choices = [
            (PHASE_INFO[phase.value]["label"], phase.value) for phase in AnalysisPhase
        ]

        phase_checkboxes = gr.CheckboxGroup(
            choices=phase_choices,
            value=[
                phase.value for phase in AnalysisPhase
            ],  # All phases selected by default
            label="Enabled Phases",
            info="Select phases to execute (order is automatic)",
        )

        # Validation message
        validation_msg = gr.Markdown(value="", visible=False)

        # Educational mode checkbox
        educational_mode_checkbox = gr.Checkbox(
            value=True,
            label="Educational Mode",
            info="Include explanations and learning notes in the report",
        )

        # Estimated execution time
        estimated_time = gr.Markdown(
            value="⏱️ Estimated execution time: ~2 minutes", visible=True
        )

        # Phase details (collapsible)
        with gr.Accordion("Phase Details", open=False):
            phase_details_md = "\n\n".join(
                [
                    f"**{info['label']}**: {info['description']}\n- Agents: {info['agents']}"
                    for phase, info in PHASE_INFO.items()
                ]
            )
            gr.Markdown(phase_details_md)

    def apply_preset(preset_name: str) -> List[str]:
        """Apply preset phase configuration.

        Args:
            preset_name: Name of preset (quick_technical, investment_research, full_analysis, custom)

        Returns:
            List of enabled phase values
        """
        if preset_name == "custom":
            # Don't change current selection
            return gr.update()

        preset_config = DEFAULT_CONFIG["phase_presets"].get(preset_name, {})
        enabled_phases = preset_config.get("phases", [])
        return enabled_phases

    def validate_phases(selected_phases: List[str]) -> Tuple[str, str]:
        """Validate phase selection and estimate execution time.

        Args:
            selected_phases: List of selected phase values

        Returns:
            tuple: (validation_message, estimated_time_message)
        """
        if not selected_phases:
            return (
                "⚠️ **Error**: At least one phase must be selected",
                "⏱️ Estimated execution time: N/A",
            )

        # Create temporary config for validation
        try:
            phases_enum = [AnalysisPhase(p) for p in selected_phases]
        except ValueError as e:
            return (
                f"⚠️ **Error**: Invalid phase selection: {e}",
                "⏱️ Estimated execution time: N/A",
            )

        config = PhaseConfiguration(enabled_phases=phases_enum)
        errors = config.validate()

        # Calculate estimated time
        time_estimates = {
            AnalysisPhase.TECHNICAL.value: 20,
            AnalysisPhase.FUNDAMENTAL.value: 35,
            AnalysisPhase.SENTIMENT.value: 25,
            AnalysisPhase.RESEARCH_SYNTHESIS.value: 18,
            AnalysisPhase.RISK.value: 18,
            AnalysisPhase.DECISION.value: 18,
        }

        total_seconds = sum(time_estimates.get(p, 20) for p in selected_phases)

        if total_seconds < 60:
            time_str = f"~{total_seconds}s"
        else:
            minutes = total_seconds // 60
            seconds = total_seconds % 60
            if seconds > 0:
                time_str = f"~{minutes}min {seconds}s"
            else:
                time_str = f"~{minutes}min"

        estimated_msg = f"⏱️ Estimated execution time: {time_str}"

        if errors:
            error_msg = "⚠️ **Validation Errors**:\n\n" + "\n".join(
                f"- {err}" for err in errors
            )
            return (error_msg, estimated_msg)
        else:
            return ("", estimated_msg)

    # Wire up preset dropdown to update checkboxes
    preset_dropdown.change(
        fn=apply_preset, inputs=[preset_dropdown], outputs=[phase_checkboxes]
    )

    # Wire up phase validation
    phase_checkboxes.change(
        fn=validate_phases,
        inputs=[phase_checkboxes],
        outputs=[validation_msg, estimated_time],
    )

    return (
        preset_dropdown,
        phase_checkboxes,
        educational_mode_checkbox,
        validation_msg,
        estimated_time,
    )


def get_phase_configuration_from_ui(
    selected_phases: List[str],
    investment_style: str,
    timeframe: str,
    educational_mode: bool = True,
) -> PhaseConfiguration:
    """Create PhaseConfiguration from UI inputs.

    Args:
        selected_phases: List of selected phase values from UI
        investment_style: Investment style value (long_term or swing_trading)
        timeframe: Selected timeframe (1d, 1w, etc.)
        educational_mode: Whether to include educational content

    Returns:
        PhaseConfiguration object
    """
    from config.models import InvestmentStyle

    # Convert strings to enums
    style_enum = InvestmentStyle(investment_style)
    phases_enum = [AnalysisPhase(p) for p in selected_phases]

    # Get chart period from investment style config
    style_config = DEFAULT_CONFIG["investment_styles"].get(investment_style, {})
    chart_period_days = style_config.get("chart_period_days", 180)

    return PhaseConfiguration(
        investment_style=style_enum,
        enabled_phases=phases_enum,
        timeframe=timeframe,
        chart_period_days=chart_period_days,
        educational_mode=educational_mode,
    )