import sys print(">>> STARTING APP INITIALIZATION <<<", flush=True) from fastapi import FastAPI from pydantic import BaseModel print(">>> FASTAPI IMPORTED <<<", flush=True) import urllib.parse import re import json from fastapi.responses import RedirectResponse app = FastAPI() @app.get("/") def read_root(): return RedirectResponse(url="/docs") class QueryRequest(BaseModel): query: str @app.post("/scrape/geocode") def scrape_geocode(req: QueryRequest): from scrapling import Fetcher fetcher = Fetcher() url = f"https://nominatim.openstreetmap.org/search?q={urllib.parse.quote(req.query)}&format=json&limit=1" try: response = fetcher.get(url) data = json.loads(response.text) if data and len(data) > 0: return { "lat": float(data[0]["lat"]), "lng": float(data[0]["lon"]), "formattedAddress": data[0]["display_name"] } except Exception as e: print("Geocode Error:", e) pass # Fallback coordinate regex (naive) search_url = f"https://html.duckduckgo.com/html/?q={urllib.parse.quote(req.query + ' coordinates lat long')}" try: resp = fetcher.get(search_url) matches = re.findall(r'(-?\d+\.\d{3,})[^\d]+(-?\d+\.\d{3,})', resp.text) if matches: return {"lat": float(matches[0][0]), "lng": float(matches[0][1]), "formattedAddress": req.query} except Exception: pass return {"lat": 0, "lng": 0, "formattedAddress": req.query} @app.post("/scrape/details") def scrape_details(req: QueryRequest): from scrapling import Fetcher fetcher = Fetcher() search_url = f"https://html.duckduckgo.com/html/?q={urllib.parse.quote(req.query + ' tourism description rating')}" try: resp = fetcher.get(search_url) snippets = [] # In duckduckgo html, snippets are in .result__snippet for el in resp.css('.result__snippet'): if el.text: snippets.append(el.text) description = " ".join(snippets[:3]) if not description: description = "A wonderful destination worth visiting." return { "rating": 4.5, # Static fallback as parsing HTML for real ratings is extremely fragile "ratingsCount": 120, "address": req.query, "description": description[:350] + "..." if len(description) > 350 else description } except Exception as e: print("Details error:", e) return { "rating": 4.5, "ratingsCount": 100, "address": req.query, "description": f"Explore the beauty and culture of {req.query}. A highly recommended spot for travelers." } @app.post("/scrape/images") def scrape_images(req: QueryRequest): from scrapling import Fetcher fetcher = Fetcher() # Pexels allows scraping more easily than google images search_url = f"https://www.pexels.com/search/{urllib.parse.quote(req.query)}/" try: resp = fetcher.get(search_url) images = [] for img in resp.css('img'): src = img.attrib.get('src') if src and 'images.pexels.com/photos' in src: # Remove query params to get high res images.append(src.split('?')[0] + "?auto=compress&cs=tinysrgb&w=800") if images: # Deduplicate and return top 5 return {"images": list(dict.fromkeys(images))[:5]} except Exception as e: print("Images error:", e) pass return {"images": ["https://images.unsplash.com/photo-1476514525535-07fb3b4ae5f1?auto=format&fit=crop&q=80&w=1200"]} if __name__ == "__main__": import uvicorn uvicorn.run(app, host="127.0.0.1", port=8000)