Miruzen commited on
Commit
6e06e81
·
verified ·
1 Parent(s): 02b0b9d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +111 -89
app.py CHANGED
@@ -1,89 +1,111 @@
1
- # app.py
2
- from fastapi import FastAPI
3
- from pydantic import BaseModel
4
- from transformers import AutoTokenizer, AutoModelForSequenceClassification, pipeline
5
- import torch
6
-
7
- app = FastAPI(title="Forex Sentiment API", version="1.0")
8
-
9
- # ===============================
10
- # Load Models
11
- # ===============================
12
- finbert_name = "ProsusAI/finbert"
13
- longformer_name = "Miruzen/LongFormer_Skripsi"
14
-
15
- device = 0 if torch.cuda.is_available() else -1
16
-
17
- print("📥 Loading FinBERT model...")
18
- finbert = pipeline("text-classification",
19
- model=finbert_name,
20
- tokenizer=finbert_name,
21
- return_all_scores=True,
22
- device=device)
23
-
24
- print("📥 Loading LongFormer model...")
25
- longformer = pipeline("text-classification",
26
- model=longformer_name,
27
- tokenizer=longformer_name,
28
- return_all_scores=True,
29
- device=device)
30
-
31
- # ===============================
32
- # Input Schema
33
- # ===============================
34
- class InputData(BaseModel):
35
- title: str | None = None
36
- content: str | None = None
37
-
38
-
39
- # ===============================
40
- # Helper Functions
41
- # ===============================
42
- def extract_scores(predictions):
43
- """Convert HF model output into {positive, neutral, negative} dict."""
44
- scores = {"positive": 0.0, "neutral": 0.0, "negative": 0.0}
45
- for item in predictions[0]:
46
- label = item["label"].lower()
47
- if "pos" in label:
48
- scores["positive"] = item["score"]
49
- elif "neg" in label:
50
- scores["negative"] = item["score"]
51
- elif "neu" in label:
52
- scores["neutral"] = item["score"]
53
- dominant = max(scores, key=scores.get)
54
- return {"label": dominant, "scores": scores}
55
-
56
-
57
- # ===============================
58
- # Main Endpoint
59
- # ===============================
60
- @app.post("/analyze")
61
- def analyze(data: InputData):
62
- result = {}
63
-
64
- if data.title:
65
- finbert_out = finbert(data.title)
66
- result["title"] = extract_scores(finbert_out)
67
-
68
- if data.content:
69
- longformer_out = longformer(data.content)
70
- result["content"] = extract_scores(longformer_out)
71
-
72
- # Gabungkan menjadi mood_score sederhana
73
- mood_score = (
74
- result.get("title", {}).get("scores", {}).get("positive", 0)
75
- + result.get("content", {}).get("scores", {}).get("positive", 0)
76
- - result.get("title", {}).get("scores", {}).get("negative", 0)
77
- - result.get("content", {}).get("scores", {}).get("negative", 0)
78
- )
79
-
80
- return {
81
- "mood_score": mood_score,
82
- "details": result,
83
- "status": "ok"
84
- }
85
-
86
-
87
- @app.get("/")
88
- def root():
89
- return {"message": "Forex Sentiment API active!"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
23
+ content: str | None = None
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
+ result = {}
78
+ errors = []
79
+
80
+ if data.title:
81
+ try:
82
+ finbert_out = call_hf_model(FINBERT_MODEL, data.title)
83
+ result["title"] = extract_scores(finbert_out)
84
+ except Exception as e:
85
+ errors.append(f"Title analysis error: {e}")
86
+
87
+ if data.content:
88
+ try:
89
+ longformer_out = call_hf_model(LONGFORMER_MODEL, data.content)
90
+ result["content"] = extract_scores(longformer_out)
91
+ except Exception as e:
92
+ errors.append(f"Content analysis error: {e}")
93
+
94
+ mood_score = (
95
+ result.get("title", {}).get("scores", {}).get("positive", 0)
96
+ + result.get("content", {}).get("scores", {}).get("positive", 0)
97
+ - result.get("title", {}).get("scores", {}).get("negative", 0)
98
+ - result.get("content", {}).get("scores", {}).get("negative", 0)
99
+ )
100
+
101
+ return {
102
+ "mood_score": mood_score,
103
+ "details": result,
104
+ "errors": errors,
105
+ "status": "ok" if not errors else "partial"
106
+ }
107
+
108
+
109
+ @app.get("/")
110
+ def root():
111
+ return {"message": "Forex Sentiment API active via router.huggingface.co!"}