Spaces:
Runtime error
Runtime error
File size: 7,682 Bytes
f041270 1f51659 f041270 1f51659 f041270 1f51659 07be4c8 f041270 1f51659 f041270 1f51659 f041270 1f51659 f041270 07be4c8 f041270 1f51659 07be4c8 1f51659 07be4c8 1f51659 07be4c8 1f51659 07be4c8 1f51659 07be4c8 f041270 07be4c8 1f51659 07be4c8 1f51659 d55dc5e 1f51659 f041270 d55dc5e 07be4c8 d55dc5e 07be4c8 d55dc5e 07be4c8 d55dc5e 07be4c8 8202192 4ff1ff7 98601b8 d55dc5e 1f51659 07be4c8 1f51659 585c750 1f51659 d55dc5e 1f51659 d55dc5e 4ff1ff7 07be4c8 d55dc5e 585c750 f041270 07be4c8 f041270 1f51659 f041270 1f51659 07be4c8 1f51659 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | # business_continuity.py
from fastapi import APIRouter, HTTPException
from pydantic import BaseModel, Field
from typing import List, Optional, Dict, Any
import os
import openai
import json
import uuid
import logging
import traceback
import re
from dotenv import load_dotenv
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
# Load environment variables from .env file
load_dotenv()
# Environment Variables
GROQ_API_KEY = os.environ.get("GROQ_API_KEY")
if GROQ_API_KEY:
GROQ_API_KEY = GROQ_API_KEY.strip()
logger.info(f"GROQ_API_KEY loaded: {'Yes' if GROQ_API_KEY else 'No'}")
# Request Models
class BusinessProcess(BaseModel):
department: str = Field(..., min_length=1, max_length=100)
sub_department: Optional[str] = Field(default="", max_length=100)
process_name: str = Field(..., min_length=1, max_length=200)
process_description: str = Field(..., min_length=1, max_length=1000)
class AnalysisData(BaseModel):
impact_analysis: Optional[Dict[str, Any]] = Field(default_factory=dict)
minimum_operating_requirements: Optional[Dict[str, Any]] = Field(default_factory=dict)
class BusinessContinuityRequest(BaseModel):
business_process: BusinessProcess
analysis_data: AnalysisData = Field(default_factory=lambda: AnalysisData())
# Response Model
class RecoveryStrategiesResponse(BaseModel):
success: bool
people_unavailability_strategy: str
people_reasoning: str
technology_data_unavailability_strategy: str
technology_reasoning: str
site_unavailability_strategy: str
site_reasoning: str
third_party_vendors_unavailability_strategy: str
vendor_reasoning: str
# Create router
business_continuity_router = APIRouter()
def call_groq_api(prompt: str, user_message: str):
"""Simple function to call GROQ API"""
if not GROQ_API_KEY:
logger.error("GROQ_API_KEY environment variable is not set")
raise Exception("GROQ_API_KEY not configured")
try:
client = openai.OpenAI(
api_key=GROQ_API_KEY,
base_url="https://api.groq.com/openai/v1",
timeout=60.0
)
response = client.chat.completions.create(
model="llama3-8b-8192",
messages=[
{"role": "system", "content": prompt},
{"role": "user", "content": user_message}
],
temperature=0.1,
max_tokens=1500
)
return response.choices[0].message.content
except Exception as e:
logger.error(f"API call failed: {str(e)}")
raise Exception(f"API call failed: {str(e)}")
@business_continuity_router.post("/api/business-continuity/generate-recovery-strategies", response_model=RecoveryStrategiesResponse)
def generate_recovery_strategies(request: BusinessContinuityRequest):
"""Generate business continuity recovery strategies"""
request_id = str(uuid.uuid4())
logger.info(f"Request {request_id}: Starting for {request.business_process.process_name}")
# Basic input validation
if not request.business_process.process_name.strip():
raise HTTPException(status_code=400, detail="Process name cannot be empty")
if not request.business_process.department.strip():
raise HTTPException(status_code=400, detail="Department cannot be empty")
try:
# Create system prompt with strong emphasis on valid JSON output
system_prompt = """You are a business continuity expert. CRITICAL: You must ONLY output a valid, parsable JSON object and nothing else. No explanations, no formatting, just pure JSON.
Your output MUST be in this EXACT format with NO DEVIATIONS:
{
"people_unavailability_strategy": "Strategy for when key staff are unavailable (2-3 sentences).",
"people_reasoning": "Why this strategy works for this process (1 sentence).",
"technology_data_unavailability_strategy": "Strategy for system failures (2-3 sentences).",
"technology_reasoning": "Why this technology strategy works (1 sentence).",
"site_unavailability_strategy": "Strategy for site unavailability (2-3 sentences).",
"site_reasoning": "Why this site strategy works (1 sentence).",
"third_party_vendors_unavailability_strategy": "Strategy for supplier disruptions (2-3 sentences).",
"vendor_reasoning": "Why this vendor strategy works (1 sentence)."
}
CRITICAL: Your output MUST be a valid JSON object with the above structure. If you cannot generate this, return an error message in the same JSON format with a "message" field indicating the error.
GIVE ONLY this JSON output. DO NOT include any other text, explanations, or formatting.
THE ENTIRE CODE DEPENDS ON THIS JSON STRUCTURE BEING CORRECT. PLEASE ensure the JSON is valid and parsable.
DO NOT add markdown code blocks, explanations, or any text before or after the JSON. ONLY output the raw JSON object."""
# Create user message - simplified
user_message = f"""Generate business continuity strategies for:
Process: {request.business_process.process_name}
Department: {request.business_process.department}
Description: {request.business_process.process_description}"""
api_response = call_groq_api(system_prompt, user_message)
logger.info(f"Request {request_id}: Received API response")
# Parse JSON response directly
try:
# Simple direct parsing - trust the LLM to format correctly
if not api_response.strip().endswith('}'):
api_response += '}'
strategies_data = json.loads(api_response)
logger.info(f"Request {request_id}: Successfully parsed JSON")
except json.JSONDecodeError as e:
# If parsing fails, just return the error
logger.error(f"Request {request_id}: JSON parsing failed - {str(e)}")
logger.error(f"Request {request_id}: Raw response preview: {api_response}")
# Safely get fields with fallbacks
return RecoveryStrategiesResponse(
success=True,
people_unavailability_strategy=strategies_data.get("people_unavailability_strategy", "Strategy not generated"),
people_reasoning=strategies_data.get("people_reasoning", "Reasoning not generated"),
technology_data_unavailability_strategy=strategies_data.get("technology_data_unavailability_strategy", "Strategy not generated"),
technology_reasoning=strategies_data.get("technology_reasoning", "Reasoning not generated"),
site_unavailability_strategy=strategies_data.get("site_unavailability_strategy", "Strategy not generated"),
site_reasoning=strategies_data.get("site_reasoning", "Reasoning not generated"),
third_party_vendors_unavailability_strategy=strategies_data.get("third_party_vendors_unavailability_strategy", "Strategy not generated"),
vendor_reasoning=strategies_data.get("vendor_reasoning", "Reasoning not generated"),
message="Successfully generated recovery strategies",
request_id=request_id
)
except HTTPException:
# Re-raise HTTP exceptions
raise
except Exception as e:
logger.error(f"Request {request_id}: Unexpected error - {str(e)}")
logger.error(f"Traceback: {traceback.format_exc()}")
@business_continuity_router.get("/api/business-continuity/health")
def health_check():
"""Health check endpoint"""
return {
"status": "healthy",
"groq_api_configured": bool(GROQ_API_KEY),
"timestamp": uuid.uuid4().hex
} |