```json
{
  "sym_variables": [
    ("x1", "apple pies"),
    ("x2", "peach pies")
  ],
  "objective_function": "7*x1 + 8*x2",
  "constraints": [
    "x1 >= 15",
    "x2 >= 12",
    "x1 <= 20",
    "x2 <= 18",
    "x1 + x2 <= 30"
  ]
}
```

```python
import gurobipy as gp
from gurobipy import GRB

# Create a new model
m = gp.Model("pie_shop")

# Create variables
apple_pies = m.addVar(vtype=GRB.INTEGER, name="apple_pies")
peach_pies = m.addVar(vtype=GRB.INTEGER, name="peach_pies")

# Set objective function
m.setObjective(7 * apple_pies + 8 * peach_pies, GRB.MAXIMIZE)

# Add constraints
m.addConstr(apple_pies >= 15, "min_apple")
m.addConstr(peach_pies >= 12, "min_peach")
m.addConstr(apple_pies <= 20, "max_apple")
m.addConstr(peach_pies <= 18, "max_peach")
m.addConstr(apple_pies + peach_pies <= 30, "total_pies")

# Optimize model
m.optimize()

# Print results
if m.status == GRB.OPTIMAL:
    print(f"Optimal profit: ${m.objVal:.2f}")
    print(f"Number of apple pies: {apple_pies.x}")
    print(f"Number of peach pies: {peach_pies.x}")
elif m.status == GRB.INFEASIBLE:
    print("The model is infeasible.")
else:
    print(f"Optimization ended with status {m.status}")

```
