-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
49cee4c
commit 1acefb3
Showing
18 changed files
with
1,315 additions
and
891 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import EarlyWarningSystem from "@/lib/EarlyWarningSystem"; | ||
|
||
export async function GET() { | ||
try { | ||
const ews = new EarlyWarningSystem(); | ||
|
||
ews.updateEWSData(); // Don't await, just run in the background | ||
|
||
return Response.json({ | ||
data: "EWS data update initiated. Check the logs for progress.", | ||
}); | ||
} catch (err) { | ||
console.error(err); | ||
return Response.json({ error: err }); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import EarlyWarningSystem from "@/lib/EarlyWarningSystem"; | ||
import { BatchPredictWebhookData } from "@/lib/types/ews"; | ||
import { NextRequest } from "next/server"; | ||
|
||
export async function POST(request: NextRequest) { | ||
try { | ||
const reqData = await request.json(); | ||
if (!reqData) throw new Error("No data provided"); | ||
|
||
const { state, course_id } = reqData as BatchPredictWebhookData; | ||
|
||
if (state === "error") { | ||
console.error( | ||
`An EWS prediction error was sent via webhook for course ${course_id}` | ||
); | ||
return Response.json({ success: true }); | ||
} | ||
|
||
const predictions = reqData.predictions; | ||
if (!predictions) throw new Error("No predictions provided"); | ||
|
||
const ews = new EarlyWarningSystem(); | ||
await ews.updateEWSPredictions(course_id, predictions); | ||
|
||
return Response.json({ success: true }); | ||
} catch (err) { | ||
console.error(err); | ||
return Response.json({ error: err }); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
"use client"; | ||
import { useState } from "react"; | ||
import { Button, Modal } from "react-bootstrap"; | ||
|
||
interface EarlyWarningInfoProps {} | ||
|
||
const EarlyWarningInfo: React.FC<EarlyWarningInfoProps> = () => { | ||
const [modalOpen, setModalOpen] = useState(false); | ||
return ( | ||
<div> | ||
<Button | ||
onClick={() => setModalOpen(true)} | ||
variant="outline-info" | ||
size="sm" | ||
> | ||
About Early Warning | ||
</Button> | ||
<Modal | ||
show={modalOpen} | ||
onHide={() => setModalOpen(false)} | ||
size="lg" | ||
aria-labelledby="contained-modal-title-vcenter" | ||
centered | ||
> | ||
<Modal.Header closeButton> | ||
<Modal.Title id="contained-modal-title-vcenter"> | ||
About Early Warning System | ||
</Modal.Title> | ||
</Modal.Header> | ||
<Modal.Body> | ||
<h5>How are predictions made?</h5> | ||
<p> | ||
The Early Warning System uses a machine learning predictive model to | ||
estimate student risk based on their academic performance relative | ||
to the averaged metrics of their peers. The model is updated every | ||
12 hours and uses the following metrics: | ||
</p> | ||
<ul> | ||
<li>Unweight Course Percentage</li> | ||
<li># of Unique Interaction Days</li> | ||
<li>% of Course Content Seen</li> | ||
<li>Per Assignment</li> | ||
<ul> | ||
<li>Unweighted Score</li> | ||
<li>Time on Task</li> | ||
<li>Time in Review</li> | ||
</ul> | ||
</ul> | ||
<h5>How is risk calculated?</h5> | ||
<p> | ||
The Early Warning System assumes a final grade of 70% as the passing | ||
threshold. Students with a predicted final grade of less than 79% | ||
are flagged with a risk level of "Warning". Students with a | ||
predicted final grade of less than 69% are flagged with a risk level | ||
of "Attention Needed". | ||
</p> | ||
<p> | ||
<strong>Note:</strong> Early Warning System predictions are not a | ||
guarantee of student performance and should only be used as a tool | ||
to identify students who may need additional support. | ||
</p> | ||
</Modal.Body> | ||
<Modal.Footer> | ||
<Button onClick={() => setModalOpen(false)}>Close</Button> | ||
</Modal.Footer> | ||
</Modal> | ||
</div> | ||
); | ||
}; | ||
|
||
export default EarlyWarningInfo; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
"use client"; | ||
import { useGlobalContext } from "@/state/globalContext"; | ||
import { useEffect, useMemo, useState } from "react"; | ||
import { EWSResult, EarlyWarningStatus } from "@/lib/types"; | ||
import EarlyWarningStudentRow from "./EarlyWarningStudentRow"; | ||
import EarlyWarningBanner from "./EarlyWarningBanner"; | ||
|
||
interface EarlyWarningResultsProps { | ||
getData: (course_id: string, privacy: boolean) => Promise<EWSResult[]>; | ||
} | ||
|
||
const EarlyWarningResults: React.FC<EarlyWarningResultsProps> = ({ | ||
getData, | ||
}) => { | ||
const [globalState] = useGlobalContext(); | ||
const [data, setData] = useState<EWSResult[]>([]); | ||
|
||
useEffect(() => { | ||
fetchData(); | ||
}, [globalState.courseID, globalState.ferpaPrivacy]); | ||
|
||
async function fetchData() { | ||
try { | ||
if (!globalState.courseID) return; | ||
const res = await getData(globalState.courseID, globalState.ferpaPrivacy); | ||
|
||
if (!res) return; | ||
setData(res); | ||
} catch (err) { | ||
console.error(err); | ||
} | ||
} | ||
|
||
const overallStatus: EarlyWarningStatus = useMemo(() => { | ||
if (!data.length) return "success"; | ||
const dangerCount = data.filter((student) => student.status === "danger"); | ||
const warningCount = data.filter((student) => student.status === "warning"); | ||
|
||
if (dangerCount.length) return "danger"; | ||
if (warningCount.length) return "warning"; | ||
return "success"; | ||
}, [data]); | ||
|
||
return ( | ||
<div className="tw-flex tw-flex-col"> | ||
<EarlyWarningBanner status={overallStatus} /> | ||
{data.length > 0 && | ||
data.map((result) => ( | ||
<EarlyWarningStudentRow key={result.name} data={result} /> | ||
))} | ||
</div> | ||
); | ||
}; | ||
|
||
export default EarlyWarningResults; |
Oops, something went wrong.