|
import streamlit as st |
|
import requests |
|
import re |
|
import torch |
|
from transformers import BertTokenizer, BertForSequenceClassification |
|
|
|
|
|
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased') |
|
model_path = '/Users/kartikrathi/Documents/News_sentiment_analysis/model' |
|
model = BertForSequenceClassification.from_pretrained(model_path) |
|
|
|
|
|
def analyze_sentiment(text): |
|
|
|
inputs = tokenizer(text, return_tensors="pt", truncation=True, padding=True, max_length=512) |
|
|
|
|
|
with torch.no_grad(): |
|
outputs = model(**inputs) |
|
|
|
|
|
logits = outputs.logits |
|
|
|
|
|
predicted_class_id = torch.argmax(logits, dim=1).item() |
|
sentiment = {0: "positive", 1: "negative", 2: "neutral"} |
|
return sentiment[predicted_class_id] |
|
|
|
|
|
def fetch_stock_news(symbol): |
|
api_token = '6679177763bcd9.48465511' |
|
url = f'https://eodhd.com/api/news?s={symbol}&offset=0&limit=2&api_token={api_token}&fmt=json' |
|
|
|
try: |
|
response = requests.get(url) |
|
response.raise_for_status() |
|
data = response.json() |
|
|
|
news_list = [] |
|
for article in data: |
|
title = article.get('title', 'Title not available') |
|
content = article.get('content', 'Content not available') |
|
url = article.get('url', 'URL not available') |
|
date = article.get('date', 'Date not available') |
|
|
|
|
|
cleaned_content = remove_sections(content) |
|
|
|
news_list.append({'title': title, 'content': cleaned_content, 'url': url, 'date': date}) |
|
|
|
return news_list |
|
|
|
except requests.exceptions.RequestException as e: |
|
print(f"Error fetching news for {symbol}: {e}") |
|
return None |
|
|
|
|
|
def remove_sections(content): |
|
|
|
patterns = [ |
|
r'About\s+.*?[\n\r]+', |
|
r'Safe\s+Harbor.*', |
|
r'Story\s+continues.*', |
|
r'Visit\s+www\.infosys\.com.*', |
|
r'Logo', |
|
] |
|
|
|
for pattern in patterns: |
|
content = re.sub(pattern, '', content, flags=re.IGNORECASE) |
|
|
|
return content.strip() |
|
|
|
|
|
def main(): |
|
st.sidebar.title('Navigation') |
|
page = st.sidebar.radio("Go to", ('Home', 'Portfolio & News')) |
|
|
|
if page == 'Home': |
|
st.title("Financial News Sentiment Analysis") |
|
st.markdown(""" |
|
This app performs sentiment analysis on financial news using FinBERT model. |
|
""") |
|
|
|
|
|
user_input = st.text_area("Enter your financial news text here:", height=200) |
|
|
|
|
|
if st.button("Analyze"): |
|
if user_input: |
|
sentiment = analyze_sentiment(user_input) |
|
if sentiment == "positive": |
|
st.markdown(f"<p style='color:green;font-size:40px;font-weight:bold'>{sentiment}</p>", unsafe_allow_html=True) |
|
elif sentiment == "negative": |
|
st.markdown(f"<p style='color:red;font-size:40px;font-weight:bold'>{sentiment}</p>", unsafe_allow_html=True) |
|
elif sentiment == "neutral": |
|
st.markdown(f"<p style='color:blue;font-size:40px;font-weight:bold'>{sentiment}</p>", unsafe_allow_html=True) |
|
else: |
|
st.warning("Please enter some text.") |
|
|
|
elif page == 'Portfolio & News': |
|
st.title('Portfolio & News') |
|
|
|
|
|
st.sidebar.subheader('Manage Portfolio & Fetch News') |
|
st.sidebar.info("Enter your portfolio/company names here to fetch news.") |
|
|
|
|
|
portfolio = st.sidebar.text_area("Enter your portfolio/company names (one per line):", height=200) |
|
|
|
if st.sidebar.button("Save"): |
|
|
|
shares = portfolio.split("\n") |
|
shares = [share.strip() + ".NSE" for share in shares if share.strip()] |
|
st.sidebar.markdown("**Shares**") |
|
st.sidebar.markdown("\n".join(shares)) |
|
|
|
|
|
if st.sidebar.button("Fetch News & Analyze Sentiment"): |
|
if portfolio: |
|
companies = portfolio.split("\n") |
|
companies = [company.strip() + ".NSE" for company in companies if company.strip()] |
|
for company in companies: |
|
st.subheader(f"Latest News for {company}:") |
|
news = fetch_stock_news(company) |
|
|
|
if news: |
|
for article in news: |
|
title = article['title'] |
|
content = article['content'] |
|
url = article['url'] |
|
date = article['date'] |
|
st.markdown(f"**Title:** [{title}]({url}) <span style='color:green;font-size:12px;'>({date})</span>", unsafe_allow_html=True) |
|
|
|
|
|
truncated_content = content[:200] + "..." |
|
st.markdown(f"**Content:** {truncated_content}") |
|
|
|
|
|
with st.expander("Expand more"): |
|
st.markdown(f"{content}") |
|
|
|
st.markdown("---") |
|
|
|
|
|
if content: |
|
sentiment = analyze_sentiment(content) |
|
if sentiment == "positive": |
|
sentiment_color = "green" |
|
elif sentiment == "negative": |
|
sentiment_color = "red" |
|
elif sentiment == "neutral": |
|
sentiment_color = "blue" |
|
|
|
st.markdown(f"**Sentiment:** <span style='color:{sentiment_color};font-weight:bold'>{sentiment}</span>", unsafe_allow_html=True) |
|
st.markdown("---") |
|
else: |
|
st.warning(f"No news articles found for {company}.") |
|
else: |
|
st.warning("Please enter portfolio/company names to fetch news.") |
|
|
|
if __name__ == '__main__': |
|
main() |
|
|