Skip to content

Commit

Permalink
Merge pull request #12 from susom/development
Browse files Browse the repository at this point in the history
Development
  • Loading branch information
Jordan-M-Schultz authored Oct 23, 2024
2 parents ea2b325 + 205baab commit 780b69d
Show file tree
Hide file tree
Showing 7 changed files with 181 additions and 28 deletions.
97 changes: 78 additions & 19 deletions MICA.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
require_once "emLoggerTrait.php";
require_once "classes/Sanitizer.php";
require_once "classes/MICAQuery.php";

require_once "vendor/autoload.php";
use Exception;
use UserRights;

class MICA extends \ExternalModules\AbstractExternalModule {
use emLoggerTrait;

const BUILD_FILE_DIR = 'mica-chatbot/dist/assets';
const SecureChatInstanceModuleName = 'secure_chat_ai';

Expand All @@ -34,6 +36,10 @@ public function initSystemContexts(){
return $initial_system_context;
}

public function getIntroText(){
return $this->getProjectSetting('chatbot_intro_text');
}

public function generateAssetFiles(): array {
$cwd = $this->getModulePath();
$assets = [];
Expand Down Expand Up @@ -65,6 +71,20 @@ public function generateAssetFiles(): array {
return $assets;
}

/**
* @param $project_id
* @param $link
* @return mixed|null
*/
function redcap_module_link_check_display($project_id, $link)
{
//Replace web link on sidebar with direct noauth link
if (isset($link) && array_key_exists('url', $link) && str_contains($link['url'], 'chatbot')) {
$link['url'] = $link['url'] . '&NOAUTH';
}
return $link;
}

/**
* @param $data
* @return mixed
Expand Down Expand Up @@ -304,6 +324,7 @@ public function loginUser($payload): array
throw new \Exception("Your MICA session was completed on $time_completed, thank you for participating");
}

// TODO Change user complete to form name
// Otherwise, login regularly
if($check['participant_name'] === $name && $check['participant_email'] === $email) { //User Successfully matched
$this->generateOneTimePassword($check[$primary_field], $check['participant_email']);
Expand Down Expand Up @@ -452,30 +473,68 @@ public function completeSession($payload) {

$check = reset($current_data);
$logs = MICAQuery::getLogsFor($this, PROJECT_ID, $participant_id);
$this->emDebug("completeSessions" , $logs, $current_data);

if(sizeof($logs)){
$saveData = array(
array(
"record_id" => $payload['record_id'],
"ts_whiteboard" => $payload['ts_whiteboard'],
)
);
$save = array(
"user_complete" => "2",
"completion_timestamp" => date("Y-m-d H:i:s"),
"raw_chat_logs" => json_encode($logs)

$save = array(
"user_complete" => "2",
"completion_timestamp" => date("Y-m-d H:i:s"),
"raw_chat_logs" => json_encode($logs)
);

$this->emDebug("completeSessions!", $save);
$save = array(array_merge($check, $save));
$response = \REDCap::saveData('json', json_encode($save), 'overwrite');

if(! $response['errors']) {
return ["success" => true];
} else {
throw new \Exception($response['errors']);
}

}

/**
* @return bool
*/
public function validatePermissions() {
$test = current(UserRights::getPrivileges(PROJECT_ID)[PROJECT_ID]);
if($test['user_rights'] === '1')
return true;
return false;
}

/**
* @return string
*/
public function fetchIncompleteSessions() {
try {
if(!$this->validatePermissions())
throw new \Exception("You do not have permissions to view this page");

$params = array(
"return_format" => "json",
"filterLogic" => "[user_complete] != '2'",
);
$save = array(array_merge($check, $save));
$response = \REDCap::saveData('json', json_encode($save), 'overwrite');

// Find user and determine validity
$json = json_decode(\REDCap::getData($params), true);
$ind = $json ?? [];

if(! $response['errors']) {
return ["success" => true];
} else {
throw new \Exception($response['errors']);
}
return json_encode([
"sessions" => $ind,
"success" => true
]);

} catch (\Exception $e) {
$this->emError($e);
return json_encode([
"error" => $e->getMessage(),
"success" => false
]);
}


}

/**
Expand Down
23 changes: 17 additions & 6 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@

"framework-version": 14,

"enable-every-page-hooks-on-system-pages": true,
"enable-every-page-hooks-on-system-pages": false,

"enable-no-auth-logging": true,

"links": {
"project": [
Expand All @@ -31,6 +33,12 @@
"icon": "gear",
"url" : "pages/chatbot.php",
"show-header-and-footer": false
},
{
"name": "Mica Session Admin",
"icon": "gear",
"url" : "pages/sessionSelector.php",
"show-header-and-footer": true
}
],
"control-center": [
Expand All @@ -42,19 +50,22 @@
"pages/chatbot"
],

"auth-ajax-actions": [

"no-auth-ajax-actions": [
"callAI",
"login",
"verifyEmail",
"completeSession",
"fetchSavedQueries"
],

"no-auth-ajax-actions": [
"callAI"
],

"project-settings": [
{
"key": "chatbot_intro_text",
"name": "Raw text to show in the UI on session start",
"required": true,
"type": "textarea"
},
{
"key": "chatbot_system_context_persona",
"name": "Raw text to inject into system context to tune the chatbot's persona",
Expand Down

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion mica-chatbot/dist/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React</title>
<script type="module" crossorigin src="/assets/index-BXI-ZlRe.js"></script>
<script type="module" crossorigin src="/assets/index-Cgm6tmUi.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-CTqSVGO7.css">
</head>
<body>
Expand Down
3 changes: 2 additions & 1 deletion mica-chatbot/src/components/messages/messages.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import "./messages.css";
export const Messages = () => {
const chat_context = useContext(ChatContext);
const newQaRef = useRef(null);
const intro_text = window.mica_jsmo_module.intro_text || "Hi I am MICA!";

const handleClick = (vote, index) => {
chat_context.updateVote(index, vote);
Expand Down Expand Up @@ -78,7 +79,7 @@ export const Messages = () => {
</React.Fragment>
))
)
: (<p className={`empty`}><em className={`soft_text`}>Hi, I'm Mica, an AI trained to help with alcohol choices. Let's explore if you'd like to change your health habits and how I can assist. To start, can you share what you enjoy about drinking?</em></p>)
: (<p className={`empty`}><em className={`soft_text`}>{intro_text}</em></p>)
}
</div>
);
Expand Down
7 changes: 7 additions & 0 deletions pages/chatbot.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,19 @@
];

$initial_system_context = $module->initSystemContexts();
$intro_text = $module->getIntroText();

$data = !empty($initial_system_context) ? $initial_system_context : null;


if ($data !== null) {
$cmds[] = "window.mica_jsmo_module.data = " . json_encode($data);
}

if(!is_null($intro_text)){
$cmds[] = "window.mica_jsmo_module.intro_text = " . json_encode($intro_text);
}

if (!empty($init_method)) {
$cmds[] = "window.mica_jsmo_module.afterRender(mica_jsmo_module." . $init_method . ")";
}
Expand Down
75 changes: 75 additions & 0 deletions pages/sessionSelector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?php
/** @var \Stanford\MICA\MICA $module */

// Check if the form was submitted (when "Complete Session" is clicked)
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['participant_id'])) {
$participant_id = $_POST['participant_id'];

// Create the payload as expected by completeSession() function
$payload = ['participant_id' => $participant_id];
$module->completeSession($payload);
}

// Fetch all incomplete mica sessions
$resp = json_decode($module->fetchIncompleteSessions(), true);
$open_sessions = $resp['sessions'] ?? [];
?>
<link rel="stylesheet" href="https://cdn.datatables.net/1.11.5/css/jquery.dataTables.min.css">
<style>
#sessionsTable_wrapper {
width: 100%; /* Ensure full width */
padding-right: 20px; /* Add margin on the right */
}
</style>
<h2>MICA Session Admin</h2>

<table id="sessionsTable" class="display">
<thead>
<tr>
<th>Participant ID</th>
<th>Participant Name</th>
<th>Baseline Complete</th>
<th>Posttest Complete</th>
<th>Complete Study</th>
<th>Withdraw Date</th>
<th>Study Comments</th>
<th>Session Time</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<?php foreach ($open_sessions as $session): ?>
<tr>
<td><?php echo htmlspecialchars($session['participant_id']); ?></td>
<td>
<?php echo htmlspecialchars($session['participant_name']); ?><br>
<small><?php echo htmlspecialchars($session['participant_email']); ?></small>
</td>
<td><?php echo $session['baseline_complete'] ? 'Yes' : 'No'; ?></td>
<td><?php echo $session['posttest_complete'] ? 'Yes' : 'No'; ?></td>
<td><?php echo $session['complete_study'] ? 'Yes' : 'No'; ?></td>
<td><?php echo !empty($session['withdraw_date']) ? htmlspecialchars($session['withdraw_date']) : 'N/A'; ?></td>
<td><?php echo !empty($session['study_comments']) ? htmlspecialchars($session['study_comments']) : ''; ?></td>
<td><?php echo htmlspecialchars($session['two_factor_code_ts']); ?></td>
<td>
<?php if (!empty($session['two_factor_code_ts'])): ?>
<form method="POST" style="display:inline;">
<input type="hidden" name="participant_id" value="<?php echo $session['participant_id']; ?>">
<button type="submit" class="complete-session-btn">
Complete Session
</button>
</form>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>

<!-- DataTables initialization -->
<script>
$(document).ready(function() {
// Initialize DataTables
$('#sessionsTable').DataTable();
});
</script>

0 comments on commit 780b69d

Please sign in to comment.