Spaces:
Sleeping
Sleeping
| from fastapi import FastAPI, HTTPException | |
| from fastapi.responses import JSONResponse | |
| from fastapi.exceptions import ResponseValidationError | |
| from starlette.requests import Request | |
| from fastapi.staticfiles import StaticFiles | |
| from pydantic import BaseModel | |
| from models.schemas import ( | |
| SEORequest, SEOResponse, | |
| YouTubeResponse, InstagramResponse, LinkedInResponse, | |
| FacebookResponse, TwitterResponse, TikTokResponse, PinterestResponse, | |
| GrammarRequest, GrammarResponse, BatchRequest | |
| ) | |
| from services.batch_analyzer import analyze_batch | |
| from services.analyzer import analyze_seo_content | |
| from services.youtube_analyzer import analyze_youtube | |
| from services.instagram_analyzer import analyze_instagram | |
| from services.linkedin_analyzer import analyze_linkedin | |
| from services.linkedin_api import get_oauth_url, exchange_code, get_user_info, create_post | |
| from services.facebook_analyzer import analyze_facebook | |
| from services.twitter_analyzer import analyze_twitter | |
| from services.tiktok_analyzer import analyze_tiktok | |
| from services.pinterest_analyzer import analyze_pinterest | |
| from services.grammar_analyzer import analyze_grammar | |
| import uvicorn | |
| import traceback | |
| app = FastAPI( | |
| title="Social Media SEO & Grammar API", | |
| description="Professional social media content analysis + grammar correction using Generative AI. Covers YouTube, Instagram, LinkedIn, Facebook, X/Twitter, TikTok, Pinterest, and grammar correction.", | |
| version="2.1.0" | |
| ) | |
| ERROR_MASK = "An internal error occurred. Please try again later." | |
| ERROR_MASK_VALIDATION = "The model returned an incomplete response. Please try again." | |
| async def validation_exception_handler(request: Request, exc: ResponseValidationError): | |
| print(f"[ValidationError] {exc}") | |
| return JSONResponse( | |
| status_code=200, | |
| content={"error": ERROR_MASK_VALIDATION}, | |
| ) | |
| def safe_analyze(analyze_fn, content: str): | |
| try: | |
| result = analyze_fn(content) | |
| if isinstance(result, dict) and result.get("error"): | |
| print(f"[Warning] Analysis completed with error: {result['error']}") | |
| return result | |
| except HTTPException: | |
| raise | |
| except Exception as e: | |
| print(f"CRITICAL SERVER ERROR: {e}\n{traceback.format_exc()}") | |
| raise HTTPException(status_code=500, detail=ERROR_MASK) | |
| # --------------------------------------------------------------------------- | |
| # Root - Serve static frontend | |
| # --------------------------------------------------------------------------- | |
| app.mount("/static", StaticFiles(directory="static"), name="static") | |
| async def read_root(): | |
| from fastapi.responses import FileResponse | |
| return FileResponse("static/index.html") | |
| # --------------------------------------------------------------------------- | |
| # Generic SEO | |
| # --------------------------------------------------------------------------- | |
| def analyze_seo(request: SEORequest): | |
| return safe_analyze(analyze_seo_content, request.content) | |
| # --------------------------------------------------------------------------- | |
| # YouTube | |
| # --------------------------------------------------------------------------- | |
| def analyze_youtube_route(request: SEORequest): | |
| return safe_analyze(analyze_youtube, request.content) | |
| # --------------------------------------------------------------------------- | |
| # --------------------------------------------------------------------------- | |
| def analyze_instagram_route(request: SEORequest): | |
| return safe_analyze(analyze_instagram, request.content) | |
| # --------------------------------------------------------------------------- | |
| # --------------------------------------------------------------------------- | |
| def analyze_linkedin_route(request: SEORequest): | |
| return safe_analyze(analyze_linkedin, request.content) | |
| def linkedin_auth_url(state: str = ""): | |
| url = get_oauth_url(state) | |
| return {"url": url} | |
| class TokenExchangeRequest(BaseModel): | |
| code: str | |
| def linkedin_exchange_token(req: TokenExchangeRequest): | |
| token_data, err = exchange_code(req.code) | |
| if err: | |
| raise HTTPException(status_code=400, detail=err) | |
| user_info, uerr = get_user_info(token_data["access_token"]) | |
| if uerr: | |
| raise HTTPException(status_code=400, detail=uerr) | |
| return { | |
| "access_token": token_data["access_token"], | |
| "expires_at": token_data["expires_at"], | |
| "user": user_info, | |
| } | |
| class PostToLinkedInRequest(BaseModel): | |
| access_token: str | |
| author_urn: str | |
| text: str | |
| hashtags: list[str] = [] | |
| def linkedin_post(req: PostToLinkedInRequest): | |
| result, err = create_post(req.access_token, req.author_urn, req.text, req.hashtags) | |
| if err: | |
| raise HTTPException(status_code=400, detail=err) | |
| return {"success": True, **result} | |
| # --------------------------------------------------------------------------- | |
| # --------------------------------------------------------------------------- | |
| def analyze_facebook_route(request: SEORequest): | |
| return safe_analyze(analyze_facebook, request.content) | |
| # --------------------------------------------------------------------------- | |
| # X / Twitter | |
| # --------------------------------------------------------------------------- | |
| def analyze_twitter_route(request: SEORequest): | |
| return safe_analyze(analyze_twitter, request.content) | |
| # --------------------------------------------------------------------------- | |
| # TikTok | |
| # --------------------------------------------------------------------------- | |
| def analyze_tiktok_route(request: SEORequest): | |
| return safe_analyze(analyze_tiktok, request.content) | |
| # --------------------------------------------------------------------------- | |
| # --------------------------------------------------------------------------- | |
| def analyze_pinterest_route(request: SEORequest): | |
| return safe_analyze(analyze_pinterest, request.content) | |
| # --------------------------------------------------------------------------- | |
| # Grammar Correction | |
| # --------------------------------------------------------------------------- | |
| def grammar_correction_route(request: GrammarRequest): | |
| return safe_analyze(analyze_grammar, request.text) | |
| # --------------------------------------------------------------------------- | |
| # Batch - Multi-Platform | |
| # --------------------------------------------------------------------------- | |
| class BatchResponse(BaseModel): | |
| results: dict | |
| def batch_analyze_route(request: BatchRequest): | |
| results = safe_analyze(lambda c: analyze_batch(c, request.platforms), request.content) | |
| return {"results": results} | |
| # --------------------------------------------------------------------------- | |
| # Entrypoint | |
| # --------------------------------------------------------------------------- | |
| if __name__ == "__main__": | |
| uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True) | |