To solve the optimization problem described, we first need to convert the natural language description into a symbolic representation. This involves defining variables for the quantities of each type of sign to be made and then formulating the objective function and constraints in terms of these variables.

Let's define:
- $x_1$ as the number of storefront signs to be made.
- $x_2$ as the number of street signs to be made.

The profit per storefront sign is $400, and the profit per street sign is $120. Therefore, the objective function to maximize profit can be written as:
\[ 400x_1 + 120x_2 \]

Now, let's formulate the constraints based on the time available for each process:
- Cutting: Each storefront sign requires 2 hours, and each street sign requires 1 hour. The total cutting time available is 100 hours. So, the constraint can be written as:
\[ 2x_1 + x_2 \leq 100 \]
- Printing: Each storefront sign requires 1 hour, and each street sign requires 0.5 hours. The total printing time available is 50 hours. So, the constraint can be written as:
\[ x_1 + 0.5x_2 \leq 50 \]
- Assembly: Each storefront sign requires 2 hours, and each street sign requires 0.8 hours. The total assembly time available is 60 hours. So, the constraint can be written as:
\[ 2x_1 + 0.8x_2 \leq 60 \]

Additionally, $x_1$ and $x_2$ must be non-negative since they represent quantities of signs.

The symbolic representation in JSON format is:
```json
{
    'sym_variables': [('x1', 'number of storefront signs'), ('x2', 'number of street signs')],
    'objective_function': '400*x1 + 120*x2',
    'constraints': ['2*x1 + x2 <= 100', 'x1 + 0.5*x2 <= 50', '2*x1 + 0.8*x2 <= 60', 'x1 >= 0', 'x2 >= 0']
}
```

Now, let's write the Gurobi code in Python to solve this optimization problem:
```python
from gurobipy import *

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

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

# Set objective function
m.setObjective(400*x1 + 120*x2, GRB.MAXIMIZE)

# Add constraints
m.addConstr(2*x1 + x2 <= 100, name='cutting_time')
m.addConstr(x1 + 0.5*x2 <= 50, name='printing_time')
m.addConstr(2*x1 + 0.8*x2 <= 60, name='assembly_time')

# Optimize model
m.optimize()

# Print results
if m.status == GRB.OPTIMAL:
    print('Optimal solution found:')
    print(f'Number of storefront signs: {x1.x}')
    print(f'Number of street signs: {x2.x}')
    print(f'Total profit: ${400*x1.x + 120*x2.x:.2f}')
else:
    print('No optimal solution found.')
```