CRYPTONEWS34 commited on
Commit
c9523a5
Β·
1 Parent(s): d04009a

Fix matplotlib dir and add httpx to requirements

Browse files
Files changed (2) hide show
  1. app.py +84 -41
  2. requirements.txt +2 -1
app.py CHANGED
@@ -7,38 +7,31 @@ os.environ["HF_HOME"] = "/tmp"
7
  os.makedirs("/tmp/huggingface", exist_ok=True)
8
  os.makedirs("/tmp/mplconfig", exist_ok=True)
9
 
10
- from transformers import AutoTokenizer, AutoModelForTokenClassification
11
-
12
  os.environ["HF_HOME"] = "/tmp"
13
- # Load the NER model
14
- tokenizer = AutoTokenizer.from_pretrained("dslim/bert-base-NER")
15
- model = AutoModelForTokenClassification.from_pretrained("dslim/bert-base-NER")
16
-
17
-
18
-
19
  from fastapi import FastAPI, HTTPException
 
20
  from pydantic import BaseModel
21
- from transformers import pipeline
22
- from fastapi.responses import StreamingResponse
23
  import matplotlib
24
- matplotlib.use('Agg') # βœ… Force headless-safe backend
25
- import matplotlib.pyplot as plt # βœ… Safe to use now
26
  import httpx
27
  import io
28
- import requests
29
- import datetime
30
- from io import BytesIO
31
  import logging
 
32
 
33
- # Configure logging
34
  logging.basicConfig(level=logging.INFO)
35
  logger = logging.getLogger(__name__)
36
 
37
- # Create FastAPI app
38
  app = FastAPI()
39
 
40
- # Load transformers models
41
  try:
 
 
42
  ner_model = pipeline("ner", model="dslim/bert-base-NER", aggregation_strategy="simple")
43
  sentiment_model = pipeline("sentiment-analysis", model="ProsusAI/finbert")
44
  logger.info("Models loaded successfully.")
@@ -47,14 +40,17 @@ except Exception as e:
47
  ner_model = None
48
  sentiment_model = None
49
 
50
- # Request body schema for sentiment and NER
51
  class TextRequest(BaseModel):
52
  text: str
53
 
54
- # Request body schema for chart
55
  class CoinRequest(BaseModel):
56
  coin_id: str
57
 
 
 
 
 
58
  @app.get("/")
59
  def home():
60
  return {"message": "Crypto News API is alive!"}
@@ -63,15 +59,12 @@ def home():
63
  def analyze_sentiment(req: TextRequest):
64
  if not sentiment_model:
65
  raise HTTPException(status_code=503, detail="Sentiment model not available")
66
- text = req.text.strip()
67
- if not text:
68
- raise HTTPException(status_code=400, detail="Text cannot be empty")
69
  try:
 
 
 
70
  result = sentiment_model(text[:512])[0]
71
- return {
72
- "label": result["label"],
73
- "score": round(result["score"] * 100, 2)
74
- }
75
  except Exception as e:
76
  logger.error(f"Sentiment analysis error: {e}")
77
  raise HTTPException(status_code=500, detail="Sentiment analysis failed")
@@ -80,10 +73,10 @@ def analyze_sentiment(req: TextRequest):
80
  def analyze_ner(req: TextRequest):
81
  if not ner_model:
82
  raise HTTPException(status_code=503, detail="NER model not available")
83
- text = req.text.strip()
84
- if not text:
85
- raise HTTPException(status_code=400, detail="Text cannot be empty")
86
  try:
 
 
 
87
  entities = ner_model(text[:512])
88
  relevant = [e['word'] for e in entities if e.get('entity_group') in ['ORG', 'PERSON', 'MISC', 'PRODUCT', 'GPE']]
89
  unique_entities = list(dict.fromkeys(relevant))[:5]
@@ -92,39 +85,89 @@ def analyze_ner(req: TextRequest):
92
  logger.error(f"NER analysis error: {e}")
93
  raise HTTPException(status_code=500, detail="NER analysis failed")
94
 
95
-
96
-
97
  @app.post("/chart")
98
  def generate_chart(req: CoinRequest):
99
  coin_id = req.coin_id.strip().lower()
100
  logger.info(f"Generating chart for coin: {coin_id}")
101
-
102
  try:
103
  url = f"https://api.coingecko.com/api/v3/coins/{coin_id}/market_chart"
104
  params = {"vs_currency": "usd", "days": "7"}
105
  response = httpx.get(url, params=params)
106
-
107
  if response.status_code != 200:
108
  logger.error(f"CoinGecko API error: {response.text}")
109
  raise HTTPException(status_code=502, detail="Failed to fetch coin data from CoinGecko")
110
-
111
  prices = response.json()["prices"]
112
- timestamps, values = zip(*prices)
113
-
114
  plt.figure(figsize=(6, 3))
115
  plt.plot(values, color="blue")
116
  plt.title(f"{coin_id.capitalize()} - Last 7 Days")
117
  plt.xlabel("Time")
118
  plt.ylabel("Price (USD)")
119
  plt.grid(True)
120
-
121
  buffer = io.BytesIO()
122
  plt.savefig(buffer, format="png")
123
  plt.close()
124
  buffer.seek(0)
125
-
126
  return StreamingResponse(buffer, media_type="image/png")
127
-
128
  except Exception as e:
129
  logger.exception(f"Chart generation error: {e}")
130
- raise HTTPException(status_code=500, detail="Chart generation failed")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  os.makedirs("/tmp/huggingface", exist_ok=True)
8
  os.makedirs("/tmp/mplconfig", exist_ok=True)
9
 
 
 
10
  os.environ["HF_HOME"] = "/tmp"
11
+ from transformers import AutoTokenizer, AutoModelForTokenClassification
12
+ from transformers import pipeline
 
 
 
 
13
  from fastapi import FastAPI, HTTPException
14
+ from fastapi.responses import StreamingResponse, FileResponse
15
  from pydantic import BaseModel
 
 
16
  import matplotlib
17
+ matplotlib.use('Agg')
18
+ import matplotlib.pyplot as plt
19
  import httpx
20
  import io
 
 
 
21
  import logging
22
+ import random
23
 
24
+ # Logging
25
  logging.basicConfig(level=logging.INFO)
26
  logger = logging.getLogger(__name__)
27
 
28
+ # FastAPI app
29
  app = FastAPI()
30
 
31
+ # Load models
32
  try:
33
+ tokenizer = AutoTokenizer.from_pretrained("dslim/bert-base-NER")
34
+ model = AutoModelForTokenClassification.from_pretrained("dslim/bert-base-NER")
35
  ner_model = pipeline("ner", model="dslim/bert-base-NER", aggregation_strategy="simple")
36
  sentiment_model = pipeline("sentiment-analysis", model="ProsusAI/finbert")
37
  logger.info("Models loaded successfully.")
 
40
  ner_model = None
41
  sentiment_model = None
42
 
43
+ # Schemas
44
  class TextRequest(BaseModel):
45
  text: str
46
 
 
47
  class CoinRequest(BaseModel):
48
  coin_id: str
49
 
50
+ class VisualRequest(BaseModel):
51
+ coin_id: str
52
+ topic: str
53
+
54
  @app.get("/")
55
  def home():
56
  return {"message": "Crypto News API is alive!"}
 
59
  def analyze_sentiment(req: TextRequest):
60
  if not sentiment_model:
61
  raise HTTPException(status_code=503, detail="Sentiment model not available")
 
 
 
62
  try:
63
+ text = req.text.strip()
64
+ if not text:
65
+ raise HTTPException(status_code=400, detail="Text cannot be empty")
66
  result = sentiment_model(text[:512])[0]
67
+ return {"label": result["label"], "score": round(result["score"] * 100, 2)}
 
 
 
68
  except Exception as e:
69
  logger.error(f"Sentiment analysis error: {e}")
70
  raise HTTPException(status_code=500, detail="Sentiment analysis failed")
 
73
  def analyze_ner(req: TextRequest):
74
  if not ner_model:
75
  raise HTTPException(status_code=503, detail="NER model not available")
 
 
 
76
  try:
77
+ text = req.text.strip()
78
+ if not text:
79
+ raise HTTPException(status_code=400, detail="Text cannot be empty")
80
  entities = ner_model(text[:512])
81
  relevant = [e['word'] for e in entities if e.get('entity_group') in ['ORG', 'PERSON', 'MISC', 'PRODUCT', 'GPE']]
82
  unique_entities = list(dict.fromkeys(relevant))[:5]
 
85
  logger.error(f"NER analysis error: {e}")
86
  raise HTTPException(status_code=500, detail="NER analysis failed")
87
 
 
 
88
  @app.post("/chart")
89
  def generate_chart(req: CoinRequest):
90
  coin_id = req.coin_id.strip().lower()
91
  logger.info(f"Generating chart for coin: {coin_id}")
 
92
  try:
93
  url = f"https://api.coingecko.com/api/v3/coins/{coin_id}/market_chart"
94
  params = {"vs_currency": "usd", "days": "7"}
95
  response = httpx.get(url, params=params)
 
96
  if response.status_code != 200:
97
  logger.error(f"CoinGecko API error: {response.text}")
98
  raise HTTPException(status_code=502, detail="Failed to fetch coin data from CoinGecko")
 
99
  prices = response.json()["prices"]
100
+ _, values = zip(*prices)
 
101
  plt.figure(figsize=(6, 3))
102
  plt.plot(values, color="blue")
103
  plt.title(f"{coin_id.capitalize()} - Last 7 Days")
104
  plt.xlabel("Time")
105
  plt.ylabel("Price (USD)")
106
  plt.grid(True)
 
107
  buffer = io.BytesIO()
108
  plt.savefig(buffer, format="png")
109
  plt.close()
110
  buffer.seek(0)
 
111
  return StreamingResponse(buffer, media_type="image/png")
 
112
  except Exception as e:
113
  logger.exception(f"Chart generation error: {e}")
114
+ raise HTTPException(status_code=500, detail="Chart generation failed")
115
+
116
+ # βœ… News image generator
117
+ def generate_news_image(topic: str) -> str:
118
+ file_path = f"/tmp/{topic.replace(' ', '_')}_news.png"
119
+ plt.figure(figsize=(6, 3))
120
+ plt.text(0.5, 0.5, f"πŸ“° {topic}", fontsize=18, ha='center')
121
+ plt.axis("off")
122
+ plt.savefig(file_path)
123
+ plt.close()
124
+ return file_path
125
+
126
+ # βœ… Chart image generator for visual endpoint (reuse)
127
+ def generate_chart_image(coin_id: str) -> str:
128
+ try:
129
+ url = f"https://api.coingecko.com/api/v3/coins/{coin_id}/market_chart"
130
+ params = {"vs_currency": "usd", "days": "7"}
131
+ response = httpx.get(url, params=params)
132
+ if response.status_code != 200:
133
+ raise Exception("CoinGecko data fetch failed")
134
+ prices = response.json()["prices"]
135
+ _, values = zip(*prices)
136
+ file_path = f"/tmp/{coin_id.replace(' ', '_')}_chart.png"
137
+ plt.figure(figsize=(6, 3))
138
+ plt.plot(values, color="green")
139
+ plt.title(f"{coin_id.capitalize()} Chart")
140
+ plt.grid(True)
141
+ plt.savefig(file_path)
142
+ plt.close()
143
+ return file_path
144
+ except Exception as e:
145
+ logger.error(f"Chart image generation error: {e}")
146
+ raise
147
+
148
+ # βœ… Random visual endpoint
149
+ @app.post("/visual")
150
+ def generate_visual(req: VisualRequest):
151
+ choice = random.choice(["chart", "news"])
152
+ logger.info(f"Generating visual: {choice}")
153
+ try:
154
+ if choice == "chart":
155
+ path = generate_chart_image(req.coin_id)
156
+ else:
157
+ path = generate_news_image(req.topic)
158
+ return FileResponse(path, media_type="image/png")
159
+ except Exception as e:
160
+ logger.error(f"Visual generation failed: {e}")
161
+ raise HTTPException(status_code=500, detail="Visual generation failed")
162
+
163
+
164
+
165
+
166
+
167
+
168
+
169
+
170
+
171
+
172
+
173
+
requirements.txt CHANGED
@@ -3,4 +3,5 @@ uvicorn[standard]
3
  transformers
4
  torch
5
  matplotlib
6
- requests
 
 
3
  transformers
4
  torch
5
  matplotlib
6
+ requests
7
+ httpx