Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move algorithm #365

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 0 additions & 33 deletions .github/workflows/algorithm.yml

This file was deleted.

26 changes: 0 additions & 26 deletions .github/workflows/match_interviews.yml

This file was deleted.

17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,20 @@ yarn dev
```

Open <http://localhost:3000> with your browser to see the result.

### Running the matching algorithm

Setup Python virtual environment:

```bash
cd algorithm
python -m venv ".venv"
.\.venv\Scripts\activate
pip install -r requirements.txt
```

Then, run the file [fetch_applicants_and_committees.py](algorithm/fetch_applicants_and_committees.py):

```bash
python fetch_applicants_and_committees.py
```
File renamed without changes.
16 changes: 0 additions & 16 deletions algorithm/README.md

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -10,112 +10,125 @@
from mip_matching.Applicant import Applicant
from mip_matching.match_meetings import match_meetings, MeetingMatch


def main():
print("Starting matching")
periods = fetch_periods()

for period in periods:
periodId = str(period["_id"])
application_end = datetime.fromisoformat(period["applicationPeriod"]["end"].replace("Z", "+00:00"))

application_end = datetime.fromisoformat(
period["applicationPeriod"]["end"].replace("Z", "+00:00"))

now = datetime.now(timezone.utc)

#or period["name"] == "Juli Opptak"
if (application_end < now and period["hasSentInterviewTimes"] == False):
if (application_end < now and period["hasSentInterviewTimes"] == False):
applicants = fetch_applicants(periodId)
committee_times = fetch_committee_times(periodId)

committee_objects = create_committee_objects(committee_times)

all_committees = {committee.name: committee for committee in committee_objects}

applicant_objects = create_applicant_objects(applicants, all_committees)

print(applicant_objects)
print(committee_objects)


all_committees = {
committee.name: committee for committee in committee_objects}

applicant_objects = create_applicant_objects(
applicants, all_committees)

match_result = match_meetings(applicant_objects, committee_objects)

print(
f"Matching finished with status {match_result["solver_status"]}")
print(
f"Matched {match_result["matched_meetings"]}/{match_result["total_wanted_meetings"]} ({match_result["matched_meetings"]/match_result["total_wanted_meetings"]:.2f}) meetings")

send_to_db(match_result, applicants, periodId)
print("Meetings sent to database")
return match_result



def send_to_db(match_result: MeetingMatch, applicants: List[dict], periodId):
load_dotenv()
formatted_results = format_match_results(match_result, applicants, periodId)
formatted_results = format_match_results(
match_result, applicants, periodId)
print("Sending to db")
print(formatted_results)

mongo_uri = os.getenv("MONGODB_URI")
db_name = os.getenv("DB_NAME")
client = MongoClient(mongo_uri, tlsCAFile=certifi.where())
db = client[db_name] # type: ignore

db = client[db_name] # type: ignore

collection = db["interviews"]

collection.insert_many(formatted_results)

client.close()


def connect_to_db(collection_name):
load_dotenv()

mongo_uri = os.getenv("MONGODB_URI")
db_name = os.getenv("DB_NAME")

client = MongoClient(mongo_uri, tlsCAFile=certifi.where())
db = client[db_name] # type: ignore

db = client[db_name] # type: ignore

collection = db[collection_name]

return collection, client


def fetch_periods():
collection, client = connect_to_db("periods")

periods = list(collection.find())

client.close()

return periods


def fetch_applicants(periodId):
collection, client = connect_to_db("applications")

applicants = list(collection.find({"periodId": periodId}))

client.close()

return applicants


def fetch_committee_times(periodId):
collection, client = connect_to_db("committees")

committee_times = list(collection.find({"periodId": periodId}))

client.close()

return committee_times


def format_match_results(match_results: MeetingMatch, applicants: List[dict], periodId) -> List[Dict]:
transformed_results = {}

for result in match_results['matchings']:
applicant_id = str(result[0])

if applicant_id not in transformed_results:
transformed_results[applicant_id] = {
"periodId": periodId,
"applicantId": applicant_id,
"interviews": []
}

committee = result[1]
time_interval = result[2]
start = time_interval.start.isoformat()
end = time_interval.end.isoformat()
room = result[3]

transformed_results[applicant_id]["interviews"].append({
"start": start,
"end": end,
Expand All @@ -125,37 +138,46 @@ def format_match_results(match_results: MeetingMatch, applicants: List[dict], pe

return list(transformed_results.values())


def create_applicant_objects(applicants_data: List[dict], all_committees: dict[str, Committee]) -> set[Applicant]:
applicants = set()
for data in applicants_data:
applicant = Applicant(name=str(data['_id']))

optional_committee_names = data.get('optionalCommittees', [])
optional_committees = {all_committees[name] for name in optional_committee_names if name in all_committees}
optional_committees = {
all_committees[name] for name in optional_committee_names if name in all_committees}
applicant.add_committees(optional_committees)

preferences = data.get('preferences', {})
preference_committees = {all_committees[committee_name] for committee_name in preferences.values() if committee_name in all_committees}
preference_committees = {all_committees[committee_name] for committee_name in preferences.values(
) if committee_name in all_committees}
applicant.add_committees(preference_committees)

for interval_data in data['selectedTimes']:
interval = TimeInterval(
start=datetime.fromisoformat(interval_data['start'].replace("Z", "+00:00")),
end=datetime.fromisoformat(interval_data['end'].replace("Z", "+00:00"))
start=datetime.fromisoformat(
interval_data['start'].replace("Z", "+00:00")),
end=datetime.fromisoformat(
interval_data['end'].replace("Z", "+00:00"))
)
applicant.add_interval(interval)

applicants.add(applicant)
return applicants


def create_committee_objects(committee_data: List[dict]) -> set[Committee]:
committees = set()
for data in committee_data:
committee = Committee(name=data['committee'], interview_length=timedelta(minutes=int(data["timeslot"])))
committee = Committee(name=data['committee'], interview_length=timedelta(
minutes=int(data["timeslot"])))
for interval_data in data['availabletimes']:
interval = TimeInterval(
start=datetime.fromisoformat(interval_data['start'].replace("Z", "+00:00")),
end=datetime.fromisoformat(interval_data['end'].replace("Z", "+00:00"))
start=datetime.fromisoformat(
interval_data['start'].replace("Z", "+00:00")),
end=datetime.fromisoformat(
interval_data['end'].replace("Z", "+00:00"))
)
room = interval_data["room"]
committee.add_interview_slot(interval, room)
Expand Down
20 changes: 0 additions & 20 deletions algorithm/pyproject.toml

This file was deleted.

Binary file modified algorithm/requirements.txt
Binary file not shown.
Loading