roger33303 commited on
Commit
c77a68c
Β·
verified Β·
1 Parent(s): 7c4168f

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +171 -0
app.py ADDED
@@ -0,0 +1,171 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from gradio import ChatMessage
3
+ from agents import build_graph
4
+ import os
5
+ import random
6
+ from dotenv import dotenv_values
7
+
8
+ js_func = """
9
+ function refresh() {
10
+ const url = new URL(window.location);
11
+
12
+ if (url.searchParams.get('__theme') !== 'dark') {
13
+ url.searchParams.set('__theme', 'dark');
14
+ window.location.href = url.href;
15
+ }
16
+ }
17
+ """
18
+
19
+
20
+ def run_agent_stream(history, question, groq_key, reddit_id, reddit_secret, reddit_agent, news_key):
21
+ os.environ["GROQ_API_KEY"] = groq_key or ""
22
+ os.environ["REDDIT_CLIENT_ID"] = reddit_id or ""
23
+ os.environ["REDDIT_CLIENT_SECRET"] = reddit_secret or ""
24
+ os.environ["REDDIT_USER_AGENT"] = reddit_agent or ""
25
+ os.environ["NEWS_API"] = news_key or ""
26
+
27
+ try:
28
+ graph = build_graph()
29
+ state = {"messages": [{"role": "user", "content": question}]}
30
+ history = history or []
31
+ history.append(ChatMessage(role="user", content=question))
32
+ history.append(ChatMessage(role="assistant", content="**Supervisor:**\n I am working with my agents to get a result. Sit tight, I’ll get back with a detailed report."))
33
+ yield history, "<div class='loader'></div>", gr.update(interactive=False)
34
+
35
+ for chunk in graph.stream(state):
36
+ agent_key = next(iter(chunk))
37
+ messages = chunk[agent_key]["messages"]
38
+ for msg in messages:
39
+ if msg.__class__.__name__ == "HumanMessage":
40
+ continue
41
+ name = getattr(msg, "name", agent_key)
42
+ if str(name).split('_')[0] == 'transfer':
43
+ continue
44
+ content = msg.content.strip()
45
+
46
+ if not content or "Transferring back" in content or "Successfully transferred" in content:
47
+ continue
48
+
49
+ is_final = msg.response_metadata.get("finish_reason") == "stop"
50
+ is_supervisor = msg.name == "supervisor"
51
+ if is_final and is_supervisor:
52
+ history.append(ChatMessage(role="assistant", content=content, metadata={"title": "βœ… Final Report"}))
53
+ yield history, "", gr.update(interactive=True)
54
+ else:
55
+ emojis = {
56
+ "Stock Analyst": "🧠",
57
+ "Web Surfer": "🌐",
58
+ "Social Media Analyst": "🎦",
59
+ "Business Journalist": "πŸ“Š"
60
+ }
61
+ emoji = emojis.get(name, random.choice(["🏹", "🧭", "🚩"]))
62
+ title = f"{emoji} {name}" if name else ""
63
+ his = ChatMessage(role="assistant", content=content, metadata={"title": title})
64
+ if his not in history:
65
+ history.append(his)
66
+ yield history, "<div class='loader'></div>", gr.update(interactive=False)
67
+ except Exception as e:
68
+ print("Error: ", e)
69
+
70
+
71
+ def load_env_file(file):
72
+ try:
73
+ values = dotenv_values(file.name)
74
+ return (
75
+ values.get("GROQ_API_KEY", ""),
76
+ values.get("REDDIT_CLIENT_ID", ""),
77
+ values.get("REDDIT_CLIENT_SECRET", ""),
78
+ values.get("REDDIT_USER_AGENT", ""),
79
+ values.get("NEWS_API", "")
80
+ )
81
+ except Exception as e:
82
+ print("Failed to load .env file:", e)
83
+ return "", "", "", "", ""
84
+
85
+
86
+ custom_css = """
87
+ <style>
88
+ .loader {
89
+ border: 4px solid #f3f3f3;
90
+ border-top: 4px solid #3498db;
91
+ border-radius: 50%;
92
+ width: 20px;
93
+ height: 20px;
94
+ animation: spin 1s linear infinite;
95
+ margin-top: 10px;
96
+ }
97
+ @keyframes spin {
98
+ 0% { transform: rotate(0deg); }
99
+ 100% { transform: rotate(360deg); }
100
+ }
101
+ #toggle-btn {
102
+ position: fixed;
103
+ top: 10px;
104
+ left: 10px;
105
+ z-index: 1000;
106
+ width: 28px;
107
+ height: 28px;
108
+ padding: 0;
109
+ font-size: 18px;
110
+ font-weight: bold;
111
+ line-height: 1;
112
+ text-align: center;
113
+ background: #eee;
114
+ border: 1px solid #ccc;
115
+ border-radius: 4px;
116
+ }
117
+ </style>
118
+ """
119
+
120
+ def toggle_sidebar(is_visible):
121
+ return (
122
+ gr.update(visible=not is_visible),
123
+ not is_visible,
124
+ "+" if is_visible else "Γ—"
125
+ )
126
+
127
+ with gr.Blocks(title="Stock Market AI", js=js_func) as demo:
128
+ gr.HTML(custom_css)
129
+ gr.Markdown("## 🧠 Stock Market AI Agent\nAnalyze a stock using multiple AI agents (fundamentals, news, sentiment, etc).")
130
+
131
+ sidebar_state = gr.State(True)
132
+ toggle_btn = gr.Button("Γ—", elem_id="toggle-btn")
133
+
134
+ with gr.Row():
135
+ with gr.Column(scale=1) as sidebar:
136
+ gr.Markdown("### πŸ” Enter Your API Keys or Upload a .env File")
137
+ file_upload = gr.File(label="Upload .env or txt file", file_types=[".txt", ".env"])
138
+ groq_key = gr.Textbox(label="GROQ_API_KEY", placeholder="Paste your GROQ API Key here", type="password")
139
+ reddit_id = gr.Textbox(label="REDDIT_CLIENT_ID (Visit: https://www.reddit.com/prefs/apps)", placeholder="Your Reddit App Client ID", type="password")
140
+ reddit_secret = gr.Textbox(label="REDDIT_CLIENT_SECRET", placeholder="Your Reddit App Secret", type="password")
141
+ reddit_agent = gr.Textbox(label="REDDIT_USER_AGENT", placeholder="Your Reddit User Agent")
142
+ news_key = gr.Textbox(label="NEWS_API", placeholder="Your Newsdata.io API Key", type="password")
143
+
144
+ with gr.Column(scale=4):
145
+ chatbot = gr.Chatbot(label="Agent Chat", type="messages", resizable=True, show_copy_button=True)
146
+ msg = gr.Textbox(label="Your Stock Question", placeholder="Should I invest in Tesla?")
147
+ spinner = gr.HTML("")
148
+ clear = gr.Button("Clear")
149
+
150
+ file_upload.change(
151
+ fn=load_env_file,
152
+ inputs=file_upload,
153
+ outputs=[groq_key, reddit_id, reddit_secret, reddit_agent, news_key]
154
+ )
155
+
156
+ toggle_btn.click(
157
+ toggle_sidebar,
158
+ inputs=[sidebar_state],
159
+ outputs=[sidebar, sidebar_state, toggle_btn]
160
+ )
161
+
162
+ msg.submit(
163
+ run_agent_stream,
164
+ inputs=[chatbot, msg, groq_key, reddit_id, reddit_secret, reddit_agent, news_key],
165
+ outputs=[chatbot, spinner, msg],
166
+ queue=True
167
+ )
168
+
169
+ clear.click(lambda: ([], "", gr.update(interactive=True)), outputs=[chatbot, spinner, msg])
170
+
171
+ demo.launch(height=100, show_error=True)