-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpec.php
More file actions
335 lines (297 loc) · 12.8 KB
/
pec.php
File metadata and controls
335 lines (297 loc) · 12.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
<?php
/**
* Patient Education Content Generator
*
* A PHP web application that uses AI to convert complex medical information
* into patient-friendly educational content.
*
* Features:
* - AI-powered simplification of medical content
* - Multiple lightweight AI models support (filtered for free models)
* - Multilingual output (6 languages)
* - Web interface with real-time results
* - REST API support
* - Configurable API endpoint via external config.php
*
* Requirements:
* - PHP 7.0+
* - cURL extension
* - JSON extension
* - Access to compatible AI API (e.g., Ollama)
*
* Usage:
* - Web interface: Access via browser
* - API endpoint: POST /pec.php with medical content
*
* API Usage:
* POST /pec.php
* Parameters:
* - content (required): Medical content to simplify
* - model (optional): AI model to use (default: qwen2.5:1.5b)
* - language (optional): Output language (default: en)
*
* Response:
* {
* "education": "simplified patient-friendly content"
* }
*
* Configuration:
* Create a config.php file with:
* - $LLM_API_ENDPOINT: AI API endpoint URL
* - $LLM_API_KEY: API key (if required)
*
* @author Costin Stroie <costinstroie@eridu.eu.org>
* @version 1.0
* @license GPL 3
*/
// Include common functions
include 'common.php';
// Configuration - Load from config.php if available, otherwise use defaults
if (file_exists('config.php')) {
include 'config.php';
} else {
// Safe defaults
$LLM_API_ENDPOINT = 'http://127.0.0.1:11434/v1';
$LLM_API_KEY = '';
$DEFAULT_TEXT_MODEL = 'qwen2.5:1.5b';
$LLM_API_FILTER = '/free/';
}
// Create chat endpoint URL
$LLM_API_ENDPOINT_CHAT = $LLM_API_ENDPOINT . '/chat/completions';
// Fetch available models from API, filtering with configured filter
$AVAILABLE_MODELS = getAvailableModels($LLM_API_ENDPOINT, $LLM_API_KEY, $LLM_API_FILTER);
// If API call fails, use default models
if (empty($AVAILABLE_MODELS)) {
$AVAILABLE_MODELS = [
'gemma3:1b' => 'Gemma 3 (1B)',
'qwen2.5:1.5b' => 'Qwen 2.5 (1.5B)'
];
}
// Set default model if not defined in config
if (!isset($DEFAULT_TEXT_MODEL)) {
$DEFAULT_TEXT_MODEL = !empty($AVAILABLE_MODELS) ? array_keys($AVAILABLE_MODELS)[0] : 'qwen2.5:1.5b';
}
/**
* Get selected model and language from POST/GET data, cookies, or use defaults
*/
$MODEL = isset($_POST['model']) ? $_POST['model'] : (isset($_GET['model']) ? $_GET['model'] : (isset($_COOKIE['pec-model']) ? $_COOKIE['pec-model'] : $DEFAULT_TEXT_MODEL));
$LANGUAGE = isset($_POST['language']) ? $_POST['language'] : (isset($_GET['language']) ? $_GET['language'] : (isset($_COOKIE['pec-language']) ? $_COOKIE['pec-language'] : 'en'));
/**
* Validate model selection
* Falls back to default model if invalid model is selected
*/
if (!array_key_exists($MODEL, $AVAILABLE_MODELS)) {
$MODEL = 'qwen2.5:1.5b'; // Default to a valid model
}
/**
* Validate language selection
* Falls back to English if invalid language is selected
*/
if (!array_key_exists($LANGUAGE, $AVAILABLE_LANGUAGES)) {
$LANGUAGE = 'en'; // Default to English
}
/**
* System prompt for the AI model
* Contains instructions for converting medical content to patient education format
*/
$SYSTEM_PROMPT = "You are a medical education specialist. Your task is to convert complex medical information into patient-friendly educational content.
CRITICAL INSTRUCTION: " . getLanguageInstruction($LANGUAGE) . "
TASK:
- Take the provided medical content and rewrite it in simple, easy-to-understand language
- Use everyday terms instead of medical jargon
- Explain medical terms when they must be used
- Keep explanations clear and concise
- Maintain accuracy while improving accessibility
- Format the output with clear headings and bullet points where appropriate
OUTPUT FORMAT:
Plain text with clear formatting. Use headings (h3 to h6 only, no h1 or h2), bullet points, and short paragraphs to improve readability.
RULES:
- Focus on what the patient needs to know
- Avoid technical terms when simpler alternatives exist
- Explain any technical terms that cannot be avoided
- Use active voice and present tense
- Include practical information when relevant (e.g., what to expect, when to seek help)
- Do not add information not present in the original content
- Do not make medical recommendations or diagnoses
- Use only h3 to h6 heading levels (### to ###### in Markdown)
- Respond only with the patient-friendly content, without additional text
EXAMPLE:
Input: \"The patient presents with acute myocardial infarction secondary to coronary artery occlusion. Percutaneous coronary intervention was performed with stent placement.\"
Output:
\"### Heart Attack Treatment
You had a heart attack, which happens when blood flow to part of your heart muscle is blocked.
To treat this, we performed a procedure called angioplasty where we:
* Inserted a thin tube into the blocked heart artery
* Opened the blockage using a small balloon
* Placed a metal stent (tube) to keep the artery open
This procedure helps restore blood flow to your heart and prevents further damage.\"";
/**
* Application state variables
* @var string|null $result Simplified content result
* @var string|null $error Error message if any
* @var bool $processing Whether analysis is in progress
* @var bool $is_api_request Whether request is API call (not web form)
*/
$result = null;
$error = null;
$processing = false;
$is_api_request = false;
/**
* Handle POST/GET requests for content simplification
* Processes both web form submissions and API requests
* Validates input, calls AI API, and processes response
*/
if (($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['content'])) ||
($_SERVER['REQUEST_METHOD'] === 'GET' && !empty($_GET['content']))) {
$processing = true;
$is_api_request = (!isset($_POST['submit']) && !isset($_GET['submit'])); // If no submit button, it's an API request
// Sanitize and validate input
$content = trim(isset($_POST['content']) ? $_POST['content'] : $_GET['content']);
// Validate content length (prevent extremely large inputs)
if (strlen($content) > 10000) {
$error = 'The content is too long. Maximum 10000 characters allowed.';
$processing = false;
}
// Validate content is not empty after trimming
elseif (empty($content)) {
$error = 'The content cannot be empty.';
$processing = false;
}
// Only proceed with API call if validation passed
if ($processing) {
// Prepare API request
$data = [
'model' => $MODEL,
'messages' => [
['role' => 'system', 'content' => $SYSTEM_PROMPT],
['role' => 'user', 'content' => "MEDICAL CONTENT TO SIMPLIFY:\n" . $content]
]
];
// Make API request using common function
$response_data = callLLMApi($LLM_API_ENDPOINT_CHAT, $data, $LLM_API_KEY);
if (isset($response_data['error'])) {
$error = $response_data['error'];
} elseif (isset($response_data['choices'][0]['message']['content'])) {
$result = trim($response_data['choices'][0]['message']['content']);
} else {
$error = 'Invalid API response format';
}
// Set cookies with the selected model and language only for web requests
if (!$is_api_request) {
setcookie('pec-model', $MODEL, time() + (30 * 24 * 60 * 60), '/'); // 30 days
setcookie('pec-language', $LANGUAGE, time() + (30 * 24 * 60 * 60), '/'); // 30 days
}
// Return JSON if it's an API request
if ($is_api_request) {
header('Access-Control-Allow-Origin: *');
header('Content-Type: application/json');
if ($error) {
echo json_encode(['error' => $error]);
} else {
echo json_encode(['education' => $result]);
}
exit;
}
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Patient Education Content Generator</title>
<link rel="stylesheet" href="style.css">
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Ctext y='.9em' font-size='90'%3E%F0%9F%A4%93%3C/text%3E%3C/svg%3E">
</head>
<body>
<div class="container">
<hgroup>
<h1>🤓 Patient Education Content Generator</h1>
<p>AI-powered simplification of medical information for patients</p>
</hgroup>
<main>
<?php if ($error): ?>
<section role="alert" class="error">
<strong>⚠️ Error:</strong>
<?php if (is_array($error)): ?>
<pre><?php echo json_encode($error, JSON_PRETTY_PRINT); ?></pre>
<?php else: ?>
<?php echo htmlspecialchars($error); ?>
<?php endif; ?>
</section>
<?php endif; ?>
<?php if ($result): ?>
<article>
<header>
<h2>Patient-Friendly Content</h2>
</header>
<div class="markdown-result">
<?php echo markdownToHtml(htmlspecialchars($result)); ?>
</div>
</article>
<?php endif; ?>
<form method="POST" action="" id="educationForm">
<fieldset>
<label for="content">Medical content:</label>
<textarea
id="content"
name="content"
rows="8"
required
placeholder="Enter complex medical content to simplify for patients... Example: The patient presents with acute myocardial infarction secondary to coronary artery occlusion. Percutaneous coronary intervention was performed with stent placement."
><?php echo isset($_POST['content']) ? htmlspecialchars($_POST['content']) : (isset($_GET['content']) ? htmlspecialchars($_GET['content']) : ''); ?></textarea>
<small>
Enter the medical content you want to convert to patient-friendly language.
</small>
<label for="model">AI model:</label>
<select id="model" name="model">
<?php foreach ($AVAILABLE_MODELS as $value => $label): ?>
<option value="<?php echo htmlspecialchars($value); ?>" <?php echo ($MODEL === $value) ? 'selected' : ''; ?>>
<?php echo htmlspecialchars($label); ?>
</option>
<?php endforeach; ?>
</select>
<small>
Select the AI model to use for content simplification.
</small>
<label for="language">Response language:</label>
<select id="language" name="language">
<?php foreach ($AVAILABLE_LANGUAGES as $value => $label): ?>
<option value="<?php echo htmlspecialchars($value); ?>" <?php echo ($LANGUAGE === $value) ? 'selected' : ''; ?>>
<?php echo htmlspecialchars($label); ?>
</option>
<?php endforeach; ?>
</select>
<small>
Select the language for the patient education content.
</small>
</fieldset>
<button type="submit" name="submit" value="1" class="btn btn-primary">
<?php if ($processing && !$result && !$error): ?>
<span class="loading"></span>
<?php endif; ?>
🤓 Generate Education Content
</button>
<div class="button-grid">
<button type="button" class="btn btn-secondary" onclick="clearForm()">
🔄 New Content
</button>
<button type="button" class="btn btn-secondary" onclick="window.location.href='index.php'">
🏠 Back to Main Menu
</button>
</div>
</form>
</main>
</div>
<script>
function clearForm() {
document.getElementById('content').value = '';
document.getElementById('model').selectedIndex = 0;
document.getElementById('language').selectedIndex = 0;
// Reload page to clear results
window.location.href = window.location.pathname;
}
</script>
</body>
</html>