Skip to content

Commit

Permalink
Merge branch 'main' into aq/course-panels
Browse files Browse the repository at this point in the history
  • Loading branch information
qiandrewj authored Dec 4, 2024
2 parents 01d73d4 + c24199e commit da8b83f
Show file tree
Hide file tree
Showing 17 changed files with 938 additions and 130 deletions.
102 changes: 78 additions & 24 deletions client/src/modules/Admin/Components/Admin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,24 @@ export const Admin = () => {
| 'profsUpdate'
| 'subjects'
| 'database'
| 'description';
| 'description'
| 'summarize'
| 'failure';
const [updated, setUpdated] = useState<updatedStates>('empty');
const successMessages = {
const messages = {
empty: '',
semester: 'New semester data successfully added',
profsReset: 'Professor data successfully reset to empty',
profsUpdate: 'Professor data successfully updated',
subjects: 'Subject full name data successfully updated',
database: 'Database successfully initialized',
description: 'Course description data successfully added'
description: 'Course description data successfully added',
summarize: 'All courses successfully summarized',
failure: 'API failed'
};
const [updatingField, setUpdatingField] = useState<string>('');

const [addSemester] = useState('');
const [addSemester] = useState(['FA24', 'SP25']);
const [isAdminModalOpen, setIsAdminModalOpen] = useState<boolean>(false);

const { isLoggedIn, token, isAuthenticating } =
Expand Down Expand Up @@ -163,6 +167,23 @@ export const Admin = () => {
}
}

// Call when user selects "Sumarize Reviews" button. Calls endpoint to generate
// summaries and tags using AI for all courses with a freshness above a certain
// threshold, then updates those courses to include these new summaries and tags.
async function summarizeReviews() {
console.log('Updating all courses with AI');
setUpdating(true);
setUpdatingField('summarizing');
const response = await axios.post('/api/ai/summarize-courses');
if (response.status == 200) {

Check warning on line 178 in client/src/modules/Admin/Components/Admin.tsx

View workflow job for this annotation

GitHub Actions / build

Expected '===' and instead saw '=='

Check warning on line 178 in client/src/modules/Admin/Components/Admin.tsx

View workflow job for this annotation

GitHub Actions / build

Expected '===' and instead saw '=='
setUpdated('summarize');
}
else {
setUpdated('failure');
}
setUpdating(false);
}

/**
* Call when user asks to un-report a reported review. Accesses the Reviews database
* and changes the reported flag for this review to false.
Expand All @@ -187,23 +208,26 @@ export const Admin = () => {
* course API for new classes and updates classes existing in the database.
* Should run once a semester, when new classes are added to the roster.
*/
async function addNewSem(semester: string) {
async function addNewSemesters(semesters: string[]) {
console.log('Adding new semester...');
setUpdating(true);
setUpdatingField('new semester');
setUpdatingField('new semesters');
//wz
const response = await axios.post('/api/admin/semester/add', {
semester,
token: token
});
const result = response.data.result;
if (result === true) {
console.log('New Semester Added');
setUpdating(false);
setUpdated('semester');
} else {
console.log('Unable to add new semester!');
for (const semester of semesters) {
const response = await axios.post('/api/admin/semester/add', {

Check warning on line 217 in client/src/modules/Admin/Components/Admin.tsx

View workflow job for this annotation

GitHub Actions / build

Unexpected `await` inside a loop

Check warning on line 217 in client/src/modules/Admin/Components/Admin.tsx

View workflow job for this annotation

GitHub Actions / build

Unexpected `await` inside a loop
semester,
token: token
});
const result = response.data.result;
if (!result) {
console.error(`Unable to add new semester ${semester}!`);
continue;
} else {
console.log(`New Semester ${semester} Added`);
}
}
setUpdating(false);
setUpdated('semester');
}

// Call when user selects "Initialize Database" button. Scrapes the Cornell
Expand Down Expand Up @@ -244,7 +268,7 @@ export const Admin = () => {
if (response.status === 200) {
console.log('Updated the professors');
setUpdating(false);
setUpdated('profsUpdate');
setUpdated('professors');
} else {
console.log('Error at setProfessors');
}
Expand Down Expand Up @@ -310,6 +334,20 @@ export const Admin = () => {
}
}

async function updateSimilarityData() {
console.log('Updatng course similarity data')
setUpdating(true)
setUpdatingField("course similarity data")
const response = await axios.post('/api/admin/rec/similarity', { token: token });
if (response.status === 200) {
console.log('Updated course similarity data')
setUpdating(false)
setUpdated('similarity')
} else {
console.log('Error at updateSimilarityData')
}
}

/**
* Handle the first click to the "Initialize Database" button. Show an alert
* and update state to remember the next click will be a double click.
Expand Down Expand Up @@ -377,7 +415,7 @@ export const Admin = () => {
disabled={updating}
type="button"
className={styles.adminButtons}
onClick={() => addNewSem(addSemester)}
onClick={() => addNewSemesters(addSemester)}
>
Add New Semester
</button>
Expand Down Expand Up @@ -413,23 +451,39 @@ export const Admin = () => {
>
Update Subjects
</button>
<button
disabled={updating}
type="button"
className={styles.adminButtons}
onClick={() => summarizeReviews()}
>
Summarize Reviews
</button>
<button
disabled={disableInit}

Check warning on line 463 in client/src/modules/Admin/Components/Admin.tsx

View workflow job for this annotation

GitHub Actions / build

'disableInit' is not defined

Check warning on line 463 in client/src/modules/Admin/Components/Admin.tsx

View workflow job for this annotation

GitHub Actions / build

'disableInit' is not defined
type="button"
className={styles.adminButtons}
onClick={() => updateSimilarityData()}
>
Update Similarity Data
</button>
{renderInitButton()}
</div>
</div>
</div >
</div >

<ManageAdminModal
open={isAdminModalOpen}
setOpen={setIsAdminModalOpen}
token={userToken}
/>

<div>{successMessages[updated]}</div>
<div>{messages[updated]}</div>

<div hidden={!updating} className="">
<p>Updating {updatingField} in the Course database.</p>
<p>This process can take up to 15 minutes.</p>
</div>
</div>
</div >

<div className="StagedReviews">
<h1>Pending Reviews</h1>
Expand Down Expand Up @@ -470,7 +524,7 @@ export const Admin = () => {
})}
</div>
</div>
</div>
</div >
);
}

Expand Down
6 changes: 3 additions & 3 deletions client/src/modules/Course/Components/Course.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export const Course = () => {
let valB = 'Not Listed';

if (a.professors) {
const profsA = a.professors.filter((prof : String) =>
const profsA = a.professors.filter((prof: String) =>
prof && prof !== 'Not Listed');
valA = profsA.length > 0
? profsA.sort()[0]
Expand All @@ -73,7 +73,7 @@ export const Course = () => {
return 1;
}
if (b.professors) {
const profsB = b.professors.filter((prof : String) =>
const profsB = b.professors.filter((prof: String) =>
prof && prof !== 'Not Listed');
valB = profsB.length > 0
? profsB.sort()[0]
Expand All @@ -87,7 +87,7 @@ export const Course = () => {
} else if (valB === 'Not Listed') {
return -1;
}

if (valA < valB) {
return -1;
} else if (valB < valA) {
Expand Down
15 changes: 14 additions & 1 deletion common/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ export interface Class {
classProfessors?: string[];
classRating?: number;
classWorkload?: number;
classDifficulty?: number; // the average difficulty rating from reviews
classDifficulty?: number;
classSummary?: string;
summaryTags?: Map<string, [string, string]>;
summaryFreshness?: number;
recommendations: Recommendation[];
}

export interface Student {
Expand Down Expand Up @@ -59,3 +63,12 @@ export interface Professor {
readonly courses: string[];
readonly major: string;
}

interface Recommendation {
readonly _id: string;
className: string;
classSub: string;
classNum: number;
tags: string[];
similarityScore: number;
}
62 changes: 61 additions & 1 deletion server/db/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,24 @@ const ClassSchema = new Schema<ClassDocument>({
classProfessors: { type: [String] }, // list of professors that have taught the course over past semesters
classRating: { type: Number }, // the average class rating from reviews
classWorkload: { type: Number }, // the average workload rating from reviews
classDifficulty: { type: Number } // the average difficulty rating from reviews
classDifficulty: { type: Number }, // the average difficulty rating from reviews
classSummary: { type: String, required: false }, // 50 word summary of the course generated by openAI
summaryTags: {
type: Map, // dictionary keys are lectures, assignments, professors, skills, and resources
of: [{ type: String }, { type: String }], // tuple where first element is the adjective and second element is its connotation
required: false
}, // tags describing lectures, assignments, professors, skills, and resources
summaryFreshness: { type: Number, default: 0 }, // number of reviews since last openAI call
recommendations: [
{
_id: { type: String },
className: { type: String },
classSub: { type: String },
classNum: { type: Number },
tags: { type: [String] }, // array of tags, like ['overall rating', 'workload', 'difficulty']
similarityScore: { type: Number }
}
]
});

export const Classes = mongoose.model<ClassDocument>('classes', ClassSchema);
Expand Down Expand Up @@ -148,3 +165,46 @@ export const Validation = mongoose.model<ValidationDocument>(
'validation',
ValidationSchema
);

/**
* Course Recommendation Metadata Collection
* Stores course description preprocessing data and pre-computation steps for
* similarity algorithm
*/
const RecommendationMetadataSchema = new Schema({
_id: { type: String },
classSub: { type: String },
classNum: { type: String },
processedDescription: { type: String },
tfidfVector: { type: Object },
});

interface RecommendationMetadataDocument extends mongoose.Document {
_id: string;
classSub: string;
classNum: string;
processedDescription: string;
tfidfVector: Object;
}

export const RecommendationMetadata = mongoose.model<RecommendationMetadataDocument>(
"recommendationMetadata",
RecommendationMetadataSchema,
);

/**
* Global Course Metadata Collection
* Stores global course data
*/
const GlobalMetadataSchema = new Schema({
idfVector: { type: Object }
});

interface GlobalMetadataDocument extends mongoose.Document {
idfVector: Object;
}

export const GlobalMetadata = mongoose.model<GlobalMetadataDocument>(
"globalnMetadata",
GlobalMetadataSchema,
);
9 changes: 8 additions & 1 deletion server/scripts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,16 @@ export {
addCrossList,
addNewSemester,
addAllCourses,
addAllDescriptions
addAllDescriptions,
addAllSimilarityData,
} from './populate-courses';

export { addAllProfessors, resetProfessors } from './populate-professors';

export {
addAllProcessedDescriptions,
addIdfVector,
addAllTfIdfVectors,
} from './populate-recdata';

export { findAllSemesters } from './utils';
Loading

0 comments on commit da8b83f

Please sign in to comment.