File size: 8,972 Bytes
adf3bae
 
 
 
 
 
 
 
 
 
 
 
a0c219b
 
 
adf3bae
 
 
a0c219b
 
 
adf3bae
 
a0c219b
adf3bae
 
a0c219b
 
 
adf3bae
 
 
a0c219b
 
 
 
 
adf3bae
 
a0c219b
0822fb7
adf3bae
 
 
 
a0c219b
 
 
adf3bae
a0c219b
41c6c11
adf3bae
 
 
 
a0c219b
 
 
adf3bae
 
5d2f635
adf3bae
 
 
 
a0c219b
 
 
adf3bae
a0c219b
 
adf3bae
a0c219b
5d2f635
adf3bae
 
 
 
 
a0c219b
 
adf3bae
a0c219b
 
41c6c11
adf3bae
 
 
 
 
9c32c56
 
 
adf3bae
9c32c56
 
 
 
 
41c6c11
a0c219b
adf3bae
 
a0c219b
 
 
adf3bae
 
a0c219b
 
 
 
 
 
 
adf3bae
 
 
a0c219b
 
 
 
 
 
adf3bae
 
 
a0c219b
 
 
 
 
 
 
 
adf3bae
 
 
 
 
a0c219b
 
 
adf3bae
a0c219b
adf3bae
 
 
 
a0c219b
adf3bae
 
 
 
 
a0c219b
 
adf3bae
a0c219b
adf3bae
 
 
 
 
9c32c56
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
adf3bae
9c32c56
adf3bae
 
 
a0c219b
 
 
 
adf3bae
a0c219b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
adf3bae
a0c219b
 
 
 
 
adf3bae
 
a0c219b
 
 
504e068
adf3bae
 
504e068
 
 
 
a0c219b
 
504e068
f2b03ec
504e068
 
adf3bae
a0c219b
 
 
9edc788
adf3bae
bfad701
f2b03ec
a0c219b
adf3bae
 
 
a0c219b
 
adf3bae
 
cf8a2ea
 
 
 
 
 
 
 
 
adf3bae
f2b03ec
7fb8179
f2b03ec
adf3bae
 
 
f2b03ec
a0c219b
504e068
f2b03ec
 
 
 
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
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
# import libraries, APis and LLMs
from crewai import Agent, Task, Crew
import os
from tools.market_data import MarketDataTool
from tools.sentiment_tool import SentimentTool
from tools.historical_data_tool import HistoricalDataTool
from tools.analytics_tool import AnalyticsTool
import gradio as gr
import warnings

warnings.filterwarnings("ignore")

# ----------------------
# ENVIRONMENT VARIABLES
# ----------------------
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
SERPER_API_KEY = os.getenv("SERPER_API_KEY")

# ----------------------
# TOOLS (structured JSON)
# ----------------------
market_data_tool = MarketDataTool()
sentiment_tool = SentimentTool()
historical_data_tool = HistoricalDataTool()
analytics_tool = AnalyticsTool()

# ----------------------
# AGENTS
# ----------------------

market_agent = Agent(
    role="Crypto Market Analyst",
    goal="Fetch live market price using CoinGecko and produce structured market JSON.",
    backstory=(
        "A disciplined market analyst who retrieves clean market data "
        "including price and market liquidity."
    ),
    verbose=False,
    allow_delegations=True,
    tools=[market_data_tool],
    llm="gpt-4o-mini"
)

sentiment_agent = Agent(
    role="Crypto Sentiment Analyst",
    goal="Analyze public sentiment on news & Reddit using Serper + OpenAI. Output structured sentiment JSON.",
    backstory="An expert in NLP-based crypto sentiment interpretation.",
    verbose=False,
    allow_delegations=True,
    tools=[sentiment_tool],
    llm="gpt-4.1"
)

historical_agent = Agent(
    role="Crypto Historical Analyst",
    goal="Analyze long-term price trends, volatility, and movement patterns using clean structured JSON.",
    backstory="A quantitative analyst specializing in historical trends.",
    verbose=False,
    allow_delegations=True,
    tools=[historical_data_tool],
    llm="gpt-4o-mini"
)

analytics_agent = Agent(
    role="Cryptocurrency Analytics",
    goal=(
        "Combine structured outputs from market, historical, and sentiment tools "
        "into final analytics including trend, volatility, alignment, and composite scoring."
    ),
    backstory="A senior quant strategist synthesizing multiple signals into coherent analytics.",
    verbose=False,
    allow_delegations=False,
    tools=[analytics_tool],
    llm="gpt-4o-mini"
)

strategy_agent = Agent(
    role="Crypto Strategy Analyst",
    goal=(
        "Convert analytics into an actionable trading stance. Integrate sentiment, volatility, "
        "risk, opportunity, and alignment to produce a structured trading strategy."
    ),
    backstory="A crypto strategist experienced in forming actionable plans.",
    verbose=False,
    llm="gpt-4.1"
)

reporting_agent = Agent(
    role="Crypto Reporting Analyst",
    goal=(
        "Produce a polished, professional, narrative-style market report written in clean Markdown. "
        "The report must use paragraphs, not bullet points, except where absolutely necessary. "
        "Each section must read like human financial analysis, with smooth transitions and explanatory context."
    ),
    backstory=(
        "You are a senior market strategist and financial writer for institutional clients. "
        "Your writing style is polished, narrative, and insight-driven β€” not bullet-point lists. "
        "You blend market data, sentiment, and strategy into clear, flowing paragraphs."
    ),
    llm="gpt-4.1",
    verbose=False,
)

# ----------------------
# TASKS
# ----------------------

market_data_task = Task(
    description=(
        "Use the market_data_tool to fetch the live market price for "
        "{cryptocurrency_selection} in {currency_selection}. "
        "Return structured JSON output only."
    ),
    expected_output="Structured JSON of current market metrics.",
    agent=market_agent,
)

sentiment_task = Task(
    description=(
        "Fetch sentiment for {cryptocurrency_selection} using sentiment_tool. "
        "Return structured JSON with sentiment, reasoning, and the raw headlines used."
    ),
    expected_output="Structured sentiment JSON (sentiment, reasoning, headlines).",
    agent=sentiment_agent,
)

historical_data_task = Task(
    description=(
        "Use the historical_data_tool to retrieve structured historical price data "
        "for {cryptocurrency_selection} over {days_selection} days."
    ),
    expected_output=(
        "Structured historical JSON with start_price, end_price, pct_change, "
        "volatility_pct, and trend."
    ),
    agent=historical_agent,
)

analytics_task = Task(
    description=(
        "Use analytics_tool to combine market_data, historical_data, and sentiment_data "
        "into final structured analytics including trend, volatility, sentiment, alignment, "
        "and composite score."
    ),
    expected_output="Structured analytics JSON.",
    agent=analytics_agent,
    inputs={
        "market_data": "{output_of_market_data_task}",
        "historical_data": "{output_of_historical_data_task}",
        "sentiment_data": "{output_of_sentiment_data_task}",
    }
)

strategy_task = Task(
    description=(
        "Based on the structured analytics, produce an actionable trading stance "
        "including: bias, strategy, risk guidance, and rationale."
    ),
    expected_output="Structured strategy JSON.",
    agent=strategy_agent,
)

reporting_task = Task(
    description=(
        "Using the outputs from all previous tasks, write a cohesive, high-quality market report "
        "in Markdown format. Each section must be written as narrative paragraphs, not bullet or numbered lists. "
        "You must synthesize insights, explain context, and avoid repeating raw field names. "
        "Required sections with H2 Markdown headings (##):\n\n"
        "## Market Overview\n"
        "Explain current price, recent movement, and key context in paragraph form.\n\n"
        "## Historical Performance\n"
        "Summarize recent price trajectory, volatility, and trend using smooth narrative sentences.\n\n"
        "## Sentiment Analysis\n"
        "Describe market sentiment, referencing sentiment sources in prose, not lists.\n\n"
        "## Analytical Summary\n"
        "Interpret composite metrics and explain what they mean for traders.\n\n"
        "## Strategy Outlook\n"
        "Provide clear strategy insights in paragraph format β€” no bullet points.\n\n"
        "## Final Takeaways\n"
        "Conclude with high-level insights in polished prose.\n\n"
        "IMPORTANT: Do NOT output bullet points or lists. Use flowing paragraphs."
    ),
    expected_output="A polished, narrative Markdown report with paragraphs only.",
    agent=reporting_agent,
)

# ----------------------
# CREW EXECUTION PIPELINE
# ----------------------

crypto_analysis_crew = Crew(
    agents=[
        market_agent,
        historical_agent,
        sentiment_agent,
        analytics_agent,
        strategy_agent,
        reporting_agent
    ],
    tasks=[
        market_data_task,
        historical_data_task,
        sentiment_task,
        analytics_task,
        strategy_task,
        reporting_task
    ],
    process="sequential",
    verbose=True
)

# ----------------------
# GRADIO UI HANDLER
# ----------------------

def generate_report(crypto_name, currency, days):
    crypto_inputs = {
        "cryptocurrency_selection": crypto_name.lower(),
        "currency_selection": currency.lower(),
        "days_selection": int(days)
    }

    # Disable button at start
    yield "", gr.update(interactive=False)

    # Run workflow
    result = crypto_analysis_crew.kickoff(inputs=crypto_inputs)

    final = result["final_output"] if isinstance(result, dict) and "final_output" in result else str(result)

    # Return report + re-enable button
    yield final, gr.update(interactive=True)

# ----------------------
# GRADIO APP
# ----------------------

with gr.Blocks(theme=gr.themes.Monochrome()) as app:

    gr.Markdown("# πŸͺ™ Crypto Intelligence Dashboard")
    gr.Markdown("Run a full multi-agent crypto analysis using structured JSON tools.")

    with gr.Row():
        crypto = gr.Textbox(
            label="Cryptocurrency (e.g. bitcoin, ethereum)",
            placeholder="Type cryptocurrency name...",
            value="bitcoin"
        )
        currency = gr.Dropdown(
            ["usd", "eur", "gbp"],
            label="Currency",
            value="usd"
        )
        days = gr.Slider(
            minimum=30, maximum=730, value=365, step=15,
            label="Historical Lookback (days)"
        )

    # ← original working button
    run_button = gr.Button("πŸš€ Run Full Analysis", variant="primary")

    report_output = gr.Markdown(label="πŸ“Š Intelligence Report")

    run_button.click(
        fn=generate_report,
        inputs=[crypto, currency, days],
        outputs=[report_output, run_button]
    )

if __name__ == "__main__":
    app.launch(server_name="0.0.0.0", server_port=7860)