```json
{
  "sym_variables": [
    ("x1", "packets of cat food"),
    ("x2", "cans of tuna")
  ],
  "objective_function": "12*x1 + 7*x2",
  "constraints": [
    "5*x1 + 7*x2 >= 700",
    "15*x1 + 12*x2 >= 1100",
    "12*x1 + 15*x2 >= 900",
    "x1 >= 0",
    "x2 >= 0"
  ]
}
```

```python
import gurobipy as gp

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

# Create variables
cat_food = model.addVar(vtype=gp.GRB.CONTINUOUS, name="cat_food")  # x1
tuna = model.addVar(vtype=gp.GRB.CONTINUOUS, name="tuna")  # x2


# Set objective function
model.setObjective(12 * cat_food + 7 * tuna, gp.GRB.MINIMIZE)

# Add constraints
model.addConstr(5 * cat_food + 7 * tuna >= 700, "carbohydrates")
model.addConstr(15 * cat_food + 12 * tuna >= 1100, "vitamins")
model.addConstr(12 * cat_food + 15 * tuna >= 900, "protein")
model.addConstr(cat_food >= 0, "cat_food_non_negative")  # Ensure non-negative values
model.addConstr(tuna >= 0, "tuna_non_negative")  # Ensure non-negative values


# Optimize model
model.optimize()

# Check for infeasibility
if model.status == gp.GRB.INFEASIBLE:
    print("The model is infeasible.")
else:
    # Print results
    print(f"Optimal cost: ${model.objVal}")
    print(f"Number of cat food packets: {cat_food.x}")
    print(f"Number of tuna cans: {tuna.x}")

```
