updated sops apis and questions generator

This commit is contained in:
2024-09-25 21:40:08 +00:00
parent 1bfc773782
commit cd10cdaf7d
11 changed files with 84 additions and 114 deletions
+1 -1
View File
@@ -4,4 +4,4 @@ app = create_app()
if __name__ == '__main__': if __name__ == '__main__':
app.run(debug=True, port=5402) app.run(host='0.0.0.0', port=5402, debug=True)
+6
View File
@@ -5,6 +5,7 @@ from src.services.chatbot import Chatbot
from src.utils.utils import delete_all_files_in_directory from src.utils.utils import delete_all_files_in_directory
from src.utils.document_loader import load_document from src.utils.document_loader import load_document
from src.services.chatbot import Chatbot from src.services.chatbot import Chatbot
from src.utils.auth import auth_check
# Initialize the Blueprint # Initialize the Blueprint
@@ -18,6 +19,7 @@ def allowed_file(filename):
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
@bot.route('/validate_worker_document', methods=['POST']) @bot.route('/validate_worker_document', methods=['POST'])
@auth_check
def validate_worker_document(): def validate_worker_document():
try: try:
# Retrieve form data # Retrieve form data
@@ -63,6 +65,7 @@ def validate_worker_document():
@bot.route('/predict_next_n_assessments', methods=['POST']) @bot.route('/predict_next_n_assessments', methods=['POST'])
@auth_check
def predict_next_n_assessments(): def predict_next_n_assessments():
try: try:
# Retrieve JSON data from the request # Retrieve JSON data from the request
@@ -94,6 +97,7 @@ def predict_next_n_assessments():
@bot.route('/use_bot_predict_assessments', methods=['POST']) @bot.route('/use_bot_predict_assessments', methods=['POST'])
@auth_check
def use_bot_predict_assessments(): def use_bot_predict_assessments():
try: try:
# Retrieve JSON data from the request # Retrieve JSON data from the request
@@ -124,6 +128,7 @@ def use_bot_predict_assessments():
@bot.route('/suggest_assessment_frequencies', methods=['POST']) @bot.route('/suggest_assessment_frequencies', methods=['POST'])
@auth_check
def use_bot_suggest_frequencies(): def use_bot_suggest_frequencies():
try: try:
# Retrieve JSON data from the request # Retrieve JSON data from the request
@@ -155,6 +160,7 @@ def use_bot_suggest_frequencies():
@bot.route('/predict_goal_achievment_proba', methods=['POST']) @bot.route('/predict_goal_achievment_proba', methods=['POST'])
@auth_check
def predict_goal_achievement(): def predict_goal_achievement():
try: try:
# Retrieve JSON data from the request # Retrieve JSON data from the request
+3
View File
@@ -9,6 +9,7 @@ from src.services.questions_generator import QuestionsGenerator
from src.utils.utils import delete_all_files_in_directory from src.utils.utils import delete_all_files_in_directory
from src.utils.document_loader import load_document from src.utils.document_loader import load_document
import json import json
from src.utils.auth import auth_check
# Initialize the Blueprint # Initialize the Blueprint
qs_b = Blueprint('questions', __name__) qs_b = Blueprint('questions', __name__)
@@ -22,7 +23,9 @@ def allowed_file(filename):
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
@qs_b.route('/generate_questions_from_sop', methods=['POST']) @qs_b.route('/generate_questions_from_sop', methods=['POST'])
@auth_check
def generate_questions_from_sop(): def generate_questions_from_sop():
# Check if the request contains data # Check if the request contains data
if not request.is_json: if not request.is_json:
+15 -3
View File
@@ -3,6 +3,7 @@ from flask import Blueprint, request, jsonify, current_app
from werkzeug.utils import secure_filename from werkzeug.utils import secure_filename
from src.services.sop_generator import (SopPersonalAssessment,SopGeneratorExecutive) from src.services.sop_generator import (SopPersonalAssessment,SopGeneratorExecutive)
from src.services.sop_document_parser import DocumentParser from src.services.sop_document_parser import DocumentParser
from src.utils.auth import auth_check
from src.utils.utils import delete_all_files_in_directory from src.utils.utils import delete_all_files_in_directory
from src.utils.document_loader import load_document from src.utils.document_loader import load_document
@@ -20,6 +21,7 @@ def allowed_file(filename):
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
@sops_bp.route('/personal_assessment/get_roles_from_doc', methods=['POST']) @sops_bp.route('/personal_assessment/get_roles_from_doc', methods=['POST'])
@auth_check
def get_roles(): def get_roles():
# Check if the post request has the file part # Check if the post request has the file part
if 'document' not in request.files: if 'document' not in request.files:
@@ -63,6 +65,7 @@ def get_roles():
@sops_bp.route('/personal_assessment/get_roles_from_questionnaire', methods=['POST']) @sops_bp.route('/personal_assessment/get_roles_from_questionnaire', methods=['POST'])
@auth_check
def get_roles_questionnaire(): def get_roles_questionnaire():
# Check if the post request has the file part # Check if the post request has the file part
questionnaire_data = request.json questionnaire_data = request.json
@@ -87,6 +90,7 @@ def get_roles_questionnaire():
@sops_bp.route('/personal_assessment/generate_sops_from_doc', methods=['POST']) @sops_bp.route('/personal_assessment/generate_sops_from_doc', methods=['POST'])
@auth_check
def generate_sops(): def generate_sops():
# Check if the POST request has the file part # Check if the POST request has the file part
if 'document' not in request.files: if 'document' not in request.files:
@@ -143,6 +147,7 @@ def generate_sops():
@sops_bp.route('/personal_assessment/generate_sops_from_questionnaire', methods=['POST']) @sops_bp.route('/personal_assessment/generate_sops_from_questionnaire', methods=['POST'])
@auth_check
def generate_sops_from_questionnaire_per(): def generate_sops_from_questionnaire_per():
""" """
Generate SOPs based on the questionnaire data provided in the request body. Generate SOPs based on the questionnaire data provided in the request body.
@@ -184,6 +189,7 @@ def generate_sops_from_questionnaire_per():
@sops_bp.route('/personal_assessment/generate_sops_by_roles_and_areas', methods=['POST']) @sops_bp.route('/personal_assessment/generate_sops_by_roles_and_areas', methods=['POST'])
@auth_check
def generate_sops_by_roles_and_areas(): def generate_sops_by_roles_and_areas():
""" """
Generate SOPs based on the roles, SOP types (will, shall, must), and areas provided in the request body. Generate SOPs based on the roles, SOP types (will, shall, must), and areas provided in the request body.
@@ -216,6 +222,7 @@ def generate_sops_by_roles_and_areas():
@sops_bp.route('/executive/generate_sop_mission_from_vision', methods=['POST']) @sops_bp.route('/executive/generate_sop_mission_from_vision', methods=['POST'])
@auth_check
def generate_executive_sops_from_doc(): def generate_executive_sops_from_doc():
""" """
Generate SOPs for executives based on a document containing vision and mission. Generate SOPs for executives based on a document containing vision and mission.
@@ -292,6 +299,7 @@ def generate_executive_sops_from_doc():
@sops_bp.route('/executive/generate_sop_managers_doc', methods=['POST']) @sops_bp.route('/executive/generate_sop_managers_doc', methods=['POST'])
@auth_check
def generate_sop_managers_doc(): def generate_sop_managers_doc():
if 'document' not in request.files: if 'document' not in request.files:
return jsonify({"error": "No file part", "message": "Please upload a file with the key 'document'."}), 400 return jsonify({"error": "No file part", "message": "Please upload a file with the key 'document'."}), 400
@@ -312,18 +320,18 @@ def generate_sop_managers_doc():
docs = load_document(file_path) docs = load_document(file_path)
# Load department managers from form data as a JSON string # Load department managers from form data as a JSON string
department_managers_json = request.form.get('department_managers', '[]') department_managers_json = request.form.get('departments_managers', '[]')
department_managers = json.loads(department_managers_json) department_managers = json.loads(department_managers_json)
sop_generator = DocumentParser() sop_generator = DocumentParser()
result = sop_generator.extract_sops_for_managers_by_department(docs, department_managers) result = sop_generator.extract_sops_for_workers_by_department(docs, department_managers)
delete_all_files_in_directory(upload_folder) delete_all_files_in_directory(upload_folder)
if not result: if not result:
return jsonify({"error": "Processing error", "message": "Failed to generate SOPs for department managers."}), 500 return jsonify({"error": "Processing error", "message": "Failed to generate SOPs for department managers."}), 500
return jsonify({"sops": result.dict(), "message": "SOPs successfully generated for department managers."}), 200 return jsonify({"sops": result, "message": "SOPs successfully generated for department managers."}), 200
except Exception as e: except Exception as e:
delete_all_files_in_directory(upload_folder) delete_all_files_in_directory(upload_folder)
@@ -334,6 +342,7 @@ def generate_sop_managers_doc():
@sops_bp.route('/executive/generate_sops_from_questionnaire', methods=['POST']) @sops_bp.route('/executive/generate_sops_from_questionnaire', methods=['POST'])
@auth_check
def generate_sops_from_questionnaire(): def generate_sops_from_questionnaire():
try: try:
data = request.json data = request.json
@@ -366,6 +375,7 @@ def generate_sops_from_questionnaire():
@sops_bp.route('/executive/get_roles_for_reference_managers', methods=['POST']) @sops_bp.route('/executive/get_roles_for_reference_managers', methods=['POST'])
@auth_check
def get_roles_for_reference_managers(): def get_roles_for_reference_managers():
try: try:
# Retrieve form data # Retrieve form data
@@ -409,6 +419,7 @@ def get_roles_for_reference_managers():
@sops_bp.route('/manager/get_roles_for_reference_workers', methods=['POST']) @sops_bp.route('/manager/get_roles_for_reference_workers', methods=['POST'])
@auth_check
def get_roles_for_reference_workers(): def get_roles_for_reference_workers():
try: try:
# Retrieve form data # Retrieve form data
@@ -450,6 +461,7 @@ def get_roles_for_reference_workers():
@sops_bp.route('/manager/generate_sop_workers_doc', methods=['POST']) @sops_bp.route('/manager/generate_sop_workers_doc', methods=['POST'])
@auth_check
def generate_sop_workers_doc(): def generate_sop_workers_doc():
try: try:
# Check if the document is provided # Check if the document is provided
+6 -3
View File
@@ -12,7 +12,7 @@ def get_questions_prompt():
Input: Input:
assessment type: (e.g., daily, weekly, biweekly) assessment type: (e.g., daily, weekly, biweekly)
frequency type: (e.g., daily, weekly, biweekly) frequency type: (e.g., daily, weekly, biweekly)
frequency number: (e.g., day 3, week 2, biweekly 1) frequency number(the current week or frequency e.g if assessment is weekly and frequcny number is 2 , it means week 2): (e.g., day 3, week 2, biweekly 1)
total duration: (e.g., 6 weeks, 12 days) total duration: (e.g., 6 weeks, 12 days)
SOPs of the assessment: SOPs of the assessment:
roles_data e.g [{"position""test position","mame":"name of staff"}] roles_data e.g [{"position""test position","mame":"name of staff"}]
@@ -23,6 +23,7 @@ def get_questions_prompt():
2. Regardless of the assement type, always use 1,2,3 for the frequency numbering, nothing else 2. Regardless of the assement type, always use 1,2,3 for the frequency numbering, nothing else
3. All questions are "yes" or "no" questions nothing extra and precise ,not long 3. All questions are "yes" or "no" questions nothing extra and precise ,not long
4. Generate a total of at least 20 questions all rounda based on the sops and roles for each frequency number 4. Generate a total of at least 20 questions all rounda based on the sops and roles for each frequency number
5. make sure the questions are up to 20 for the current frequency
Example response: Example response:
questions questions
@@ -36,7 +37,8 @@ def get_questions_prompt():
"assigned_to": "name", "assigned_to": "name",
"role": "person role", "role": "person role",
"question": "e.g., Is the internal project team being followed according to the SOP?" "question": "e.g., Is the internal project team being followed according to the SOP?"
"area_tag":"timeline" "area_tag":"timeline",
"postion":"person position"
} }
] ## up to at least 20 questions ] ## up to at least 20 questions
}, },
@@ -48,7 +50,8 @@ def get_questions_prompt():
"assigned_to": "name", "assigned_to": "name",
"role": "person role", "role": "person role",
"question": "e.g., Have communication protocols been followed for the task at hand?". "question": "e.g., Have communication protocols been followed for the task at hand?".
"area_tag":"communication" "area_tag":"communication",
"position":"person position"
} ## up to at least 20 questions } ## up to at least 20 questions
] ]
} }
+6 -6
View File
@@ -317,16 +317,16 @@ def get_sop_for_department_workers():
} }
''' '''
def get_sop_for_department_workers(): def get_sop_for_department_managers():
return '''Generate SOPs for each worker under the unique department based on the information the workers info provided return '''Generate SOPs for each manager under the unique department based on the information the managers info provided
Instructions: Instructions:
1. Focus on the provided department and manager role. 1. Focus on the provided department and manager role.
2. Categorize SOPs into "must," "shall," and "will." 2. Categorize SOPs into "must," "shall," and "will."
3. SOPs should be actionable and relevant to the worker's duties. 3. SOPs should be actionable and relevant to the manager's duties.
4. If no SOPs can be generated, return empty lists for each category. 4. If no SOPs can be generated, return empty lists for each category.
5. Use the provided document and the workers and department information to generate the SOP. 5. Use the provided document and the managers and department information to generate the SOP.
6. If the provided document cannot provide SOPs for a specific worker stated, then return an empty list for the SOP for that worker. 6. If the provided document cannot provide SOPs for a specific manager stated, then return an empty list for the SOP for that worker.
Example forma Example forma
{ {
@@ -335,7 +335,7 @@ def get_sop_for_department_workers():
"name": "Department A", "name": "Department A",
"managers": [ "managers": [
{ {
"name": "Worker A", "name": "manager A",
"must": ["Conduct weekly meetings"], "must": ["Conduct weekly meetings"],
"shall": ["Submit monthly reports"], "shall": ["Submit monthly reports"],
"will": ["Improve efficiency"] "will": ["Improve efficiency"]
+1 -1
View File
@@ -103,7 +103,7 @@ class QuestionsGenerator:
{"role": "user", "content": f"Roles Data: {roles_data}"} {"role": "user", "content": f"Roles Data: {roles_data}"}
], ],
response_format=AssementQuestion, # Ensure you specify the correct format response_format=AssementQuestion, # Ensure you specify the correct format
max_tokens=4096, max_tokens=10000,
temperature=0.1 temperature=0.1
) )
+13 -13
View File
@@ -85,7 +85,7 @@ class DocumentParser:
} }
], ],
response_format=VisionMissionResponse, response_format=VisionMissionResponse,
max_tokens=4096, max_tokens=1600,
temperature=0.1 temperature=0.1
) )
@@ -120,7 +120,7 @@ class DocumentParser:
} }
], ],
response_format=Roles_response, response_format=Roles_response,
max_tokens=1024, max_tokens=4096,
temperature=0.1 temperature=0.1
) )
@@ -172,7 +172,7 @@ class DocumentParser:
{"role": "user", "content": [{"type": "text", "text": text} for text in docs_text]} {"role": "user", "content": [{"type": "text", "text": text} for text in docs_text]}
], ],
response_format=DepartmentsAndWorkersResponse, # Use the updated response schema response_format=DepartmentsAndWorkersResponse, # Use the updated response schema
max_tokens=4096, max_tokens=16000,
temperature=0.1 temperature=0.1
) )
@@ -212,7 +212,7 @@ class DocumentParser:
{"role": "system", "content": f"The reference roles are{reference_roles} while the extracted roles are {extracted_managers}"}, {"role": "system", "content": f"The reference roles are{reference_roles} while the extracted roles are {extracted_managers}"},
{"role": "user", "content": prompt} {"role": "user", "content": prompt}
], ],
max_tokens=1024, max_tokens=16000,
temperature=0.1, temperature=0.1,
response_format=RolesComparisonResponse response_format=RolesComparisonResponse
) )
@@ -257,7 +257,7 @@ class DocumentParser:
{"role": "system", "content": f"The reference roles are{reference_roles} while the extracted roles are {extracted_workers}"}, {"role": "system", "content": f"The reference roles are{reference_roles} while the extracted roles are {extracted_workers}"},
{"role": "user", "content": prompt} {"role": "user", "content": prompt}
], ],
max_tokens=1024, max_tokens=16000,
temperature=0.1, temperature=0.1,
response_format=RolesComparisonResponse response_format=RolesComparisonResponse
) )
@@ -288,7 +288,7 @@ class DocumentParser:
{"role": "user", "content": [{"type": "text", "text": text} for text in docs_text]} {"role": "user", "content": [{"type": "text", "text": text} for text in docs_text]}
], ],
response_format=DepartmentMembers, # Use the updated response schema response_format=DepartmentMembers, # Use the updated response schema
max_tokens=4096, max_tokens=16000,
temperature=0.1 temperature=0.1
) )
@@ -316,7 +316,7 @@ class DocumentParser:
{"role": "user", "content": [{"type": "text", "text": text} for text in docs_text]} {"role": "user", "content": [{"type": "text", "text": text} for text in docs_text]}
], ],
response_format=WorkerSOPsResponse, # Use the updated response schema response_format=WorkerSOPsResponse, # Use the updated response schema
max_tokens=4096, max_tokens=16000,
temperature=0.1 temperature=0.1
) )
@@ -328,24 +328,24 @@ class DocumentParser:
def extract_sops_for_managers_by_department(self, docs,depts_managers): def extract_sops_for_managers_by_department(self, docs,depts_managers):
""" """
Extract sops for managers from the document. Extract departments, managers, and workers from the document.
:param docs: List of document chunks :param docs: List of document chunks
:return: Dictionary containing departments, their managers, :return: Dictionary containing departments, their managers, and workers.
""" """
try: try:
docs_text = self._extract_text_from_docs(docs) docs_text = self._extract_text_from_docs(docs)
prompt = get_sop_for_department_workers() # Update your prompt to handle managers and workers prompt = get_sop_for_department_managers() # Update your prompt to handle managers and workers
response = self.client.beta.chat.completions.parse( response = self.client.beta.chat.completions.parse(
model=self.model, model=self.model,
messages=[ messages=[
{"role": "system", "content": prompt}, {"role": "system", "content": prompt},
{"role": "user", "content": f"Mangers information: {depts_managers}"}, {"role": "user", "content": f"Workers information: {depts_managers}"},
{"role": "user", "content": [{"type": "text", "text": text} for text in docs_text]} {"role": "user", "content": [{"type": "text", "text": text} for text in docs_text]}
], ],
response_format=ManagerWithSOPs, # Use the updated response schema response_format=WorkerSOPsResponse, # Use the updated response schema
max_tokens=4096, max_tokens=16000,
temperature=0.1 temperature=0.1
) )
+6 -6
View File
@@ -59,7 +59,7 @@ class SopPersonalAssessment:
} }
], ],
response_format=SOPsResponse, response_format=SOPsResponse,
max_tokens=2048, max_tokens=16000,
temperature=0.1 temperature=0.1
) )
@@ -94,7 +94,7 @@ class SopPersonalAssessment:
} }
], ],
response_format=RoleSops, response_format=RoleSops,
max_tokens=1024, max_tokens=16000,
temperature=0.1 temperature=0.1
) )
extracted_text = json.loads(response.choices[0].message.content) extracted_text = json.loads(response.choices[0].message.content)
@@ -127,7 +127,7 @@ class SopPersonalAssessment:
} }
], ],
response_format=Roles_response, response_format=Roles_response,
max_tokens=1024, max_tokens=16000,
temperature=0.1 temperature=0.1
) )
extracted_text = json.loads(response.choices[0].message.content) extracted_text = json.loads(response.choices[0].message.content)
@@ -180,7 +180,7 @@ class SopGeneratorExecutive:
} }
], ],
response_format=Categories, response_format=Categories,
max_tokens=2048, max_tokens=16000,
temperature=0.1 temperature=0.1
) )
@@ -214,7 +214,7 @@ class SopGeneratorExecutive:
{"role": "user", "content": f"Generate SOPs for {role['position']} in {department['name']} department."} {"role": "user", "content": f"Generate SOPs for {role['position']} in {department['name']} department."}
], ],
response_format=ManagerSOPs, response_format=ManagerSOPs,
max_tokens=1024, max_tokens=16000,
temperature=0.1 temperature=0.1
) )
manager_sops = json.loads(response.choices[0].message.content) manager_sops = json.loads(response.choices[0].message.content)
@@ -246,7 +246,7 @@ class SopGeneratorExecutive:
{"role": "user", "content": f"Generate SOPs based on this questionnaire:\n{user_content}\n\nExecutives to consider: {', '.join(executives)}\nManagers to consider: {', '.join(managers)}\nDepartments to consider: {', '.join(departments)}"} {"role": "user", "content": f"Generate SOPs based on this questionnaire:\n{user_content}\n\nExecutives to consider: {', '.join(executives)}\nManagers to consider: {', '.join(managers)}\nDepartments to consider: {', '.join(departments)}"}
], ],
response_format={"type": "json_object"}, response_format={"type": "json_object"},
max_tokens=4096, max_tokens=16000,
temperature=0.1 temperature=0.1
) )
+24
View File
@@ -0,0 +1,24 @@
import os
from functools import wraps
from flask import Flask, session, redirect, url_for, request, g, jsonify
from dotenv import load_dotenv
load_dotenv()
API_KEY = os.getenv("API_KEY")
def auth_check(func):
@wraps(func)
def decorated_function(*args, **kwargs):
auth_header = request.headers.get('Authorization')
if not auth_header or not auth_header.startswith('Bearer '):
return jsonify({"error": "Unauthorized", "message": "API key is missing or invalid."}), 401
token = auth_header.split(' ')[1]
if token != API_KEY:
return jsonify({"error": "Unauthorized", "message": "API key does not match."}), 401
g.authenticated = True
return func(*args, **kwargs)
return decorated_function
+3 -81
View File
@@ -1,81 +1,3 @@
# Example usage import os
'''from scripts.run_assessment_prediction_trainer import CompanyModelPipeline API_KEY = "erp_" + os.urandom(16).hex()
company_ids = ['testid'] print(API_KEY)
input_base_path = '/root/ds_erp_ai/data/raw/erp_assessment_prediction' # The base path where the raw data for each company is stored
pipeline = CompanyModelPipeline(company_ids=company_ids, input_base_path=input_base_path)
pipeline.run_pipeline()'''
'''from src.pipeline.inference import AssessmentInference
inference = AssessmentInference(
company_id="testid",num_assessments=2
)
result = inference.run()
print(result)
'''
'''
response2 = bot.predict_next_n_assessment(
company_info=company_info,
companyid="testid",
N=3
)
print(f"Predictions {response2}")
from src.services.chatbot import Chatbot
company_info = {
'company_name': "ABC Corp",
'company_size': "Medium", # Can be "Small", "Medium", or "Large"
'departments': ["Sales", "Marketing", "IT", "Finance", "HR", "Logistics"]
}
bot = Chatbot()
response = bot.predict_based_on_past_assessment(
query="Should i make my next assessment weekly or biweekly to meet up to deadline?",
company_info=company_info,
companyid="testid"
)
print(f"Result: {response}")
from src.services.sop_document_parser import DocumentParser
from src.utils.document_loader import load_document
path = r"/root/ds_erp_ai/data/raw/test_sop.pdf"
parser = DocumentParser()
workers_department = [
{"name": "sales", "workers": ["sales manager"]},
{"name": "development", "workers": ["deployment officer"]}
]
res = parser.extract_sops_for_workers_by_department(
docs=load_document(path), # Load the document for processing
depts_workers=workers_department
)
print(res)'''
from src.services.chatbot import Chatbot
bot = Chatbot(
)
company_info = {
"company_name": "Example Co",
"company_size": "Medium",
"departments": ["HR", "Finance", "IT"]
}
response = bot.predict_goal_achievement_probability(
company_info=company_info,
companyid="testid"
)
print(response)