import os import logging from flask import Flask, render_template, request, jsonify from flask_cors import CORS import json from datetime import datetime, date from scrapers.horoscope_scraper import HoroscopeScraper from scrapers.astrology_com_scraper import AstrologyComScraper from scrapers.horoscope_com_scraper import HoroscopeComScraper # Set up logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) # Create Flask app app = Flask(__name__) app.secret_key = os.environ.get("SESSION_SECRET", "dev_secret_key") # Enable CORS CORS(app) # Initialize scrapers scrapers = { "astrology.com": AstrologyComScraper(), "horoscope.com": HoroscopeComScraper(), } @app.route('/') def index(): """Main page""" return render_template('simple_index.html') @app.route('/api/health') def health_check(): """Health check endpoint""" return jsonify({ "status": "ok", "message": "Horoscope API is running", "scrapers": list(scrapers.keys()) }) @app.route('/api/horoscope/scrape', methods=['POST']) def scrape_horoscope(): """Scrape horoscope for a specific sign""" data = request.get_json() if not data: return jsonify({"error": "Missing request data"}), 400 sign = data.get('sign', '').lower() source = data.get('source', 'astrology.com') # Validate inputs if not sign: return jsonify({"error": "Missing 'sign' parameter"}), 400 if sign not in scrapers["astrology.com"].ZODIAC_SIGNS: return jsonify({"error": f"Invalid zodiac sign: {sign}"}), 400 if source not in scrapers: return jsonify({"error": f"Unknown source: {source}"}), 400 try: # Scrape horoscope scraper = scrapers[source] result = scraper.scrape_sign(scraper.base_url, sign) if result.get('success', False): return jsonify({ "success": True, "sign": sign, "source": source, "prediction": result.get('prediction', ''), "date": result.get('date', date.today().isoformat()), "scraped_at": datetime.now().isoformat() }) else: return jsonify({ "success": False, "error": result.get('error', 'Unknown error occurred') }), 500 except Exception as e: logger.error(f"Error scraping horoscope: {str(e)}") return jsonify({ "success": False, "error": f"Scraping failed: {str(e)}" }), 500 @app.route('/api/horoscope/scrape-all', methods=['POST']) def scrape_all_horoscopes(): """Scrape horoscopes for all signs from all sources""" data = request.get_json() or {} results = {} # Get all zodiac signs signs = scrapers["astrology.com"].ZODIAC_SIGNS for sign in signs: results[sign] = {} for source_name, scraper in scrapers.items(): try: result = scraper.scrape_sign(scraper.base_url, sign) if result.get('success', False): results[sign][source_name] = { "success": True, "prediction": result.get('prediction', ''), "date": result.get('date', date.today().isoformat()), "scraped_at": datetime.now().isoformat() } else: results[sign][source_name] = { "success": False, "error": result.get('error', 'Unknown error') } except Exception as e: logger.error(f"Error scraping {sign} from {source_name}: {str(e)}") results[sign][source_name] = { "success": False, "error": str(e) } return jsonify({ "success": True, "results": results, "scraped_at": datetime.now().isoformat() }) @app.route('/api/horoscope/consolidate', methods=['POST']) def consolidate_horoscope(): """Consolidate horoscope predictions using OpenAI""" data = request.get_json() if not data: return jsonify({"error": "Missing request data"}), 400 predictions = data.get('predictions', []) sign = data.get('sign', '').lower() if not predictions: return jsonify({"error": "No predictions provided"}), 400 if not sign: return jsonify({"error": "Missing 'sign' parameter"}), 400 # Check if OpenAI API key is available openai_api_key = os.environ.get("OPENAI_API_KEY") if not openai_api_key: return jsonify({ "error": "OpenAI API key not configured. Please provide OPENAI_API_KEY." }), 500 try: from openai import OpenAI client = OpenAI(api_key=openai_api_key) # Create prompt for consolidation sources_text = "" for i, pred in enumerate(predictions, 1): source = pred.get("source", f"Source {i}") prediction = pred.get("prediction", "No prediction available") sources_text += f"SOURCE {i} ({source}):\n{prediction}\n\n" prompt = f""" Please analyze and consolidate these daily horoscope predictions for {sign.upper()}. {sources_text} Create a single, coherent daily horoscope prediction that synthesizes the information from all sources. Focus on the common themes and advice while maintaining the mystical and guiding tone typical of horoscopes. The response should be 2-3 paragraphs long and should NOT mention the sources or that it's a consolidation. Respond with JSON in this format: {{ "consolidated_prediction": "The consolidated horoscope text..." }} """ # Call OpenAI API response = client.chat.completions.create( model="gpt-4o", messages=[ {"role": "system", "content": "You are an expert astrologer specializing in synthesizing horoscope predictions."}, {"role": "user", "content": prompt} ], response_format={"type": "json_object"}, temperature=0.7 ) # Parse the response content = response.choices[0].message.content if content: result = json.loads(content) else: result = {"consolidated_prediction": "Unable to generate consolidated prediction."} return jsonify({ "success": True, "sign": sign, "consolidated_prediction": result.get("consolidated_prediction", ""), "sources_count": len(predictions), "consolidated_at": datetime.now().isoformat() }) except ImportError: return jsonify({ "error": "OpenAI library not available. Please install: pip install openai" }), 500 except Exception as e: logger.error(f"Error consolidating horoscopes: {str(e)}") return jsonify({ "error": f"Consolidation failed: {str(e)}" }), 500 @app.route('/api/signs') def get_zodiac_signs(): """Get list of zodiac signs""" return jsonify({ "signs": scrapers["astrology.com"].ZODIAC_SIGNS }) if __name__ == "__main__": logger.info("Starting simple horoscope API server") app.run(host="0.0.0.0", port=5000, debug=True)