Miruzen commited on
Commit
174bc58
Β·
verified Β·
1 Parent(s): f81d02f

Compatibility adjust

Browse files
Files changed (1) hide show
  1. app.py +91 -74
app.py CHANGED
@@ -1,22 +1,52 @@
1
  from fastapi import FastAPI
2
  from pydantic import BaseModel
3
- import requests
4
- import os
 
 
 
 
 
 
 
5
 
6
  app = FastAPI(title="Forex Sentiment API", version="2.0")
7
 
8
  # ===============================
9
- # Konfigurasi
10
  # ===============================
11
- HF_ROUTER_URL = "https://router.huggingface.co/hf-inference/models"
12
- HF_API_KEY = os.getenv("HF_API_KEY")
13
-
14
  FINBERT_MODEL = "ProsusAI/finbert"
15
  LONGFORMER_MODEL = "Miruzen/LongFormer_Skripsi"
16
 
 
 
17
 
18
  # ===============================
19
- # Input Schema
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  # ===============================
21
  class InputData(BaseModel):
22
  title: str | None = None
@@ -24,93 +54,80 @@ class InputData(BaseModel):
24
 
25
 
26
  # ===============================
27
- # Helper Functions
28
  # ===============================
29
- def call_hf_model(model_name: str, text: str):
30
- """Kirim teks ke model Hugging Face menggunakan router API baru"""
31
- headers = {
32
- "Authorization": f"Bearer {HF_API_KEY}",
33
- "Content-Type": "application/json",
34
- }
35
-
36
- payload = {
37
- "inputs": text,
38
- "options": {"wait_for_model": True}
39
- }
40
-
41
- url = f"{HF_ROUTER_URL}/{model_name}"
42
- response = requests.post(url, headers=headers, json=payload)
43
-
44
- if response.status_code != 200:
45
- raise Exception(
46
- f"HF API error ({response.status_code}): {response.text}"
47
- )
48
-
49
- return response.json()
50
-
51
-
52
  def extract_scores(predictions):
53
- """Convert HF model output into {positive, neutral, negative} dict."""
54
  scores = {"positive": 0.0, "neutral": 0.0, "negative": 0.0}
 
 
 
 
 
 
 
 
55
 
56
- # Router API sometimes returns either list of lists or single list
57
- data = predictions[0] if isinstance(predictions, list) else predictions
58
- if isinstance(data, list) and len(data) > 0 and isinstance(data[0], dict):
59
- for item in data:
60
- label = item.get("label", "").lower()
61
- if "pos" in label:
62
- scores["positive"] = item["score"]
63
- elif "neg" in label:
64
- scores["negative"] = item["score"]
65
- elif "neu" in label:
66
- scores["neutral"] = item["score"]
67
-
68
- dominant = max(scores, key=scores.get)
69
- return {"label": dominant, "scores": scores}
70
 
71
 
72
  # ===============================
73
- # Main Endpoint
74
  # ===============================
75
  @app.post("/analyze")
76
  def analyze(data: InputData):
77
- print("πŸš€ Incoming request:", data)
78
- print("πŸ“‘ Using router endpoint:", HF_ROUTER_URL)
79
- print("πŸ”‘ Using key starts with:", HF_API_KEY[:10])
80
 
81
  result = {}
82
  errors = []
83
 
84
-
85
- if data.title:
86
- try:
87
- finbert_out = call_hf_model(FINBERT_MODEL, data.title)
88
  result["title"] = extract_scores(finbert_out)
89
- except Exception as e:
90
- errors.append(f"Title analysis error: {e}")
91
 
92
- if data.content:
93
- try:
94
- longformer_out = call_hf_model(LONGFORMER_MODEL, data.content)
95
  result["content"] = extract_scores(longformer_out)
96
- except Exception as e:
97
- errors.append(f"Content analysis error: {e}")
 
 
 
 
 
 
 
 
 
 
98
 
99
- mood_score = (
100
- result.get("title", {}).get("scores", {}).get("positive", 0)
101
- + result.get("content", {}).get("scores", {}).get("positive", 0)
102
- - result.get("title", {}).get("scores", {}).get("negative", 0)
103
- - result.get("content", {}).get("scores", {}).get("negative", 0)
104
- )
105
 
106
- return {
107
- "mood_score": mood_score,
108
- "details": result,
109
- "errors": errors,
110
- "status": "ok" if not errors else "partial"
111
- }
 
 
 
112
 
113
 
 
 
 
114
  @app.get("/")
115
  def root():
116
- return {"message": "Forex Sentiment API active via router.huggingface.co!"}
 
1
  from fastapi import FastAPI
2
  from pydantic import BaseModel
3
+ from transformers import AutoTokenizer, AutoModelForSequenceClassification, pipeline
4
+ import torch
5
+ import logging
6
+
7
+ # ===============================
8
+ # πŸ”§ Logging setup
9
+ # ===============================
10
+ logging.basicConfig(level=logging.INFO)
11
+ logger = logging.getLogger("forex-sentiment")
12
 
13
  app = FastAPI(title="Forex Sentiment API", version="2.0")
14
 
15
  # ===============================
16
+ # πŸš€ Model configuration
17
  # ===============================
 
 
 
18
  FINBERT_MODEL = "ProsusAI/finbert"
19
  LONGFORMER_MODEL = "Miruzen/LongFormer_Skripsi"
20
 
21
+ device = 0 if torch.cuda.is_available() else -1
22
+ logger.info(f"🧠 Using device: {'GPU' if device == 0 else 'CPU'}")
23
 
24
  # ===============================
25
+ # πŸ“¦ Load Models
26
+ # ===============================
27
+ logger.info("πŸ“₯ Loading FinBERT model...")
28
+ finbert = pipeline(
29
+ "text-classification",
30
+ model=FINBERT_MODEL,
31
+ tokenizer=FINBERT_MODEL,
32
+ return_all_scores=True,
33
+ device=device
34
+ )
35
+
36
+ logger.info("πŸ“₯ Loading LongFormer model...")
37
+ longformer = pipeline(
38
+ "text-classification",
39
+ model=LONGFORMER_MODEL,
40
+ tokenizer=LONGFORMER_MODEL,
41
+ return_all_scores=True,
42
+ device=device
43
+ )
44
+
45
+ logger.info("βœ… Models loaded successfully!")
46
+
47
+
48
+ # ===============================
49
+ # 🧾 Input Schema
50
  # ===============================
51
  class InputData(BaseModel):
52
  title: str | None = None
 
54
 
55
 
56
  # ===============================
57
+ # 🧩 Helper Functions
58
  # ===============================
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  def extract_scores(predictions):
60
+ """Convert pipeline output into standardized sentiment dict"""
61
  scores = {"positive": 0.0, "neutral": 0.0, "negative": 0.0}
62
+ for item in predictions[0]:
63
+ label = item["label"].lower()
64
+ if "pos" in label:
65
+ scores["positive"] = item["score"]
66
+ elif "neg" in label:
67
+ scores["negative"] = item["score"]
68
+ elif "neu" in label:
69
+ scores["neutral"] = item["score"]
70
 
71
+ sentiment = max(scores, key=scores.get)
72
+ return {"label": sentiment, "scores": scores}
 
 
 
 
 
 
 
 
 
 
 
 
73
 
74
 
75
  # ===============================
76
+ # πŸ” Main Endpoint
77
  # ===============================
78
  @app.post("/analyze")
79
  def analyze(data: InputData):
80
+ logger.info(f"πŸ“° Incoming request: title='{data.title}' | content='{data.content}'")
 
 
81
 
82
  result = {}
83
  errors = []
84
 
85
+ try:
86
+ if data.title:
87
+ logger.info("βš™οΈ Analyzing title with FinBERT...")
88
+ finbert_out = finbert(data.title)
89
  result["title"] = extract_scores(finbert_out)
90
+ else:
91
+ result["title"] = None
92
 
93
+ if data.content:
94
+ logger.info("βš™οΈ Analyzing content with LongFormer...")
95
+ longformer_out = longformer(data.content)
96
  result["content"] = extract_scores(longformer_out)
97
+ else:
98
+ result["content"] = None
99
+
100
+ # οΏ½οΏ½ Mood score sederhana
101
+ mood_score = (
102
+ (result.get("title", {}).get("scores", {}).get("positive", 0) +
103
+ result.get("content", {}).get("scores", {}).get("positive", 0))
104
+ - (result.get("title", {}).get("scores", {}).get("negative", 0) +
105
+ result.get("content", {}).get("scores", {}).get("negative", 0))
106
+ )
107
+
108
+ logger.info("βœ… Analysis completed successfully")
109
 
110
+ return {
111
+ "title": result.get("title"),
112
+ "content": result.get("content"),
113
+ "mood_score": mood_score,
114
+ "status": "ok"
115
+ }
116
 
117
+ except Exception as e:
118
+ logger.exception("❌ Error during sentiment analysis")
119
+ errors.append(str(e))
120
+ return {
121
+ "title": None,
122
+ "content": None,
123
+ "errors": errors,
124
+ "status": "error"
125
+ }
126
 
127
 
128
+ # ===============================
129
+ # 🩡 Health Check
130
+ # ===============================
131
  @app.get("/")
132
  def root():
133
+ return {"message": "βœ… Forex Sentiment API active and ready!"}