from fastapi import FastAPI, HTTPException from fastapi.middleware.cors import CORSMiddleware from fastapi.staticfiles import StaticFiles from fastapi.responses import FileResponse from pydantic import BaseModel from openai import OpenAI import os import json from dotenv import load_dotenv load_dotenv() app = FastAPI() # Enable CORS for frontend development app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) gpt_client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) class ImageAdEssentials(BaseModel): phsychologyTriggers: str angles: list[str] concepts: list[str] class ImageAdEssentialsOutput(BaseModel): output: list[ImageAdEssentials] class ResearchRequest(BaseModel): niche: str target_audience: str prompt: str product_description: str @app.post("/api/research") async def conduct_research(request: ResearchRequest): try: messages = [ { "role": "system", "content": [ { "type": "text", "text": """You are the researcher for the e-commerce brand company which does research on trending angles, concepts and psychology trigers based on the user input. The e-commerce brand company name is Amalfa which is a contemporary jewellery brand known in the Indian market for its demi-fine and fashion jewellery collections. Amalfa aims to be a style-forward, expressive brand for today's youth and modern women, blending trend-driven design with accessible pricing. A psychology trigger is an emotional or cognitive stimulus that pushes someone toward action—clicking, signing up, or buying—before logic kicks in. An ad angle is the reason someone should care right now. Same product → different reasons to click → different angles. An ad concept is the creative execution style or storyline you use to deliver an angle. Keeping in mind all this, make sure you provide different angles and concepts we can try based on the phsychology triggers for the image ads for the given input based on e-commerce brand. User will provide you the category on which he needs to run the ads, his requirement, product description and what is target audience.""" } ] }, { "role": "user", "content": [ { "type": "text", "text": f"""Following are the inputs: Niche: {request.niche} Target Audience: {request.target_audience} User Prompt: {request.prompt} Product Description: {request.product_description} Provide the different phsychology triggers, angles and concept based on the given input.""" } ] } ] completion = gpt_client.beta.chat.completions.parse( model="gpt-4o", messages=messages, response_format=ImageAdEssentialsOutput, ) response = completion.choices[0].message if response.parsed: return response.parsed.output else: raise HTTPException(status_code=500, detail=response.refusal) except Exception as e: raise HTTPException(status_code=500, detail=str(e)) # Mount the static files directory # Ensure the directory exists in the Docker container if os.path.exists("frontend/dist"): app.mount("/", StaticFiles(directory="frontend/dist", html=True), name="static") @app.get("/{full_path:path}") async def serve_frontend(full_path: str): # Serve index.html for any path that doesn't match an API route if not full_path.startswith("api/"): return FileResponse("frontend/dist/index.html") raise HTTPException(status_code=404, detail="Not Found") if __name__ == "__main__": import uvicorn # Allow port to be set by environment variable (useful for Hugging Face) port = int(os.getenv("PORT", 8000)) uvicorn.run(app, host="0.0.0.0", port=port)