File size: 7,796 Bytes
0a40ab8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
# src/utils/groq_client.py
import os
from groq import Groq, RateLimitError, APIError
import time

# Initialize Groq client using environment variable
# Ensure GROQ_API_KEY is set in the environment where the Flask app runs
client = Groq(
    api_key=os.environ.get("GROQ_API_KEY"),
)

# Define a default model
DEFAULT_MODEL = "llama3-8b-8192" # Or choose another suitable model like llama3-70b-8192, mixtral-8x7b-32768

def call_groq(prompt: str, system_prompt: str = "You are a helpful assistant specializing in legislative analysis and drafting.", model: str = DEFAULT_MODEL, max_retries: int = 3, initial_delay: int = 1) -> str | None:
    """Calls the Groq API with a given prompt and handles basic errors/retries."""
    
    if not client.api_key:
        print("Error: GROQ_API_KEY environment variable not set.")
        return "Error: Groq API key not configured."
        
    retries = 0
    delay = initial_delay
    while retries < max_retries:
        try:
            chat_completion = client.chat.completions.create(
                messages=[
                    {
                        "role": "system",
                        "content": system_prompt,
                    },
                    {
                        "role": "user",
                        "content": prompt,
                    }
                ],
                model=model,
                # Optional parameters:
                # temperature=0.7,
                # max_tokens=1024,
                # top_p=1,
                # stop=None,
                # stream=False,
            )
            return chat_completion.choices[0].message.content
        except RateLimitError as e:
            retries += 1
            print(f"Rate limit exceeded. Retrying in {delay} seconds... (Attempt {retries}/{max_retries})")
            time.sleep(delay)
            delay *= 2 # Exponential backoff
        except APIError as e:
            print(f"Groq API Error: {e.status_code} - {e.message}")
            # Depending on the error, you might want to retry or just return None/error message
            return f"Error: Groq API request failed ({e.status_code})."
        except Exception as e:
            print(f"An unexpected error occurred calling Groq: {e}")
            return f"Error: An unexpected error occurred while contacting the AI model."

    print(f"Failed to call Groq API after {max_retries} retries.")
    return "Error: AI model request failed after multiple retries due to rate limits."

# --- Specific Task Functions ---

def generate_draft_content(policy_intent: str) -> str | None:
    """Uses Groq to generate initial draft content based on policy intent."""
    system_prompt = "You are an AI assistant specialized in legislative drafting. Based on the provided policy intent, generate a concise initial draft for a new regulation or law. Focus on clear, actionable language suitable for legislation."
    prompt = f"Policy Intent: {policy_intent}\n\nGenerate an initial legislative draft based on this intent:"
    return call_groq(prompt, system_prompt)

def perform_impact_analysis(document_content: str, analysis_type: str) -> tuple[str | None, float | None, str | None]:
    """Uses Groq to perform impact analysis on a given document.
    Returns: (predicted_impact, confidence_score, rationale)
    """
    system_prompt = f"You are an AI legislative analyst. Analyze the provided legislative text and predict its potential {analysis_type.lower()} impact. Provide a summary of the predicted impact, a confidence score (0.0 to 1.0), and a brief rationale for your prediction."
    prompt = f"Legislative Text:\n```\n{document_content}\n```\n\nAnalyze the {analysis_type.lower()} impact of this text. Format your response strictly as follows:\nPredicted Impact: [Your summary here]\nConfidence Score: [A number between 0.0 and 1.0]\nRationale: [Your explanation here]"
    
    response = call_groq(prompt, system_prompt)
    
    if response and response.startswith("Predicted Impact:"):
        try:
            lines = response.split("\n")
            impact = lines[0].replace("Predicted Impact:", "").strip()
            score_line = next((line for line in lines if line.startswith("Confidence Score:")), None)
            rationale_line = next((line for line in lines if line.startswith("Rationale:")), None)
            
            score = None
            if score_line:
                try:
                    score_str = score_line.replace("Confidence Score:", "").strip()
                    score = float(score_str)
                    if not (0.0 <= score <= 1.0):
                        score = None # Invalid score
                except ValueError:
                    score = None # Could not parse score
            
            rationale = None
            if rationale_line:
                 # Find the start index of Rationale and take everything after it
                rationale_start_index = response.find("Rationale:")
                if rationale_start_index != -1:
                    rationale = response[rationale_start_index + len("Rationale:"):].strip()
                else: # Fallback if split didn't work as expected
                     rationale = rationale_line.replace("Rationale:", "").strip()

            return impact, score, rationale
        except Exception as e:
            print(f"Error parsing Groq impact analysis response: {e}")
            return f"Error parsing AI response: {response}", None, None
    else:
        # Return the raw response or error message if parsing failed
        return response or "Error: No response from AI model.", None, None

def generate_recommendation(criteria: str) -> tuple[str | None, str | None, str | None, str | None]:
    """Uses Groq to generate a legislative recommendation based on criteria.
    Returns: (recommendation_type, details, rationale, priority)
    """
    system_prompt = "You are an AI legislative analyst. Based on the provided criteria, suggest a legislative recommendation (e.g., Update, Consolidation, Removal). Provide details, rationale, and a priority level (Low, Medium, High)."
    prompt = f"Criteria for Recommendation: {criteria}\n\nGenerate a legislative recommendation based on these criteria. Format your response strictly as follows:\nType: [Update/Consolidation/Removal]\nDetails: [Specific recommendation details]\nRationale: [Justification for the recommendation]\nPriority: [Low/Medium/High]"
    
    response = call_groq(prompt, system_prompt)
    
    if response and response.startswith("Type:"):
        try:
            lines = response.split("\n")
            rec_type = lines[0].replace("Type:", "").strip()
            details_line = next((line for line in lines if line.startswith("Details:")), None)
            rationale_line = next((line for line in lines if line.startswith("Rationale:")), None)
            priority_line = next((line for line in lines if line.startswith("Priority:")), None)
            
            details = details_line.replace("Details:", "").strip() if details_line else None
            rationale = rationale_line.replace("Rationale:", "").strip() if rationale_line else None
            priority = priority_line.replace("Priority:", "").strip() if priority_line else None
            
            # Basic validation for priority
            if priority not in ["Low", "Medium", "High"]:
                priority = "Medium" # Default if invalid
                
            return rec_type, details, rationale, priority
        except Exception as e:
            print(f"Error parsing Groq recommendation response: {e}")
            return "Error", f"Error parsing AI response: {response}", None, "Medium"
    else:
        return "Error", response or "Error: No response from AI model.", None, "Medium"