Commit
Β·
3eb5edf
1
Parent(s):
81e730f
fix: Correct model initialization order
Browse files- api/main.py +43 -90
api/main.py
CHANGED
|
@@ -63,6 +63,7 @@ FINAL_EMBEDDING_PATH = EMBEDDING_MODEL_PATH if os.path.exists(EMBEDDING_MODEL_PA
|
|
| 63 |
_llm_instance: Optional[Llama] = None
|
| 64 |
_vector_store: Optional[Any] = None
|
| 65 |
_ai_strategist: Optional[AIStrategist] = None
|
|
|
|
| 66 |
_support_agent: Optional[SupportAgent] = None
|
| 67 |
_budget_predictor = None
|
| 68 |
_influencer_matcher = None
|
|
@@ -506,16 +507,15 @@ app = FastAPI(title="Reachify AI Service (Deploy-Ready)", version="11.0.0")
|
|
| 506 |
|
| 507 |
@app.on_event("startup")
|
| 508 |
def startup_event():
|
| 509 |
-
|
|
|
|
| 510 |
_budget_predictor, _influencer_matcher, _performance_predictor, _payout_forecaster, \
|
| 511 |
_earnings_optimizer, _earnings_encoder, _likes_predictor, _comments_predictor, \
|
| 512 |
_revenue_forecaster, _performance_scorer
|
| 513 |
|
| 514 |
-
|
| 515 |
-
|
| 516 |
-
# === FIX #3: The Model Download and Loading Logic ===
|
| 517 |
try:
|
| 518 |
-
# Step 1: Download the model if it doesn't exist
|
| 519 |
os.makedirs(MODEL_SAVE_DIRECTORY, exist_ok=True)
|
| 520 |
if not os.path.exists(LLAMA_MODEL_PATH):
|
| 521 |
print(f" - LLM model not found locally. Downloading '{MODEL_FILENAME}'...")
|
|
@@ -523,51 +523,48 @@ def startup_event():
|
|
| 523 |
repo_id=MODEL_REPO,
|
| 524 |
filename=MODEL_FILENAME,
|
| 525 |
local_dir=MODEL_SAVE_DIRECTORY,
|
| 526 |
-
local_dir_use_symlinks=False
|
| 527 |
)
|
| 528 |
print(" - β
Model downloaded successfully.")
|
| 529 |
else:
|
| 530 |
print(f" - LLM model found at {LLAMA_MODEL_PATH}. Skipping download.")
|
| 531 |
|
| 532 |
-
|
| 533 |
-
|
| 534 |
-
|
| 535 |
-
model_path=LLAMA_MODEL_PATH,
|
| 536 |
-
n_gpu_layers=0, # Ensure CPU usage on free tier
|
| 537 |
-
n_ctx=2048,
|
| 538 |
-
verbose=False,
|
| 539 |
-
use_mmap=False
|
| 540 |
-
)
|
| 541 |
-
print(" - β
LLM Loaded into Memory on CPU.")
|
| 542 |
|
| 543 |
except Exception as e:
|
| 544 |
print(f" - β FATAL ERROR: Could not download or load LLM model: {e}")
|
| 545 |
traceback.print_exc()
|
| 546 |
-
|
| 547 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 548 |
|
| 549 |
-
|
| 550 |
-
|
| 551 |
-
try:
|
| 552 |
_vector_store = VectorStore()
|
| 553 |
print(" - β
RAG Engine Ready.")
|
| 554 |
-
|
| 555 |
-
|
| 556 |
-
|
| 557 |
-
|
| 558 |
-
|
| 559 |
-
|
| 560 |
-
|
| 561 |
-
|
| 562 |
-
|
| 563 |
-
|
| 564 |
-
|
| 565 |
-
|
| 566 |
-
|
| 567 |
-
db_path=DB_PATH
|
| 568 |
-
)
|
| 569 |
-
print(" - β
Support Agent ready.")
|
| 570 |
-
|
| 571 |
print(" - Loading ML models from joblib files...")
|
| 572 |
model_paths = {
|
| 573 |
'budget': ('_budget_predictor', 'budget_predictor_v1.joblib'),
|
|
@@ -1943,15 +1940,11 @@ def generate_weekly_plan_route(request: WeeklyPlanRequest): # <--- async hata d
|
|
| 1943 |
|
| 1944 |
@app.post("/chat/creative", response_model=Dict[str, str], summary="Brainstorming chat with AI Creative Director")
|
| 1945 |
def creative_chat_endpoint(request: CreativeChatRequest):
|
| 1946 |
-
|
| 1947 |
-
|
| 1948 |
-
Returns a short, punchy, expert response using RAG + LLM.
|
| 1949 |
-
"""
|
| 1950 |
try:
|
| 1951 |
-
# Convert Pydantic history to list of dicts
|
| 1952 |
history_list = [m.model_dump() for m in request.history]
|
| 1953 |
-
|
| 1954 |
-
response_text = director.chat(
|
| 1955 |
user_message=request.message,
|
| 1956 |
history=history_list,
|
| 1957 |
task_context=request.task_context
|
|
@@ -1959,59 +1952,19 @@ def creative_chat_endpoint(request: CreativeChatRequest):
|
|
| 1959 |
return {"reply": response_text}
|
| 1960 |
except Exception as e:
|
| 1961 |
print(f"π¨ Creative Chat Error: {e}")
|
| 1962 |
-
raise HTTPException(status_code=500, detail="AI Director
|
| 1963 |
|
| 1964 |
|
| 1965 |
@app.post("/generate/final-from-chat", response_model=FinalScriptResponse, summary="Generates final structured script from chat history")
|
| 1966 |
def finalize_script_endpoint(request: FinalizeScriptRequest):
|
| 1967 |
-
|
| 1968 |
-
|
| 1969 |
-
This version is ROBUST and handles messy LLM output.
|
| 1970 |
-
"""
|
| 1971 |
try:
|
| 1972 |
history_list = [m.model_dump() for m in request.history]
|
| 1973 |
-
|
| 1974 |
-
raw_text = director.generate_final_plan(
|
| 1975 |
task_context=request.task_context,
|
| 1976 |
history=history_list
|
| 1977 |
)
|
| 1978 |
-
|
| 1979 |
-
print(f" - π€ Raw Final Plan from LLM:\n---\n{raw_text}\n---")
|
| 1980 |
-
|
| 1981 |
-
# --- IDIOT-PROOF PARSING LOGIC ---
|
| 1982 |
-
plan = { "hook": "", "script": "", "visuals": [], "tools": [] }
|
| 1983 |
-
|
| 1984 |
-
# Try to find JSON first
|
| 1985 |
-
try:
|
| 1986 |
-
import json
|
| 1987 |
-
json_match = re.search(r'\{.*\}', raw_text, re.DOTALL)
|
| 1988 |
-
if json_match:
|
| 1989 |
-
parsed = json.loads(json_match.group(0))
|
| 1990 |
-
plan["hook"] = parsed.get("hook", "")
|
| 1991 |
-
plan["script"] = parsed.get("script", "")
|
| 1992 |
-
plan["visuals"] = parsed.get("visuals", [])
|
| 1993 |
-
plan["tools"] = parsed.get("tools", [])
|
| 1994 |
-
|
| 1995 |
-
# Agar ek bhi cheez mil gayi to return kar do
|
| 1996 |
-
if plan["hook"] or plan["script"]:
|
| 1997 |
-
return FinalScriptResponse(**plan)
|
| 1998 |
-
except:
|
| 1999 |
-
pass # JSON parsing fail hua to aage badho
|
| 2000 |
-
|
| 2001 |
-
# Fallback to Regex if no JSON found
|
| 2002 |
-
hook_match = re.search(r"Hook:?\s*\"(.*?)\"", raw_text, re.IGNORECASE)
|
| 2003 |
-
script_match = re.search(r"Script:?\s*\"(.*?)\"", raw_text, re.IGNORECASE)
|
| 2004 |
-
|
| 2005 |
-
plan["hook"] = hook_match.group(1) if hook_match else "Start with a bang!"
|
| 2006 |
-
|
| 2007 |
-
# Agar script nahi mili to poora raw text hi script maan lo
|
| 2008 |
-
plan["script"] = script_match.group(1) if script_match else raw_text
|
| 2009 |
-
|
| 2010 |
-
plan["visuals"] = ["Close up shot", "Wide shot"]
|
| 2011 |
-
plan["tools"] = ["CapCut"]
|
| 2012 |
-
|
| 2013 |
-
return FinalScriptResponse(**plan)
|
| 2014 |
-
|
| 2015 |
except Exception as e:
|
| 2016 |
print(f"π¨ Finalize Script Error: {e}")
|
| 2017 |
-
raise HTTPException(status_code=500, detail="Failed to generate final plan.")
|
|
|
|
| 63 |
_llm_instance: Optional[Llama] = None
|
| 64 |
_vector_store: Optional[Any] = None
|
| 65 |
_ai_strategist: Optional[AIStrategist] = None
|
| 66 |
+
_creative_director: Optional[CreativeDirector] = None
|
| 67 |
_support_agent: Optional[SupportAgent] = None
|
| 68 |
_budget_predictor = None
|
| 69 |
_influencer_matcher = None
|
|
|
|
| 507 |
|
| 508 |
@app.on_event("startup")
|
| 509 |
def startup_event():
|
| 510 |
+
# Make sure we can modify the global variables
|
| 511 |
+
global _llm_instance, _creative_director, _support_agent, _ai_strategist, _vector_store, \
|
| 512 |
_budget_predictor, _influencer_matcher, _performance_predictor, _payout_forecaster, \
|
| 513 |
_earnings_optimizer, _earnings_encoder, _likes_predictor, _comments_predictor, \
|
| 514 |
_revenue_forecaster, _performance_scorer
|
| 515 |
|
| 516 |
+
# === MODEL DOWNLOAD AND LOAD LOGIC ===
|
| 517 |
+
print("--- π AI Service Starting Up... ---")
|
|
|
|
| 518 |
try:
|
|
|
|
| 519 |
os.makedirs(MODEL_SAVE_DIRECTORY, exist_ok=True)
|
| 520 |
if not os.path.exists(LLAMA_MODEL_PATH):
|
| 521 |
print(f" - LLM model not found locally. Downloading '{MODEL_FILENAME}'...")
|
|
|
|
| 523 |
repo_id=MODEL_REPO,
|
| 524 |
filename=MODEL_FILENAME,
|
| 525 |
local_dir=MODEL_SAVE_DIRECTORY,
|
| 526 |
+
local_dir_use_symlinks=False
|
| 527 |
)
|
| 528 |
print(" - β
Model downloaded successfully.")
|
| 529 |
else:
|
| 530 |
print(f" - LLM model found at {LLAMA_MODEL_PATH}. Skipping download.")
|
| 531 |
|
| 532 |
+
print(" - Loading Llama LLM into memory...")
|
| 533 |
+
_llm_instance = Llama(model_path=LLAMA_MODEL_PATH, n_gpu_layers=0, n_ctx=2048, verbose=False, use_mmap=False)
|
| 534 |
+
print(" - β
LLM Loaded.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 535 |
|
| 536 |
except Exception as e:
|
| 537 |
print(f" - β FATAL ERROR: Could not download or load LLM model: {e}")
|
| 538 |
traceback.print_exc()
|
| 539 |
+
# If LLM fails to load, we can't continue.
|
| 540 |
+
# Set instance to None and the rest of the app will know.
|
| 541 |
+
_llm_instance = None
|
| 542 |
+
return # Stop the startup process here.
|
| 543 |
+
|
| 544 |
+
# === INITIALIZE AI COMPONENTS (NOW THAT LLM IS LOADED) ===
|
| 545 |
+
# This logic now runs ONLY IF the LLM loaded successfully.
|
| 546 |
+
try:
|
| 547 |
+
print(" - Initializing Creative Director...")
|
| 548 |
+
_creative_director = CreativeDirector(llm_instance=_llm_instance)
|
| 549 |
+
print(" - β
Creative Director is online.")
|
| 550 |
|
| 551 |
+
if VectorStore:
|
| 552 |
+
print(" - Initializing Vector Store...")
|
|
|
|
| 553 |
_vector_store = VectorStore()
|
| 554 |
print(" - β
RAG Engine Ready.")
|
| 555 |
+
|
| 556 |
+
print(" - Initializing AI Strategist...")
|
| 557 |
+
_ai_strategist = AIStrategist(llm_instance=_llm_instance, store=_vector_store)
|
| 558 |
+
print(" - β
AI Strategist ready.")
|
| 559 |
+
|
| 560 |
+
print(" - Initializing Support Agent...")
|
| 561 |
+
_support_agent = SupportAgent(llm_instance=_llm_instance, embedding_path=EMBEDDING_MODEL_PATH, db_path=DB_PATH)
|
| 562 |
+
print(" - β
Support Agent ready.")
|
| 563 |
+
except Exception as e:
|
| 564 |
+
print(f" - β FAILED to initialize core AI components: {e}")
|
| 565 |
+
traceback.print_exc()
|
| 566 |
+
|
| 567 |
+
# === LOAD SKLEARN MODELS (This part is independent of the LLM) ===
|
|
|
|
|
|
|
|
|
|
|
|
|
| 568 |
print(" - Loading ML models from joblib files...")
|
| 569 |
model_paths = {
|
| 570 |
'budget': ('_budget_predictor', 'budget_predictor_v1.joblib'),
|
|
|
|
| 1940 |
|
| 1941 |
@app.post("/chat/creative", response_model=Dict[str, str], summary="Brainstorming chat with AI Creative Director")
|
| 1942 |
def creative_chat_endpoint(request: CreativeChatRequest):
|
| 1943 |
+
if not _creative_director:
|
| 1944 |
+
raise HTTPException(status_code=503, detail="AI Creative Director is not available due to a startup error.")
|
|
|
|
|
|
|
| 1945 |
try:
|
|
|
|
| 1946 |
history_list = [m.model_dump() for m in request.history]
|
| 1947 |
+
response_text = _creative_director.chat(
|
|
|
|
| 1948 |
user_message=request.message,
|
| 1949 |
history=history_list,
|
| 1950 |
task_context=request.task_context
|
|
|
|
| 1952 |
return {"reply": response_text}
|
| 1953 |
except Exception as e:
|
| 1954 |
print(f"π¨ Creative Chat Error: {e}")
|
| 1955 |
+
raise HTTPException(status_code=500, detail="An error occurred with the AI Director.")
|
| 1956 |
|
| 1957 |
|
| 1958 |
@app.post("/generate/final-from-chat", response_model=FinalScriptResponse, summary="Generates final structured script from chat history")
|
| 1959 |
def finalize_script_endpoint(request: FinalizeScriptRequest):
|
| 1960 |
+
if not _creative_director:
|
| 1961 |
+
raise HTTPException(status_code=503, detail="AI Creative Director is not available due to a startup error.")
|
|
|
|
|
|
|
| 1962 |
try:
|
| 1963 |
history_list = [m.model_dump() for m in request.history]
|
| 1964 |
+
return _creative_director.generate_final_plan(
|
|
|
|
| 1965 |
task_context=request.task_context,
|
| 1966 |
history=history_list
|
| 1967 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1968 |
except Exception as e:
|
| 1969 |
print(f"π¨ Finalize Script Error: {e}")
|
| 1970 |
+
raise HTTPException(status_code=500, detail="Failed to generate the final plan.")
|