```json
{
  "sym_variables": [
    ("x1", "number of cleaners"),
    ("x2", "number of receptionists")
  ],
  "objective_function": "500*x1 + 350*x2",
  "constraints": [
    "x1 + x2 >= 100",
    "x2 >= 20",
    "x2 >= (1/3)*x1",
    "500*x1 + 350*x2 <= 30000",
    "x1 >= 0",
    "x2 >= 0"
  ]
}
```

```python
import gurobipy as gp
from gurobipy import GRB

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

# Create variables
cleaners = model.addVar(lb=0, vtype=GRB.INTEGER, name="cleaners")
receptionists = model.addVar(lb=0, vtype=GRB.INTEGER, name="receptionists")

# Set objective function
model.setObjective(500 * cleaners + 350 * receptionists, GRB.MINIMIZE)

# Add constraints
model.addConstr(cleaners + receptionists >= 100, "total_staff")
model.addConstr(receptionists >= 20, "min_receptionists")
model.addConstr(receptionists >= (1/3) * cleaners, "receptionists_to_cleaners_ratio")
model.addConstr(500 * cleaners + 350 * receptionists <= 30000, "wage_bill")


# Optimize model
model.optimize()

# Check if a solution was found
if model.status == GRB.OPTIMAL:
    print(f"Optimal solution found. Weekly wage bill: ${model.objVal}")
    print(f"Number of cleaners: {cleaners.x}")
    print(f"Number of receptionists: {receptionists.x}")
elif model.status == GRB.INFEASIBLE:
    print("Model is infeasible. No solution found.")
else:
    print(f"Optimization terminated with status {model.status}")

```
