File size: 6,792 Bytes
6fde63f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import os
import random
import numpy as np
import matplotlib.pyplot as plt
from openai import OpenAI
from Sim_Engine import simulate_period

client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))

def summarize_initial_conditions(n_rows, n_cols):
    num_parcels = n_rows * n_cols
    avg_forage = round(random.uniform(6.5, 8.0), 1)
    degraded_pct = round(random.uniform(0.0, 2.0), 1)
    riparian_health = random.choice(["excellent", "moderate", "fragile"])
    elk_corridor_status = random.choice([
        "completely intact and lightly used",
        "intact but under slight pressure from cattle movement",
        "showing signs of fragmentation near key crossings"
    ])
    rainfall_outlook = random.choice(["normal", "below average", "above average"])

    return (
        f"There are {num_parcels} parcels in total. Grazing has not yet occurred.\n"
        f"Average forage availability is {avg_forage} AUMs per parcel, with about {degraded_pct}% of land already degraded due to prior conditions.\n"
        f"Riparian zone condition is {riparian_health}, and the elk movement corridor is {elk_corridor_status}.\n"
        f"The seasonal rainfall outlook is {rainfall_outlook}."
    )

def plot_forage_map_to_file(parcel_dict, n_rows, n_cols, title="Forage Map", save_path="forage_map.png"):
    forage_map = np.array([
        [parcel_dict[(i, j)]["forage"] for j in range(n_cols)]
        for i in range(n_rows)
    ])
    fig, ax = plt.subplots(figsize=(8, 6))
    cax = ax.imshow(forage_map, cmap='YlGn', origin='upper')
    fig.colorbar(cax, label="Forage AUMs")
    ax.set_title(title)
    ax.axis('off')
    plt.tight_layout()
    plt.savefig(save_path)
    plt.close(fig)

def elk_feedback(plan_choice, current_summary):
    prompt = f"""
You represent a coalition of elk-related interests: conservationists, hunting advocates, and the hospitality/lodging industry.
A student has selected the **'{plan_choice}'** cattle grazing strategy. Below are the current ecological conditions:
-----
{current_summary}
-----
Please do the following:
- Explicitly choose **one elk management strategy** from the list:
  - **Preserve**: strict elk protections, no hunting, unrestricted movement
  - **Cooperate**: shared use corridor, some riparian restrictions, sustainable elk population
  - **Exploit**: prioritize hunting/tourism, tolerate reduced elk numbers and access
- Reflect each group's view briefly, but unify the final position.
- Justify your strategy choice based on the above ecological indicators.
"""
    response = client.chat.completions.create(
        model="gpt-3.5-turbo",
        messages=[{"role": "user", "content": prompt}],
        temperature=0.8
    )
    return response.choices[0].message.content

def usfs_feedback(plan_choice, student_essay, current_summary):
    # Extract the AUM line from the summary
    aum_line = ""
    for line in current_summary.split("\n"):
        if "Average forage availability" in line:
            aum_line = line.strip()
            break

    prompt = f"""
You are a USFS land management agent evaluating a student’s cattle grazing proposal.

The student selected the **'{plan_choice}'** strategy and submitted this justification:
-----
{student_essay}
-----

Here are the current rangeland conditions:
-----
{current_summary}
-----

🚨 **Must Include Block**:
You must include this sentence exactly in your response:
→ "{aum_line}"

Then provide your evaluation:
- Comment on forage, degradation, riparian and corridor health
- State whether the plan is ecologically sound
- Suggest improvements if needed
- Keep the tone professional, clear, and grounded in the data
"""

    response = client.chat.completions.create(
        model="gpt-3.5-turbo",
        messages=[{"role": "user", "content": prompt}],
        temperature=0.7
    )
    return response.choices[0].message.content

def simulate_and_summarizeold(plan_choice, round_counter, parcel_dict, parcel_map, cluster_labels, n_rows, n_cols, elk_pressure):
    # Interpret strategy
    strategy_map = {
        "conservative": "conservative",
        "normal": "moderate",
        "aggressive": "aggressive"
    }
    strategy = strategy_map.get(plan_choice.lower(), "moderate")

    # ✅ Reuse incoming parcel_dict — do not reset
    simulate_period(parcel_dict, grazing_strategy=strategy, elk_pressure=elk_pressure)

    # Extract summary
    forage_vals = [p["forage"] for p in parcel_dict.values()]
    avg_forage = sum(forage_vals) / len(forage_vals)
    degraded_pct = 100 * sum(p["health"] < 0.5 for p in parcel_dict.values()) / len(parcel_dict)

    summary = (
        f"After Round {round_counter} with the '{plan_choice}' plan:\n"
        f"Avg forage: {avg_forage:.1f} AUMs, Parcels with low health (<0.5): {degraded_pct:.1f}%"
    )

    # Generate map visuals
    from Sim_Engine import get_forage_map, get_health_map, plot_forage_map, plot_health_map
    forage_map = get_forage_map(parcel_dict, n_rows, n_cols)
    health_map = get_health_map(parcel_dict, n_rows, n_cols)
    plot_forage_map(forage_map, title=f"Forage Map (Round {round_counter})", save_path="forage_map.png")
    plot_health_map(health_map, title=f"Health Map (Round {round_counter})", save_path="health_map.png")

    return summary, "forage_map.png", "health_map.png", round_counter + 1, parcel_dict

def simulate_and_summarize(plan_choice, round_counter, parcel_map, cluster_labels, n_rows, n_cols, run_full_simulation, history):

    strategy_map = {
        "conservative": "conservative",
        "normal": "moderate",
        "aggressive": "aggressive"
    }
    strategy = strategy_map.get(plan_choice.lower())
    parcel_dict = run_full_simulation(parcel_map, cluster_labels, n_rows, n_cols, strategy=strategy)

    plot_forage_map_to_file(parcel_dict, n_rows, n_cols, title=f"Round {round_counter} Forage Map")

    # ✅ ADD THIS BLOCK
    from Sim_Engine import get_health_map, plot_health_map
    health_map = get_health_map(parcel_dict, n_rows, n_cols)
    plot_health_map(health_map, title=f"Round {round_counter} Health Map", save_path="health_map.png")

    
    forage_vals = [p["forage"] for p in parcel_dict.values()]
    avg_forage = sum(forage_vals) / len(forage_vals)
    degraded_pct = 100 * sum(p["degraded"] for p in parcel_dict.values()) / len(parcel_dict)

    summary = (
        f"After Round {round_counter} with the '{plan_choice}' plan:\n"
        f"Avg forage: {avg_forage:.1f} AUMs, Degraded parcels: {degraded_pct:.1f}%"
    )
    return summary, "forage_map.png", "health_map.png", round_counter + 1


def full_response(plan_choice, essay_text, current_summary):
    elk_resp = elk_feedback(plan_choice, current_summary)
    usfs_resp = usfs_feedback(plan_choice, essay_text, current_summary)
    return elk_resp, usfs_resp