diff --git a/1-getting-started-lessons/1-intro-to-programming-languages/README.md b/1-getting-started-lessons/1-intro-to-programming-languages/README.md index 5c791192..f824629b 100644 --- a/1-getting-started-lessons/1-intro-to-programming-languages/README.md +++ b/1-getting-started-lessons/1-intro-to-programming-languages/README.md @@ -198,6 +198,9 @@ Compare some programming languages. What are some of the unique traits of JavaSc Study a bit on the different languages available to the programmer. Try to write a line in one language, and then rewrite it in two others. What did you learn? + ## Assignment [Reading the Docs](assignment.md) + +> Note: When selecting tools for your assignment, do not choose editors, browsers, or command line tools already listed above. \ No newline at end of file diff --git a/1-getting-started-lessons/1-intro-to-programming-languages/assignment.md b/1-getting-started-lessons/1-intro-to-programming-languages/assignment.md index c1206550..c38f830f 100644 --- a/1-getting-started-lessons/1-intro-to-programming-languages/assignment.md +++ b/1-getting-started-lessons/1-intro-to-programming-languages/assignment.md @@ -1,11 +1,17 @@ -# Reading the Docs - ## Instructions -There are many tools that a web developer may need that are on the [MDN documentation for client-side tooling](https://developer.mozilla.org/docs/Learn/Tools_and_testing/Understanding_client-side_tools/Overview). Select 3 tools not covered in the lesson, explain why a web developer would use it, and search for a tool that falls under this category and share its documentation. Do not use the same tool example on MDN docs. +There are many tools that a web developer may need that are listed on the [MDN documentation for client-side tooling](https://developer.mozilla.org/docs/Learn/Tools_and_testing/Understanding_client-side_tools/Overview). Select **three tools** that are **not covered in this lesson** (excluding [list specific tools or refer to lesson content]), explain **why** a web developer would use each tool, and find a tool that fits each category. For each, share a link to its official documentation (not the example used on MDN). + +**Format:** +- Tool name +- Why a web developer would use it (2-3 sentences) +- Link to documentation + +**Length:** +- Each explanation should be 2-3 sentences. ## Rubric Exemplary | Adequate | Needs Improvement --- | --- | -- | -|Explained why web developer would use tool| Explained how, but not why developer would use tool| Did not mention how or why a developer would use tool | \ No newline at end of file +Explained why web developer would use tool | Explained how, but not why developer would use tool | Did not mention how or why a developer would use tool | \ No newline at end of file diff --git a/1-getting-started-lessons/2-github-basics/README.md b/1-getting-started-lessons/2-github-basics/README.md index 1ff79081..dceb6efd 100644 --- a/1-getting-started-lessons/2-github-basics/README.md +++ b/1-getting-started-lessons/2-github-basics/README.md @@ -146,7 +146,7 @@ Let's say you have a folder locally with some code project and you want to start git push -u origin main ``` - This sends your commits in your "main" branch to GitHub. + This sends your commits in your "main" branch to GitHub. Setting the `upstream` branch including `-u` in the command establishes a link between your local branch and the remote branch, so you can simply use git push or git pull without specifying the branch name in the future. Git will automatically use the upstream branch and you won't need to specify the branch name explicitly in future commands. 2. **To add more changes**. If you want to continue making changes and pushing them to GitHub you’ll just need to use the following three commands: @@ -243,7 +243,11 @@ Let's go through a contributor workflow. Assume the contributor has already _for git merge main ``` - This will bring in all changes from `main` into your branch and hopefully you can just continue. If not, VS Code will tell you where Git is _confused_ and you just alter the affected files to say which content is the most accurate. + The `git merge main` command will bring in all changes from `main` into your branch. Hopefully you can just continue. If not, VS Code will tell you where Git is _confused_ and you just alter the affected files to say which content is the most accurate. + + To switch to a different branch, use the modern `git switch` command: + ```bash + git switch [branch_name] 1. **Send your work to GitHub**. Sending your work to GitHub means two things. Pushing your branch to your repo and then open up a PR, Pull Request. diff --git a/1-getting-started-lessons/README.md b/1-getting-started-lessons/README.md index 914084ad..9a549ab9 100644 --- a/1-getting-started-lessons/README.md +++ b/1-getting-started-lessons/README.md @@ -1,6 +1,6 @@ # Getting Started with Web Development -In this section of the curriculum, you will be introduced to non project-based concepts important to becoming a professional developer. +In this section of the curriculum, you will be introduced to non project-based concepts important to become a professional developer. ### Topics diff --git a/10-ai-framework-project/README.md b/10-ai-framework-project/README.md new file mode 100644 index 00000000..3962b66d --- /dev/null +++ b/10-ai-framework-project/README.md @@ -0,0 +1,374 @@ +# AI Framework + +There are many AI frameworks out there that when used can severely quicken up the time it takes to build a project. In this project we will focus on understanding what problems these frameworks address and build such a project ourselves. + +## Why a framework + +When it comes to using AI there are different approaches and different reasons for choosing these approaches, here are some: + +- **No SDK**, most AI models allows you to interact directly with the AI model via for example HTTP requests. That approach works and may sometimes be your only option if an SDK option is missing. +- **SDK**. Using an SDK is usually the recommended approach as it allows you to type less code to interact with your model. It usually is limited to a specific model and if using different models, you might need to write new code to support those additional models. +- **A framework**. A framework usually takes things to another level in the sense that if you need to use different models, there's one API for all of them, what differs is usually the initial set up. Additionally frameworks brings in useful abstractions like in the AI space, they can deal with tools, memory, workflows, agents and more while writing less code. Because frameworks are usually opinionated they can really be helpful if you buy into how they do things but may fall short if you try to do something bespoke that the framework isn't made for. Sometimes a framework can also simplify too much and you may therefore not learn an important topic that later may harm performance for example. + +Generally, use the right tool for the job. + +## Introduction + +In this lesson, we'll learn to: + +- Use a common AI framework. +- Address common problems like chat conversations, tool usage, memory and context. +- Leverage this to build AI apps. + +## First prompt + +In our first app example, we'll learn how to connect to an AI model and query it using a prompt. + +### Using Python + +For this example, we'll use Langchain to connect to GitHub Models. We can use a class called `ChatOpenAI` and give it the fields `api_key`, `base_url` and `model`. The token is something that automatically is populated within GitHub Codespaces and if you're running the app locally, you need to set up a personal access token for this to work. + +```python +from langchain_openai import ChatOpenAI +import os + +llm = ChatOpenAI( + api_key=os.environ["GITHUB_TOKEN"], + base_url="https://models.github.ai/inference", + model="openai/gpt-4o-mini", +) + +# works +response = llm.invoke("What's the capital of France?") +print(response.content) +``` + +In this code, we: + +- Call `ChatOpenAI` to create a client. +- Use `llm.invoke` with a prompt to create a response +- Print the response with `print(response.content)`. + +You should see a response similar to: + +```text +The capital of France is Paris. +``` + +## Chat conversation + +In the preceding section, you saw how we used what's normally known as zero shot prompting, a single prompt followed by a response. + +However, often you find yourself in a situation where you need to maintain a conversation of several messages being exchanged between yourself and the AI assistant. + +### Using Python + +In langchain, we can store the conversation in a list. The `HumanMessage` represents a message from a user, and `SystemMessage` is a message meant to set the "personality" of the AI. In below example you see how we instruct the AI to assume the personality of Captain Picard and for the human/user to ask "Tell me about you" as the prompt. + +```python +messages = [ + SystemMessage(content="You are Captain Picard of the Starship Enterprise"), + HumanMessage(content="Tell me about you"), +] +``` + +The full code for this example looks like so: + +```python +from langchain_core.messages import HumanMessage, SystemMessage +from langchain_openai import ChatOpenAI +import os + +llm = ChatOpenAI( + api_key=os.environ["GITHUB_TOKEN"], + base_url="https://models.github.ai/inference", + model="openai/gpt-4o-mini", +) + +messages = [ + SystemMessage(content="You are Captain Picard of the Starship Enterprise"), + HumanMessage(content="Tell me about you"), +] + + +# works +response = llm.invoke(messages) +print(response.content) +``` + +You should see an outcome similar to: + +```text +I am Captain Jean-Luc Picard, the commanding officer of the USS Enterprise (NCC-1701-D), a starship in the United Federation of Planets. My primary mission is to explore new worlds, seek out new life and new civilizations, and boldly go where no one has gone before. + +I believe in the importance of diplomacy, reason, and the pursuit of knowledge. My crew is diverse and skilled, and we often face challenges that test our resolve, ethics, and ingenuity. Throughout my career, I have encountered numerous species, grappled with complex moral dilemmas, and have consistently sought peaceful solutions to conflicts. + +I hold the ideals of the Federation close to my heart, believing in the importance of cooperation, understanding, and respect for all sentient beings. My experiences have shaped my leadership style, and I strive to be a thoughtful and just captain. How may I assist you further? +``` + +To keep the state of the conversation, you can add the response from a chat, so conversation is remembered, here's how to do that: + +```python +from langchain_core.messages import HumanMessage, SystemMessage +from langchain_openai import ChatOpenAI +import os + +llm = ChatOpenAI( + api_key=os.environ["GITHUB_TOKEN"], + base_url="https://models.github.ai/inference", + model="openai/gpt-4o-mini", +) + +messages = [ + SystemMessage(content="You are Captain Picard of the Starship Enterprise"), + HumanMessage(content="Tell me about you"), +] + + +# works +response = llm.invoke(messages) + +print(response.content) + +print("---- Next ----") + +messages.append(response) +messages.append(HumanMessage(content="Now that I know about you, I'm Chris, can I be in your crew?")) + +response = llm.invoke(messages) + +print(response.content) + +``` + +What we can see from the above conversation is how we invoke the LLM two times, first with the conversation consisting of just two messages but then a second time with more messages added to the conversation. + +In fact, if you run this, you will see the second response being something like: + +```text +Welcome aboard, Chris! It's always a pleasure to meet those who share a passion for exploration and discovery. While I cannot formally offer you a position on the Enterprise right now, I encourage you to pursue your aspirations. We are always in need of talented individuals with diverse skills and backgrounds. + +If you are interested in space exploration, consider education and training in the sciences, engineering, or diplomacy. The values of curiosity, resilience, and teamwork are crucial in Starfleet. Should you ever find yourself on a starship, remember to uphold the principles of the Federation: peace, understanding, and respect for all beings. Your journey can lead you to remarkable adventures, whether in the stars or on the ground. Engage! +``` + +I'll take that as a maybe ;) + +## Streaming responses + +TODO + +## Prompt templates + +TODO + +## Structured output + +TODO + +## Tool calling + +Tools are how we give the LLM extra skills. The idea is to tell the LLM about functions it has and if a prompt is made that matches the description of one of these tools then we call them. + +### Using Python + +Let's add some tools like so: + +```python +from typing_extensions import Annotated, TypedDict + +class add(TypedDict): + """Add two integers.""" + + # Annotations must have the type and can optionally include a default value and description (in that order). + a: Annotated[int, ..., "First integer"] + b: Annotated[int, ..., "Second integer"] + +tools = [add] + +functions = { + "add": lambda a, b: a + b +} +``` + +What we're doing here is to create a description of a tool called `add`. By inheriting from `TypedDict` and adding members like `a` and `b` of type `Annotated` this can be converted to a schema that the LLM can understand. The creation of functions is a dictionary that ensures that we know what to do if a specific tool is identified. + +Let's see how we call the LLM with this tool next: + +```python +llm = ChatOpenAI( + api_key=os.environ["GITHUB_TOKEN"], + base_url="https://models.github.ai/inference", + model="openai/gpt-4o-mini", +) + +llm_with_tools = llm.bind_tools(tools) +``` + +Here we call `bind_tools` with our `tools` array and thereby the LLM `llm_with_tools` now has knowledge of this tool. + +To use this new LLM, we can type the following code: + +```python +query = "What is 3 + 12?" + +res = llm_with_tools.invoke(query) +if(res.tool_calls): + for tool in res.tool_calls: + print("TOOL CALL: ", functions[tool["name"]](**tool["args"])) +print("CONTENT: ",res.content) +``` + +Now that we call `invoke` on this new llm, that has tools, we maybe the the property `tool_calls` populated. If so, any identified tools has a `name` and `args` property that identifies what tool should be called and with arguments. The full code looks like so: + +```python +from langchain_core.messages import HumanMessage, SystemMessage +from langchain_openai import ChatOpenAI +import os +from typing_extensions import Annotated, TypedDict + +class add(TypedDict): + """Add two integers.""" + + # Annotations must have the type and can optionally include a default value and description (in that order). + a: Annotated[int, ..., "First integer"] + b: Annotated[int, ..., "Second integer"] + +tools = [add] + +functions = { + "add": lambda a, b: a + b +} + +llm = ChatOpenAI( + api_key=os.environ["GITHUB_TOKEN"], + base_url="https://models.github.ai/inference", + model="openai/gpt-4o-mini", +) + +llm_with_tools = llm.bind_tools(tools) + +query = "What is 3 + 12?" + +res = llm_with_tools.invoke(query) +if(res.tool_calls): + for tool in res.tool_calls: + print("TOOL CALL: ", functions[tool["name"]](**tool["args"])) +print("CONTENT: ",res.content) +``` + +Running this code, you should see output similar to: + +```text +TOOL CALL: 15 +CONTENT: +``` + +What this output mean is that the LLM analyzed the prompt "What is 3 + 12" as meaning that the `add` tool should be called and it knew that thanks to its name, description and member field descriptions. That the answer is 15 is because of our code using the dictionary `functions` to invoke it: + +```python +print("TOOL CALL: ", functions[tool["name"]](**tool["args"])) +``` + +### A more interesting tool that calls a web api + +Tools that adds two numbers is interesting as it illustrates how tool calling works but usually tools tend to do something more interesting like for example calling a Web API, let's do just that with this code: + +```python +class joke(TypedDict): + """Tell a joke.""" + + # Annotations must have the type and can optionally include a default value and description (in that order). + category: Annotated[str, ..., "The joke category"] + +def get_joke(category: str) -> str: + response = requests.get(f"https://api.chucknorris.io/jokes/random?category={category}", headers={"Accept": "application/json"}) + if response.status_code == 200: + return response.json().get("value", f"Here's a {category} joke!") + return f"Here's a {category} joke!" + +functions = { + "add": lambda a, b: a + b, + "joke": lambda category: get_joke(category) +} + +query = "Tell me a joke about animals" + +# the rest of the code is the same +``` + +Now if you run this code you will get a response saying something like: + +```text +TOOL CALL: Chuck Norris once rode a nine foot grizzly bear through an automatic car wash, instead of taking a shower. +CONTENT: +``` + +Here's the code in its entirety: + +```python +from langchain_openai import ChatOpenAI +import requests +import os +from typing_extensions import Annotated, TypedDict + +class add(TypedDict): + """Add two integers.""" + + # Annotations must have the type and can optionally include a default value and description (in that order). + a: Annotated[int, ..., "First integer"] + b: Annotated[int, ..., "Second integer"] + +class joke(TypedDict): + """Tell a joke.""" + + # Annotations must have the type and can optionally include a default value and description (in that order). + category: Annotated[str, ..., "The joke category"] + +tools = [add, joke] + +def get_joke(category: str) -> str: + response = requests.get(f"https://api.chucknorris.io/jokes/random?category={category}", headers={"Accept": "application/json"}) + if response.status_code == 200: + return response.json().get("value", f"Here's a {category} joke!") + return f"Here's a {category} joke!" + +functions = { + "add": lambda a, b: a + b, + "joke": lambda category: get_joke(category) +} + +llm = ChatOpenAI( + api_key=os.environ["GITHUB_TOKEN"], + base_url="https://models.github.ai/inference", + model="openai/gpt-4o-mini", +) + +llm_with_tools = llm.bind_tools(tools) + +query = "Tell me a joke about animals" + +res = llm_with_tools.invoke(query) +if(res.tool_calls): + for tool in res.tool_calls: + # print("TOOL CALL: ", tool) + print("TOOL CALL: ", functions[tool["name"]](**tool["args"])) +print("CONTENT: ",res.content) +``` + +## Embedding + +vectorize content, compare via cosine similarity + +https://python.langchain.com/docs/how_to/embed_text/ + +### document loaders + +pdf and csv + +## Building an app + +TODO + +## Assignment + +## Summary diff --git a/10-ai-framework-project/code/python/app-chat.py b/10-ai-framework-project/code/python/app-chat.py new file mode 100644 index 00000000..273710c8 --- /dev/null +++ b/10-ai-framework-project/code/python/app-chat.py @@ -0,0 +1,29 @@ +from langchain_core.messages import HumanMessage, SystemMessage +from langchain_openai import ChatOpenAI +import os + +llm = ChatOpenAI( + api_key=os.environ["GITHUB_TOKEN"], + base_url="https://models.github.ai/inference", + model="openai/gpt-4o-mini", +) + +messages = [ + SystemMessage(content="You are Captain Picard of the Starship Enterprise"), + HumanMessage(content="Tell me about you"), +] + + +# works +response = llm.invoke(messages) + +print(response.content) + +print("---- Next ----") + +messages.append(response) +messages.append(HumanMessage(content="Now that I know about you, I'm Chris, can I be in your crew?")) + +response = llm.invoke(messages) + +print(response.content) diff --git a/10-ai-framework-project/code/python/app-tools.py b/10-ai-framework-project/code/python/app-tools.py new file mode 100644 index 00000000..00aeaeac --- /dev/null +++ b/10-ai-framework-project/code/python/app-tools.py @@ -0,0 +1,47 @@ +from langchain_openai import ChatOpenAI +import requests +import os +from typing_extensions import Annotated, TypedDict + +class add(TypedDict): + """Add two integers.""" + + # Annotations must have the type and can optionally include a default value and description (in that order). + a: Annotated[int, ..., "First integer"] + b: Annotated[int, ..., "Second integer"] + +class joke(TypedDict): + """Tell a joke.""" + + # Annotations must have the type and can optionally include a default value and description (in that order). + category: Annotated[str, ..., "The joke category"] + +tools = [add, joke] + +def get_joke(category: str) -> str: + response = requests.get(f"https://api.chucknorris.io/jokes/random?category={category}", headers={"Accept": "application/json"}) + if response.status_code == 200: + return response.json().get("value", f"Here's a {category} joke!") + return f"Here's a {category} joke!" + +functions = { + "add": lambda a, b: a + b, + "joke": lambda category: get_joke(category) +} + +llm = ChatOpenAI( + api_key=os.environ["GITHUB_TOKEN"], + base_url="https://models.github.ai/inference", + model="openai/gpt-4o-mini", +) + +llm_with_tools = llm.bind_tools(tools) + +query = "Tell me a joke about animals" + +res = llm_with_tools.invoke(query) +if(res.tool_calls): + for tool in res.tool_calls: + # print("TOOL CALL: ", tool) + print("TOOL CALL: ", functions[tool["name"]](**tool["args"])) +print("CONTENT: ",res.content) \ No newline at end of file diff --git a/10-ai-framework-project/code/python/app.py b/10-ai-framework-project/code/python/app.py new file mode 100644 index 00000000..82e57ab0 --- /dev/null +++ b/10-ai-framework-project/code/python/app.py @@ -0,0 +1,14 @@ +# pip install -qU "langchain[openai]" + +from langchain_openai import ChatOpenAI +import os + +llm = ChatOpenAI( + api_key=os.environ["GITHUB_TOKEN"], + base_url="https://models.github.ai/inference", + model="openai/gpt-4o-mini", +) + +# works +response = llm.invoke("What is the capital of France") +print(response.content) \ No newline at end of file diff --git a/10-ai-framework-project/solution/README.md b/10-ai-framework-project/solution/README.md new file mode 100644 index 00000000..e69de29b diff --git a/2-js-basics/1-data-types/assignment.md b/2-js-basics/1-data-types/assignment.md index 720dd7d2..30c25550 100644 --- a/2-js-basics/1-data-types/assignment.md +++ b/2-js-basics/1-data-types/assignment.md @@ -2,10 +2,10 @@ ## Instructions -Imagine you are building a shopping cart. Write some documentation on the data types that you would need to complete your shopping experience. How did you arrive at your choices? +Imagine you are building a shopping cart. Write documentation on the data types you would need to complete your shopping experience. For each data type, explain how and why you would use it, and provide an example. The six JavaScript data types are: String, Number, Boolean, Null, Undefined, and Object. ## Rubric Criteria | Exemplary | Adequate | Needs Improvement --- | --- | --- | -- | -||The six data types are listed and explored in detail, documenting their use|Four datatypes are explored|Two data types are explored| \ No newline at end of file +Data Types | All six data types are listed, explored in detail, and documented with examples | Four data types are explored with some explanation | Two data types are explored with minimal explanation | \ No newline at end of file diff --git a/3-terrarium/1-intro-to-html/assignment.md b/3-terrarium/1-intro-to-html/assignment.md index 349b6b06..7522030c 100644 --- a/3-terrarium/1-intro-to-html/assignment.md +++ b/3-terrarium/1-intro-to-html/assignment.md @@ -1,11 +1,39 @@ -# Practice your HTML: Build a blog mockup +# HTML Practice Assignment: Build a Blog Mockup + +## Objective + +Design and hand-code the HTML structure for a personal blog homepage. This exercise will help you practice semantic HTML, layout planning, and code organization. ## Instructions -Imagine you are designing, or redesigning, your personal web site. Create a graphical mockup of your site, and then write down the HTML markup you would use to build out the various elements of the site. You can do this on paper, and scan it, or use software of your choice, just make sure to hand-code the HTML markup. +1. **Design Your Blog Mockup** + - Sketch a visual mockup of your blog homepage. Include key sections such as header, navigation, main content, sidebar, and footer. + - You may use paper and scan your sketch, or use digital tools (e.g., Figma, Adobe XD, Canva, or even PowerPoint). + +2. **Identify HTML Elements** + - List the HTML elements you plan to use for each section (e.g., `
`, `