Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
43 / 43
100.00% covered (success)
100.00%
3 / 3
CRAP
100.00% covered (success)
100.00%
1 / 1
RolePlayConfigController
100.00% covered (success)
100.00%
43 / 43
100.00% covered (success)
100.00%
3 / 3
6
100.00% covered (success)
100.00%
1 / 1
 index
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
2
 updateSection
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
3
 testPrompt
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace App\Http\Controllers\v2\Admin;
4
5use App\Http\Controllers\Controller;
6use App\Http\Models\RolePlayConfig;
7use Illuminate\Http\JsonResponse;
8use Illuminate\Http\Request;
9
10/**
11 * Controller for managing RolePlay platform configuration via CMC.
12 *
13 * Provides endpoints to view and update the global RolePlayConfig document,
14 * which consolidates voices, names, images, personalities, VAPI defaults,
15 * objections, and scorecards used by the roleplay simulation engine.
16 *
17 * Only accessible by users with the VENGRESO_ADMIN role.
18 */
19class RolePlayConfigController extends Controller
20{
21    /**
22     * Valid config sections that can be updated individually.
23     *
24     * @var array<string>
25     */
26    private const VALID_SECTIONS = [
27        'voices',
28        'personalities',
29        'names',
30        'images',
31        'vapi_defaults',
32        'default_objections',
33        'default_scorecards',
34    ];
35
36    /**
37     * Get the global RolePlay configuration.
38     *
39     * Returns the full global config document including voices, names,
40     * images, personalities, VAPI defaults, objections, and scorecards.
41     *
42     * @param Request $request
43     * @return JsonResponse
44     *
45     * @response 200 {
46     *   "result": {
47     *     "id": "...",
48     *     "type": "global",
49     *     "voices": {"male": [...], "female": [...]},
50     *     "names": {"male": [...], "female": [...]},
51     *     "images": {"male": [...], "female": [...]},
52     *     "personalities": [...],
53     *     "vapi_defaults": {...},
54     *     "default_objections": [...],
55     *     "default_scorecards": {...}
56     *   }
57     * }
58     * @response 404 {"error": "Global configuration not found."}
59     */
60    public function index(Request $request): JsonResponse
61    {
62        $config = RolePlayConfig::getGlobal();
63
64        if (!$config) {
65            return response()->json([
66                'error' => 'Global configuration not found.',
67            ], 404);
68        }
69
70        return response()->json([
71            'status' => 'success',
72            'data' => $config,
73        ]);
74    }
75
76    /**
77     * Update a specific section of the global RolePlay configuration.
78     *
79     * Accepts a section name as a URL parameter and the new value in the
80     * request body. Only sections listed in VALID_SECTIONS are allowed.
81     *
82     * @param Request $request
83     * @param string $section The config section to update (e.g., 'voices', 'personalities')
84     * @return JsonResponse
85     *
86     * @response 200 {
87     *   "result": {
88     *     "status": "success",
89     *     "data": {...}
90     *   }
91     * }
92     * @response 400 {"error": "Invalid section. Allowed sections: voices, personalities, ..."}
93     * @response 404 {"error": "Global configuration not found."}
94     * @response 422 {"error": "The value field is required."}
95     */
96    public function updateSection(Request $request, string $section): JsonResponse
97    {
98        if (!in_array($section, self::VALID_SECTIONS, true)) {
99            return response()->json([
100                'error' => 'Invalid section. Allowed sections: ' . implode(', ', self::VALID_SECTIONS),
101            ], 400);
102        }
103
104        $request->validate([
105            'value' => 'required|array',
106        ]);
107
108        $config = RolePlayConfig::getGlobal();
109
110        if (!$config) {
111            return response()->json([
112                'error' => 'Global configuration not found.',
113            ], 404);
114        }
115
116        $config->updateSection($section, $request->input('value'));
117
118        return response()->json([
119            'status' => 'success',
120            'data' => $config->fresh(),
121        ]);
122    }
123
124    /**
125     * Test a prompt template by replacing placeholders with sample data.
126     *
127     * Accepts a product type, prompt text, and a map of placeholder values.
128     * Returns the prompt with all placeholders replaced. Does not make any
129     * actual AI calls — this is purely a string substitution preview.
130     *
131     * @param Request $request
132     * @return JsonResponse
133     *
134     * @response 200 {
135     *   "result": {
136     *     "status": "success",
137     *     "data": {
138     *       "product": "roleplay_cold_call",
139     *       "rendered_prompt": "Hello John, calling about..."
140     *     }
141     *   }
142     * }
143     * @response 422 {"error": "The product field is required."}
144     */
145    public function testPrompt(Request $request): JsonResponse
146    {
147        $request->validate([
148            'product' => 'required|string',
149            'prompt' => 'required|string',
150            'placeholders' => 'sometimes|array',
151        ]);
152
153        $prompt = $request->input('prompt');
154        $placeholders = $request->input('placeholders', []);
155
156        $keys = array_keys($placeholders);
157        $values = array_values($placeholders);
158        $renderedPrompt = str_replace($keys, $values, $prompt);
159
160        return response()->json([
161            'status' => 'success',
162            'data' => [
163                'product' => $request->input('product'),
164                'rendered_prompt' => $renderedPrompt,
165            ],
166        ]);
167    }
168}