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 quantities of neon and metal signs, formulating the objective function based on profits, and listing the constraints related to crafting and installation hours.

Let's define:
- \(x_1\) as the number of neon signs
- \(x_2\) as the number of metal signs

The objective function aims to maximize profit. Given that each neon sign provides a profit of $200 and each metal sign provides a profit of $100, the objective function can be represented as:
\[ \text{Maximize:} \quad 200x_1 + 100x_2 \]

The constraints are based on the available hours for crafting and installation:
- Each neon sign takes 3 hours for crafting, so \(x_1\) neon signs take \(3x_1\) hours.
- Each metal sign takes 2 hours for crafting, so \(x_2\) metal signs take \(2x_2\) hours.
- The total available hours for crafting is 950, leading to the constraint: \(3x_1 + 2x_2 \leq 950\).
- For installation:
  - Each neon sign takes 2 hours, so \(x_1\) neon signs take \(2x_1\) hours.
  - Each metal sign takes 1.5 hours, so \(x_2\) metal signs take \(1.5x_2\) hours.
  - The total available hours for installation is 400, leading to the constraint: \(2x_1 + 1.5x_2 \leq 400\).

Additionally, \(x_1 \geq 0\) and \(x_2 \geq 0\) because the number of signs cannot be negative.

Thus, the symbolic representation of the problem is:
```json
{
  'sym_variables': [('x1', 'number of neon signs'), ('x2', 'number of metal signs')],
  'objective_function': '200*x1 + 100*x2',
  'constraints': ['3*x1 + 2*x2 <= 950', '2*x1 + 1.5*x2 <= 400', 'x1 >= 0', 'x2 >= 0']
}
```

To solve this problem using Gurobi in Python, we'll use the following code:

```python
from gurobipy import *

# Create a new model
m = Model("Sign_Crafting")

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

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

# Add constraints
m.addConstr(3*x1 + 2*x2 <= 950, name="crafting_hours")
m.addConstr(2*x1 + 1.5*x2 <= 400, name="installation_hours")

# Optimize the model
m.optimize()

# Print the solution
if m.status == GRB.OPTIMAL:
    print("Optimal solution found:")
    print(f"Number of neon signs: {x1.x}")
    print(f"Number of metal signs: {x2.x}")
    print(f"Maximum profit: ${200*x1.x + 100*x2.x:.2f}")
else:
    print("No optimal solution found")
```