|
|
|
import os |
|
from groq import Groq, RateLimitError, APIError |
|
import time |
|
|
|
|
|
|
|
client = Groq( |
|
api_key=os.environ.get("GROQ_API_KEY"), |
|
) |
|
|
|
|
|
DEFAULT_MODEL = "llama3-8b-8192" |
|
|
|
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, |
|
|
|
|
|
|
|
|
|
|
|
|
|
) |
|
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 |
|
except APIError as e: |
|
print(f"Groq API Error: {e.status_code} - {e.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." |
|
|
|
|
|
|
|
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 |
|
except ValueError: |
|
score = None |
|
|
|
rationale = None |
|
if rationale_line: |
|
|
|
rationale_start_index = response.find("Rationale:") |
|
if rationale_start_index != -1: |
|
rationale = response[rationale_start_index + len("Rationale:"):].strip() |
|
else: |
|
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 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 |
|
|
|
|
|
if priority not in ["Low", "Medium", "High"]: |
|
priority = "Medium" |
|
|
|
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" |
|
|
|
|