added apis for executives sops

This commit is contained in:
2024-09-06 01:48:32 +00:00
parent 67d30fbc6a
commit 690f80bc6e
6 changed files with 571 additions and 375 deletions
Binary file not shown.
+107 -36
View File
@@ -2,8 +2,8 @@ import os
from flask import Blueprint, request, jsonify, current_app 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 (SopGenerator,SopGeneratorDocument, from src.services.sop_generator import (SopGeneratorDocument,
SopPersonalAssessment) SopPersonalAssessment,SopGeneratorExecutive)
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
@@ -12,7 +12,7 @@ import json
sops_bp = Blueprint('sops', __name__) sops_bp = Blueprint('sops', __name__)
# Initialize SopGenerator # Initialize SopGenerator
sop_generator = SopGenerator()
ALLOWED_EXTENSIONS = {'pdf', 'doc', 'docx'} ALLOWED_EXTENSIONS = {'pdf', 'doc', 'docx'}
@@ -120,7 +120,7 @@ def generate_questions_from_sop():
@sops_bp.route('/generate_sops_from_doc', methods=['POST']) @sops_bp.route('/personal_assessment/generate_sops_from_doc', methods=['POST'])
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:
@@ -167,7 +167,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'])
def generate_sops_from_questionnaire(): 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.
The request body is expected to contain plain-text information for vision, roles, responsibilities, and project details. The request body is expected to contain plain-text information for vision, roles, responsibilities, and project details.
@@ -236,32 +236,29 @@ def generate_sops_by_roles_and_areas():
}), 500 }), 500
@sops_bp.route('/executive/generate_sops_from_questionnaire', methods=['POST'])
def generate_executive_sops_from_questionnaire():
try:
# Get data from the request body
data = request.json
# Generate SOPs based on the questionnaire answers @sops_bp.route('/executive/generate_sop_mission_from_vision', methods=['POST'])
sops_response = sop_generator.generate_executive_sops_from_questionnaire(data)
return jsonify({"sops": sops_response, "message": "SOPs successfully generated from the questionnaire."}), 200
except Exception as e:
return jsonify({"error": "Processing error", "message": f"An error occurred while generating SOPs: {str(e)}"}), 500
@sops_bp.route('/executive/generate_sops_from_doc', methods=['POST'])
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.
""" """
# Check if the POST request has the file part # Check if the POST request has the file part and roles
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
if 'executives' not in request.form:
return jsonify({"error": "No roles provided", "message": "Please provide roles as a JSON array."}), 400
try:
executives = request.form.get('executives')
# Manually load roles from the string to JSON
executives = json.loads(executives)
except json.JSONDecodeError:
return jsonify({"error": "Invalid JSON", "message": "The roles must be a valid JSON array."}), 400
except ValueError as e:
return jsonify({"error": "Invalid roles format", "message": str(e)}), 400
file = request.files['document'] file = request.files['document']
# If the user does not select a file, the browser may also submit an empty part without filename # If the user does not select a file, the browser may also submit an empty part without filename
@@ -280,29 +277,32 @@ def generate_executive_sops_from_doc():
# Use the utility function to generate docs from the file # Use the utility function to generate docs from the file
docs = load_document(file_path) docs = load_document(file_path)
sop_doc = SopGeneratorDocument()
vision_mission = sop_doc.extract_vision_mission(docs)
# Use LLM to extract Vision and Mission sections from the document if not vision_mission:
vision_section, mission_section = sop_generator.extract_vision_and_mission(docs) return jsonify({"error": "Vision and Mission generation error ", "message": "Error in generating mssion and viso."}), 400
if not vision_section or not mission_section: # Check if both vision and mission are empty
if not vision_mission.get('vision') and not vision_mission.get('mission'):
# Cleanup: Delete all files in the upload directory if parsing fails # Cleanup: Delete all files in the upload directory if parsing fails
delete_all_files_in_directory(upload_folder) delete_all_files_in_directory(upload_folder)
return jsonify({"error": "Missing Vision and Mission", "message": "The document does not contain or properly define the company's vision and mission."}), 400 return jsonify({"error": "Missing Vision and Mission", "message": "The document does not contain mission and vision."}), 400
# Organize extracted data print(f"Vision and mission: {vision_mission}")
extracted_data = {
"role": "Executive",
"organization vision": [vision_section],
"organization strategic goals": [mission_section]
}
# Generate SOPs based on the extracted vision and goals ex_sop = SopGeneratorExecutive()
sops_response = sop_generator.generate_executive_sops_from_questionnaire(extracted_data)
result = {}
for exe in executives:
sops = ex_sop.extract_sops_from_executive_vision_goals_doc(vision_mission, exe)
result[exe] = sops
# Cleanup: Delete all files in the upload directory after processing # Cleanup: Delete all files in the upload directory after processing
delete_all_files_in_directory(upload_folder) delete_all_files_in_directory(upload_folder)
return jsonify({"sops": sops_response, "message": "SOPs successfully generated from the document."}), 200 return jsonify({"sops": result, "message": "SOPs successfully generated from the document."}), 200
except Exception as e: except Exception as e:
# Cleanup: Delete all files in the upload directory if an error occurs # Cleanup: Delete all files in the upload directory if an error occurs
@@ -310,3 +310,74 @@ def generate_executive_sops_from_doc():
return jsonify({"error": "Processing error", "message": f"An error occurred while processing the document: {str(e)}"}), 500 return jsonify({"error": "Processing error", "message": f"An error occurred while processing the document: {str(e)}"}), 500
return jsonify({"error": "File type not allowed", "message": "The uploaded file type is not allowed. Please upload a PDF, DOC, or DOCX file."}), 400 return jsonify({"error": "File type not allowed", "message": "The uploaded file type is not allowed. Please upload a PDF, DOC, or DOCX file."}), 400
@sops_bp.route('/executive/generate_sop_managers_doc', methods=['POST'])
def generate_sop_managers_doc():
if 'document' not in request.files:
return jsonify({"error": "No file part", "message": "Please upload a file with the key 'document'."}), 400
file = request.files['document']
if file.filename == '':
return jsonify({"error": "No selected file", "message": "A file was not selected for upload. Please select a valid file."}), 400
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
upload_folder = current_app.config['UPLOAD_FOLDER']
file_path = os.path.join(upload_folder, filename)
file.save(file_path)
try:
docs = load_document(file_path)
sop_generator = SopGeneratorExecutive()
result = sop_generator.generate_sops_for_department_managers(docs)
delete_all_files_in_directory(upload_folder)
if not result:
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
except Exception as e:
delete_all_files_in_directory(upload_folder)
return jsonify({"error": "Processing error", "message": f"An error occurred while processing the document: {str(e)}"}), 500
return jsonify({"error": "File type not allowed", "message": "The uploaded file type is not allowed. Please upload a PDF, DOC, or DOCX file."}), 400
@sops_bp.route('/executive/generate_sops_from_questionnaire', methods=['POST'])
def generate_sops_from_questionnaire():
try:
data = request.json
questionnaire_data = data.get('questionnaire')
executives = data.get('executives', [])
managers = data.get('managers', [])
departments = data.get('departments', [])
if not questionnaire_data or not executives or not managers or not departments:
return jsonify({"error": "Missing data", "message": "Please provide questionnaire data, executives, managers, and departments."}), 400
sop_generator = SopGeneratorExecutive()
result = sop_generator.generate_sops_from_questionnaire(questionnaire_data, executives, managers, departments)
if not result:
return jsonify({"error": "Processing error", "message": "Failed to generate SOPs from questionnaire."}), 500
# Convert Pydantic models to dictionaries
serializable_result = {
"executive_sops": {exec: sops.dict() for exec, sops in result["executive_sops"].items()},
"department_sops": result["department_sops"].dict()
}
return jsonify({"sops": serializable_result, "message": "SOPs successfully generated from questionnaire."}), 200
except Exception as e:
return jsonify({"error": "Processing error", "message": f"An error occurred while processing the request: {str(e)}"}), 500
+38 -3
View File
@@ -23,6 +23,41 @@ class SOPsResponse(BaseModel):
vission:List[str] vission:List[str]
class VisionMissionResponse(BaseModel): class VisionMissionResponse(BaseModel):
vision: Optional[str] vision: List[str]
mission: Optional[str] mission: List[str]
message: str
class Categories(BaseModel):
must: Optional[List[str]] = Field(default_factory=list)
shall: Optional[List[str]] = Field(default_factory=list)
will: Optional[List[str]] = Field(default_factory=list)
class ExecutivesSops(BaseModel):
executive_sops: List[RoleSops]
class ManagerialRole(BaseModel):
title: str
responsibilities: List[str]
class Department(BaseModel):
name: str
managerial_roles: List[ManagerialRole]
class DepartmentsAndRolesResponse(BaseModel):
departments: List[Department]
class ManagerSOPs(BaseModel):
must: List[str] = Field(default_factory=list)
shall: List[str] = Field(default_factory=list)
will: List[str] = Field(default_factory=list)
class ManagerWithSOPs(BaseModel):
title: str
sops: ManagerSOPs
class DepartmentManagerSOPs(BaseModel):
name: str
managers: List[ManagerWithSOPs]
class ExecutiveManagerSOPsResponse(BaseModel):
departments: List[DepartmentManagerSOPs]
+143
View File
@@ -43,4 +43,147 @@ def get_sop_personalassessment_from_area_role(role,areas,sop_types):
Contextual Inference: If SOPs for the area are not explicitly stated, infer them from the role and area context provided. Contextual Inference: If SOPs for the area are not explicitly stated, infer them from the role and area context provided.
Empty Lists: If no SOPs are generated, return an empty list for each category. Empty Lists: If no SOPs are generated, return an empty list for each category.
Format: The SOPs should be direct and concise. Format: The SOPs should be direct and concise.
""" """
def get_sop_executive_from_vision_goals(executive):
return f"""Your task is to generate Standard Operating Procedures (SOPs) for executives namely:{executive} based on the provided vision and goals/mission.
You must extract and categorize the SOPs into three categories: "must," "shall," and "will."
Instructions:
1. **Vision**: Use the provided vision to align SOPs with the overall direction of the organization.
2. **Goals**: Utilize the specified goals to create SOPs that support their achievement.
3. **Executive-level SOPs**:
- Categorize the SOPs under three categories: "must," "shall," and "will."
- The SOPs should be directly aligned with executive responsibilities and decision-making.
- Ensure the SOPs reflect high-level strategic thinking and leadership expectations.
- If SOPs are not explicitly mentioned, infer them from the context of the vision and goals, but only if there is clear evidence. Do not generate or assume SOPs that are not directly supported by the information provided.
- If no SOPs can be generated, return an empty list for each category.
Provide the generated SOPs based on the vision and goals, focusing on executive-level responsibilities and actions."""
def get_vision_mission_extraction_from_doc():
return """Extract vision and mission statements from the document:
1. Analyze for explicit or implicit statements.
2. Vision: Long-term aspirations or ideal future state.
3. Mission: Organization's purpose, core functions, or primary objectives.
4. Include multiple statements if found.
5. Infer from context if not explicit.
6. Format as two lists: vision and mission.
7. Return empty list if none found for either category.
Provide extracted or inferred vision and mission statements."""
''' def get_sop_executive_for_managers():
return Your task is to extract the "Vision", "Mission", and executive-generated Standard Operating Procedures (SOPs) specifically for managers from the provided document.
Instructions:
1. **Vision**: Extract the vision of the company or organization as outlined by the executives.
2. **Mission**: Extract the mission of the company or organization. If not explicitly mentioned, consider the mission as the company's strategic goals.
3. **Executive-generated SOPs for Managers**:
- Categorize the SOPs under three categories: "must," "shall," and "will."
- The SOPs should be specific to the managerial role (e.g., handling team performance, reporting, budgeting, etc.).
- If SOPs for managers are not explicitly stated, infer them from the context provided by the executives, but only if there is clear evidence within the document.
- Do not generate or assume SOPs that are not directly supported by the document or the executive directives.
- If no SOPs are found for managers, return an empty list for each category.
Provide the extracted sections exactly as they appear in the document.
'''
def get_departments_and_roles_extraction_prompt():
return """
Extract departments and their senior managerial roles from the document.
Include only managerial positions (e.g., Department Head, Director, Manager).
For each role, list 2-3 key responsibilities.
Do not add any departments or roles that are not explicitly mentioned in the document.
Format as JSON:
{
"departments": [
{
"name": "Department Name",
"managerial_roles": [
{
"title": "Managerial Role Title",
"responsibilities": ["Key Responsibility 1", "Key Responsibility 2"]
}
]
}
]
}
If no departments or roles are found in the document, return an empty list for departments.
"""
def get_sop_for_department_managers():
return '''Generate Standard Operating Procedures (SOPs) for the specified managerial role in the given department.
Instructions:
1. Focus on the specific managerial role and department provided.
2. Generate relevant SOPs categorized as "must," "shall," and "will."
3. Ensure SOPs are actionable, clear, and directly related to the manager's responsibilities.
4. Consider the department's specific needs when creating the SOPs.
5. Return an empty list for each category if no relevant SOPs can be generated.
Format the response as a JSON object with "must", "shall", and "will" categories, each containing a list of SOPs.
Example format:
{
"must": [
"Conduct weekly team meetings to review project progress",
],
"shall": [
"Provide monthly performance reports to upper management",
],
"will": [
"Explore ways to improve department efficiency",
]
}
'''
def get_sop_executive_from_questionnaire():
return '''Generate Standard Operating Procedures (SOPs) for specific executives and department managers based on the provided questionnaire responses.
Instructions:
1. Use the organizational vision and strategic goals to create overarching SOPs for each executive.
2. Use the departmental strategic goals to create specific SOPs for each department's managers.
3. Categorize all SOPs into "must," "shall," and "will" categories.
4. Ensure SOPs are actionable, clear, and directly related to the provided information.
5. For executives, focus on high-level, strategic SOPs that align with the overall vision and goals.
6. For department managers, create department-specific SOPs based on their strategic goals.
7. Only generate SOPs for the specified departments.
Format the response as a JSON object with the following structure:
{
"executives": {
"Executive Name 1": {
"must": ["SOP 1", "SOP 2", ...],
"shall": ["SOP 1", "SOP 2", ...],
"will": ["SOP 1", "SOP 2", ...]
},
"Executive Name 2": {
"must": ["SOP 1", "SOP 2", ...],
"shall": ["SOP 1", "SOP 2", ...],
"will": ["SOP 1", "SOP 2", ...]
},
...
},
"departments": [
{
"name": "Department Name",
"managers": {
"must": ["SOP 1", "SOP 2", ...],
"shall": ["SOP 1", "SOP 2", ...],
"will": ["SOP 1", "SOP 2", ...]
}
},
...
]
}
Ensure that each specified department has its own set of SOPs.
'''
+212 -309
View File
@@ -6,315 +6,6 @@ from typing import List, Dict, Optional
from src.prompts.sops import * from src.prompts.sops import *
from src.models.response_schemas import * from src.models.response_schemas import *
class SopGenerator:
def __init__(self):
self.api_key = os.getenv("OPENAI_API_KEY")
self.client = OpenAI(api_key=self.api_key)
self.model = "gpt-4o-mini"
def _extract_text_from_docs(self, docs):
"""Extract text content from document objects."""
return [doc.page_content for doc in docs]
def get_roles(self, docs) -> RolesResponse:
docs_text = self._extract_text_from_docs(docs)
response = self.client.beta.chat.completions.parse(
model=self.model,
messages=[
{
"role": "system",
"content": '''Suppose you are a role/position extractor from a company document.
You extract the roles as a list, e.g., ["financial analyst", "data scientist", etc.].
If no roles are found, return an empty list.''',
},
{
"role": "user",
"content": [{"type": "text", "text": text} for text in docs_text],
}
],
response_format=RolesResponse,
max_tokens=1024,
temperature=0.1
)
return json.loads(response.choices[0].message.content)
def check_role_sop(self, roles: str, docs) -> SOPsFound:
docs_text = self._extract_text_from_docs(docs)
response = self.client.beta.chat.completions.parse(
model=self.model,
messages=[
{
"role": "system",
"content": f'''Your role is to check if the SOPs for the provided roles "{roles}" are found in the document.
You are validating if the document can provide the SOPs.
Return status=True with a proper message if found, and status=False with a proper message if not.
Keep the message short, e.g., "SOPs found for the role: {roles}" or "SOPs not found for the role: {roles}".'''
},
{
"role": "user",
"content": [{"type": "text", "text": text} for text in docs_text],
}
],
response_format=SOPsFound,
max_tokens=1024,
temperature=0.1
)
return json.loads(response.choices[0].message.content)
def generate_sops_from_doc(self, roles: List[str], docs) -> SOPsResponse:
roles_sops_all = {}
docs_text = self._extract_text_from_docs(docs)
for role in roles:
response = self.client.beta.chat.completions.parse(
model=self.model,
messages=[
{
"role": "system",
"content": f'''Your job is to extract Standard Operating Procedure (SOP) questions specifically for the role of "{role}" from the provided text.
Instructions:
Categorization: Organize the questions under three categories: "must," "shall," and "will."
Direct Questions: The questions should be directly addressed to the person in the role. Do not reference the role itself in the question.
Contextual Inference: If SOPs for the role are not explicitly stated, infer them from the context, but only if there is clear evidence within the text. Do not generate or assume SOPs that are not directly supported by the document.
Empty Lists: If no SOPs are found for the role, return an empty list for each category.
Format: The questions should be direct and concise, e.g., "Have you completed all the required reports?"
Example:
Category: Must
Have you completed all the required reports?
Category: Shall
Are you ensuring that all team members follow the safety protocols?
Category: Will
Are you planning to review the budget next week?''',
},
{
"role": "user",
"content": [{"type": "text", "text": text} for text in docs_text],
}
],
response_format=RoleSOPs,
max_tokens=1024,
temperature=0.1
)
role_sop = json.loads(response.choices[0].message.content)
roles_sops_all[role] = role_sop
return roles_sops_all
def generate_sops_from_info(self, roles: List[Dict[str, str]]):
roles_sops_all = {}
for role_info in roles:
role_title = role_info.get("title", "Unknown Role")
print(f"Role title : {role_title}")
response = self.client.beta.chat.completions.parse(
model=self.model,
messages=[
{
"role": "system",
"content": f'''Your job is to generate Standard Operating Procedures (SOPs) for the role of "{role_title}" based on the following information provided:
Responsibilities: {role_info.get("responsibilities", "Not provided")}
Objectives: {role_info.get("objectives", "Not provided")}
Tools: {role_info.get("tools", "Not provided")}
Challenges: {role_info.get("challenges", "Not provided")}
Instructions:
Categorization: Organize the SOPs under three categories: "must," "shall," and "will."
Direct Instructions: The SOPs should directly address the responsibilities, objectives, and challenges.
Contextual Inference: If SOPs for the role are not explicitly stated, infer them from the context provided.
Empty Lists: If no SOPs are generated, return an empty list for each category.
Format: The SOPs should be direct and concise.
''',
}
],
response_format=RoleSOPs,
max_tokens=1024,
temperature=0.1
)
role_sop = json.loads(response.choices[0].message.content)
roles_sops_all[role_title] = role_sop
return roles_sops_all
def generate_sops_by_role_and_area(self, role: str, areas: str) -> RoleSops:
response = self.client.beta.chat.completions.parse(
model=self.model,
messages=[
{
"role": "system",
"content": f'''Your job is to generate Standard Operating Procedures (SOPs) for the role of "{role}" with a focus on the areas "{areas}" based on the following instructions:
Instructions:
Categorization: Organize the SOPs under the selected categories: a checkboxex of the three categories "must" , "shall" and "will"
Direct Instructions: The SOPs should directly address responsibilities, objectives, and challenges related to the area of "{areas}" for the role of "{role}".
Contextual Inference: If SOPs for the area are not explicitly stated, infer them from the role and area context provided.
Empty Lists: If no SOPs are generated, return an empty list for each category.
Format: The SOPs should be direct and concise.
''',
}
],
response_format=RoleSOPs,
max_tokens=1024,
temperature=0.1
)
return json.loads(response.choices[0].message.content)
def generate_executive_sops_from_questionnaire(self, data: dict) -> RoleSops:
"""
Generate SOPs based on the answers from an executive questionnaire.
:param data: A dictionary containing the vision, strategic goals, and department goals.
:return: SOPs categorized by "must", "shall", and "will".
"""
vision_list = data.get("organization vision", [])
strategic_goals = data.get("organization strategic goals", [])
department_goals = data.get("department goals", [])
# Format vision and goals as text
formatted_vision = "\n".join([f"- {vision}" for vision in vision_list])
formatted_goals = "\n".join([f"- {goal}" for goal in strategic_goals])
formatted_department_goals = "\n".join([
f"{dept}: " + ", ".join([f"{goal}" for goal in goals])
for dept_dict in department_goals
for dept, goals in dept_dict.items()
])
response = self.client.beta.chat.completions.parse(
model=self.model,
messages=[
{
"role": "system",
"content": f'''Generate Standard Operating Procedures (SOPs) for an executive role based on the following information:
Organizational Vision:
{formatted_vision}
Organizational Strategic Goals:
{formatted_goals}
Departmental Strategic Goals:
{formatted_department_goals}
Instructions:
Categorization: Organize the SOPs under three categories: "must," "shall," and "will."
Direct Instructions: The SOPs should address leadership responsibilities for achieving the vision, strategic contribution, and goals outlined.
Empty Lists: If no SOPs are generated, return an empty list for each category.
Format: SOPs should be direct and concise.
''',
}
],
response_format=RoleSops,
max_tokens=1024,
temperature=0.1
)
return json.loads(response.choices[0].message.content)
def generate_executive_sops_from_doc(self,docs) -> SOPsResponse:
docs_text = self._extract_text_from_docs(docs)
response = self.client.beta.chat.completions.parse(
model=self.model,
messages=[
{
"role": "system",
"content": f'''Your job is to extract Standard Operating Procedure (SOP) questions specifically for the role of "{role}" from the provided text.
Instructions:
Categorization: Organize the questions under three categories: "must," "shall," and "will."
Direct Questions: The questions should be directly addressed to the person in the role. Do not reference the role itself in the question.
Contextual Inference: If SOPs for the role are not explicitly stated, infer them from the context, but only if there is clear evidence within the text. Do not generate or assume SOPs that are not directly supported by the document.
Empty Lists: If no SOPs are found for the role, return an empty list for each category.
Format: The questions should be direct and concise, e.g., "Have you completed all the required reports?"
Example:
Category: Must
Have you completed all the required reports?
Category: Shall
Are you ensuring that all team members follow the safety protocols?
Category: Will
Are you planning to review the budget next week?''',
},
{
"role": "user",
"content": [{"type": "text", "text": text} for text in docs_text],
}
],
response_format=VisionMissionResponse,
max_tokens=1024,
temperature=0.1
)
return response
def extract_vision_and_mission(self, docs: str):
"""
Use LLM to extract Vision and Mission from the document text.
:param document_text: The text content of the document.
:return: (vision_section, mission_section)
"""
docs_text = self._extract_text_from_docs(docs)
response = self.client.beta.chat.completions.parse(
model=self.model,
messages=[
{
"role": "system",
"content": '''You are a helpful assistant that extracts specific sections from business documents.
Your task is to extract the "Vision" and "Mission" sections (or "Goals" if "Mission" is not found).
mission is basically same as goals just mission as goals if not found
Provide the sections exactly as they appear in the document.'''
},
{
"role": "user",
"content": [{"type": "text", "text": text} for text in docs_text],
}
],
max_tokens=1024,
temperature=0.1,
response_format=VisionMissionResponse,
)
# Parse the response from the LLM
extracted_text = json.loads(response.choices[0].message.content)
# Assuming the response contains fields for 'vision' and 'mission' (or 'goals')
vision_section = extracted_text["vision"]
mission_section = extracted_text["mission"]
return vision_section, mission_section
class SopGeneratorDocument: class SopGeneratorDocument:
def __init__(self): def __init__(self):
self.api_key = os.getenv("OPENAI_API_KEY") self.api_key = os.getenv("OPENAI_API_KEY")
@@ -362,6 +53,70 @@ class SopGeneratorDocument:
except: except:
return False return False
def extract_vision_mission(self, docs) -> VisionMissionResponse:
"""
Extracts Vision, Mission, and SOPs categorized into 'must,' 'shall,' and 'will' from the document.
:param docs: The document(s) from which to extract information.
:return: VisionMissionResponse containing the vision, mission, and role-specific SOPs.
"""
try:
docs_text = self._extract_text_from_docs(docs)
prompt = get_vision_mission_extraction_from_doc()
response = self.client.beta.chat.completions.parse(
model=self.model,
messages=[
{
"role": "system",
"content": f'''{prompt}'''
},
{
"role": "user",
"content": [{"type": "text", "text": text} for text in docs_text],
}
],
response_format=VisionMissionResponse,
max_tokens=4096,
temperature=0.1
)
# Parse the response from the LLM
extracted_text = json.loads(response.choices[0].message.content)
return extracted_text
except:
return False
def extract_departments_and_managers(self, docs):
"""
Extract departments and managerial roles from the document.
:param docs: List of document chunks
:return: Dictionary containing departments and their managerial roles
"""
try:
docs_text = self._extract_text_from_docs(docs)
prompt = get_departments_and_roles_extraction_prompt()
response = self.client.beta.chat.completions.parse(
model=self.model,
messages=[
{"role": "system", "content": prompt},
{"role": "user", "content": [{"type": "text", "text": text} for text in docs_text]}
],
response_format=DepartmentsAndRolesResponse,
max_tokens=4096,
temperature=0.1
)
return json.loads(response.choices[0].message.content)
except json.JSONDecodeError:
return False
class SopPersonalAssessment: class SopPersonalAssessment:
@@ -462,3 +217,151 @@ class SopPersonalAssessment:
return False return False
class SopGeneratorExecutive:
def __init__(self):
self.api_key = os.getenv("OPENAI_API_KEY")
self.client = OpenAI(api_key=self.api_key)
self.model = "gpt-4o-mini"
def extract_sops_from_executive_vision_goals_doc(self, data: dict,executives:List) -> SOPsResponse:
"""
Extracts SOPs categorized into 'must,' 'shall,' and 'will' based on executive vision and goals.
:param data: A dictionary containing vision and goals.
:return: SOPsResponse containing the SOPs for executives
"""
try:
vision = data.get("vision", "No vision provided")
goals = data.get("goals", "No goals provided")
prompt = get_sop_executive_from_vision_goals(executives)
user_content = f'''
Vision: {vision}
Goals: {goals}
'''
response = self.client.beta.chat.completions.parse(
model=self.model,
messages=[
{
"role": "system",
"content": f'''{prompt}'''
},
{
"role": "user",
"content": user_content,
}
],
response_format=Categories,
max_tokens=2048,
temperature=0.1
)
extracted_text = json.loads(response.choices[0].message.content)
return extracted_text
except Exception as e:
print(f"Error occurred: {str(e)}")
return False
def generate_sops_for_department_managers(self, docs):
try:
# First, extract departments and managers
sop_doc = SopGeneratorDocument()
departments_and_roles = sop_doc.extract_departments_and_managers(docs)
if not departments_and_roles or not departments_and_roles.get('departments'):
return False
departments_with_sops = []
for department in departments_and_roles['departments']:
managers_with_sops = []
for role in department['managerial_roles']:
prompt = get_sop_for_department_managers()
response = self.client.beta.chat.completions.parse(
model=self.model,
messages=[
{"role": "system", "content": prompt},
{"role": "user", "content": f"Generate SOPs for {role['title']} in {department['name']} department."}
],
response_format=ManagerSOPs,
max_tokens=1024,
temperature=0.1
)
manager_sops = json.loads(response.choices[0].message.content)
managers_with_sops.append(ManagerWithSOPs(title=role['title'], sops=manager_sops))
departments_with_sops.append(DepartmentManagerSOPs(
name=department['name'],
managers=managers_with_sops
))
return ExecutiveManagerSOPsResponse(departments=departments_with_sops)
except Exception as e:
print(f"Error in generate_sops_for_department_managers: {str(e)}")
return False
def generate_sops_from_questionnaire(self, questionnaire_data: dict, executives: List[str], managers: List[str], departments: List[str]):
try:
prompt = get_sop_executive_from_questionnaire()
# Prepare the questionnaire data for the prompt
user_content = json.dumps(questionnaire_data, indent=2)
response = self.client.beta.chat.completions.parse(
model=self.model,
messages=[
{"role": "system", "content": prompt},
{"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"},
max_tokens=4096,
temperature=0.1
)
sops_data = json.loads(response.choices[0].message.content)
# Process executive SOPs
executive_sops = {}
for executive in executives:
if executive in sops_data['executives']:
executive_sops[executive] = Categories(**sops_data['executives'][executive])
else:
executive_sops[executive] = Categories()
# Process department manager SOPs
departments_with_sops = []
for dept_name in departments:
dept_data = next((d for d in sops_data['departments'] if d['name'].lower() == dept_name.lower()), None)
if dept_data:
managers_with_sops = [
ManagerWithSOPs(
title=manager,
sops=ManagerSOPs(**dept_data['managers'])
)
for manager in managers
]
if managers_with_sops:
departments_with_sops.append(DepartmentManagerSOPs(
name=dept_name,
managers=managers_with_sops
))
return {
"executive_sops": executive_sops,
"department_sops": ExecutiveManagerSOPsResponse(departments=departments_with_sops)
}
except Exception as e:
print(f"Error in generate_sops_from_questionnaire: {str(e)}")
return False
+69 -25
View File
@@ -1,37 +1,81 @@
from src.services.sop_generator import SopGenerator from src.services.sop_generator import SopGeneratorDocument, SopGeneratorExecutive
from src.utils.document_loader import load_document from src.utils.document_loader import load_document
from src.services.sop_generator import SopPersonalAssessment
file_path = "/root/ds_erp_ai/data/raw/document.doc" file_path = "/root/ds_erp_ai/data/raw/document.doc"
docs = load_document(file_path) docs = load_document(file_path)
from src.services.sop_generator import SopGeneratorDocument sop_doc = SopGeneratorDocument()
sop = SopPersonalAssessment() sop_executive = SopGeneratorExecutive()
if __name__ == "__main__": if __name__ == "__main__":
# Assuming 'sop' is an instance of SopGenerator and 'docs' is the loaded document content. # Test the generate_sops_from_questionnaire function
# Step 1: Get the roles from the document questionnaire_data = {
"organizational_vision": {
roles = [ "question_1_answer": "Our vision is to lead the market in innovative product solutions.",
{ "question_2_answer": "We see our organization contributing by expanding into new regions and enhancing service quality.",
"role": "Content Marketing Specialist", "question_3_answer": "The key elements of our vision focus on scalability, customer satisfaction, and technological advancement."
"sop_types": ["will", "shall"],
"areas": ["communication", "development"]
}, },
{ "organizational_strategic_goals": {
"role": "Digital Marketing Specialist", "question_1_answer": "The strategic direction is to increase market share and improve operational efficiency.",
"sop_types": ["must"], "question_2_answer": "We aim to achieve a 20% reduction in operating costs by streamlining internal processes.",
"areas": ["finance", "project management"] "question_3_answer": "The process aligns with our goal to reduce costs while maintaining high product quality."
}, },
{ "departmental_strategic_goals": {
"role": "Information Technology Officer", "sales_department_answer": "Increase sales by 15% in the next fiscal year through better lead generation and customer retention.",
"sop_types": ["shall", "must"], "finance_department_answer": "Ensure a balanced budget by optimizing resource allocation and reducing overhead costs."
"areas": ["development", "communication", "operations"] }
} }
]
executives = ["CEO", "COO"]
managers = ["Sales Manager", "Finance Manager"]
sops_from_questionnaire = sop_executive.generate_sops_from_questionnaire(questionnaire_data, executives, managers)
sops = sop.generate_sops_by_role_and_area(roles) if sops_from_questionnaire:
print(f"sops:{sops}") print("Generated SOPs from Questionnaire:")
# Print Executive SOPs
print("\nExecutive SOPs:")
for executive, sops in sops_from_questionnaire["executive_sops"].items():
print(f" {executive}:")
print(" Must SOPs:")
for sop in sops.must:
print(f" - {sop}")
print(" Shall SOPs:")
for sop in sops.shall:
print(f" - {sop}")
print(" Will SOPs:")
for sop in sops.will:
print(f" - {sop}")
# Print Department Manager SOPs
print("\nDepartment Manager SOPs:")
for department in sops_from_questionnaire["department_sops"].departments:
print(f" Department: {department.name}")
for manager in department.managers:
print(f" Manager: {manager.title}")
print(" Must SOPs:")
for sop in manager.sops.must:
print(f" - {sop}")
print(" Shall SOPs:")
for sop in manager.sops.shall:
print(f" - {sop}")
print(" Will SOPs:")
for sop in manager.sops.will:
print(f" - {sop}")
else:
print("Failed to generate SOPs from questionnaire.")
# You can keep the previous tests if you want
departments_and_roles = sop_doc.extract_departments_and_managers(docs)
if departments_and_roles:
print("\nExtracted Departments and Roles:")
for department in departments_and_roles.get('departments', []):
print(f"\nDepartment: {department['name']}")
for role in department.get('managerial_roles', []):
print(f" Role: {role['title']}")
print(f" Responsibilities: {', '.join(role['responsibilities'])}")
else:
print("Failed to extract departments and roles.")
v_ms = sop_doc.extract_vision_mission(docs)
print(f"\nVision and Mission: {v_ms}")