mirror of
https://github.com/arc53/DocsGPT.git
synced 2025-11-29 08:33:20 +00:00
226 lines
6.3 KiB
Python
226 lines
6.3 KiB
Python
"""
|
|
Shared utilities, database connections, and helper functions for user API routes.
|
|
"""
|
|
|
|
import datetime
|
|
import os
|
|
import uuid
|
|
from functools import wraps
|
|
from typing import Optional, Tuple
|
|
|
|
from bson.dbref import DBRef
|
|
from bson.objectid import ObjectId
|
|
from flask import current_app, jsonify, make_response, Response
|
|
from pymongo import ReturnDocument
|
|
from werkzeug.utils import secure_filename
|
|
|
|
from application.core.mongo_db import MongoDB
|
|
from application.core.settings import settings
|
|
from application.storage.storage_creator import StorageCreator
|
|
from application.vectorstore.vector_creator import VectorCreator
|
|
|
|
|
|
storage = StorageCreator.get_storage()
|
|
|
|
|
|
mongo = MongoDB.get_client()
|
|
db = mongo[settings.MONGO_DB_NAME]
|
|
|
|
|
|
conversations_collection = db["conversations"]
|
|
sources_collection = db["sources"]
|
|
prompts_collection = db["prompts"]
|
|
feedback_collection = db["feedback"]
|
|
agents_collection = db["agents"]
|
|
token_usage_collection = db["token_usage"]
|
|
shared_conversations_collections = db["shared_conversations"]
|
|
users_collection = db["users"]
|
|
user_logs_collection = db["user_logs"]
|
|
user_tools_collection = db["user_tools"]
|
|
attachments_collection = db["attachments"]
|
|
|
|
|
|
try:
|
|
agents_collection.create_index(
|
|
[("shared", 1)],
|
|
name="shared_index",
|
|
background=True,
|
|
)
|
|
users_collection.create_index("user_id", unique=True)
|
|
except Exception as e:
|
|
print("Error creating indexes:", e)
|
|
|
|
|
|
current_dir = os.path.dirname(
|
|
os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
)
|
|
|
|
|
|
def generate_minute_range(start_date, end_date):
|
|
"""Generate a dictionary with minute-level time ranges."""
|
|
return {
|
|
(start_date + datetime.timedelta(minutes=i)).strftime("%Y-%m-%d %H:%M:00"): 0
|
|
for i in range(int((end_date - start_date).total_seconds() // 60) + 1)
|
|
}
|
|
|
|
|
|
def generate_hourly_range(start_date, end_date):
|
|
"""Generate a dictionary with hourly time ranges."""
|
|
return {
|
|
(start_date + datetime.timedelta(hours=i)).strftime("%Y-%m-%d %H:00"): 0
|
|
for i in range(int((end_date - start_date).total_seconds() // 3600) + 1)
|
|
}
|
|
|
|
|
|
def generate_date_range(start_date, end_date):
|
|
"""Generate a dictionary with daily date ranges."""
|
|
return {
|
|
(start_date + datetime.timedelta(days=i)).strftime("%Y-%m-%d"): 0
|
|
for i in range((end_date - start_date).days + 1)
|
|
}
|
|
|
|
|
|
def ensure_user_doc(user_id):
|
|
"""
|
|
Ensure user document exists with proper agent preferences structure.
|
|
|
|
Args:
|
|
user_id: The user ID to ensure
|
|
|
|
Returns:
|
|
The user document
|
|
"""
|
|
default_prefs = {
|
|
"pinned": [],
|
|
"shared_with_me": [],
|
|
}
|
|
|
|
user_doc = users_collection.find_one_and_update(
|
|
{"user_id": user_id},
|
|
{"$setOnInsert": {"agent_preferences": default_prefs}},
|
|
upsert=True,
|
|
return_document=ReturnDocument.AFTER,
|
|
)
|
|
|
|
prefs = user_doc.get("agent_preferences", {})
|
|
updates = {}
|
|
if "pinned" not in prefs:
|
|
updates["agent_preferences.pinned"] = []
|
|
if "shared_with_me" not in prefs:
|
|
updates["agent_preferences.shared_with_me"] = []
|
|
if updates:
|
|
users_collection.update_one({"user_id": user_id}, {"$set": updates})
|
|
user_doc = users_collection.find_one({"user_id": user_id})
|
|
return user_doc
|
|
|
|
|
|
def resolve_tool_details(tool_ids):
|
|
"""
|
|
Resolve tool IDs to their details.
|
|
|
|
Args:
|
|
tool_ids: List of tool IDs
|
|
|
|
Returns:
|
|
List of tool details with id, name, and display_name
|
|
"""
|
|
tools = user_tools_collection.find(
|
|
{"_id": {"$in": [ObjectId(tid) for tid in tool_ids]}}
|
|
)
|
|
return [
|
|
{
|
|
"id": str(tool["_id"]),
|
|
"name": tool.get("name", ""),
|
|
"display_name": tool.get("displayName", tool.get("name", "")),
|
|
}
|
|
for tool in tools
|
|
]
|
|
|
|
|
|
def get_vector_store(source_id):
|
|
"""
|
|
Get the Vector Store for a given source ID.
|
|
|
|
Args:
|
|
source_id (str): source id of the document
|
|
|
|
Returns:
|
|
Vector store instance
|
|
"""
|
|
store = VectorCreator.create_vectorstore(
|
|
settings.VECTOR_STORE,
|
|
source_id=source_id,
|
|
embeddings_key=os.getenv("EMBEDDINGS_KEY"),
|
|
)
|
|
return store
|
|
|
|
|
|
def handle_image_upload(
|
|
request, existing_url: str, user: str, storage, base_path: str = "attachments/"
|
|
) -> Tuple[str, Optional[Response]]:
|
|
"""
|
|
Handle image file upload from request.
|
|
|
|
Args:
|
|
request: Flask request object
|
|
existing_url: Existing image URL (fallback)
|
|
user: User ID
|
|
storage: Storage instance
|
|
base_path: Base path for upload
|
|
|
|
Returns:
|
|
Tuple of (image_url, error_response)
|
|
"""
|
|
image_url = existing_url
|
|
|
|
if "image" in request.files:
|
|
file = request.files["image"]
|
|
if file.filename != "":
|
|
filename = secure_filename(file.filename)
|
|
upload_path = f"{settings.UPLOAD_FOLDER.rstrip('/')}/{user}/{base_path.rstrip('/')}/{uuid.uuid4()}_{filename}"
|
|
try:
|
|
storage.save_file(file, upload_path, storage_class="STANDARD")
|
|
image_url = upload_path
|
|
except Exception as e:
|
|
current_app.logger.error(f"Error uploading image: {e}")
|
|
return None, make_response(
|
|
jsonify({"success": False, "message": "Image upload failed"}),
|
|
400,
|
|
)
|
|
return image_url, None
|
|
|
|
|
|
def require_agent(func):
|
|
"""
|
|
Decorator to require valid agent webhook token.
|
|
|
|
Args:
|
|
func: Function to decorate
|
|
|
|
Returns:
|
|
Wrapped function
|
|
"""
|
|
|
|
@wraps(func)
|
|
def wrapper(*args, **kwargs):
|
|
webhook_token = kwargs.get("webhook_token")
|
|
if not webhook_token:
|
|
return make_response(
|
|
jsonify({"success": False, "message": "Webhook token missing"}), 400
|
|
)
|
|
agent = agents_collection.find_one(
|
|
{"incoming_webhook_token": webhook_token}, {"_id": 1}
|
|
)
|
|
if not agent:
|
|
current_app.logger.warning(
|
|
f"Webhook attempt with invalid token: {webhook_token}"
|
|
)
|
|
return make_response(
|
|
jsonify({"success": False, "message": "Agent not found"}), 404
|
|
)
|
|
kwargs["agent"] = agent
|
|
kwargs["agent_id_str"] = str(agent["_id"])
|
|
return func(*args, **kwargs)
|
|
|
|
return wrapper
|