mirror of
http://88.130.71.182:3000/BlitTech/contexta_be.git
synced 2026-06-12 23:23:21 +00:00
fixed bugs
This commit is contained in:
@@ -53,7 +53,6 @@ async def create_chatbot(data: ChatbotCreate, user=Depends(get_current_user)):
|
||||
vector_store.create_collection(collection_name)
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to create Qdrant collection: {e}")
|
||||
# Continue without vector store for now
|
||||
collection_name = None
|
||||
|
||||
chatbot_data = {
|
||||
@@ -67,6 +66,7 @@ async def create_chatbot(data: ChatbotCreate, user=Depends(get_current_user)):
|
||||
"max_tokens": data.max_tokens,
|
||||
"primary_color": data.primary_color,
|
||||
"welcome_message": data.welcome_message,
|
||||
"logo_url": data.logo_url,
|
||||
"category": data.category,
|
||||
"industry": data.industry,
|
||||
"languages": data.languages,
|
||||
@@ -227,6 +227,7 @@ def _format_chatbot(chatbot: dict, supabase) -> ChatbotResponse:
|
||||
max_tokens=chatbot.get("max_tokens", 1000),
|
||||
primary_color=chatbot.get("primary_color", "#6366f1"),
|
||||
welcome_message=chatbot.get("welcome_message", "Hello! How can I help?"),
|
||||
logo_url=chatbot.get("logo_url"),
|
||||
category=chatbot.get("category"),
|
||||
industry=chatbot.get("industry"),
|
||||
languages=chatbot.get("languages", ["en"]),
|
||||
@@ -237,4 +238,4 @@ def _format_chatbot(chatbot: dict, supabase) -> ChatbotResponse:
|
||||
conversation_count=conv_count.count or 0,
|
||||
created_at=chatbot.get("created_at"),
|
||||
published_at=chatbot.get("published_at"),
|
||||
)
|
||||
)
|
||||
@@ -60,6 +60,7 @@ async def list_marketplace_chatbots(
|
||||
languages=c.get("languages", ["en"]),
|
||||
primary_color=c.get("primary_color", "#6366f1"),
|
||||
welcome_message=c.get("welcome_message", "Hello!"),
|
||||
logo_url=c.get("logo_url"),
|
||||
average_rating=c.get("average_rating"),
|
||||
total_conversations=c.get("total_conversations", 0),
|
||||
company_name=company_data.get("name"),
|
||||
@@ -74,23 +75,27 @@ async def list_marketplace_chatbots(
|
||||
total=total,
|
||||
page=page,
|
||||
limit=limit,
|
||||
has_more=(offset + limit) < total,
|
||||
has_more=(offset + limit < total),
|
||||
)
|
||||
|
||||
|
||||
@router.get("/chatbots/{chatbot_id}", response_model=ChatbotPublicResponse)
|
||||
async def get_marketplace_chatbot(chatbot_id: str):
|
||||
async def get_marketplace_chatbot(chatbot_id: str, user=Depends(get_optional_user)):
|
||||
supabase = get_supabase()
|
||||
result = supabase.table("chatbots").select("*, companies(name, logo_url)") \
|
||||
.eq("id", chatbot_id) \
|
||||
.eq("is_published", True) \
|
||||
.execute()
|
||||
|
||||
result = supabase.table("chatbots").select(
|
||||
"*, companies(name, logo_url)"
|
||||
).eq("id", chatbot_id).eq("is_published", True).execute()
|
||||
|
||||
if not result.data:
|
||||
raise HTTPException(status_code=404, detail="Chatbot not found in marketplace")
|
||||
raise HTTPException(status_code=404, detail="Chatbot not found")
|
||||
|
||||
c = result.data[0]
|
||||
company_data = c.get("companies") or {}
|
||||
|
||||
conv_count = supabase.table("conversations").select("id", count="exact") \
|
||||
.eq("chatbot_id", chatbot_id).execute()
|
||||
|
||||
return ChatbotPublicResponse(
|
||||
id=c["id"],
|
||||
name=c["name"],
|
||||
@@ -100,8 +105,9 @@ async def get_marketplace_chatbot(chatbot_id: str):
|
||||
languages=c.get("languages", ["en"]),
|
||||
primary_color=c.get("primary_color", "#6366f1"),
|
||||
welcome_message=c.get("welcome_message", "Hello!"),
|
||||
logo_url=c.get("logo_url"),
|
||||
average_rating=c.get("average_rating"),
|
||||
total_conversations=c.get("total_conversations", 0),
|
||||
total_conversations=conv_count.count or 0,
|
||||
company_name=company_data.get("name"),
|
||||
company_logo=company_data.get("logo_url"),
|
||||
created_at=c.get("created_at"),
|
||||
@@ -130,4 +136,4 @@ async def rate_chatbot(
|
||||
new_avg = (current + rating.rating) / 2
|
||||
|
||||
supabase.table("chatbots").update({"average_rating": round(new_avg, 1)}).eq("id", chatbot_id).execute()
|
||||
return {"message": "Rating submitted", "new_average": round(new_avg, 1)}
|
||||
return {"message": "Rating submitted", "new_average": round(new_avg, 1)}
|
||||
107
app/routers/models.py
Normal file
107
app/routers/models.py
Normal file
@@ -0,0 +1,107 @@
|
||||
"""
|
||||
Models router - serves available AI models based on user subscription plan.
|
||||
|
||||
Single source of truth flow:
|
||||
config.py (PLAN_LIMITS + MODEL_CATALOG) → this router → frontend
|
||||
|
||||
To add/remove/rename a model, only edit config.py.
|
||||
"""
|
||||
from fastapi import APIRouter, Depends
|
||||
from app.dependencies import get_current_user
|
||||
from app.database import get_supabase
|
||||
from app.config import PLAN_LIMITS, MODEL_CATALOG, DEFAULT_MODELS
|
||||
from typing import List, Optional
|
||||
from pydantic import BaseModel
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
router = APIRouter(prefix="/models", tags=["Models"])
|
||||
|
||||
|
||||
# ─── Response Models ───────────────────────────────────────────────────────────
|
||||
|
||||
class AvailableModel(BaseModel):
|
||||
id: str
|
||||
name: str
|
||||
provider: str
|
||||
badge: str
|
||||
description: Optional[str] = None
|
||||
is_default: bool = False
|
||||
|
||||
|
||||
class ModelsResponse(BaseModel):
|
||||
models: List[AvailableModel]
|
||||
plan: str
|
||||
default_model: Optional[str] = None
|
||||
has_premium_access: bool
|
||||
upgrade_label: Optional[str] = None
|
||||
|
||||
|
||||
# ─── Helpers ───────────────────────────────────────────────────────────────────
|
||||
|
||||
def _get_user_plan(user_id: str) -> str:
|
||||
"""Get user's current subscription plan."""
|
||||
supabase = get_supabase()
|
||||
result = supabase.table("subscriptions") \
|
||||
.select("plan") \
|
||||
.eq("user_id", user_id) \
|
||||
.eq("status", "active") \
|
||||
.execute()
|
||||
return result.data[0]["plan"] if result.data else "free"
|
||||
|
||||
|
||||
# ─── Endpoint ─────────────────────────────────────────────────────────────────
|
||||
|
||||
@router.get("/available", response_model=ModelsResponse)
|
||||
async def get_available_models(user=Depends(get_current_user)):
|
||||
"""
|
||||
Returns the list of AI models the user can access based on their plan.
|
||||
Frontend uses this to populate model selection dynamically.
|
||||
|
||||
- free: gets a default model for preview/testing
|
||||
- starter: Fireworks AI models
|
||||
- pro: Fireworks + OpenAI + Anthropic + Google
|
||||
- enterprise: all models
|
||||
"""
|
||||
plan = _get_user_plan(user.id)
|
||||
plan_config = PLAN_LIMITS.get(plan, PLAN_LIMITS["free"])
|
||||
allowed_model_ids = plan_config.get("models", [])
|
||||
|
||||
# Enterprise wildcard → resolve to all catalog models
|
||||
if "*" in allowed_model_ids:
|
||||
allowed_model_ids = list(MODEL_CATALOG.keys())
|
||||
|
||||
# Build model list from catalog metadata
|
||||
default_model_id = DEFAULT_MODELS.get(plan)
|
||||
models: List[AvailableModel] = []
|
||||
|
||||
for model_id in allowed_model_ids:
|
||||
meta = MODEL_CATALOG.get(model_id)
|
||||
if not meta:
|
||||
logger.warning(f"Model '{model_id}' in PLAN_LIMITS[{plan}] but not in MODEL_CATALOG — skipping")
|
||||
continue
|
||||
|
||||
models.append(AvailableModel(
|
||||
id=model_id,
|
||||
name=meta["name"],
|
||||
provider=meta["provider"],
|
||||
badge=meta["badge"],
|
||||
description=meta.get("description"),
|
||||
is_default=(model_id == default_model_id),
|
||||
))
|
||||
|
||||
# Determine upgrade messaging
|
||||
has_premium = plan in ("pro", "enterprise")
|
||||
upgrade_label = None
|
||||
if plan == "free":
|
||||
upgrade_label = "Upgrade to Starter for more models and publishing"
|
||||
elif plan == "starter":
|
||||
upgrade_label = "Upgrade to Pro for GPT-4o, Claude, Gemini"
|
||||
|
||||
return ModelsResponse(
|
||||
models=models,
|
||||
plan=plan,
|
||||
default_model=default_model_id,
|
||||
has_premium_access=has_premium,
|
||||
upgrade_label=upgrade_label,
|
||||
)
|
||||
Reference in New Issue
Block a user