Spaces:
Sleeping
Sleeping
Upload api.py
Browse files
api.py
ADDED
@@ -0,0 +1,129 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from fastapi import FastAPI
|
2 |
+
from pydantic import BaseModel
|
3 |
+
from utils import fetch_news, analyze_sentiment, extract_topics, generate_tts
|
4 |
+
import random
|
5 |
+
|
6 |
+
# Set up the FastAPI server with a name and description
|
7 |
+
app = FastAPI(title="News Sentiment API", description="Analyze news sentiment for companies")
|
8 |
+
|
9 |
+
class CompanyInput(BaseModel):
|
10 |
+
"""Simple model to validate incoming company name."""
|
11 |
+
company: str
|
12 |
+
|
13 |
+
@app.post("/analyze")
|
14 |
+
async def analyze_company(input: CompanyInput):
|
15 |
+
"""Take a company name and return its news sentiment analysis."""
|
16 |
+
company = input.company
|
17 |
+
articles_data = fetch_news(company)
|
18 |
+
if not articles_data:
|
19 |
+
return {"error": f"No articles found for {company}. Check logs for details."}
|
20 |
+
|
21 |
+
articles = []
|
22 |
+
sentiments = {"Positive": 0, "Negative": 0, "Neutral": 0}
|
23 |
+
positive_articles = []
|
24 |
+
negative_articles = []
|
25 |
+
neutral_articles = []
|
26 |
+
|
27 |
+
for article in articles_data:
|
28 |
+
summary = article["summary"].strip() or article["title"].split(" - ")[0].strip()
|
29 |
+
source = article["title"].split(" - ")[-1].strip() if " - " in article["title"] else ""
|
30 |
+
if source in summary:
|
31 |
+
summary = summary.replace(source, "").strip()
|
32 |
+
summary = f"{summary.rstrip(' -')} - {source}"
|
33 |
+
|
34 |
+
sentiment = analyze_sentiment(summary)
|
35 |
+
topics = extract_topics(summary)
|
36 |
+
sentiments[sentiment] += 1
|
37 |
+
|
38 |
+
title = article["title"].split(" - ")[0].strip()
|
39 |
+
if sentiment == "Positive":
|
40 |
+
positive_articles.append(title)
|
41 |
+
elif sentiment == "Negative":
|
42 |
+
negative_articles.append(title)
|
43 |
+
else:
|
44 |
+
neutral_articles.append(title)
|
45 |
+
|
46 |
+
articles.append({
|
47 |
+
"Title": article["title"],
|
48 |
+
"Summary": summary,
|
49 |
+
"Sentiment": sentiment,
|
50 |
+
"Topics": topics,
|
51 |
+
"Link": article["link"],
|
52 |
+
"PubDate": article["pub_date"]
|
53 |
+
})
|
54 |
+
|
55 |
+
detailed_comparisons = [f"- News {i + 1} {article['Sentiment'].lower()}ly discusses {', '.join(article['Topics'])}"
|
56 |
+
for i, article in enumerate(articles)]
|
57 |
+
dominant_sentiment = max(sentiments, key=sentiments.get)
|
58 |
+
trends = f"{company} News Trends: {dominant_sentiment}"
|
59 |
+
|
60 |
+
total_articles = sum(sentiments.values())
|
61 |
+
sentiment_count = f"{sentiments['Positive']} positive, {sentiments['Negative']} negative, {sentiments['Neutral']} neutral"
|
62 |
+
|
63 |
+
intro_phrases = [
|
64 |
+
f"Spanning {total_articles} recent reports, the narrative surrounding {company} tilts {dominant_sentiment.lower()}, with {sentiment_count}.",
|
65 |
+
f"Across {total_articles} articles in recent coverage, {company}’s story emerges as predominantly {dominant_sentiment.lower()}, reflecting {sentiment_count}.",
|
66 |
+
f"Drawing from {total_articles} latest publications, {company}’s news landscape leans {dominant_sentiment.lower()}, underscored by {sentiment_count}."
|
67 |
+
]
|
68 |
+
positive_phrases = [
|
69 |
+
f"With {len(positive_articles)} favorable accounts, {company} demonstrates notable progress, exemplified by '{random.choice(positive_articles) if positive_articles else 'no specific examples available'}'.",
|
70 |
+
f"Boasting {len(positive_articles)} positive developments, {company} showcases strength, as evidenced in '{random.choice(positive_articles) if positive_articles else 'no notable instances'}'.",
|
71 |
+
f"Highlighted by {len(positive_articles)} encouraging reports, {company} is forging ahead, with '{random.choice(positive_articles) if positive_articles else 'no standout reports'}' standing out."
|
72 |
+
]
|
73 |
+
negative_phrases = [
|
74 |
+
f"However, {len(negative_articles)} troubling narratives raise concerns, including '{random.choice(negative_articles) if negative_articles else 'no specific concerns noted'}'.",
|
75 |
+
f"Yet, {len(negative_articles)} adverse reports signal challenges, such as '{random.choice(negative_articles) if negative_articles else 'no highlighted issues'}'.",
|
76 |
+
f"Nevertheless, {len(negative_articles)} concerning stories cast a shadow, notably '{random.choice(negative_articles) if negative_articles else 'no notable setbacks'}'."
|
77 |
+
]
|
78 |
+
neutral_phrases = [
|
79 |
+
f"Additionally, {len(neutral_articles)} impartial updates provide context, such as '{random.choice(neutral_articles) if neutral_articles else 'no neutral updates available'}'.",
|
80 |
+
f"Meanwhile, {len(neutral_articles)} balanced accounts offer insight, including '{random.choice(neutral_articles) if neutral_articles else 'no balanced reports'}'.",
|
81 |
+
f"Furthermore, {len(neutral_articles)} objective pieces contribute details, like '{random.choice(neutral_articles) if neutral_articles else 'no objective details'}'."
|
82 |
+
]
|
83 |
+
outlook_phrases_positive = [
|
84 |
+
f"In summary, {company} appears poised for a favorable trajectory.",
|
85 |
+
f"All told, {company} stands on the cusp of a promising future.",
|
86 |
+
f"Ultimately, {company} is positioned for an optimistic course ahead."
|
87 |
+
]
|
88 |
+
outlook_phrases_negative = [
|
89 |
+
f"In conclusion, {company} confronts a challenging path forward.",
|
90 |
+
f"Overall, {company} navigates a formidable road ahead.",
|
91 |
+
f"To conclude, {company} faces a demanding horizon."
|
92 |
+
]
|
93 |
+
outlook_phrases_mixed = [
|
94 |
+
f"In the final analysis, {company} balances opportunity and uncertainty.",
|
95 |
+
f"On balance, {company} presents a complex outlook moving forward.",
|
96 |
+
f"Ultimately, {company} reflects a blend of prospects and hurdles."
|
97 |
+
]
|
98 |
+
|
99 |
+
final_text = random.choice(intro_phrases) + " "
|
100 |
+
if positive_articles:
|
101 |
+
final_text += random.choice(positive_phrases) + " "
|
102 |
+
if negative_articles:
|
103 |
+
final_text += random.choice(negative_phrases) + " "
|
104 |
+
if neutral_articles:
|
105 |
+
final_text += random.choice(neutral_phrases) + " "
|
106 |
+
if sentiments["Positive"] > sentiments["Negative"]:
|
107 |
+
final_text += random.choice(outlook_phrases_positive)
|
108 |
+
elif sentiments["Negative"] > sentiments["Positive"]:
|
109 |
+
final_text += random.choice(outlook_phrases_negative)
|
110 |
+
else:
|
111 |
+
final_text += random.choice(outlook_phrases_mixed)
|
112 |
+
|
113 |
+
print(f"Generated dynamic final sentiment for {company}: {final_text}")
|
114 |
+
|
115 |
+
return {
|
116 |
+
"Company": company,
|
117 |
+
"Articles": articles,
|
118 |
+
"Comparative Sentiment Score": {
|
119 |
+
"Sentiment Distribution": f"Positive: {sentiments['Positive']}, Negative: {sentiments['Negative']}, Neutral: {sentiments['Neutral']}",
|
120 |
+
"Trends": trends,
|
121 |
+
"Detailed Comparisons": "\n".join(detailed_comparisons)
|
122 |
+
},
|
123 |
+
"Final Sentiment Analysis": final_text.strip(),
|
124 |
+
"Audio": None
|
125 |
+
}
|
126 |
+
|
127 |
+
if __name__ == "__main__":
|
128 |
+
import uvicorn
|
129 |
+
uvicorn.run(app, host="0.0.0.0", port=8000) # Start the API server on port 8000
|