GovindRoy commited on
Commit
5ca4128
ยท
verified ยท
1 Parent(s): 221a4b2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +40 -24
app.py CHANGED
@@ -1,44 +1,58 @@
1
- import os, re, openai, pandas as pd, traceback
 
 
 
 
2
  from collections import Counter, defaultdict
3
  from apscheduler.schedulers.background import BackgroundScheduler
4
  import gradio as gr
 
5
  from utils import (
6
  SECTOR, DYN, save_dynamic,
7
  fetch_news, keyword_hit,
8
  validate_ticker, send_tg, ist_now
9
  )
10
 
 
11
  openai.api_base = "https://api.groq.com/openai/v1"
12
  openai.api_key = os.getenv("GROQ_API_KEY")
13
 
 
14
  def llm_reason(theme, tickers, headlines):
15
- prompt = f"""Theme: {theme}
 
16
  Sample news: {' | '.join(headlines[:4])}
17
 
18
- Write TWO crisp bullets (<60 words) explaining why {', '.join(tickers)} benefit now."""
 
19
  rsp = openai.ChatCompletion.create(
20
  model="llama3-70b-8192",
21
  messages=[{"role":"user","content":prompt}],
22
- temperature=0.35, max_tokens=130
 
23
  )
24
  return rsp.choices[0].message.content.strip()
25
 
 
26
  def suggest_tickers(theme):
27
  ask = openai.ChatCompletion.create(
28
  model="llama3-8b-8192",
29
  messages=[{"role":"user","content":
30
- f"List up to 5 NSE tickers that will benefit from '{theme}'. Return commaโ€‘separated tickers only."}],
31
- temperature=0.4, max_tokens=20
 
 
32
  )
33
  raw = re.split(r"[,\s]+", ask.choices[0].message.content.strip())
34
  return [validate_ticker(t.upper()) for t in raw]
35
 
 
36
  def _daily_job():
37
- """Core logic, may raise exceptions."""
38
  news = fetch_news()
39
  freq = Counter()
40
  hits = defaultdict(list)
41
 
 
42
  for art in news:
43
  text = art["title"] + " " + art.get("description", "")
44
  for theme, cfg in SECTOR.items():
@@ -46,10 +60,10 @@ def _daily_job():
46
  freq[theme] += 1
47
  hits[theme].append(art["title"])
48
 
 
49
  if not freq:
50
- return pd.DataFrame([], columns=["theme","hits","stocks","reason"])
51
 
52
- rows, cards = [], []
53
  for theme, count in freq.most_common():
54
  base = SECTOR[theme]["tickers"]
55
  extra = DYN.get(theme, [])
@@ -64,41 +78,43 @@ def _daily_job():
64
 
65
  cards.append(
66
  f"*{theme}* ({count} hits)\n"
67
- f"Stocks: {', '.join('`'+t[:-3]+'`' for t in tickers)}\n{reason}"
 
68
  )
69
- rows.append({"theme":theme, "hits":count,
70
- "stocks":', '.join(tickers), "reason":reason})
 
 
 
 
71
 
72
  header = f"๐Ÿ“ˆ *Macro Theme Brief* {ist_now().strftime('%dย %bย %Y %H:%M')}"
73
  send_tg(header + "\n\n" + "\n\n".join(cards))
74
  return pd.DataFrame(rows)
75
 
 
76
  def daily_job_safe():
77
  try:
78
- result = _daily_job()
79
- return result
80
- except Exception as e:
81
  tb = traceback.format_exc()
82
- # Log to Space logs
83
  print("Error in daily_job:", tb)
84
- # Show traceback in UI
85
- return f"```python\n{tb}\n```"
86
 
87
- # โ”€โ”€ Scheduler โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
88
  sched = BackgroundScheduler(timezone="UTC")
89
- sched.add_job(daily_job_safe, trigger="cron", hour=2, minute=30) # 08:00 IST
90
  sched.start()
91
 
92
- # โ”€โ”€ Gradio UI โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
93
  if __name__ == "__main__":
94
- import os
95
  port = int(os.environ.get("PORT", 7860))
96
  with gr.Blocks() as demo:
97
- gr.Markdown("### ๐Ÿ‡ฎ๐Ÿ‡ณ Macroโ€‘Themeย Bot ย (Elecย MFG | Semicon | Hโ‚‚ | Ethanol | RE)")
98
  out = gr.Textbox(lines=20, label="Output / Error")
99
  gr.Button("Run now").click(fn=daily_job_safe, outputs=out)
100
  demo.launch(
101
  server_name="0.0.0.0",
102
  server_port=port,
103
- ssr_mode=False,
104
  )
 
1
+ import os
2
+ import re
3
+ import openai
4
+ import pandas as pd
5
+ import traceback
6
  from collections import Counter, defaultdict
7
  from apscheduler.schedulers.background import BackgroundScheduler
8
  import gradio as gr
9
+
10
  from utils import (
11
  SECTOR, DYN, save_dynamic,
12
  fetch_news, keyword_hit,
13
  validate_ticker, send_tg, ist_now
14
  )
15
 
16
+ # โ”€โ”€ initialize LLM client โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
17
  openai.api_base = "https://api.groq.com/openai/v1"
18
  openai.api_key = os.getenv("GROQ_API_KEY")
19
 
20
+ # โ”€โ”€ helper: ask LLM for rationale โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
21
  def llm_reason(theme, tickers, headlines):
22
+ prompt = f"""
23
+ Theme: {theme}
24
  Sample news: {' | '.join(headlines[:4])}
25
 
26
+ Write TWO crisp bullets (<60 words total) explaining why {', '.join(tickers)} benefit now.
27
+ """
28
  rsp = openai.ChatCompletion.create(
29
  model="llama3-70b-8192",
30
  messages=[{"role":"user","content":prompt}],
31
+ temperature=0.35,
32
+ max_tokens=130
33
  )
34
  return rsp.choices[0].message.content.strip()
35
 
36
+ # โ”€โ”€ helper: ask LLM for new tickers โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
37
  def suggest_tickers(theme):
38
  ask = openai.ChatCompletion.create(
39
  model="llama3-8b-8192",
40
  messages=[{"role":"user","content":
41
+ f"List up to 5 NSE tickers that will benefit from '{theme}'. Return comma-separated tickers only."
42
+ }],
43
+ temperature=0.4,
44
+ max_tokens=20
45
  )
46
  raw = re.split(r"[,\s]+", ask.choices[0].message.content.strip())
47
  return [validate_ticker(t.upper()) for t in raw]
48
 
49
+ # โ”€โ”€ core logic (may raise) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
50
  def _daily_job():
 
51
  news = fetch_news()
52
  freq = Counter()
53
  hits = defaultdict(list)
54
 
55
+ # count keyword hits per theme
56
  for art in news:
57
  text = art["title"] + " " + art.get("description", "")
58
  for theme, cfg in SECTOR.items():
 
60
  freq[theme] += 1
61
  hits[theme].append(art["title"])
62
 
63
+ rows, cards = [], []
64
  if not freq:
65
+ return pd.DataFrame(rows, columns=["theme","hits","stocks","reason"])
66
 
 
67
  for theme, count in freq.most_common():
68
  base = SECTOR[theme]["tickers"]
69
  extra = DYN.get(theme, [])
 
78
 
79
  cards.append(
80
  f"*{theme}* ({count} hits)\n"
81
+ f"Stocks: {', '.join('`'+t[:-3]+'`' for t in tickers)}\n"
82
+ f"{reason}"
83
  )
84
+ rows.append({
85
+ "theme": theme,
86
+ "hits": count,
87
+ "stocks": ', '.join(tickers),
88
+ "reason": reason
89
+ })
90
 
91
  header = f"๐Ÿ“ˆ *Macro Theme Brief* {ist_now().strftime('%dย %bย %Y %H:%M')}"
92
  send_tg(header + "\n\n" + "\n\n".join(cards))
93
  return pd.DataFrame(rows)
94
 
95
+ # โ”€โ”€ safe wrapper (catches & displays errors) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
96
  def daily_job_safe():
97
  try:
98
+ return _daily_job()
99
+ except Exception:
 
100
  tb = traceback.format_exc()
 
101
  print("Error in daily_job:", tb)
102
+ return "```python\n" + tb + "\n```"
 
103
 
104
+ # โ”€โ”€ schedule to run at 08:00 IST (02:30 UTC) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
105
  sched = BackgroundScheduler(timezone="UTC")
106
+ sched.add_job(daily_job_safe, trigger="cron", hour=2, minute=30)
107
  sched.start()
108
 
109
+ # โ”€โ”€ Gradio UI โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
110
  if __name__ == "__main__":
 
111
  port = int(os.environ.get("PORT", 7860))
112
  with gr.Blocks() as demo:
113
+ gr.Markdown("### ๐Ÿ‡ฎ๐Ÿ‡ณ Macroโ€‘Theme Bot (Elecย MFG | Semicon | Hโ‚‚ | Ethanol | RE)")
114
  out = gr.Textbox(lines=20, label="Output / Error")
115
  gr.Button("Run now").click(fn=daily_job_safe, outputs=out)
116
  demo.launch(
117
  server_name="0.0.0.0",
118
  server_port=port,
119
+ ssr_mode=False
120
  )