Spaces:
Sleeping
Sleeping
Upload 148 files
Browse files- src/.DS_Store +0 -0
- src/apis/.DS_Store +0 -0
- src/apis/__pycache__/create_app.cpython-311.pyc +0 -0
- src/apis/config/firebase_config.py +36 -0
- src/apis/controllers/.DS_Store +0 -0
- src/apis/controllers/__pycache__/chat_controller.cpython-311.pyc +0 -0
- src/apis/controllers/__pycache__/comment_controller.cpython-311.pyc +0 -0
- src/apis/controllers/chat_controller.py +1 -1
- src/apis/controllers/comment_controller.py +113 -0
- src/apis/create_app.py +2 -0
- src/apis/models/.DS_Store +0 -0
- src/apis/models/__pycache__/post_models.cpython-311.pyc +0 -0
- src/apis/models/post_models.py +2 -2
- src/apis/providers/firebase_provider.py +64 -0
- src/apis/routes/.DS_Store +0 -0
- src/apis/routes/__pycache__/comment_route.cpython-311.pyc +0 -0
- src/apis/routes/__pycache__/post_router.cpython-311.pyc +0 -0
- src/apis/routes/comment_route.py +98 -0
- src/apis/routes/post_router.py +15 -8
- src/langgraph/.DS_Store +0 -0
- src/langgraph/multi_agent/.DS_Store +0 -0
- src/langgraph/multi_agent/chat/__pycache__/chat_flow.cpython-311.pyc +0 -0
- src/langgraph/multi_agent/chat/chat_flow.py +1 -3
- src/langgraph/multi_agent/planner/__pycache__/react_agent.cpython-311.pyc +0 -0
- src/langgraph/multi_agent/planner/react_agent.py +5 -95
- src/utils/.DS_Store +0 -0
- src/utils/__pycache__/mongo.cpython-311.pyc +0 -0
- src/utils/__pycache__/redis.cpython-311.pyc +0 -0
- src/utils/mongo.py +1 -1
- src/utils/redis.py +1 -0
src/.DS_Store
CHANGED
|
Binary files a/src/.DS_Store and b/src/.DS_Store differ
|
|
|
src/apis/.DS_Store
CHANGED
|
Binary files a/src/apis/.DS_Store and b/src/apis/.DS_Store differ
|
|
|
src/apis/__pycache__/create_app.cpython-311.pyc
CHANGED
|
Binary files a/src/apis/__pycache__/create_app.cpython-311.pyc and b/src/apis/__pycache__/create_app.cpython-311.pyc differ
|
|
|
src/apis/config/firebase_config.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import firebase_admin
|
| 2 |
+
from firebase_admin import credentials
|
| 3 |
+
from firebase_admin import storage
|
| 4 |
+
|
| 5 |
+
import os
|
| 6 |
+
from dotenv import load_dotenv
|
| 7 |
+
|
| 8 |
+
# Load environment variables
|
| 9 |
+
load_dotenv()
|
| 10 |
+
firebase_url_storageBucket = os.getenv("FIREBASE_URL_STORAGEBUCKET")
|
| 11 |
+
|
| 12 |
+
# Get credentials from environment variables
|
| 13 |
+
credential_firebase = {
|
| 14 |
+
"type": os.getenv("TYPE"),
|
| 15 |
+
"project_id": os.getenv("PROJECT_ID"),
|
| 16 |
+
"private_key_id": os.getenv("FIREBASE_PRIVATE_KEY_ID"),
|
| 17 |
+
"private_key": os.getenv("PRIVATE_KEY"),
|
| 18 |
+
"client_email": os.getenv("CLIENT_EMAIL"),
|
| 19 |
+
"client_id": os.getenv("CLIENT_ID"),
|
| 20 |
+
"auth_uri": os.getenv("AUTH_URI"),
|
| 21 |
+
"token_uri": os.getenv("TOKEN_URI"),
|
| 22 |
+
"auth_provider_x509_cert_url": os.getenv("AUTH_PROVIDER_X509_CERT_URL"),
|
| 23 |
+
"client_x509_cert_url": os.getenv("CLIENT_X509_CERT_URL"),
|
| 24 |
+
"universe_domain": os.getenv("UNIVERSE_DOMAIN"),
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
# Check if the app is not initialized yet
|
| 29 |
+
if not firebase_admin._apps:
|
| 30 |
+
# Initialize the app with the credentials
|
| 31 |
+
cred = credentials.Certificate(credential_firebase)
|
| 32 |
+
firebase_admin.initialize_app(cred, {"storageBucket": firebase_url_storageBucket})
|
| 33 |
+
|
| 34 |
+
# Initialize Firestore
|
| 35 |
+
firebase_bucket = storage.bucket(app=firebase_admin.get_app())
|
| 36 |
+
print("Storage connected")
|
src/apis/controllers/.DS_Store
CHANGED
|
Binary files a/src/apis/controllers/.DS_Store and b/src/apis/controllers/.DS_Store differ
|
|
|
src/apis/controllers/__pycache__/chat_controller.cpython-311.pyc
CHANGED
|
Binary files a/src/apis/controllers/__pycache__/chat_controller.cpython-311.pyc and b/src/apis/controllers/__pycache__/chat_controller.cpython-311.pyc differ
|
|
|
src/apis/controllers/__pycache__/comment_controller.cpython-311.pyc
ADDED
|
Binary file (6.64 kB). View file
|
|
|
src/apis/controllers/chat_controller.py
CHANGED
|
@@ -65,7 +65,7 @@ async def save_history(user_id, human_message, ai_message, intent):
|
|
| 65 |
# )
|
| 66 |
# return {"message": "History updated"}
|
| 67 |
# await set_key_redis(f"chat_history_{user_id}", str(messages_add_to_history_cache))
|
| 68 |
-
|
| 69 |
|
| 70 |
|
| 71 |
async def chat_streaming_function(user, data: Chat, background_tasks: BackgroundTasks):
|
|
|
|
| 65 |
# )
|
| 66 |
# return {"message": "History updated"}
|
| 67 |
# await set_key_redis(f"chat_history_{user_id}", str(messages_add_to_history_cache))
|
| 68 |
+
return {"message": "History created"}
|
| 69 |
|
| 70 |
|
| 71 |
async def chat_streaming_function(user, data: Chat, background_tasks: BackgroundTasks):
|
src/apis/controllers/comment_controller.py
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import Dict
|
| 2 |
+
from datetime import datetime
|
| 3 |
+
from src.utils.mongo import CommentCRUD, LikeCRUD
|
| 4 |
+
from src.utils.logger import logger
|
| 5 |
+
from datetime import datetime
|
| 6 |
+
from bson import ObjectId
|
| 7 |
+
from datetime import datetime
|
| 8 |
+
from bson import ObjectId
|
| 9 |
+
from src.utils.mongo import UserCRUD
|
| 10 |
+
from asyncio import gather
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
def serialize_datetime(obj):
|
| 14 |
+
if isinstance(obj, datetime):
|
| 15 |
+
return obj.isoformat()
|
| 16 |
+
if isinstance(obj, ObjectId):
|
| 17 |
+
return str(obj)
|
| 18 |
+
return obj
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
async def create_a_comment_controller(content: str, user_id: str, post_id: str) -> Dict:
|
| 22 |
+
try:
|
| 23 |
+
comment = {
|
| 24 |
+
"content": content,
|
| 25 |
+
"user_id": user_id,
|
| 26 |
+
"post_id": post_id,
|
| 27 |
+
}
|
| 28 |
+
await CommentCRUD.create(comment)
|
| 29 |
+
return {"status": "success", "message": "Comment created successfully"}
|
| 30 |
+
except Exception as e:
|
| 31 |
+
return {"status": "error", "message": str(e)}
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
async def get_comments_of_a_post_controller(post_id: str) -> Dict:
|
| 35 |
+
try:
|
| 36 |
+
comments = await CommentCRUD.read({"post_id": post_id})
|
| 37 |
+
logger.info(f"COMMENTS: {comments}")
|
| 38 |
+
user_ids = [comment.get("user_id") for comment in comments]
|
| 39 |
+
user_infos = await gather(
|
| 40 |
+
*[UserCRUD.find_by_id(user_id) for user_id in user_ids]
|
| 41 |
+
)
|
| 42 |
+
user_info_map = {
|
| 43 |
+
user_info.get("_id"): user_info for user_info in user_infos if user_info
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
serialized_comments = []
|
| 47 |
+
for comment in comments:
|
| 48 |
+
user_id = comment.get("user_id")
|
| 49 |
+
user_info = user_info_map.get(user_id)
|
| 50 |
+
serialized_comment = {
|
| 51 |
+
"id": serialize_datetime(comment.get("_id")),
|
| 52 |
+
"content": comment.get("content"),
|
| 53 |
+
"user_id": comment.get("user_id"),
|
| 54 |
+
"post_id": comment.get("post_id"),
|
| 55 |
+
"created_at": serialize_datetime(comment.get("created_at")),
|
| 56 |
+
"updated_at": serialize_datetime(comment.get("updated_at")),
|
| 57 |
+
"user_info": (
|
| 58 |
+
{
|
| 59 |
+
"name": user_info.get("name"),
|
| 60 |
+
"picture": user_info.get("picture"),
|
| 61 |
+
}
|
| 62 |
+
if user_info
|
| 63 |
+
else None
|
| 64 |
+
),
|
| 65 |
+
}
|
| 66 |
+
serialized_comments.append(serialized_comment)
|
| 67 |
+
return {"status": "success", "message": serialized_comments}
|
| 68 |
+
except Exception as e:
|
| 69 |
+
logger.error(f"Error getting post: {str(e)}")
|
| 70 |
+
return {"status": "error", "message": str(e)}
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
async def update_a_comment_controller(
|
| 74 |
+
user_id: str, comment_id: str, content: str
|
| 75 |
+
) -> Dict:
|
| 76 |
+
try:
|
| 77 |
+
exist_data = await CommentCRUD.find_by_id(comment_id)
|
| 78 |
+
if exist_data is None:
|
| 79 |
+
return {"status": "error", "message": "Comment not found"}
|
| 80 |
+
if exist_data["user_id"] != user_id:
|
| 81 |
+
return {
|
| 82 |
+
"status": "error",
|
| 83 |
+
"message": "You are not allowed to update this comment",
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
await CommentCRUD.update(
|
| 87 |
+
{"_id": ObjectId(comment_id)},
|
| 88 |
+
{
|
| 89 |
+
"content": content,
|
| 90 |
+
},
|
| 91 |
+
)
|
| 92 |
+
return {"status": "success", "message": "Post updated successfully"}
|
| 93 |
+
except Exception as e:
|
| 94 |
+
logger.error(f"Error updating post: {str(e)}")
|
| 95 |
+
return {"status": "error", "message": str(e)}
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
async def delete_a_comment_controller(user_id: str, comment_id: str) -> Dict:
|
| 99 |
+
try:
|
| 100 |
+
exist_data = await CommentCRUD.find_by_id(comment_id)
|
| 101 |
+
if exist_data is None:
|
| 102 |
+
return {"status": "error", "message": "Comment not found"}
|
| 103 |
+
if exist_data["user_id"] != user_id:
|
| 104 |
+
return {
|
| 105 |
+
"status": "error",
|
| 106 |
+
"message": "You are not allowed to delete this comment",
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
await CommentCRUD.delete({"_id": ObjectId(comment_id)})
|
| 110 |
+
return {"status": "success", "message": "Comment deleted successfully"}
|
| 111 |
+
except Exception as e:
|
| 112 |
+
logger.error(f"Error deleting post: {str(e)}")
|
| 113 |
+
return {"status": "error", "message": str(e)}
|
src/apis/create_app.py
CHANGED
|
@@ -8,6 +8,7 @@ from src.apis.routes.travel_dest_route import router as router_travel_dest
|
|
| 8 |
from src.apis.routes.scheduling_router import router as router_scheduling
|
| 9 |
from src.apis.routes.planner_route import router as router_planner
|
| 10 |
from src.apis.routes.post_router import router as router_post
|
|
|
|
| 11 |
api_router = APIRouter()
|
| 12 |
api_router.include_router(router_chat)
|
| 13 |
api_router.include_router(router_auth)
|
|
@@ -17,6 +18,7 @@ api_router.include_router(router_travel_dest)
|
|
| 17 |
api_router.include_router(router_scheduling)
|
| 18 |
api_router.include_router(router_planner)
|
| 19 |
api_router.include_router(router_post)
|
|
|
|
| 20 |
|
| 21 |
|
| 22 |
def create_app():
|
|
|
|
| 8 |
from src.apis.routes.scheduling_router import router as router_scheduling
|
| 9 |
from src.apis.routes.planner_route import router as router_planner
|
| 10 |
from src.apis.routes.post_router import router as router_post
|
| 11 |
+
from src.apis.routes.comment_route import router as router_comment
|
| 12 |
api_router = APIRouter()
|
| 13 |
api_router.include_router(router_chat)
|
| 14 |
api_router.include_router(router_auth)
|
|
|
|
| 18 |
api_router.include_router(router_scheduling)
|
| 19 |
api_router.include_router(router_planner)
|
| 20 |
api_router.include_router(router_post)
|
| 21 |
+
api_router.include_router(router_comment)
|
| 22 |
|
| 23 |
|
| 24 |
def create_app():
|
src/apis/models/.DS_Store
CHANGED
|
Binary files a/src/apis/models/.DS_Store and b/src/apis/models/.DS_Store differ
|
|
|
src/apis/models/__pycache__/post_models.cpython-311.pyc
CHANGED
|
Binary files a/src/apis/models/__pycache__/post_models.cpython-311.pyc and b/src/apis/models/__pycache__/post_models.cpython-311.pyc differ
|
|
|
src/apis/models/post_models.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
| 1 |
from pydantic import Field
|
| 2 |
from .BaseModel import BaseDocument
|
| 3 |
|
|
|
|
| 4 |
class Comment(BaseDocument):
|
| 5 |
content: str = Field("", description="Post's content")
|
| 6 |
user_id: str = Field("", description="User's id")
|
|
@@ -11,8 +12,7 @@ class Comment(BaseDocument):
|
|
| 11 |
"example": {
|
| 12 |
"content": "John Doe",
|
| 13 |
"user_id": "1234567890",
|
| 14 |
-
"
|
| 15 |
-
"comment_ids": ["1234567890"],
|
| 16 |
}
|
| 17 |
}
|
| 18 |
}
|
|
|
|
| 1 |
from pydantic import Field
|
| 2 |
from .BaseModel import BaseDocument
|
| 3 |
|
| 4 |
+
|
| 5 |
class Comment(BaseDocument):
|
| 6 |
content: str = Field("", description="Post's content")
|
| 7 |
user_id: str = Field("", description="User's id")
|
|
|
|
| 12 |
"example": {
|
| 13 |
"content": "John Doe",
|
| 14 |
"user_id": "1234567890",
|
| 15 |
+
"post_id": "1234567890",
|
|
|
|
| 16 |
}
|
| 17 |
}
|
| 18 |
}
|
src/apis/providers/firebase_provider.py
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from src.apis.config.firebase_config import firebase_bucket
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
def upload_file_to_storage(file_path, file_name):
|
| 5 |
+
"""
|
| 6 |
+
Upload a file to Firebase Storage
|
| 7 |
+
param:
|
| 8 |
+
file_path: str - The path of the file on local machine to be uploaded
|
| 9 |
+
return:
|
| 10 |
+
str - The public URL of the uploaded file
|
| 11 |
+
"""
|
| 12 |
+
file_name = file_name
|
| 13 |
+
blob = firebase_bucket.blob(file_name)
|
| 14 |
+
blob.upload_from_filename(file_path)
|
| 15 |
+
blob.make_public()
|
| 16 |
+
|
| 17 |
+
return blob.public_url
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
def delete_file_from_storage(file_name):
|
| 21 |
+
"""
|
| 22 |
+
Delete a file from Firebase Storage
|
| 23 |
+
param:
|
| 24 |
+
file_name: str - The name of the file to be deleted
|
| 25 |
+
return:
|
| 26 |
+
bool - True if the file is deleted successfully, False if the file is not found
|
| 27 |
+
"""
|
| 28 |
+
try:
|
| 29 |
+
blob = firebase_bucket.blob(file_name)
|
| 30 |
+
blob.delete()
|
| 31 |
+
return True
|
| 32 |
+
except Exception as e:
|
| 33 |
+
print("Error:", e)
|
| 34 |
+
return False
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def list_all_files_in_storage():
|
| 38 |
+
"""
|
| 39 |
+
View all files in Firebase Storage
|
| 40 |
+
return:
|
| 41 |
+
dict - Dictionary with keys are names and values are url of all files in Firebase Storage
|
| 42 |
+
"""
|
| 43 |
+
blobs = firebase_bucket.list_blobs()
|
| 44 |
+
blob_dict = {blob.name: blob.public_url for blob in blobs}
|
| 45 |
+
return blob_dict
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
def download_file_from_storage(file_name, destination_path):
|
| 49 |
+
"""
|
| 50 |
+
Download a file from Firebase Storage
|
| 51 |
+
param:
|
| 52 |
+
file_name: str - The name of the file to be downloaded
|
| 53 |
+
destination_path: str - The path to save the downloaded file
|
| 54 |
+
return:
|
| 55 |
+
bool - True if the file is downloaded successfully, False if the file is not found
|
| 56 |
+
"""
|
| 57 |
+
try:
|
| 58 |
+
blob = firebase_bucket.blob(file_name)
|
| 59 |
+
blob.download_to_filename(destination_path)
|
| 60 |
+
print("da tai xun thanh cong")
|
| 61 |
+
return True
|
| 62 |
+
except Exception as e:
|
| 63 |
+
print("Error:", e)
|
| 64 |
+
return False
|
src/apis/routes/.DS_Store
CHANGED
|
Binary files a/src/apis/routes/.DS_Store and b/src/apis/routes/.DS_Store differ
|
|
|
src/apis/routes/__pycache__/comment_route.cpython-311.pyc
ADDED
|
Binary file (5.91 kB). View file
|
|
|
src/apis/routes/__pycache__/post_router.cpython-311.pyc
CHANGED
|
Binary files a/src/apis/routes/__pycache__/post_router.cpython-311.pyc and b/src/apis/routes/__pycache__/post_router.cpython-311.pyc differ
|
|
|
src/apis/routes/comment_route.py
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fastapi import APIRouter, status, Depends, BackgroundTasks
|
| 2 |
+
from typing import Annotated, Optional
|
| 3 |
+
from fastapi.responses import JSONResponse
|
| 4 |
+
from pydantic import Field
|
| 5 |
+
from src.apis.models.user_models import User
|
| 6 |
+
from src.apis.models.BaseModel import BaseDocument
|
| 7 |
+
from src.apis.middlewares.auth_middleware import get_current_user
|
| 8 |
+
from src.apis.controllers.comment_controller import (
|
| 9 |
+
create_a_comment_controller,
|
| 10 |
+
get_comments_of_a_post_controller,
|
| 11 |
+
update_a_comment_controller,
|
| 12 |
+
delete_a_comment_controller,
|
| 13 |
+
)
|
| 14 |
+
from src.utils.redis import set_key_redis, get_key_redis
|
| 15 |
+
from src.utils.logger import logger
|
| 16 |
+
|
| 17 |
+
router = APIRouter(prefix="/comment", tags=["Comment"])
|
| 18 |
+
|
| 19 |
+
user_dependency = Annotated[User, Depends(get_current_user)]
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
class BodyComment(BaseDocument):
|
| 23 |
+
content: str = Field("", description="Comment's content")
|
| 24 |
+
post_id: str = Field("", description="Post's id")
|
| 25 |
+
|
| 26 |
+
class Config:
|
| 27 |
+
json_schema_extra = {
|
| 28 |
+
"example": {
|
| 29 |
+
"content": "John Doe",
|
| 30 |
+
"post_id": "1234567890",
|
| 31 |
+
}
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
@router.post("/create", status_code=status.HTTP_201_CREATED)
|
| 36 |
+
async def create_comment(body: BodyComment, user: user_dependency):
|
| 37 |
+
if user is None:
|
| 38 |
+
return JSONResponse(content={"message": "User not found"}, status_code=404)
|
| 39 |
+
user_id = user["id"]
|
| 40 |
+
result = await create_a_comment_controller(
|
| 41 |
+
body.content,
|
| 42 |
+
user_id,
|
| 43 |
+
body.post_id,
|
| 44 |
+
)
|
| 45 |
+
if result["status"] == "error":
|
| 46 |
+
return JSONResponse(content=result, status_code=404)
|
| 47 |
+
else:
|
| 48 |
+
return JSONResponse(content=result, status_code=201)
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
@router.get("/get/{post_id}", status_code=status.HTTP_200_OK)
|
| 52 |
+
async def get_comments_of_a_post(post_id: str):
|
| 53 |
+
result = await get_comments_of_a_post_controller(post_id)
|
| 54 |
+
if result["status"] == "error":
|
| 55 |
+
return JSONResponse(content=result, status_code=404)
|
| 56 |
+
else:
|
| 57 |
+
return JSONResponse(content=result, status_code=200)
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
class BodyUpdateComment(BaseDocument):
|
| 61 |
+
comment_id: str = Field("", description="Comment's id")
|
| 62 |
+
content: Optional[str] = Field("", description="Comment's content")
|
| 63 |
+
|
| 64 |
+
class Config:
|
| 65 |
+
json_schema_extra = {
|
| 66 |
+
"example": {
|
| 67 |
+
"comment_id": "1234567890",
|
| 68 |
+
"content": "John Doe",
|
| 69 |
+
}
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
@router.patch("/update/", status_code=status.HTTP_200_OK)
|
| 74 |
+
async def update_comment(body: BodyUpdateComment, user: user_dependency):
|
| 75 |
+
if user is None:
|
| 76 |
+
return JSONResponse(content={"message": "User not found"}, status_code=404)
|
| 77 |
+
result = await update_a_comment_controller(
|
| 78 |
+
user["id"],
|
| 79 |
+
body.comment_id,
|
| 80 |
+
body.content,
|
| 81 |
+
)
|
| 82 |
+
logger.info(f"RESULT: {result}")
|
| 83 |
+
if result["status"] == "error":
|
| 84 |
+
return JSONResponse(content=result, status_code=404)
|
| 85 |
+
else:
|
| 86 |
+
return JSONResponse(content=result, status_code=200)
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
@router.delete("/delete/{comment_id}", status_code=status.HTTP_200_OK)
|
| 90 |
+
async def delete_comment(comment_id: str, user: user_dependency):
|
| 91 |
+
if user is None:
|
| 92 |
+
return JSONResponse(content={"message": "User not found"}, status_code=404)
|
| 93 |
+
result = await delete_a_comment_controller(user["id"], comment_id)
|
| 94 |
+
logger.info(f"RESULT: {result}")
|
| 95 |
+
if result["status"] == "error":
|
| 96 |
+
return JSONResponse(content=result, status_code=404)
|
| 97 |
+
else:
|
| 98 |
+
return JSONResponse(content=result, status_code=200)
|
src/apis/routes/post_router.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
from fastapi import APIRouter, status, Depends
|
| 2 |
from typing import Annotated, Optional
|
| 3 |
from fastapi.responses import JSONResponse
|
| 4 |
from pydantic import Field
|
|
@@ -12,6 +12,7 @@ from src.apis.controllers.post_controller import (
|
|
| 12 |
update_a_post_controller,
|
| 13 |
delete_a_post_controller,
|
| 14 |
)
|
|
|
|
| 15 |
from src.utils.logger import logger
|
| 16 |
|
| 17 |
router = APIRouter(prefix="/post", tags=["Post"])
|
|
@@ -60,8 +61,13 @@ async def get_post(post_id: str):
|
|
| 60 |
|
| 61 |
|
| 62 |
@router.get("/list", status_code=status.HTTP_200_OK)
|
| 63 |
-
async def list_all_posts():
|
| 64 |
-
result = await
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
if result["status"] == "error":
|
| 66 |
return JSONResponse(content=result, status_code=404)
|
| 67 |
else:
|
|
@@ -69,8 +75,9 @@ async def list_all_posts():
|
|
| 69 |
|
| 70 |
|
| 71 |
class BodyUpdatePost(BaseDocument):
|
| 72 |
-
content:
|
| 73 |
-
|
|
|
|
| 74 |
|
| 75 |
class Config:
|
| 76 |
json_schema_extra = {
|
|
@@ -81,13 +88,13 @@ class BodyUpdatePost(BaseDocument):
|
|
| 81 |
}
|
| 82 |
|
| 83 |
|
| 84 |
-
@router.patch("/update/
|
| 85 |
-
async def update_post(
|
| 86 |
if user is None:
|
| 87 |
return JSONResponse(content={"message": "User not found"}, status_code=404)
|
| 88 |
result = await update_a_post_controller(
|
| 89 |
user["id"],
|
| 90 |
-
post_id,
|
| 91 |
body.content,
|
| 92 |
body.destination_id,
|
| 93 |
)
|
|
|
|
| 1 |
+
from fastapi import APIRouter, status, Depends, BackgroundTasks
|
| 2 |
from typing import Annotated, Optional
|
| 3 |
from fastapi.responses import JSONResponse
|
| 4 |
from pydantic import Field
|
|
|
|
| 12 |
update_a_post_controller,
|
| 13 |
delete_a_post_controller,
|
| 14 |
)
|
| 15 |
+
from src.utils.redis import set_key_redis, get_key_redis
|
| 16 |
from src.utils.logger import logger
|
| 17 |
|
| 18 |
router = APIRouter(prefix="/post", tags=["Post"])
|
|
|
|
| 61 |
|
| 62 |
|
| 63 |
@router.get("/list", status_code=status.HTTP_200_OK)
|
| 64 |
+
async def list_all_posts(background_tasks: BackgroundTasks):
|
| 65 |
+
# result = await get_key_redis("all_posts")
|
| 66 |
+
result = None
|
| 67 |
+
result = eval(result) if result else None
|
| 68 |
+
if not result:
|
| 69 |
+
result = await list_all_posts_controller()
|
| 70 |
+
# background_tasks.add_task(set_key_redis, "all_posts", str(result),20)
|
| 71 |
if result["status"] == "error":
|
| 72 |
return JSONResponse(content=result, status_code=404)
|
| 73 |
else:
|
|
|
|
| 75 |
|
| 76 |
|
| 77 |
class BodyUpdatePost(BaseDocument):
|
| 78 |
+
content: str = Field(..., description="Post's content", min_length=1)
|
| 79 |
+
post_id: str = Field(..., description="Post's id", min_length=1)
|
| 80 |
+
destination_id: str = Field(..., description="Destination's id", min_length=1)
|
| 81 |
|
| 82 |
class Config:
|
| 83 |
json_schema_extra = {
|
|
|
|
| 88 |
}
|
| 89 |
|
| 90 |
|
| 91 |
+
@router.patch("/update/", status_code=status.HTTP_200_OK)
|
| 92 |
+
async def update_post(body: BodyUpdatePost, user: user_dependency):
|
| 93 |
if user is None:
|
| 94 |
return JSONResponse(content={"message": "User not found"}, status_code=404)
|
| 95 |
result = await update_a_post_controller(
|
| 96 |
user["id"],
|
| 97 |
+
body.post_id,
|
| 98 |
body.content,
|
| 99 |
body.destination_id,
|
| 100 |
)
|
src/langgraph/.DS_Store
CHANGED
|
Binary files a/src/langgraph/.DS_Store and b/src/langgraph/.DS_Store differ
|
|
|
src/langgraph/multi_agent/.DS_Store
CHANGED
|
Binary files a/src/langgraph/multi_agent/.DS_Store and b/src/langgraph/multi_agent/.DS_Store differ
|
|
|
src/langgraph/multi_agent/chat/__pycache__/chat_flow.cpython-311.pyc
CHANGED
|
Binary files a/src/langgraph/multi_agent/chat/__pycache__/chat_flow.cpython-311.pyc and b/src/langgraph/multi_agent/chat/__pycache__/chat_flow.cpython-311.pyc differ
|
|
|
src/langgraph/multi_agent/chat/chat_flow.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
from langgraph.graph import END,
|
| 2 |
from langchain_community.tools.tavily_search import TavilySearchResults
|
| 3 |
from langgraph.prebuilt import tools_condition
|
| 4 |
from src.langgraph.langchain.llm import llm
|
|
@@ -19,7 +19,6 @@ from src.langgraph.utils_function.function_graph import (
|
|
| 19 |
from src.langgraph.tools.destination_tools import destination_recommendation
|
| 20 |
from src.utils.logger import logger
|
| 21 |
|
| 22 |
-
# Primary Assistant
|
| 23 |
primary_assistant_tools = [
|
| 24 |
TavilySearchResults(max_results=2),
|
| 25 |
destination_recommendation,
|
|
@@ -96,7 +95,6 @@ class ChatBot:
|
|
| 96 |
raise ValueError("Invalid route")
|
| 97 |
|
| 98 |
def node(self):
|
| 99 |
-
|
| 100 |
self.builder.add_node("leave_skill", leave_skill_fn)
|
| 101 |
self.builder.add_node("fetch_history", get_history)
|
| 102 |
self.builder.add_node("classify_intent", classify_user_intent_fn)
|
|
|
|
| 1 |
+
from langgraph.graph import END, START, StateGraph
|
| 2 |
from langchain_community.tools.tavily_search import TavilySearchResults
|
| 3 |
from langgraph.prebuilt import tools_condition
|
| 4 |
from src.langgraph.langchain.llm import llm
|
|
|
|
| 19 |
from src.langgraph.tools.destination_tools import destination_recommendation
|
| 20 |
from src.utils.logger import logger
|
| 21 |
|
|
|
|
| 22 |
primary_assistant_tools = [
|
| 23 |
TavilySearchResults(max_results=2),
|
| 24 |
destination_recommendation,
|
|
|
|
| 95 |
raise ValueError("Invalid route")
|
| 96 |
|
| 97 |
def node(self):
|
|
|
|
| 98 |
self.builder.add_node("leave_skill", leave_skill_fn)
|
| 99 |
self.builder.add_node("fetch_history", get_history)
|
| 100 |
self.builder.add_node("classify_intent", classify_user_intent_fn)
|
src/langgraph/multi_agent/planner/__pycache__/react_agent.cpython-311.pyc
CHANGED
|
Binary files a/src/langgraph/multi_agent/planner/__pycache__/react_agent.cpython-311.pyc and b/src/langgraph/multi_agent/planner/__pycache__/react_agent.cpython-311.pyc differ
|
|
|
src/langgraph/multi_agent/planner/react_agent.py
CHANGED
|
@@ -20,100 +20,6 @@ def create_react_agent(
|
|
| 20 |
*,
|
| 21 |
stop_sequence: Union[bool, List[str]] = True,
|
| 22 |
) -> Runnable:
|
| 23 |
-
"""Create an agent that uses ReAct prompting.
|
| 24 |
-
|
| 25 |
-
Based on paper "ReAct: Synergizing Reasoning and Acting in Language Models"
|
| 26 |
-
(https://arxiv.org/abs/2210.03629)
|
| 27 |
-
|
| 28 |
-
.. warning::
|
| 29 |
-
This implementation is based on the foundational ReAct paper but is older and not well-suited for production applications.
|
| 30 |
-
For a more robust and feature-rich implementation, we recommend using the `create_react_agent` function from the LangGraph library.
|
| 31 |
-
See the [reference doc](https://langchain-ai.github.io/langgraph/reference/prebuilt/#langgraph.prebuilt.chat_agent_executor.create_react_agent)
|
| 32 |
-
for more information.
|
| 33 |
-
|
| 34 |
-
Args:
|
| 35 |
-
llm: LLM to use as the agent.
|
| 36 |
-
tools: Tools this agent has access to.
|
| 37 |
-
prompt: The prompt to use. See Prompt section below for more.
|
| 38 |
-
output_parser: AgentOutputParser for parse the LLM output.
|
| 39 |
-
tools_renderer: This controls how the tools are converted into a string and
|
| 40 |
-
then passed into the LLM. Default is `render_text_description`.
|
| 41 |
-
stop_sequence: bool or list of str.
|
| 42 |
-
If True, adds a stop token of "Observation:" to avoid hallucinates.
|
| 43 |
-
If False, does not add a stop token.
|
| 44 |
-
If a list of str, uses the provided list as the stop tokens.
|
| 45 |
-
|
| 46 |
-
Default is True. You may to set this to False if the LLM you are using
|
| 47 |
-
does not support stop sequences.
|
| 48 |
-
|
| 49 |
-
Returns:
|
| 50 |
-
A Runnable sequence representing an agent. It takes as input all the same input
|
| 51 |
-
variables as the prompt passed in does. It returns as output either an
|
| 52 |
-
AgentAction or AgentFinish.
|
| 53 |
-
|
| 54 |
-
Examples:
|
| 55 |
-
|
| 56 |
-
.. code-block:: python
|
| 57 |
-
|
| 58 |
-
from langchain import hub
|
| 59 |
-
from langchain_community.llms import OpenAI
|
| 60 |
-
from langchain.agents import AgentExecutor, create_react_agent
|
| 61 |
-
|
| 62 |
-
prompt = hub.pull("hwchase17/react")
|
| 63 |
-
model = OpenAI()
|
| 64 |
-
tools = ...
|
| 65 |
-
|
| 66 |
-
agent = create_react_agent(model, tools, prompt)
|
| 67 |
-
agent_executor = AgentExecutor(agent=agent, tools=tools)
|
| 68 |
-
|
| 69 |
-
agent_executor.invoke({"input": "hi"})
|
| 70 |
-
|
| 71 |
-
# Use with chat history
|
| 72 |
-
from langchain_core.messages import AIMessage, HumanMessage
|
| 73 |
-
agent_executor.invoke(
|
| 74 |
-
{
|
| 75 |
-
"input": "what's my name?",
|
| 76 |
-
# Notice that chat_history is a string
|
| 77 |
-
# since this prompt is aimed at LLMs, not chat models
|
| 78 |
-
"chat_history": "Human: My name is Bob\\nAI: Hello Bob!",
|
| 79 |
-
}
|
| 80 |
-
)
|
| 81 |
-
|
| 82 |
-
Prompt:
|
| 83 |
-
|
| 84 |
-
The prompt must have input keys:
|
| 85 |
-
* `tools`: contains descriptions and arguments for each tool.
|
| 86 |
-
* `tool_names`: contains all tool names.
|
| 87 |
-
* `agent_scratchpad`: contains previous agent actions and tool outputs as a string.
|
| 88 |
-
|
| 89 |
-
Here's an example:
|
| 90 |
-
|
| 91 |
-
.. code-block:: python
|
| 92 |
-
|
| 93 |
-
from langchain_core.prompts import PromptTemplate
|
| 94 |
-
|
| 95 |
-
template = '''Answer the following questions as best you can. You have access to the following tools:
|
| 96 |
-
|
| 97 |
-
{tools}
|
| 98 |
-
|
| 99 |
-
Use the following format:
|
| 100 |
-
|
| 101 |
-
Question: the input question you must answer
|
| 102 |
-
Thought: you should always think about what to do
|
| 103 |
-
Action: the action to take, should be one of [{tool_names}]
|
| 104 |
-
Action Input: the input to the action
|
| 105 |
-
Observation: the result of the action
|
| 106 |
-
... (this Thought/Action/Action Input/Observation can repeat N times)
|
| 107 |
-
Thought: I now know the final answer
|
| 108 |
-
Final Answer: the final answer to the original input question
|
| 109 |
-
|
| 110 |
-
Begin!
|
| 111 |
-
|
| 112 |
-
Question: {input}
|
| 113 |
-
Thought:{agent_scratchpad}'''
|
| 114 |
-
|
| 115 |
-
prompt = PromptTemplate.from_template(template)
|
| 116 |
-
""" # noqa: E501
|
| 117 |
missing_vars = {"tools", "tool_names", "agent_scratchpad"}.difference(
|
| 118 |
prompt.input_variables + list(prompt.partial_variables)
|
| 119 |
)
|
|
@@ -125,7 +31,11 @@ def create_react_agent(
|
|
| 125 |
tool_names=", ".join([t.name for t in tools]),
|
| 126 |
)
|
| 127 |
if stop_sequence:
|
| 128 |
-
stop =
|
|
|
|
|
|
|
|
|
|
|
|
|
| 129 |
llm_with_stop = llm.bind(stop=stop)
|
| 130 |
else:
|
| 131 |
llm_with_stop = llm
|
|
|
|
| 20 |
*,
|
| 21 |
stop_sequence: Union[bool, List[str]] = True,
|
| 22 |
) -> Runnable:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
missing_vars = {"tools", "tool_names", "agent_scratchpad"}.difference(
|
| 24 |
prompt.input_variables + list(prompt.partial_variables)
|
| 25 |
)
|
|
|
|
| 31 |
tool_names=", ".join([t.name for t in tools]),
|
| 32 |
)
|
| 33 |
if stop_sequence:
|
| 34 |
+
stop = (
|
| 35 |
+
["\nObservation", "\nFinal", "Answer:"]
|
| 36 |
+
if stop_sequence is True
|
| 37 |
+
else stop_sequence
|
| 38 |
+
)
|
| 39 |
llm_with_stop = llm.bind(stop=stop)
|
| 40 |
else:
|
| 41 |
llm_with_stop = llm
|
src/utils/.DS_Store
CHANGED
|
Binary files a/src/utils/.DS_Store and b/src/utils/.DS_Store differ
|
|
|
src/utils/__pycache__/mongo.cpython-311.pyc
CHANGED
|
Binary files a/src/utils/__pycache__/mongo.cpython-311.pyc and b/src/utils/__pycache__/mongo.cpython-311.pyc differ
|
|
|
src/utils/__pycache__/redis.cpython-311.pyc
CHANGED
|
Binary files a/src/utils/__pycache__/redis.cpython-311.pyc and b/src/utils/__pycache__/redis.cpython-311.pyc differ
|
|
|
src/utils/mongo.py
CHANGED
|
@@ -93,7 +93,7 @@ class MongoCRUD:
|
|
| 93 |
async def update(self, query: Dict, data: Dict) -> int:
|
| 94 |
"""Update documents in the collection based on a query asynchronously."""
|
| 95 |
await self._ensure_ttl_index()
|
| 96 |
-
data["updated_at"] =
|
| 97 |
if self.ttl_seconds is not None:
|
| 98 |
data["expire_at"] = data["updated_at"] + timedelta(seconds=self.ttl_seconds)
|
| 99 |
update_data = self.model(**data).model_dump(exclude_unset=True)
|
|
|
|
| 93 |
async def update(self, query: Dict, data: Dict) -> int:
|
| 94 |
"""Update documents in the collection based on a query asynchronously."""
|
| 95 |
await self._ensure_ttl_index()
|
| 96 |
+
data["updated_at"] = get_date_time().replace(tzinfo=None)
|
| 97 |
if self.ttl_seconds is not None:
|
| 98 |
data["expire_at"] = data["updated_at"] + timedelta(seconds=self.ttl_seconds)
|
| 99 |
update_data = self.model(**data).model_dump(exclude_unset=True)
|
src/utils/redis.py
CHANGED
|
@@ -11,6 +11,7 @@ async def set_key_redis(key, value, time=300):
|
|
| 11 |
|
| 12 |
|
| 13 |
async def get_key_redis(key):
|
|
|
|
| 14 |
return await redis_client.get(key)
|
| 15 |
|
| 16 |
|
|
|
|
| 11 |
|
| 12 |
|
| 13 |
async def get_key_redis(key):
|
| 14 |
+
|
| 15 |
return await redis_client.get(key)
|
| 16 |
|
| 17 |
|