To solve the given optimization problem, we first need to convert the natural language description into a symbolic representation. This involves defining variables for the unknown quantities and translating the objective function and constraints into algebraic expressions.

Let's define:
- $x_1$ as the number of batches of cupcakes.
- $x_2$ as the number of batches of cakes.

The profit per batch of cupcakes is $10, and the profit per batch of cake is $25. Thus, the objective function to maximize profit can be written as:
\[ 10x_1 + 25x_2 \]

Now, let's consider the constraints based on the availability of oven and cooling rack time.

- Each batch of cupcakes requires 20 minutes in the oven, so $x_1$ batches will require $20x_1$ minutes. Similarly, each batch of cakes requires 60 minutes in the oven, so $x_2$ batches will require $60x_2$ minutes. The total oven time available per month is 9000 minutes. Therefore, the constraint for oven time can be expressed as:
\[ 20x_1 + 60x_2 \leq 9000 \]

- For cooling rack time, each batch of cupcakes requires 60 minutes, and each batch of cakes requires 120 minutes. The total cooling rack time available per month is 12000 minutes. Thus, the constraint for cooling rack time can be written as:
\[ 60x_1 + 120x_2 \leq 12000 \]

Additionally, we should consider non-negativity constraints since the number of batches cannot be negative:
\[ x_1 \geq 0, x_2 \geq 0 \]

Given this analysis, the symbolic representation of the problem can be encapsulated as follows:

```json
{
    'sym_variables': [('x1', 'number of batches of cupcakes'), ('x2', 'number of batches of cakes')],
    'objective_function': '10*x1 + 25*x2',
    'constraints': [
        '20*x1 + 60*x2 <= 9000',
        '60*x1 + 120*x2 <= 12000',
        'x1 >= 0',
        'x2 >= 0'
    ]
}
```

To solve this linear programming problem using Gurobi in Python, we can write the following code:

```python
from gurobipy import *

# Create a model
m = Model("Dessert_Optimization")

# Define variables
x1 = m.addVar(vtype=GRB.CONTINUOUS, name="cupcakes", lb=0)
x2 = m.addVar(vtype=GRB.CONTINUOUS, name="cakes", lb=0)

# Set the objective function
m.setObjective(10*x1 + 25*x2, GRB.MAXIMIZE)

# Add constraints
m.addConstr(20*x1 + 60*x2 <= 9000, "oven_time")
m.addConstr(60*x1 + 120*x2 <= 12000, "cooling_rack_time")

# Optimize the model
m.optimize()

# Print results
if m.status == GRB.OPTIMAL:
    print("Optimal solution found.")
    print(f"Number of batches of cupcakes: {x1.x}")
    print(f"Number of batches of cakes: {x2.x}")
    print(f"Maximum profit: ${10*x1.x + 25*x2.x:.2f}")
else:
    print("No optimal solution found.")
```