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

Course changes #148

Merged
merged 21 commits into from
Mar 23, 2022
Merged
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
76 changes: 48 additions & 28 deletions kit/src/lib/DocNotebookDropdown.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -44,44 +44,64 @@
<svelte:window on:resize={onResize} />

<div class="flex space-x-1 {classNames}" bind:this={dropdownEl}>
<Dropdown btnLabel="" classNames="colab-dropdown" noBtnClass useDeprecatedJS={false}>
<slot slot="button">
{#if googleColabOptions.length === 1}
<a href={googleColabOptions[0].value} target="_blank">
<img
alt="Open In Colab"
class="!m-0"
src="https://colab.research.google.com/assets/colab-badge.svg"
/>
</slot>
<slot slot="menu">
{#each googleColabOptions as { label, value }}
<DropdownEntry
classNames="text-sm !no-underline"
iconClassNames="text-gray-500"
{label}
onClick={() => onClick(value)}
useDeprecatedJS={false}
</a>
{:else}
<Dropdown btnLabel="" classNames="colab-dropdown" noBtnClass useDeprecatedJS={false}>
<slot slot="button">
<img
alt="Open In Colab"
class="!m-0"
src="https://colab.research.google.com/assets/colab-badge.svg"
/>
{/each}
</slot>
</Dropdown>
<Dropdown btnLabel="" classNames="colab-dropdown" noBtnClass useDeprecatedJS={false}>
<slot slot="button">
</slot>
<slot slot="menu">
{#each googleColabOptions as { label, value }}
<DropdownEntry
classNames="text-sm !no-underline"
iconClassNames="text-gray-500"
{label}
onClick={() => onClick(value)}
useDeprecatedJS={false}
/>
{/each}
</slot>
</Dropdown>
{/if}
{#if awsStudioOptions.length === 1}
<a href={awsStudioOptions[0].value} target="_blank">
<img
alt="Open In Studio Lab"
class="!m-0"
src="https://studiolab.sagemaker.aws/studiolab.svg"
/>
</slot>
<slot slot="menu">
{#each awsStudioOptions as { label, value }}
<DropdownEntry
classNames="text-sm !no-underline"
iconClassNames="text-gray-500"
{label}
onClick={() => onClick(value)}
useDeprecatedJS={false}
</a>
{:else}
<Dropdown btnLabel="" classNames="colab-dropdown" noBtnClass useDeprecatedJS={false}>
<slot slot="button">
<img
alt="Open In Studio Lab"
class="!m-0"
src="https://studiolab.sagemaker.aws/studiolab.svg"
/>
{/each}
</slot>
</Dropdown>
</slot>
<slot slot="menu">
{#each awsStudioOptions as { label, value }}
<DropdownEntry
classNames="text-sm !no-underline"
iconClassNames="text-gray-500"
{label}
onClick={() => onClick(value)}
useDeprecatedJS={false}
/>
{/each}
</slot>
</Dropdown>
{/if}
</div>
2 changes: 1 addition & 1 deletion kit/src/lib/FrameworkContentBlock.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
<svelte:window on:hashchange={onHashChange} />

<div class="border border-gray-200 rounded-xl px-4 relative" bind:this={containerEl}>
<div class="flex h-[22px] mt-[-12.5px] justify-between leading-none" >
<div class="flex h-[22px] mt-[-12.5px] justify-between leading-none">
<div class="flex px-1 items-center space-x-1 bg-white dark:bg-gray-950">
<svelte:component this={Icon} />
<span>{label}</span>
Expand Down
37 changes: 37 additions & 0 deletions kit/src/lib/FrameworkSwitchCourse.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<script lang="ts">
import type { CourseFramework } from "./types";

import IconPytorch from "./IconPytorch.svelte";
import IconTensorflow from "./IconTensorflow.svelte";

export let fw: CourseFramework;

const FRAMEWORKS = [
{
id: "pt",
classNames: "bg-red-50 dark:bg-transparent text-red-600",
icon: IconPytorch,
name: "Pytorch"
},
{
id: "tf",
classNames: "bg-orange-50 dark:bg-transparent text-yellow-600",
icon: IconTensorflow,
name: "TensorFlow"
}
] as const;
</script>

<div class="bg-white leading-none border border-gray-100 rounded-lg flex p-0.5 w-56 text-sm mb-4">
{#each FRAMEWORKS as f, i}
<a
class="flex justify-center flex-1 py-1.5 px-2.5 focus:outline-none !no-underline
rounded-{i ? 'r' : 'l'}
{f.id === fw ? f.classNames : 'text-gray-500 filter grayscale'}"
href="?fw={f.id}"
>
<svelte:component this={f.icon} classNames="mr-1.5" />
{f.name}
</a>
{/each}
</div>
101 changes: 101 additions & 0 deletions kit/src/lib/Question.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<script lang="ts">
import { onMount } from "svelte";

import { answers } from "./stores";

export let choices: Choice[];

interface Choice {
text: string;
explain: string;
correct?: boolean;
selected?: boolean;
}

const id = randomId();

let isFalse: boolean = false;
let isIncomplete: boolean = false;
let selected: number[] = [];
let submitted: number[] = [];

onMount(() => {
$answers = { ...$answers, [id]: { correct: false } };
});

function checkAnswer() {
isFalse = false;
isIncomplete = false;

for (let i = 0; i < choices.length; i++) {
const c = choices[i];
if (c.correct && !selected.includes(i)) {
isIncomplete = true;
} else if (!c.correct && selected.includes(i)) {
isFalse = true;
}
}
submitted = selected;
$answers = { ...$answers, [id]: { correct: !isIncomplete && !isFalse } };
const isChapterComplete = Object.values($answers).every(({ correct }) => correct);
if (isChapterComplete) {
const event = new Event("ChapterComplete");
window.dispatchEvent(event);
}
}

function randomId(prefix = "_"): string {
// Return a unique-ish random id string
// Math.random should be unique because of its seeding algorithm.
// Convert it to base 36 (numbers + letters), and grab the first 9 characters
// after the decimal.
return `${prefix}${Math.random().toString(36).substr(2, 9)}`;
}
</script>

<div>
<form on:submit|preventDefault={() => checkAnswer()}>
{#each choices as choice, index}
<label class="block">
<input
autocomplete="off"
bind:group={selected}
class="form-input -mt-1.5 mr-2"
name="choice"
type="checkbox"
value={index}
/>
{@html choice.text}
</label>
{#if submitted && submitted.includes(index)}
<div
class="alert alert-{!!choice.correct ? 'success' : 'error'} mt-1 mb-2.5 leading-normal"
>
<span class="font-bold">
{!!choice.correct ? "Correct!" : "Incorrect."}
</span>
{@html choice.explain}
</div>
{/if}
{/each}
<div class="flex flex-row items-center mt-3">
<button class="btn px-4 mr-4" type="submit" disabled={!selected.length}> Submit </button>

{#if submitted.length}
<div class="font-semibold leading-snug">
{#if isFalse}
<span class="text-red-900 dark:text-red-200">
Looks like at least one of your answers is wrong, try again!
</span>
{:else if isIncomplete}
<span class="text-red-900 dark:text-red-200">
You didn't select all the correct answers, there's more!
</span>
{:else}
<span class="text-green-900 dark:text-green-200"> You got all the answers! </span>
{/if}
</div>
{/if}
</div>
</form>
</div>
3 changes: 3 additions & 0 deletions kit/src/lib/stores.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,6 @@ export function getFrameworkStore(key: Framework): Writable<FrameworkState> {
}
return frameworks[key];
}

// used for Question.svelte
export const answers = writable<{ [key: string]: { correct: boolean } }>({});
2 changes: 2 additions & 0 deletions kit/src/lib/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export type Group = "group1" | "group2";

export type Framework = "pytorch" | "tensorflow" | "jax";

export type CourseFramework = "pt" | "tf";
28 changes: 24 additions & 4 deletions src/doc_builder/build_doc.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ def generate_frontmatter_in_text(text, file_name=None):
Args:
text (`str`): The text in which to convert the links.
"""
is_disabled = "<!-- DISABLE-FRONTMATTER-SECTIONS -->" in text
text = text.split("\n")
root = None
is_inside_codeblock = False
Expand All @@ -270,6 +271,10 @@ def generate_frontmatter_in_text(text, file_name=None):
node = FrontmatterNode(title, local)
if header_level == 1:
root = node
# doc writers may choose to disable frontmatter generation
# currenly used in Quiz sections of hf course
if is_disabled:
break
else:
if root is None:
raise ValueError(
Expand Down Expand Up @@ -337,7 +342,16 @@ def build_notebooks(doc_folder, notebook_dir, package=None, mapping=None, page_i
raise type(e)(f"There was an error when converting {file} to a notebook.\n" + e.args[0]) from e


def build_doc(package_name, doc_folder, output_dir, clean=True, version="master", language="en", notebook_dir=None):
def build_doc(
package_name,
doc_folder,
output_dir,
clean=True,
version="master",
language="en",
notebook_dir=None,
is_python_module=False,
):
"""
Build the documentation of a package.

Expand All @@ -352,19 +366,22 @@ def build_doc(package_name, doc_folder, output_dir, clean=True, version="master"
language (`str`, *optional*, defaults to `"en"`): The language of the doc.
notebook_dir (`str` or `os.PathLike`, *optional*):
If provided, where to save the notebooks generated from the doc file with an [[open-in-colab]] marker.
is_python_module (`bool`, *optional*, defaults to `False`):
Whether the docs being built are for python module. (For example, HF Course is not a python module).
"""
page_info = {"version": version, "language": language, "package_name": package_name}
if clean and Path(output_dir).exists():
shutil.rmtree(output_dir)

read_doc_config(doc_folder)

package = importlib.import_module(package_name)
package = importlib.import_module(package_name) if is_python_module else None
anchors_mapping = build_mdx_files(package, doc_folder, output_dir, page_info)
sphinx_refs = check_toc_integrity(doc_folder, output_dir)
sphinx_refs.extend(convert_anchors_mapping_to_sphinx_format(anchors_mapping, package))
build_sphinx_objects_ref(sphinx_refs, output_dir, page_info)
resolve_links(output_dir, package, anchors_mapping, page_info)
if is_python_module:
build_sphinx_objects_ref(sphinx_refs, output_dir, page_info)
resolve_links(output_dir, package, anchors_mapping, page_info)
generate_frontmatter(output_dir)

if notebook_dir is not None:
Expand Down Expand Up @@ -395,6 +412,9 @@ def check_toc_integrity(doc_folder, output_dir):
while len(toc) > 0:
part = toc.pop(0)
toc_sections.extend([sec["local"] for sec in part["sections"] if "local" in sec])
for sec in part["sections"]:
if "local_fw" in sec:
toc_sections.extend(sec["local_fw"].values())
# There should be one sphinx ref per page
for sec in part["sections"]:
if "local" in sec:
Expand Down
16 changes: 13 additions & 3 deletions src/doc_builder/commands/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ def build_command(args):
"the doc-builder package installed, so you need to run the command from inside the doc-builder repo."
)

if args.version is None:
if args.not_python_module:
version = get_default_branch_name(args.path_to_docs)
elif args.version is None:
module = importlib.import_module(args.library_name)
version = module.__version__

Expand All @@ -86,6 +88,7 @@ def build_command(args):
version=version,
language=args.language,
notebook_dir=args.notebook_dir,
is_python_module=not args.not_python_module,
)

# dev build should not update _versions.yml
Expand All @@ -112,7 +115,8 @@ def build_command(args):
shutil.copy(f, dest)

# Move the objects.inv file at the root
shutil.move(tmp_dir / "kit" / "src" / "routes" / "objects.inv", tmp_dir / "objects.inv")
if not args.not_python_module:
shutil.move(tmp_dir / "kit" / "src" / "routes" / "objects.inv", tmp_dir / "objects.inv")

# Build doc with node
working_dir = str(tmp_dir / "kit")
Expand Down Expand Up @@ -143,7 +147,8 @@ def build_command(args):
shutil.rmtree(output_path)
shutil.copytree(tmp_dir / "kit" / "build", output_path)
# Move the objects.inv file back
shutil.move(tmp_dir / "objects.inv", output_path / "objects.inv")
if not args.not_python_module:
shutil.move(tmp_dir / "objects.inv", output_path / "objects.inv")


def build_command_parser(subparsers=None):
Expand All @@ -170,6 +175,11 @@ def build_command_parser(subparsers=None):
)
parser.add_argument("--notebook_dir", type=str, help="Where to save the generated notebooks.", default=None)
parser.add_argument("--html", action="store_true", help="Whether or not to build HTML files instead of MDX files.")
parser.add_argument(
"--not_python_module",
action="store_true",
help="Whether docs files do NOT have correspoding python module (like HF course & hub docs).",
)

if subparsers is not None:
parser.set_defaults(func=build_command)
Expand Down
Loading