XCL Web Application Platform 2.5.0
The XoopsCube Legacy Project
Loading...
Searching...
No Matches
legacy_ai_assistant.php
1<?php
12
14{
15 private $api_token;
16 private $api_url = 'https://api-inference.huggingface.co/models/';
17 private $supported_languages = [
18 'en' => 'English',
19 'fr' => 'French',
20 'ja' => 'Japanese',
21 'pt' => 'Portuguese',
22 'ru' => 'Russian'
23 ];
24
25 public function __construct($options)
26 {
27 // Debug configuration with better visibility
28 // error_log("AI Block Constructor Options: " . json_encode($options));
29
30 // Fix token extraction
31 if (is_array($options)) {
32 $this->api_token = $options['api_token'] ?? '';
33 } else if (is_string($options)) {
34 $values = explode('|', $options);
35 $this->api_token = trim($values[0] ?? '');
36 }
37
38 // Validate token format
39 if (!empty($this->api_token) && !preg_match('/^hf_/', $this->api_token)) {
40 //error_log("Invalid token format. Should start with 'hf_'");
41 }
42
43 // error_log("Token Status: " . (empty($this->api_token) ? 'Empty' : 'Present'));
44 }
45
46 public function processRequest($content, $type, $sourceLang = '', $targetLang = '')
47 {
48 if (empty($content)) {
49 throw new Exception(_MB_LEGACY_BLOCK_AI_NO_CONTENT);
50 }
51
52 try {
53 switch($type) {
54 case 'translate':
55 // Use Facebook's mBART model for translations
56 $model = "facebook/mbart-large-50-many-to-many-mmt";
57
58 // Map language codes to mBART format if needed
59 $mbartSourceLang = $this->getMbartLangCode($sourceLang);
60 $mbartTargetLang = $this->getMbartLangCode($targetLang);
61
62 $data = [
63 'inputs' => $content,
64 'parameters' => [
65 'src_lang' => $mbartSourceLang,
66 'tgt_lang' => $mbartTargetLang
67 ]
68 ];
69
70 // debug
71 // error_log("Using mBART model with src_lang: $mbartSourceLang, tgt_lang: $mbartTargetLang");
72 break;
73 case 'summarize':
74 $model = "facebook/bart-large-cnn";
75 $data = [
76 'inputs' => $content,
77 'parameters' => [
78 'max_length' => 130,
79 'min_length' => 30,
80 ]
81 ];
82 break;
83 default: // enhance
84 $model = "facebook/bart-large-cnn";
85 $data = [
86 'inputs' => $content,
87 'parameters' => ['max_length' => 100]
88 ];
89 }
90
91 $result = $this->callHuggingFace($model, $data);
92
93 // Debug response
94 // error_log("API Result: " . print_r($result, true));
95
96 // Handle different response formats
97 if (is_array($result)) {
98 // Direct array response
99 if (isset($result['generated_text'])) {
100 return $result['generated_text'];
101 }
102 // Array of results
103 if (isset($result[0])) {
104 foreach(['summary_text', 'translation_text', 'generated_text'] as $key) {
105 if (isset($result[0][$key])) {
106 return $result[0][$key];
107 }
108 }
109 }
110 // Raw array response
111 return json_encode($result);
112 }
113
114 // String response
115 return (string)$result;
116
117 } catch (Exception $e) {
118 // Debug error
119 // error_log("AI Processing Error: " . $e->getMessage());
120 throw new Exception(_MB_LEGACY_BLOCK_AI_ERROR . ': ' . $e->getMessage());
121 }
122 }
123
124 // Helper method to map our language codes to mBART format
125 private function getMbartLangCode($langCode) {
126 $mbartMap = [
127 'en' => 'en_XX',
128 'fr' => 'fr_XX',
129 'ja' => 'ja_XX',
130 'pt' => 'pt_XX',
131 'ru' => 'ru_RU' // Updated to ru_RU instead of ru_XX
132 ];
133
134 return $mbartMap[$langCode] ?? 'en_XX'; // Default to English if not found
135 }
136
137 private function callHuggingFace($model, $data)
138 {
139 if (empty($this->api_token)) {
140 // Debug error
141 // error_log("Missing API token in callHuggingFace");
142 throw new Exception(_MB_LEGACY_BLOCK_AI_NO_TOKEN);
143 }
144
145 $url = $this->api_url . $model;
146
147 // Debug request
148 /* error_log("Making API request:");
149 error_log("- URL: " . $url);
150 error_log("- Token Length: " . strlen($this->api_token));
151 error_log("- Data: " . json_encode($data)); */
152
153 $ch = curl_init($url);
154 curl_setopt_array($ch, [
155 CURLOPT_RETURNTRANSFER => true,
156 CURLOPT_POST => true,
157 CURLOPT_POSTFIELDS => json_encode($data),
158 CURLOPT_HTTPHEADER => [
159 'Authorization: Bearer ' . $this->api_token,
160 'Content-Type: application/json',
161 'Accept: application/json',
162 'Origin: ' . (isset($_SERVER['HTTPS']) ? 'https://' : 'http://') . $_SERVER['HTTP_HOST']
163 ],
164 // SSL settings
165 CURLOPT_SSL_VERIFYPEER => false,
166 CURLOPT_SSL_VERIFYHOST => 0,
167 CURLOPT_TIMEOUT => 30,
168 // Debug info
169 CURLOPT_VERBOSE => true
170 ]);
171
172 // Capture CURL debug output
173 $verbose = fopen('php://temp', 'w+');
174 curl_setopt($ch, CURLOPT_STDERR, $verbose);
175
176 $response = curl_exec($ch);
177 $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
178 $error = curl_error($ch);
179
180 // Log verbose debug info
181 rewind($verbose);
182 $verboseLog = stream_get_contents($verbose);
183 // debug
184 // error_log("CURL Debug: " . $verboseLog);
185
186 curl_close($ch);
187
188 // Log response details
189 // error_log("HTTP Code: " . $httpCode);
190
191 if ($error) {
192 throw new Exception("cURL Error: " . $error);
193 }
194
195 // Improved error handling with specific messages for common errors
196 if ($httpCode !== 200) {
197 // Handle specific HTTP error codes
198 switch ($httpCode) {
199 case 403:
200 // error_log("API Authorization Error: " . substr($response, 0, 200) . "...");
201 throw new Exception(_MB_LEGACY_BLOCK_AI_ERROR);
202 case 404:
203 // error_log("Model Not Found: " . $model);
204 throw new Exception(_MB_LEGACY_BLOCK_AI_ERROR);
205 case 429:
206 // error_log("Rate Limit Exceeded: " . substr($response, 0, 200) . "...");
207 throw new Exception(_MB_LEGACY_BLOCK_AI_ERROR);
208 default:
209 // error_log("API Error (HTTP $httpCode): " . substr($response, 0, 200) . "...");
210 throw new Exception(_MB_LEGACY_BLOCK_AI_ERROR);
211 }
212 }
213
214 $result = json_decode($response, true);
215 if (json_last_error() !== JSON_ERROR_NONE) {
216 // Try to return raw response if JSON decode fails
217 return $response;
218 }
219
220 return $result;
221 }
222}
223
224// Block functions should be outside the class
225function b_legacy_ai_assistant_show($options)
226{
227 $action = ''; //enhance, translate
228
229 // Parse options from pipe-separated string if needed
230 if (is_string($options)) {
231 $values = explode('|', $options);
232 } else {
233 $values = $options;
234 }
235
236 // TODO block bid if further duplication, used in block JavaScript
237 if (isset($block['bid'])) {
238 // access the bid key
239 $block_id = $block['bid'];
240 } else {
241 // handle the case where the bid key is not defined
242 $block_id = '888'; // or some other default value
243 }
244
245 // Create block array with named options
246 $block = array(
247 'title' => _MB_LEGACY_BLOCK_AI_NAME,
248 'options' => array(
249 'bid' => $block_id,
250 'api_token' => $values[0] ?? '',
251 'max_tokens' => intval($values[1] ?? 1000),
252 'temperature' => floatval($values[2] ?? 0.7),
253 'model' => $values[3] ?? 'gpt-3.5-turbo',
254 'side' => intval($values[4] ?? 0)
255 )
256 );
257
258 error_log("Block Options: " . print_r($block['options'], true));
259
260 // Process AI request if needed
261 if (isset($_POST['ai_action']) && $_POST['ai_action'] === 'query') {
262 try {
263 $aiBlock = new Legacy_AIAssistantBlock($block['options']);
264
265 // Get action type from POST
266 $action = $_POST['type'] ?? 'enhance';
267 $content = $_POST['ai_content'] ?? '';
268
269 if (empty($content)) {
270 throw new Exception(_MB_LEGACY_BLOCK_AI_NO_CONTENT);
271 }
272
273 // Handle translation specific parameters
274 if ($action === 'translate') {
275 $sourceLang = $_POST['source_lang'] ?? '';
276 $targetLang = $_POST['target_lang'] ?? '';
277
278 if (empty($sourceLang) || empty($targetLang)) {
279 throw new Exception(_MB_LEGACY_BLOCK_AI_LANG_ERROR);
280 }
281
282 if ($sourceLang === $targetLang) {
283 throw new Exception(_MB_LEGACY_BLOCK_AI_LANG_SAME_ERROR);
284 }
285
286 $result = $aiBlock->processRequest($content, $action, $sourceLang, $targetLang);
287 } else {
288 // For non-translation actions
289 $result = $aiBlock->processRequest($content, $action);
290 }
291
292 header('Content-Type: application/json');
293 echo json_encode(['success' => true, 'result' => $result]);
294
295 } catch (Exception $e) {
296 error_log("AI Block Error: " . $e->getMessage());
297 header('Content-Type: application/json');
298 echo json_encode([
299 'success' => false,
300 'error' => $e->getMessage()
301 ]);
302 }
303 exit;
304 }
305
306 return $block;
307}
308
309function b_legacy_ai_assistant_edit($options)
310{
311 // Parse options
312 if (is_string($options)) {
313 $values = explode('|', $options);
314 $options = [
315 'api_token' => $values[0] ?? '',
316 'max_tokens' => $values[1] ?? 1000,
317 'temperature' => $values[2] ?? 0.7,
318 'model' => $values[3] ?? 'facebook/mbart-large-50-many-to-many-mmt',
319 'side' => $values[4] ?? 0
320 ];
321 }
322
323 $form = '<table class="outer">';
324
325 // API Token field
326 $form .= '<tr>';
327 $form .= '<td class="head">' . _MB_LEGACY_BLOCK_AI_TOKEN . '</td>';
328 $form .= '<td class="even">';
329 $form .= '<input type="text" name="options[0]" value="' .
330 htmlspecialchars($options['api_token']) .
331 '" size="60" placeholder="hf_..." required>';
332 $form .= '</td></tr>';
333
334 // Max tokens
335 $form .= '<tr>';
336 $form .= '<td class="head">' . _MB_LEGACY_BLOCK_AI_TOKENS . '</td>';
337 $form .= '<td class="even">';
338 $form .= '<input type="number" name="options[1]" value="' .
339 intval($options['max_tokens']) . '" min="1" max="4000">';
340 $form .= '</td></tr>';
341
342 // Temperature
343 $form .= '<tr>';
344 $form .= '<td class="head">' . _MB_LEGACY_BLOCK_AI_TEMP . '</td>';
345 $form .= '<td class="even">';
346 $form .= '<input type="number" name="options[2]" value="' .
347 floatval($options['temperature']) . '" min="0" max="1" step="0.1">';
348 $form .= '</td></tr>';
349
350 // Model selection - Updated to use Hugging Face models
351 $form .= '<tr>';
352 $form .= '<td class="head">' . _MB_LEGACY_BLOCK_AI_MODEL . '</td>';
353 $form .= '<td class="even"><select name="options[3]">';
354 $form .= '<option value="facebook/mbart-large-50-many-to-many-mmt"' .
355 ($options['model'] === 'facebook/mbart-large-50-many-to-many-mmt' ? ' selected' : '') .
356 '>mBART-50 (Translation)</option>';
357 $form .= '<option value="facebook/bart-large-cnn"' .
358 ($options['model'] === 'facebook/bart-large-cnn' ? ' selected' : '') .
359 '>BART-CNN (Summarization)</option>';
360 $form .= '</select></td></tr>';
361
362 // Side (hidden)
363 $form .= '<input type="hidden" name="options[4]" value="' .
364 intval($options['side']) . '">';
365
366 $form .= '</table>';
367
368 return $form;
369}