To solve this optimization problem, we first need to define the symbolic representation of the variables and the objective function, as well as identify all constraints given in the natural language description.

Let's denote:
- \(x_1\) as the number of printed arts produced,
- \(x_2\) as the number of paintings produced.

The profit per printed art sold is $5, and the profit per painting sold is $8. Thus, the objective function to maximize profits can be written as:
\[ \text{Maximize:} \quad 5x_1 + 8x_2 \]

Given constraints are:
- Time for printing: \(10x_1 + 0x_2 \leq 150\) (since paintings take 0 minutes for printing),
- Time for framing: \(5x_1 + 15x_2 \leq 400\).

Additionally, we have non-negativity constraints since the company cannot produce a negative number of items:
\[ x_1 \geq 0, \quad x_2 \geq 0 \]

Thus, our symbolic representation in JSON format is:

```json
{
    'sym_variables': [('x1', 'number of printed arts'), ('x2', 'number of paintings')],
    'objective_function': '5*x1 + 8*x2',
    'constraints': ['10*x1 <= 150', '5*x1 + 15*x2 <= 400', 'x1 >= 0', 'x2 >= 0']
}
```

Now, let's implement this problem using Gurobi in Python:

```python
from gurobipy import *

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

# Define variables
x1 = m.addVar(lb=0, vtype=GRB.INTEGER, name="printed_arts")
x2 = m.addVar(lb=0, vtype=GRB.INTEGER, name="paintings")

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

# Add constraints
m.addConstr(10*x1 <= 150, "printing_time")
m.addConstr(5*x1 + 15*x2 <= 400, "framing_time")

# Optimize model
m.optimize()

# Print solution
if m.status == GRB.OPTIMAL:
    print("Optimal solution found:")
    print(f"Number of printed arts: {x1.x}")
    print(f"Number of paintings: {x2.x}")
    print(f"Maximum profit: ${5*x1.x + 8*x2.x}")
else:
    print("No optimal solution found")
```