|
import os |
|
from flask import Blueprint, request, jsonify |
|
import requests |
|
from pymongo import MongoClient |
|
from bson.objectid import ObjectId |
|
from werkzeug.utils import secure_filename |
|
|
|
from application.api.user.tasks import ingest |
|
|
|
from application.core.settings import settings |
|
from application.vectorstore.vector_creator import VectorCreator |
|
|
|
mongo = MongoClient(settings.MONGO_URI) |
|
db = mongo["docsgpt"] |
|
conversations_collection = db["conversations"] |
|
vectors_collection = db["vectors"] |
|
prompts_collection = db["prompts"] |
|
feedback_collection = db["feedback"] |
|
user = Blueprint('user', __name__) |
|
|
|
current_dir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) |
|
|
|
@user.route("/api/delete_conversation", methods=["POST"]) |
|
def delete_conversation(): |
|
|
|
conversation_id = request.args.get("id") |
|
|
|
conversations_collection.delete_one( |
|
{ |
|
"_id": ObjectId(conversation_id), |
|
} |
|
) |
|
|
|
return {"status": "ok"} |
|
|
|
@user.route("/api/get_conversations", methods=["get"]) |
|
def get_conversations(): |
|
|
|
conversations = conversations_collection.find().sort("date", -1) |
|
list_conversations = [] |
|
for conversation in conversations: |
|
list_conversations.append({"id": str(conversation["_id"]), "name": conversation["name"]}) |
|
|
|
|
|
|
|
return jsonify(list_conversations) |
|
|
|
|
|
@user.route("/api/get_single_conversation", methods=["get"]) |
|
def get_single_conversation(): |
|
|
|
conversation_id = request.args.get("id") |
|
conversation = conversations_collection.find_one({"_id": ObjectId(conversation_id)}) |
|
return jsonify(conversation['queries']) |
|
|
|
@user.route("/api/update_conversation_name", methods=["POST"]) |
|
def update_conversation_name(): |
|
|
|
data = request.get_json() |
|
id = data["id"] |
|
name = data["name"] |
|
conversations_collection.update_one({"_id": ObjectId(id)},{"$set":{"name":name}}) |
|
return {"status": "ok"} |
|
|
|
|
|
@user.route("/api/feedback", methods=["POST"]) |
|
def api_feedback(): |
|
data = request.get_json() |
|
question = data["question"] |
|
answer = data["answer"] |
|
feedback = data["feedback"] |
|
|
|
|
|
feedback_collection.insert_one( |
|
{ |
|
"question": question, |
|
"answer": answer, |
|
"feedback": feedback, |
|
} |
|
) |
|
return {"status": "ok"} |
|
|
|
@user.route("/api/delete_by_ids", methods=["get"]) |
|
def delete_by_ids(): |
|
"""Delete by ID. These are the IDs in the vectorstore""" |
|
|
|
ids = request.args.get("path") |
|
if not ids: |
|
return {"status": "error"} |
|
|
|
if settings.VECTOR_STORE == "faiss": |
|
result = vectors_collection.delete_index(ids=ids) |
|
if result: |
|
return {"status": "ok"} |
|
return {"status": "error"} |
|
|
|
@user.route("/api/delete_old", methods=["get"]) |
|
def delete_old(): |
|
"""Delete old indexes.""" |
|
import shutil |
|
|
|
path = request.args.get("path") |
|
dirs = path.split("/") |
|
dirs_clean = [] |
|
for i in range(0, len(dirs)): |
|
dirs_clean.append(secure_filename(dirs[i])) |
|
|
|
|
|
if dirs_clean[0] not in ["indexes", "vectors"]: |
|
return {"status": "error"} |
|
path_clean = "/".join(dirs_clean) |
|
vectors_collection.delete_one({"name": dirs_clean[-1], 'user': dirs_clean[-2]}) |
|
if settings.VECTOR_STORE == "faiss": |
|
try: |
|
shutil.rmtree(os.path.join(current_dir, path_clean)) |
|
except FileNotFoundError: |
|
pass |
|
else: |
|
vetorstore = VectorCreator.create_vectorstore( |
|
settings.VECTOR_STORE, path=os.path.join(current_dir, path_clean) |
|
) |
|
vetorstore.delete_index() |
|
|
|
return {"status": "ok"} |
|
|
|
@user.route("/api/upload", methods=["POST"]) |
|
def upload_file(): |
|
"""Upload a file to get vectorized and indexed.""" |
|
if "user" not in request.form: |
|
return {"status": "no user"} |
|
user = secure_filename(request.form["user"]) |
|
if "name" not in request.form: |
|
return {"status": "no name"} |
|
job_name = secure_filename(request.form["name"]) |
|
|
|
if "file" not in request.files: |
|
print("No file part") |
|
return {"status": "no file"} |
|
file = request.files["file"] |
|
if file.filename == "": |
|
return {"status": "no file name"} |
|
|
|
if file: |
|
filename = secure_filename(file.filename) |
|
|
|
save_dir = os.path.join(current_dir, settings.UPLOAD_FOLDER, user, job_name) |
|
|
|
if not os.path.exists(save_dir): |
|
os.makedirs(save_dir) |
|
|
|
file.save(os.path.join(save_dir, filename)) |
|
task = ingest.delay(settings.UPLOAD_FOLDER, [".rst", ".md", ".pdf", ".txt", ".docx", |
|
".csv", ".epub", ".html", ".mdx"], |
|
job_name, filename, user) |
|
|
|
task_id = task.id |
|
return {"status": "ok", "task_id": task_id} |
|
else: |
|
return {"status": "error"} |
|
|
|
@user.route("/api/task_status", methods=["GET"]) |
|
def task_status(): |
|
"""Get celery job status.""" |
|
task_id = request.args.get("task_id") |
|
from application.celery import celery |
|
task = celery.AsyncResult(task_id) |
|
task_meta = task.info |
|
return {"status": task.status, "result": task_meta} |
|
|
|
|
|
@user.route("/api/combine", methods=["GET"]) |
|
def combined_json(): |
|
user = "local" |
|
"""Provide json file with combined available indexes.""" |
|
|
|
|
|
data = [ |
|
{ |
|
"name": "default", |
|
"language": "default", |
|
"version": "", |
|
"description": "default", |
|
"fullName": "default", |
|
"date": "default", |
|
"docLink": "default", |
|
"model": settings.EMBEDDINGS_NAME, |
|
"location": "remote", |
|
} |
|
] |
|
|
|
|
|
for index in vectors_collection.find({"user": user}): |
|
data.append( |
|
{ |
|
"name": index["name"], |
|
"language": index["language"], |
|
"version": "", |
|
"description": index["name"], |
|
"fullName": index["name"], |
|
"date": index["date"], |
|
"docLink": index["location"], |
|
"model": settings.EMBEDDINGS_NAME, |
|
"location": "local", |
|
} |
|
) |
|
if settings.VECTOR_STORE == "faiss": |
|
data_remote = requests.get("https://d3dg1063dc54p9.cloudfront.net/combined.json").json() |
|
for index in data_remote: |
|
index["location"] = "remote" |
|
data.append(index) |
|
|
|
return jsonify(data) |
|
|
|
|
|
@user.route("/api/docs_check", methods=["POST"]) |
|
def check_docs(): |
|
|
|
data = request.get_json() |
|
|
|
if data["docs"].split("/")[0] == "local": |
|
return {"status": "exists"} |
|
vectorstore = "vectors/" + data["docs"] |
|
base_path = "https://raw.githubusercontent.com/arc53/DocsHUB/main/" |
|
if os.path.exists(vectorstore) or data["docs"] == "default": |
|
return {"status": "exists"} |
|
else: |
|
r = requests.get(base_path + vectorstore + "index.faiss") |
|
|
|
if r.status_code != 200: |
|
return {"status": "null"} |
|
else: |
|
if not os.path.exists(vectorstore): |
|
os.makedirs(vectorstore) |
|
with open(vectorstore + "index.faiss", "wb") as f: |
|
f.write(r.content) |
|
|
|
|
|
r = requests.get(base_path + vectorstore + "index.pkl") |
|
with open(vectorstore + "index.pkl", "wb") as f: |
|
f.write(r.content) |
|
|
|
return {"status": "loaded"} |
|
|
|
@user.route("/api/create_prompt", methods=["POST"]) |
|
def create_prompt(): |
|
data = request.get_json() |
|
content = data["content"] |
|
name = data["name"] |
|
if name == "": |
|
return {"status": "error"} |
|
user = "local" |
|
resp = prompts_collection.insert_one( |
|
{ |
|
"name": name, |
|
"content": content, |
|
"user": user, |
|
} |
|
) |
|
new_id = str(resp.inserted_id) |
|
return {"id": new_id} |
|
|
|
@user.route("/api/get_prompts", methods=["GET"]) |
|
def get_prompts(): |
|
user = "local" |
|
prompts = prompts_collection.find({"user": user}) |
|
list_prompts = [] |
|
list_prompts.append({"id": "default", "name": "default", "type": "public"}) |
|
list_prompts.append({"id": "creative", "name": "creative", "type": "public"}) |
|
list_prompts.append({"id": "strict", "name": "strict", "type": "public"}) |
|
for prompt in prompts: |
|
list_prompts.append({"id": str(prompt["_id"]), "name": prompt["name"], "type": "private"}) |
|
|
|
return jsonify(list_prompts) |
|
|
|
@user.route("/api/get_single_prompt", methods=["GET"]) |
|
def get_single_prompt(): |
|
prompt_id = request.args.get("id") |
|
if prompt_id == 'default': |
|
with open(os.path.join(current_dir, "prompts", "chat_combine_default.txt"), "r") as f: |
|
chat_combine_template = f.read() |
|
return jsonify({"content": chat_combine_template}) |
|
elif prompt_id == 'creative': |
|
with open(os.path.join(current_dir, "prompts", "chat_combine_creative.txt"), "r") as f: |
|
chat_reduce_creative = f.read() |
|
return jsonify({"content": chat_reduce_creative}) |
|
elif prompt_id == 'strict': |
|
with open(os.path.join(current_dir, "prompts", "chat_combine_strict.txt"), "r") as f: |
|
chat_reduce_strict = f.read() |
|
return jsonify({"content": chat_reduce_strict}) |
|
|
|
|
|
prompt = prompts_collection.find_one({"_id": ObjectId(prompt_id)}) |
|
return jsonify({"content": prompt["content"]}) |
|
|
|
@user.route("/api/delete_prompt", methods=["POST"]) |
|
def delete_prompt(): |
|
data = request.get_json() |
|
id = data["id"] |
|
prompts_collection.delete_one( |
|
{ |
|
"_id": ObjectId(id), |
|
} |
|
) |
|
return {"status": "ok"} |
|
|
|
@user.route("/api/update_prompt", methods=["POST"]) |
|
def update_prompt_name(): |
|
data = request.get_json() |
|
id = data["id"] |
|
name = data["name"] |
|
content = data["content"] |
|
|
|
if name == "": |
|
return {"status": "error"} |
|
prompts_collection.update_one({"_id": ObjectId(id)},{"$set":{"name":name, "content": content}}) |
|
return {"status": "ok"} |
|
|
|
|
|
|
|
|
|
|
|
|