Skip to content

Commit

Permalink
Merge pull request #187 from priyanshuverma-dev/fix-bugs-apis
Browse files Browse the repository at this point in the history
fixes: API and bugs in data fetching
  • Loading branch information
kom-senapati authored Oct 25, 2024
2 parents 1ef5cca + 62177cb commit de12aca
Show file tree
Hide file tree
Showing 9 changed files with 319 additions and 377 deletions.
135 changes: 24 additions & 111 deletions app/api_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,18 @@
session,
Response,
)
import json, re
import re

from sqlalchemy import func
from .models import User, Chatbot, Chat, Image
from sqlalchemy.exc import IntegrityError
from flask_login import login_user, login_required
from flask_login import login_user
from typing import Union, List, Optional, Dict
from .ai import chat_with_chatbot
from .constants import BOT_AVATAR_API, USER_AVATAR_API
from .helpers import create_default_chatbots
from datetime import datetime, date
from datetime import datetime
import re
import random
from flask_jwt_extended import (
create_access_token,
jwt_required,
Expand Down Expand Up @@ -385,24 +384,6 @@ def api_anonymous_chatbot() -> Union[Response, tuple[Response, int]]:
)


@api_bp.route("/api/chat/<int:chat_id>/delete", methods=["POST"])
@login_required
def api_chat_delete(chat_id: int) -> Union[Response, tuple[Response, int]]:
chat: Chat = Chat.query.get_or_404(chat_id)
if chat.user_id != current_user.id:
return (
jsonify({"error": "Unauthorized access."}),
403,
)
chat.query.filter_by(id=chat_id).delete()
return (
jsonify(
{"success": True, "message": "Message deleted.", "chat": chat.chatbot_id}
),
200,
)


@api_bp.route("/api/chatbot/<int:chatbot_id>/clear", methods=["POST"])
@jwt_required()
def api_clear_chats(chatbot_id: int) -> Union[Response, tuple[Response, int]]:
Expand Down Expand Up @@ -461,95 +442,7 @@ def api_user_info():
if user is None:
return jsonify({"success": False, "message": "User not found."}), 404

user_info = {
"name": user.name,
"username": user.username,
"email": user.email,
"avatar": user.avatar,
"bio": user.bio,
}
return jsonify({"success": True, "user": user_info}), 200

except Exception as e:
return jsonify({"success": False, "message": str(e)}), 500


@api_bp.route("/api/dashboard_data", methods=["GET"])
@jwt_required()
def api_get_dashboard_data():
try:
create_default_chatbots(db)
uid: str = get_jwt_identity()
chatbots: List[Chatbot] = Chatbot.query.filter(Chatbot.user_id == uid).all()
system_chatbots: List[Chatbot] = Chatbot.query.filter(
Chatbot.generated_by == "system"
).all()
# Fetch Chatbot of the Day (for simplicity, pick one at random)
chatbot_of_the_day: Chatbot = (
db.session.query(Chatbot)
.filter(Chatbot.public == True) # Only select public chatbots
.order_by(func.random())
.first()
)
image_of_the_day: Image = (
db.session.query(Image)
.filter(Image.public == True) # Only select public images
.order_by(func.random())
.first()
)

# Fetch Message or Quote of the Day
quotes = [
"The best way to predict the future is to invent it.",
"Do not wait to strike till the iron is hot; but make it hot by striking.",
"Whether you think you can or think you can’t, you’re right.",
"The only limit to our realization of tomorrow is our doubts of today.",
]
quote_of_the_day = random.choice(quotes)

programming_tips = [
"Always keep your code DRY (Don't Repeat Yourself).",
"Use version control to manage your code.",
"Write unit tests for your code to ensure quality.",
"Use meaningful variable names to improve readability.",
"Keep functions small and focused on a single task.",
]
tip_of_the_day = random.choice(programming_tips)

# Response data
response = {
"success": True,
"chatbot_of_the_day": (
chatbot_of_the_day.to_dict() if chatbot_of_the_day else None
),
"image_of_the_day": (
image_of_the_day.to_dict() if image_of_the_day else None
),
"quote_of_the_day": quote_of_the_day,
"tip": tip_of_the_day,
"systemBots": [bot.to_dict() for bot in system_chatbots],
"bots": [bot.to_dict() for bot in chatbots],
"date": date.today().strftime("%Y-%m-%d"),
}
return jsonify(response), 200

except Exception as e:
return jsonify({"success": False, "message": str(e)}), 500


@api_bp.route("/api/hub_data", methods=["GET"])
@jwt_required()
def api_get_hub_data():
try:
public_chatbots: List[Chatbot] = Chatbot.query.filter_by(public=True).all()
public_images: List[Image] = Image.query.filter_by(public=True).all()
# Response data
response = {
"success": True,
"bots": [bot.to_dict() for bot in public_chatbots],
"images": [image.to_dict() for image in public_images],
}
return jsonify(response), 200
return jsonify({"success": True, "user": user.to_dict()}), 200

except Exception as e:
return jsonify({"success": False, "message": str(e)}), 500
Expand Down Expand Up @@ -587,6 +480,7 @@ def api_get_user_data(username: str):
@jwt_required()
def api_get_data():
try:
create_default_chatbots(db)
uid: str = get_jwt_identity()
queues_req: str = request.args.get("queues")
o_uid: str = request.args.get("uid")
Expand All @@ -603,6 +497,7 @@ def api_get_data():
"public_bots",
"public_images",
"user_bots",
"trend_today",
}
queues = [q for q in queues if q in valid_queues]

Expand Down Expand Up @@ -634,6 +529,24 @@ def api_get_data():
).all()
response["user_bots"] = [bot.to_dict() for bot in o_chatbots]

if "trend_today" in queues:
chatbot_of_the_day: Chatbot = (
db.session.query(Chatbot)
.filter(Chatbot.public == True) # Only select public chatbots
.order_by(func.random())
.first()
)
image_of_the_day: Image = (
db.session.query(Image)
.filter(Image.public == True) # Only select public images
.order_by(func.random())
.first()
)
response["trend_today"] = {
"chatbot": chatbot_of_the_day.to_dict(),
"image": image_of_the_day.to_dict(),
}

return jsonify(response), 200

except Exception as e:
Expand Down
13 changes: 13 additions & 0 deletions client/src/components/BotsLoading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Skeleton } from "./ui/skeleton";

export default function BotsLoading({ count = 6 }: { count?: number }) {
return Array.from({ length: count }).map((_, i) => (
<div key={i} className="flex flex-col space-y-3">
<Skeleton className="h-[125px] w-[250px] rounded-xl" />
<div className="space-y-2">
<Skeleton className="h-4 w-[250px]" />
<Skeleton className="h-4 w-[200px]" />
</div>
</div>
));
}
86 changes: 77 additions & 9 deletions client/src/components/ChatbotCard.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,37 @@
import { MessageCircle } from "lucide-react";
import {
Edit,
GlobeIcon,
GlobeLockIcon,
MessageCircle,
Trash2,
} from "lucide-react";
import { Link } from "react-router-dom";
import { LikeAndReport } from "./LikeAndReport";
import {
useDeleteChatbotModal,
useUpdateChatbotModal,
} from "@/stores/modal-store";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { publishChatbot } from "@/lib/queries";

export function ChatbotCard({
chatbot,
queryKeys,
userId,
}: {
chatbot: Chatbot;
queryKeys: string[];
userId?: number;
}) {
const showActions = userId === chatbot.user_id;

const deleteModal = useDeleteChatbotModal();
const updateModal = useUpdateChatbotModal();
const rq = useQueryClient();
const mutation = useMutation({
mutationFn: publishChatbot,
onSuccess: () => rq.invalidateQueries({ queryKey: queryKeys }),
});
return (
<>
<div className="min-w-80 bg-light dark:bg-dark p-6 rounded-lg transition-all drop-shadow hover:shadow border border-lighter dark:border-darker flex flex-col justify-between h-64">
Expand All @@ -32,14 +55,59 @@ export function ChatbotCard({
>
<MessageCircle />
</Link>

<LikeAndReport
id={chatbot.id}
likes={chatbot.likes}
reports={chatbot.reports}
type="chatbot"
queryKeys={queryKeys}
/>
{showActions ? (
<>
<button
className="text-yellow-500 hover:text-yellow-600 transition duration-300 p-2 rounded hover:bg-yellow-100 dark:hover:bg-yellow-700/10 dark:text-yellow-400 dark:hover:text-yellow-300"
title="Update"
onClick={() =>
updateModal.onOpen({
id: chatbot.id,
prevName: chatbot.name,
prevPrompt: chatbot.prompt,
})
}
>
<Edit />
</button>
{chatbot.public ? (
<button
className="text-red-500 hover:text-red-600 transition duration-300 p-2 rounded hover:bg-red-100 dark:hover:bg-red-700/10 dark:text-red-400 dark:hover:text-red-300"
title="Unpublish"
onClick={() => mutation.mutate(chatbot.id)}
>
<GlobeLockIcon />
</button>
) : (
<button
className="text-green-500 hover:text-green-600 transition duration-300 p-2 rounded hover:bg-green-100 dark:hover:bg-green-700/10 dark:text-green-400 dark:hover:text-green-300"
title="Publish"
onClick={() => mutation.mutate(chatbot.id)}
>
<GlobeIcon />
</button>
)}
<button
className="text-red-500 hover:text-red-600 transition duration-300 p-2 rounded hover:bg-red-100 dark:hover:bg-red-700/10 dark:text-red-400 dark:hover:text-red-300"
title="Delete"
onClick={() =>
deleteModal.onOpen({
id: chatbot.id,
})
}
>
<Trash2 />
</button>
</>
) : (
<LikeAndReport
id={chatbot.id}
likes={chatbot.likes}
reports={chatbot.reports}
type="chatbot"
queryKeys={queryKeys}
/>
)}
</div>
</div>
</>
Expand Down
5 changes: 1 addition & 4 deletions client/src/components/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@ export default function Navbar() {
const { user, loading } = useAuth();
return (
<nav className="flex justify-between items-center px-6 py-4 rounded-md border-b-2 dark:border-darker border-lighter">
<Link
to="/dashboard"
className="text-5xl brand font-extrabold text-gray-500 hover:text-gray-700 dark:text-white dark:hover:text-gray-300"
>
<Link to="/dashboard" className="text-5xl brand font-extrabold">
Bot Verse
</Link>
{loading ? (
Expand Down
35 changes: 5 additions & 30 deletions client/src/lib/queries.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,10 @@
import axios from "axios";
import { SERVER_URL } from "./utils";

interface DashboardResponse {
success: boolean;
tip: string;
quote_of_the_day: string;
image_of_the_day: ImageGen;
chatbot_of_the_day: Chatbot;
systemBots: Chatbot[];
bots: Chatbot[];
date: Date;
}
interface ChatbotResponse {
chats: Chat[];
bot: Chatbot;
}
interface HubResponse {
bots: Chatbot[];
images: ImageGen[];
}

interface ProfileResponse {
user: User;
Expand All @@ -31,22 +17,6 @@ export const authHeaders = {
Authorization: `Bearer ${token || ""}`,
};

export const fetchDashboardData = async (): Promise<
DashboardResponse | undefined
> => {
const { data } = await axios.get(`${SERVER_URL}/api/dashboard_data`, {
headers: authHeaders,
});
return data;
};

export const fetchHubData = async (): Promise<HubResponse | undefined> => {
const { data } = await axios.get(`${SERVER_URL}/api/hub_data`, {
headers: authHeaders,
});
return data;
};

export const fetchProfileData = async (
username: string
): Promise<ProfileResponse> => {
Expand Down Expand Up @@ -122,6 +92,10 @@ interface DataResponse {
public_bots?: Chatbot[]; // Optional property
user_bots?: Chatbot[]; // Optional property
public_images?: ImageGen[]; // Optional property
trend_today?: {
chatbot: Chatbot;
image: ImageGen;
}; // Optional property
}

const validQueues = [
Expand All @@ -131,6 +105,7 @@ const validQueues = [
"public_bots",
"public_images",
"user_bots",
"trend_today",
] as const;

type ValidQueue = (typeof validQueues)[number];
Expand Down
Loading

0 comments on commit de12aca

Please sign in to comment.