updates Mar6

This commit is contained in:
belviskhoremk
2026-03-06 22:37:40 +00:00
parent 2ed998058e
commit 9dccc83293
23 changed files with 2257 additions and 74 deletions

View File

@@ -45,6 +45,10 @@ class ChatbotAnalyticsResponse(BaseModel):
top_queries: List[TopQuery]
languages_used: Dict[str, int]
peak_hour: Optional[int] # 0-23
unanswered_count: int = 0
unanswered_queries: List[TopQuery] = []
feedback_positive: int = 0
feedback_negative: int = 0
class OverviewAnalyticsResponse(BaseModel):
@@ -212,6 +216,13 @@ async def get_analytics_overview(user=Depends(get_current_user)):
if rating:
all_ratings.append(rating)
# Feedback counts
fb_result = supabase.table("message_feedback").select("feedback", count="exact") \
.eq("chatbot_id", cid).execute()
total_fb = fb_result.count or 0
fb_pos = sum(1 for f in (fb_result.data or []) if f.get("feedback") == "positive")
fb_neg = total_fb - fb_pos
# Average messages per conversation
avg_msgs = round(msg_count / conv_count, 1) if conv_count > 0 else 0.0
@@ -223,7 +234,7 @@ async def get_analytics_overview(user=Depends(get_current_user)):
total_messages=msg_count,
average_messages_per_conversation=avg_msgs,
average_rating=rating,
total_ratings=0, # would need a ratings table for precise count
total_ratings=total_fb,
conversations_today=today_count,
conversations_this_week=week_count,
conversations_this_month=month_count,
@@ -231,6 +242,8 @@ async def get_analytics_overview(user=Depends(get_current_user)):
top_queries=top_queries,
languages_used=lang_counts,
peak_hour=peak,
feedback_positive=fb_pos,
feedback_negative=fb_neg,
))
# Overall average rating
@@ -345,6 +358,48 @@ async def get_chatbot_analytics(chatbot_id: str, user=Depends(get_current_user))
avg_msgs = round(msg_count / conv_count, 1) if conv_count > 0 else 0.0
# Feedback counts
fb_pos = 0
fb_neg = 0
if conv_ids and conv_ids != [""]:
feedback = supabase.table("message_feedback").select("feedback") \
.eq("chatbot_id", chatbot_id).execute()
for f in (feedback.data or []):
if f["feedback"] == "positive":
fb_pos += 1
else:
fb_neg += 1
# Unanswered queries (low confidence)
unanswered_queries: List[TopQuery] = []
unanswered_count = 0
if conv_ids and conv_ids != [""]:
try:
low_conf_msgs = supabase.table("messages").select("id, conversation_id, confidence_score") \
.in_("conversation_id", conv_ids[:100]) \
.eq("role", "assistant") \
.lt("confidence_score", 0.2) \
.limit(200).execute()
unanswered_count = len(low_conf_msgs.data or [])
# For each low-confidence assistant message, find the preceding user message
if low_conf_msgs.data:
unanswered_q_counts: Dict[str, int] = {}
for lm in low_conf_msgs.data[:20]: # limit work
prev_user = supabase.table("messages").select("content") \
.eq("conversation_id", lm["conversation_id"]) \
.eq("role", "user") \
.lt("created_at", lm.get("created_at", "9999")) \
.order("created_at", desc=True) \
.limit(1).execute()
if prev_user.data:
q = (prev_user.data[0].get("content") or "")[:100].strip()
if q:
unanswered_q_counts[q] = unanswered_q_counts.get(q, 0) + 1
top_unanswered = sorted(unanswered_q_counts.items(), key=lambda x: -x[1])[:5]
unanswered_queries = [TopQuery(query=q, count=n) for q, n in top_unanswered]
except Exception:
pass # unanswered queries is optional
return ChatbotAnalyticsResponse(
chatbot_id=chatbot_id,
chatbot_name=cb.get("name", "Untitled"),
@@ -353,7 +408,7 @@ async def get_chatbot_analytics(chatbot_id: str, user=Depends(get_current_user))
total_messages=msg_count,
average_messages_per_conversation=avg_msgs,
average_rating=cb.get("average_rating"),
total_ratings=0,
total_ratings=fb_pos + fb_neg,
conversations_today=today_count,
conversations_this_week=week_count,
conversations_this_month=month_count,
@@ -361,4 +416,56 @@ async def get_chatbot_analytics(chatbot_id: str, user=Depends(get_current_user))
top_queries=top_queries,
languages_used=lang_counts,
peak_hour=peak,
unanswered_count=unanswered_count,
unanswered_queries=unanswered_queries,
feedback_positive=fb_pos,
feedback_negative=fb_neg,
)
@router.get("/chatbot/{chatbot_id}/gaps", response_model=List[TopQuery])
async def get_knowledge_gaps(chatbot_id: str, user=Depends(get_current_user)):
"""Returns top queries where the bot had low confidence (knowledge gaps). Starter+ only."""
plan = _get_user_plan(user.id)
_check_analytics_access(plan)
supabase = get_supabase()
company = supabase.table("companies").select("id").eq("owner_id", user.id).execute()
if not company.data:
raise HTTPException(status_code=404, detail="Company not found")
chatbot = supabase.table("chatbots").select("id") \
.eq("id", chatbot_id).eq("company_id", company.data[0]["id"]).execute()
if not chatbot.data:
raise HTTPException(status_code=404, detail="Chatbot not found")
# Find conversations
convs = supabase.table("conversations").select("id").eq("chatbot_id", chatbot_id).execute()
conv_ids = [c["id"] for c in (convs.data or [])]
if not conv_ids:
return []
# Low confidence assistant messages
low_conf = supabase.table("messages").select("id, conversation_id, created_at") \
.in_("conversation_id", conv_ids[:100]) \
.eq("role", "assistant") \
.lt("confidence_score", 0.2) \
.limit(100).execute()
if not low_conf.data:
return []
q_counts: Dict[str, int] = {}
for msg in low_conf.data[:30]:
prev = supabase.table("messages").select("content") \
.eq("conversation_id", msg["conversation_id"]) \
.eq("role", "user") \
.order("created_at", desc=True) \
.limit(1).execute()
if prev.data:
content = (prev.data[0].get("content") or "")[:100].strip()
if content:
q_counts[content] = q_counts.get(content, 0) + 1
sorted_gaps = sorted(q_counts.items(), key=lambda x: -x[1])[:10]
return [TopQuery(query=q, count=n) for q, n in sorted_gaps]