Skip to content

Commit

Permalink
renaming/simplifying j2; integrating nbconvert
Browse files Browse the repository at this point in the history
Made a host of changes. Namely:
1. Tore through `nbconvert` source code to move most of the logic from
   the Jinja templates into actual code that can be made a bit more
   readable and easily understood. (There's no real "structure" to the
   Jinja templates that NBConvert uses for Jupyter notebooks.)
2. Began migration of banner generation to their own file, for closer
   associations and allowing for some localized utility extraction.
3. Setup some new `j2` templates that we'll be needing post-Hugo
   transition on the website.
4. Started laying ground-work for `kaggle.py`'s ability to diff
   notebooks to avoid constantly re-uploading.
  • Loading branch information
John M committed Jan 9, 2020
1 parent 7387307 commit f01de39
Show file tree
Hide file tree
Showing 28 changed files with 1,090 additions and 254 deletions.
76 changes: 76 additions & 0 deletions .github/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# ucfai's `autobot`

As managing a course/club is rather involved, coupled with the
ever-changing-hands-nature of such a group, it becomes difficult to onboard
newcomers on the processes and structures that have been settled upon by prior
folks. To overcome this, [@ionlights][git-ionlights] initially developed a bot
to handle this. Since then, many others have contributed to expanding `autobot`'s
capabilities to handle nearly all of the managerial and distributed tasks of AI@UCF.

[git-ionlights]: https://github.com/ionlights

## Documentation

<font color=red>**This is currently under development.**</font>

We've taken time to document as thoroughly, and unobtrustively, as possible
&ndash; and you can find a web-based version of the documentation at
https://ucfai.org/docs/admin/bot.

# Development

## Code Structure

```bash
autobot
├── apis # any external resource we need access to are defined here.
├── log.py # logging, mixed-in with Python's `logger`
├── main.py # package entrypoint, parsers, and high-level operations
├── meta # OO-like containers for Groups, Coordinators, and Meetings
│ └── groups.py # sets up specific attributes for each Group
├── safety.py # figures out the right paths and configurations
├── templates # these are used for creating semesters, banners, etc.
└── utils # specific actions, since these don't quite make sense in OO
```

## General Structure

`autobot` focuses on managing 4 different verticals:

1. Generate minimal content needed for a given `group`'s semester.
1. Maintain and update the website to ensure content is publicly accessible.
1. Perform routine genertion for various social platforms, e.g. uploading meetings
to YouTube, generating email and instagram banners, etc.
1. Onboard new leadership to make sure everyone has appropriate access on a
variety of plaforms we use in managing AI@UCF.

## Installation

Just about everything is packaged in a `conda` environment. To install you need
to make sure you have [Anaconda][anaconda] or [Miniconda][miniconda] on your
system. Once installed, proceed with the following:

[anaconda]: https://www.anaconda.com/distribution/
[miniconda]: https://docs.conda.io/en/latest/miniconda.html

```bash
$ conda env create -f envs/{macos,linux}.yml # pick one of the OSes
$ conda activate ucfai-admin # or `source activate ucfai-admin`
$ pip install -e . # make sure you're in the same place as this README
$ autobot -h # this should output something that looks like "help"
```

Since you're probably developing the `autobot`, make sure you have the related
groups laid out like the following `tree` output shows:

```bash
ucfai
├── bot
├── core
├── data-science
├── intelligence
└── supplementary
```

**Note:** If you need help decrypting any files ending in `.gpg`, contact
[@ionlights][git-ionlights].
2 changes: 2 additions & 0 deletions autobot/apis/github.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,6 @@ def add_coordinators(grp: Group) -> None:

for coord in grp.coords.items():
_team.add_membership(coord.github, role=roles(coord.role))


# endregion
1 change: 1 addition & 0 deletions autobot/apis/instagram.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from autobot.meta.meeting import Meeting


def make_post(mtg: Meeting):
raise NotImplementedError()
45 changes: 36 additions & 9 deletions autobot/apis/kaggle.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,54 @@
import subprocess
from pathlib import Path

from tqdm import tqdm

from autobot import ORG_NAME
from autobot.utils import paths
from autobot.meta.meeting import Meeting

KAGGLE_USERNAME = "ucfaibot"
KAGGLE_CONFIG_DIR = Path(__file__).parent.parent.parent


def push_kernel(meeting: Meeting):
# TODO: prevent Kaggle from pushing every notebook, every time
def _configure_environment() -> None:
if "KAGGLE_CONFIG_DIR" not in os.environ:
os.environ["KAGGLE_CONFIG_DIR"] = str(
Path(__file__).parent.parent.parent
)
os.environ["KAGGLE_CONFIG_DIR"] = str(KAGGLE_CONFIG_DIR)
elif "KAGGLE_CONFIG_DIR" in os.environ and os.environ["KAGGLE_CONFIG_DIR"] != str(
KAGGLE_CONFIG_DIR
):
tqdm.write(f"Found `KAGGLE_CONFIG_DIR = {os.environ['KAGGLE_CONFIG_DIR']}`")


def pull_kernel(meeting: Meeting) -> None:
_configure_environment()

cwd = os.getcwd()
os.chdir(paths.repo_meeting_folder(meeting))
subprocess.call("kaggle k push", shell=True)
os.chdir(paths.tmp_meeting_folder(meeting))
subprocess.call(
f"kaggle k pull -wp {KAGGLE_USERNAME}/{slug_kernel(meeting)}", shell=True
)
os.chdir(cwd)


def diff_kernel(meeting: Meeting) -> bool:
# TODO download and diff this kernel from the local copy
pass
_configure_environment()
pull_kernel(meeting)

cwd = os.getcwd()
# TODO compute sha256 over the meeting's Workbook and what we pulled from Kaggle, compare the hexdigests


def push_kernel(meeting: Meeting) -> None:
_configure_environment()

if diff_kernel(meeting):
cwd = os.getcwd()
os.chdir(paths.repo_meeting_folder(meeting))
subprocess.call("kaggle k push", shell=True)
os.chdir(cwd)
else:
tqdm.write("Kernels are the same. Skipping.")


def slug_kernel(meeting: Meeting) -> str:
Expand Down
4 changes: 2 additions & 2 deletions autobot/apis/ucf.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ def make_schedule(group: Group, schedule: Dict):
meeting_time = pd.Timedelta(hours=int(time_s[:2]), minutes=int(time_s[2:]))
meeting_dates += meeting_time

logging.info(f"Meeting dates\n{meeting_dates}")
# logging.info(f"Meeting dates\n{meeting_dates}")

schedule = [MeetingMeta(pd.to_datetime(mtg), room) for mtg in meeting_dates]
logging.debug(schedule)
# logging.debug(schedule)

return schedule

Expand Down
3 changes: 2 additions & 1 deletion autobot/apis/youtube.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from autobot.meta import Meeting


def upload(meeting: Meeting):
pass
pass
24 changes: 12 additions & 12 deletions autobot/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,34 +169,34 @@ def _parse_and_load_meetings(group: Group):
)
continue

# TODO (@ch1pless) word-wrap the syllabus to 88 characters (this makes for easier reading)
# TODO (@ch1pless) write things like meeting dates and rooms if non-existent, to avoid imputing – since this can be less than ideal for some actions

return syllabus


def semester_upkeep(meeting: Meeting, overwrite: bool = False) -> None:
tqdm.write(f"{repr(meeting)} ~ {str(meeting)}")

# Perform initial directory checks/clean-up
meetings.update_or_create_folders_and_files(meeting)
# meetings.update_or_create_folders_and_files(meeting)

# Make edit in the group-specific repo
meetings.update_or_create_notebook(meeting, overwrite=overwrite)
# meetings.download_papers(meeting)
meetings.download_papers(meeting)
# kaggle.push_kernel(meeting)

# Make edits in the ucfai.org repo
# meetings.render_banner(meeting)
# meetings.render_instagram_post(meeting)
# meetings.export_notebook_as_post(meeting)
# banners.render_cover(meeting)
# banners.render_weekly_instagram_post(meeting) # this actually needs a more global setting
meetings.export_notebook_as_post(meeting)

# Video Rendering and such
# Video Rendering and Upload
# videos.dispatch_recording(meeting) # unsure that this is needed

# videos.render_banner(meeting)

# this could fire off a request to GCP to avoid long-running
# banners.render_video_background(meeting)
# this could fire off a request to GCP to avoid long-running local renders
# videos.compile_and_render(meeting)

# youtube.upload(meeting)
# videos.upload(meeting)


def semester_upkeep_all(group: Group, overwrite: bool = False) -> None:
Expand Down
Binary file added autobot/templates/banners/banner.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes.
Loading

0 comments on commit f01de39

Please sign in to comment.