| # # tasks/news_tasks.py - SIMPLIFIED VERSION THAT ALWAYS WORKS | |
| # from celery_worker import celery | |
| # from core.database import SessionLocal | |
| # from models.analysis_job import AnalysisJob | |
| # from uuid import UUID | |
| # import logging | |
| # from datetime import datetime | |
| # import yfinance as yf | |
| # logger = logging.getLogger(__name__) | |
| # def get_stock_basic_info(ticker: str): | |
| # """Get basic stock information to create realistic content""" | |
| # try: | |
| # stock = yf.Ticker(ticker) | |
| # info = stock.info | |
| # return { | |
| # 'name': info.get('longName', ticker.replace('.NS', '')), | |
| # 'sector': info.get('sector', 'Unknown'), | |
| # 'industry': info.get('industry', 'Unknown'), | |
| # 'current_price': info.get('currentPrice', 0), | |
| # 'previous_close': info.get('previousClose', 0) | |
| # } | |
| # except Exception as e: | |
| # logger.warning(f"Could not get stock info for {ticker}: {e}") | |
| # return { | |
| # 'name': ticker.replace('.NS', ''), | |
| # 'sector': 'Unknown', | |
| # 'industry': 'Unknown', | |
| # 'current_price': 0, | |
| # 'previous_close': 0 | |
| # } | |
| # def create_realistic_articles(ticker: str, company_name: str, stock_info: dict): | |
| # """Create realistic articles based on stock information""" | |
| # # Calculate price movement for realistic sentiment | |
| # current_price = stock_info.get('current_price', 0) | |
| # previous_close = stock_info.get('previous_close', 0) | |
| # price_change = 0 | |
| # if current_price and previous_close: | |
| # price_change = ((current_price - previous_close) / previous_close) * 100 | |
| # # Generate articles based on actual stock performance | |
| # articles = [] | |
| # if price_change > 2: | |
| # articles.extend([ | |
| # { | |
| # "title": f"{company_name} Shares Rally {price_change:.1f}% on Strong Market Sentiment", | |
| # "url": f"https://finance.yahoo.com/quote/{ticker}", | |
| # "source": "Market Analysis", | |
| # "sentiment": "Positive", | |
| # "sentiment_score": 0.8 | |
| # }, | |
| # { | |
| # "title": f"Investors Show Confidence in {company_name} as Stock Gains Momentum", | |
| # "url": f"https://www.moneycontrol.com/india/stockpricequote/{ticker}", | |
| # "source": "Financial Express", | |
| # "sentiment": "Positive", | |
| # "sentiment_score": 0.7 | |
| # } | |
| # ]) | |
| # elif price_change < -2: | |
| # articles.extend([ | |
| # { | |
| # "title": f"{company_name} Stock Declines {abs(price_change):.1f}% Amid Market Volatility", | |
| # "url": f"https://finance.yahoo.com/quote/{ticker}", | |
| # "source": "Market Watch", | |
| # "sentiment": "Negative", | |
| # "sentiment_score": 0.8 | |
| # }, | |
| # { | |
| # "title": f"Market Correction Impacts {company_name} Share Price", | |
| # "url": f"https://www.moneycontrol.com/india/stockpricequote/{ticker}", | |
| # "source": "Economic Times", | |
| # "sentiment": "Negative", | |
| # "sentiment_score": 0.6 | |
| # } | |
| # ]) | |
| # else: | |
| # articles.extend([ | |
| # { | |
| # "title": f"{company_name} Stock Shows Steady Performance in Current Market", | |
| # "url": f"https://finance.yahoo.com/quote/{ticker}", | |
| # "source": "Yahoo Finance", | |
| # "sentiment": "Neutral", | |
| # "sentiment_score": 0.5 | |
| # }, | |
| # { | |
| # "title": f"Technical Analysis: {company_name} Maintains Stable Trading Range", | |
| # "url": f"https://www.moneycontrol.com/india/stockpricequote/{ticker}", | |
| # "source": "Market Analysis", | |
| # "sentiment": "Neutral", | |
| # "sentiment_score": 0.5 | |
| # } | |
| # ]) | |
| # # Add sector-specific articles | |
| # sector = stock_info.get('sector', 'Unknown') | |
| # if sector != 'Unknown': | |
| # articles.extend([ | |
| # { | |
| # "title": f"{sector} Sector Update: Key Players Including {company_name} in Focus", | |
| # "url": "https://example.com/sector-analysis", | |
| # "source": "Sector Reports", | |
| # "sentiment": "Neutral", | |
| # "sentiment_score": 0.6 | |
| # }, | |
| # { | |
| # "title": f"Industry Outlook: {stock_info.get('industry', 'Market')} Trends Affecting {company_name}", | |
| # "url": "https://example.com/industry-outlook", | |
| # "source": "Industry Analysis", | |
| # "sentiment": "Positive", | |
| # "sentiment_score": 0.6 | |
| # } | |
| # ]) | |
| # # Add general market articles | |
| # articles.extend([ | |
| # { | |
| # "title": f"Quarterly Performance Review: {company_name} Financials and Market Position", | |
| # "url": f"https://finance.yahoo.com/quote/{ticker}/financials", | |
| # "source": "Financial Reports", | |
| # "sentiment": "Neutral", | |
| # "sentiment_score": 0.5 | |
| # }, | |
| # { | |
| # "title": f"Analyst Coverage: Investment Recommendations for {company_name} Stock", | |
| # "url": "https://example.com/analyst-coverage", | |
| # "source": "Research Reports", | |
| # "sentiment": "Positive", | |
| # "sentiment_score": 0.7 | |
| # }, | |
| # { | |
| # "title": f"Market Sentiment Analysis: Retail vs Institutional Interest in {company_name}", | |
| # "url": "https://example.com/market-sentiment", | |
| # "source": "Market Research", | |
| # "sentiment": "Neutral", | |
| # "sentiment_score": 0.5 | |
| # } | |
| # ]) | |
| # return articles[:8] # Return top 8 articles | |
| # def try_real_news_sources(ticker: str, company_name: str): | |
| # """Attempt to get real news, but don't fail if it doesn't work""" | |
| # real_articles = [] | |
| # try: | |
| # # Try Yahoo Finance news (most reliable) | |
| # logger.info(f"Attempting to fetch real Yahoo Finance news for {ticker}") | |
| # stock = yf.Ticker(ticker) | |
| # news = stock.news | |
| # if news: | |
| # logger.info(f"Found {len(news)} Yahoo Finance articles") | |
| # for article in news[:5]: # Take first 5 | |
| # if article.get('title'): | |
| # # Simple sentiment analysis | |
| # title_lower = article['title'].lower() | |
| # if any(word in title_lower for word in ['gain', 'rise', 'growth', 'profit', 'strong']): | |
| # sentiment = 'Positive' | |
| # score = 0.7 | |
| # elif any(word in title_lower for word in ['fall', 'decline', 'loss', 'weak', 'drop']): | |
| # sentiment = 'Negative' | |
| # score = 0.7 | |
| # else: | |
| # sentiment = 'Neutral' | |
| # score = 0.5 | |
| # real_articles.append({ | |
| # "title": article['title'].strip(), | |
| # "url": article.get('link', ''), | |
| # "source": article.get('publisher', 'Yahoo Finance'), | |
| # "sentiment": sentiment, | |
| # "sentiment_score": score, | |
| # "is_real": True | |
| # }) | |
| # logger.info(f"Successfully retrieved {len(real_articles)} real articles") | |
| # except Exception as e: | |
| # logger.warning(f"Could not fetch real news: {e}") | |
| # return real_articles | |
| # @celery.task | |
| # def run_intelligence_analysis(job_id: str): | |
| # """Simplified intelligence analysis that always provides results""" | |
| # db = SessionLocal() | |
| # job = None | |
| # try: | |
| # logger.info(f"Starting intelligence analysis for job {job_id}") | |
| # # Get job | |
| # job = db.query(AnalysisJob).filter(AnalysisJob.id == UUID(job_id)).first() | |
| # if not job or not job.result: | |
| # raise ValueError(f"Job {job_id} not found or has no initial data.") | |
| # job.status = "INTELLIGENCE_GATHERING" | |
| # db.commit() | |
| # current_data = job.result | |
| # ticker = current_data.get("ticker") | |
| # company_name = current_data.get("company_name", ticker.replace('.NS', '')) | |
| # logger.info(f"Analyzing {company_name} ({ticker})") | |
| # # Get basic stock information | |
| # stock_info = get_stock_basic_info(ticker) | |
| # logger.info(f"Stock info: {stock_info['name']} - {stock_info['sector']}") | |
| # # Try to get real news first | |
| # real_articles = try_real_news_sources(ticker, company_name) | |
| # # Create realistic articles | |
| # realistic_articles = create_realistic_articles(ticker, company_name, stock_info) | |
| # # Combine real and realistic articles | |
| # all_articles = real_articles + realistic_articles | |
| # # Remove duplicates and limit to 10 articles | |
| # seen_titles = set() | |
| # unique_articles = [] | |
| # for article in all_articles: | |
| # if article['title'] not in seen_titles: | |
| # seen_titles.add(article['title']) | |
| # unique_articles.append(article) | |
| # final_articles = unique_articles[:10] | |
| # # Count sentiments | |
| # sentiment_counts = {'Positive': 0, 'Negative': 0, 'Neutral': 0} | |
| # for article in final_articles: | |
| # sentiment_counts[article['sentiment']] += 1 | |
| # # Create intelligence briefing | |
| # intelligence_briefing = { | |
| # "articles": final_articles, | |
| # "sentiment_summary": { | |
| # "total_items": len(final_articles), | |
| # "positive": sentiment_counts['Positive'], | |
| # "negative": sentiment_counts['Negative'], | |
| # "neutral": sentiment_counts['Neutral'], | |
| # "real_articles": len(real_articles), | |
| # "generated_articles": len(realistic_articles), | |
| # "analysis_timestamp": datetime.now().isoformat() | |
| # } | |
| # } | |
| # # Update job result | |
| # new_result = current_data.copy() | |
| # new_result['intelligence_briefing'] = intelligence_briefing | |
| # job.result = new_result | |
| # job.status = "INTELLIGENCE_COMPLETE" | |
| # db.commit() | |
| # logger.info(f"Intelligence analysis completed successfully:") | |
| # logger.info(f"- Total articles: {len(final_articles)}") | |
| # logger.info(f"- Real articles: {len(real_articles)}") | |
| # logger.info(f"- Generated articles: {len(realistic_articles)}") | |
| # logger.info(f"- Sentiment: {sentiment_counts}") | |
| # return str(job.result) | |
| # except Exception as e: | |
| # logger.error(f"Intelligence analysis failed for job {job_id}: {e}") | |
| # if job: | |
| # job.status = "FAILED" | |
| # error_data = job.result if job.result else {} | |
| # error_data['error'] = f"Intelligence analysis failed: {str(e)}" | |
| # job.result = error_data | |
| # db.commit() | |
| # return f"Error: {e}" | |
| # finally: | |
| # db.close() | |
| # from celery_worker import celery | |
| # from core.database import SessionLocal | |
| # from models.analysis_job import AnalysisJob | |
| # from tools.news_tools import get_combined_news_and_sentiment | |
| # from uuid import UUID | |
| # @celery.task | |
| # def run_intelligence_analysis(job_id: str): | |
| # with SessionLocal() as db: | |
| # job = db.query(AnalysisJob).filter(AnalysisJob.id == UUID(job_id)).first() | |
| # if not job or not job.result: | |
| # print(f"Job {job_id} not found or has no data for intelligence.") | |
| # return | |
| # try: | |
| # job.status = "INTELLIGENCE_GATHERING" | |
| # db.commit() | |
| # current_data = job.result | |
| # ticker = current_data.get("ticker") | |
| # company_name = current_data.get("company_name") | |
| # intelligence_briefing = get_combined_news_and_sentiment(ticker, company_name) | |
| # new_result = dict(current_data) | |
| # new_result['intelligence_briefing'] = intelligence_briefing | |
| # job.result = new_result | |
| # db.commit() | |
| # print(f"Intelligence analysis for job {job_id} completed successfully.") | |
| # return "Intelligence gathering successful." | |
| # except Exception as e: | |
| # print(f"Error during intelligence analysis for job {job_id}: {e}") | |
| # job.status = "FAILED" | |
| # error_data = job.result if job.result else {} | |
| # error_data['error'] = f"Intelligence analysis failed: {str(e)}" | |
| # job.result = error_data | |
| # db.commit() | |
| # return f"Intelligence gathering failed: {e}" | |
| from celery_worker import celery | |
| from tools.news_tools import get_combined_news_and_sentiment | |
| def get_intelligence_task(ticker: str, company_name: str): | |
| print(f"Executing get_intelligence_task for {company_name}...") | |
| # This task now depends on the company_name from the first task's result | |
| return get_combined_news_and_sentiment(ticker, company_name) |