joe

@joe@jws.news

I am a humble Milwaukeean. I write code, travel, ride two-wheeled transportation, and love my dogs. This is my blog. You can also follow as @joe (mastodon), @steinbring (kbin / lemmy), or @steinbring (pixelfed).

This profile is from a federated server and may be incomplete. Browse more on the original instance.

joe, to ai

A few weeks back, I thought about getting an AI model to return the “Flavor of the Day” for a Culver’s location. If you ask Llama 3:70b “The website https://www.culvers.com/restaurants/glendale-wi-bayside-dr lists “today’s flavor of the day”. What is today’s flavor of the day?”, it doesn’t give a helpful answer.

https://i0.wp.com/jws.news/wp-content/uploads/2024/05/Screenshot-2024-05-09-at-12.29.28%E2%80%AFPM.png?resize=1024%2C690&ssl=1

If you ask ChatGPT 4 the same question, it gives an even less useful answer.

https://i0.wp.com/jws.news/wp-content/uploads/2024/05/Screenshot-2024-05-09-at-12.33.42%E2%80%AFPM.png?resize=1024%2C782&ssl=1

If you check the website, today’s flavor of the day is Chocolate Caramel Twist.

https://i0.wp.com/jws.news/wp-content/uploads/2024/05/Screenshot-2024-05-09-at-12.41.21%E2%80%AFPM.png?resize=1024%2C657&ssl=1

So, how can we get a proper answer? Ten years ago, when I wrote “The Milwaukee Soup App”, I used the Kimono (which is long dead) to scrape the soup of the day. You could also write a fiddly script to scrape the value manually. It turns out that there is another option, though. You could use Scrapegraph-ai. ScrapeGraphAI is a web scraping Python library that uses LLM and direct graph logic to create scraping pipelines for websites, documents, and XML files. Just say which information you want to extract and the library will do it for you.

Let’s take a look at an example. The project has an official demo where you need to provide an OpenAI API key, select a model, provide a link to scrape, and write a prompt.

https://i0.wp.com/jws.news/wp-content/uploads/2024/05/Screenshot-2024-05-09-at-12.35.29%E2%80%AFPM.png?resize=1024%2C660&ssl=1

As you can see, it reliably gives you the flavor of the day (in a nice JSON object). It will go even further, though because if you point it at the monthly calendar, you can ask it for the flavor of the day and soup of the day for the remainder of the month and it can do that as well.

https://i0.wp.com/jws.news/wp-content/uploads/2024/05/Screenshot-2024-05-09-at-1.14.43%E2%80%AFPM.png?resize=1024%2C851&ssl=1

Running it locally with Llama 3 and Nomic

I am running Python 3.12 on my Mac but when you run pip install scrapegraphai to install the dependencies, it throws an error. The project lists the prerequisite of Python 3.8+, so I downloaded 3.9 and installed the library into a new virtual environment.

Let’s see what the code looks like.

You will notice that just like in yesterday’s How to build a RAG system post, we are using both a main model and an embedding model.

So, what does the output look like?

https://i0.wp.com/jws.news/wp-content/uploads/2024/05/Screenshot-2024-05-09-at-2.28.10%E2%80%AFPM.png?resize=1024%2C800&ssl=1

At this point, if you want to harvest flavors of the day for each location, you can do so pretty simply. You just need to loop through each of Culver’s location websites.

Have a question, comment, etc? Please feel free to drop a comment, below.

https://jws.news/2024/how-to-use-ai-to-make-web-scraping-easier/

joe, (edited ) to ai

Back in January, we started looking at AI and how to run a large language model (LLM) locally (instead of just using something like ChatGPT or Gemini). A tool like Ollama is great for building a system that uses AI without dependence on OpenAI. Today, we will look at creating a Retrieval-augmented generation (RAG) application, using Python, LangChain, Chroma DB, and Ollama. Retrieval-augmented generation is the process of optimizing the output of a large language model, so it references an authoritative knowledge base outside of its training data sources before generating a response. If you have a source of truth that isn’t in the training data, it is a good way to get the model to know about it. Let’s get started!

Your RAG will need a model (like llama3 or mistral), an embedding model (like mxbai-embed-large), and a vector database. The vector database contains relevant documentation to help the model answer specific questions better. For this demo, our vector database is going to be Chroma DB. You will need to “chunk” the text you are feeding into the database. Let’s start there.

Chunking

There are many ways of choosing the right chunk size and overlap but for this demo, I am just going to use a chunk size of 7500 characters and an overlap of 100 characters. I am also going to use LangChain‘s CharacterTextSplitter to do the chunking. It means that the last 100 characters in the value will be duplicated in the next database record.

The Vector Database

A vector database is a type of database designed to store, manage, and manipulate vector embeddings. Vector embeddings are representations of data (such as text, images, or sounds) in a high-dimensional space, where each data item is represented as a dense vector of real numbers. When you query a vector database, your query is transformed into a vector of real numbers. The database then uses this vector to perform similarity searches.

https://i0.wp.com/jws.news/wp-content/uploads/2024/05/Screenshot-2024-05-08-at-2.36.49%E2%80%AFPM.png?resize=665%2C560&ssl=1

You can think of it as being like a two-dimensional chart with points on it. One of those points is your query. The rest are your database records. What are the points that are closest to the query point?

Embedding Model

To do this, you can’t just use an Ollama model. You need to also use an embedding model. There are three that are available to pull from the Ollama library as of the writing of this. For this demo, we are going to be using nomic-embed-text.

Main Model

Our main model for this demo is going to be phi3. It is a 3.8B parameters model that was trained by Microsoft.

LangChain

You will notice that today’s demo is heavily using LangChain. LangChain is an open-source framework designed for developing applications that use LLMs. It provides tools and structures that enhance the customization, accuracy, and relevance of the outputs produced by these models. Developers can leverage LangChain to create new prompt chains or modify existing ones. LangChain pretty much has APIs for everything that we need to do in this app.

The Actual App

Before we start, you are going to want to pip install tiktoken langchain langchain-community langchain-core. You are also going to want to ollama pull phi3 and ollama pull nomic-embed-text. This is going to be a CLI app. You can run it from the terminal like python3 app.py "<Question Here>".

You also need a sources.txt file containing the URLs of things that you want to have in your vector database.

So, what is happening here? Our app.py file is reading sources.txt to get a list of URLs for news stories from Tuesday’s Apple event. It then uses WebBaseLoader to download the pages behind those URLs, uses CharacterTextSplitter to chunk the data, and creates the vectorstore using Chroma. It then creates and invokes rag_chain.

Here is what the output looks like:

https://i0.wp.com/jws.news/wp-content/uploads/2024/05/Screenshot-2024-05-08-at-4.09.36%E2%80%AFPM.png?resize=1024%2C845&ssl=1

The May 7th event is too recent to be in the model’s training data. This makes sure that the model knows about it. You could also feed the model company policy documents, the rules to a board game, or your diary and it will magically know that information. Since you are running the model in Ollama, there is no risk of that information getting out, too. It is pretty awesome.

Have any questions, comments, etc? Feel free to drop a comment, below.

https://jws.news/2024/how-to-build-a-rag-system-using-python-ollama-langchain-and-chroma-db/

#AI #ChromaDB #Chunking #LangChain #LLM #Ollama #Python #RAG

joe, to random

Yesterday, I wrote about how I moved a mastodon bot from Pipedream to a docker container. Docker is an efficient way of running isolated little scripts like that. Today, I wanted to review some basic debugging techniques to ensure your script runs as expected.

What docker images exist on the system?

When we looked at how to dockerize a node app, I said that you create a docker image and then run it as a container. So, how do you list the docker images on a system? You run docker images.

https://i0.wp.com/jws.news/wp-content/uploads/2024/05/Screenshot-2024-05-04-at-12.37.35%E2%80%AFPM.png?resize=1024%2C856&ssl=1

What docker containers exist on the system?

If you run docker ps, you can get what containers are running, and if you run docker ps -a, it will include containers that aren’t running.

https://i0.wp.com/jws.news/wp-content/uploads/2024/05/Screenshot-2024-05-04-at-12.46.33%E2%80%AFPM.png?resize=1024%2C856&ssl=1

How do you access a container’s shell?

Like a VM or a system running on bare metal, you can get a shell inside of the docker container. The first step is knowing the container ID for the container you want a shell for. If you look at the output from the docker ps command, you can find it.

https://i0.wp.com/jws.news/wp-content/uploads/2024/05/Screenshot-2024-05-04-at-12.46.33%E2%80%AFPM-2.png?resize=1024%2C856&ssl=1

At this point, you run docker exec -it [container id] /bin/sh to get a shell inside the container.

https://i0.wp.com/jws.news/wp-content/uploads/2024/05/Screenshot-2024-05-04-at-1.12.14%E2%80%AFPM.png?resize=1024%2C856&ssl=1

Once you know that the image is there, know if it is running or not, and have a shell inside the container, you should be able to find what is wrong with your container.

Have a questions, comment, etc? Feel free to drop a comment, below.

https://jws.news/2024/debugging-a-docker-container/

joe, to mastodon

Back in 2022, I created “Good Morning, Milwaukee!“. It is a bot that posts every day at 6 am with the weather, the times for sunrise and sunset, and a photo from around the city. When I first wrote it, I wrote it in Node and put it up on Pipedream. Lately, there have been some issues with the weather API that it was using, so I decided to replace it with the OpenWeather API but I figured that while I was at it, I would rewrite it in Python, dockerize it, and run it on my new home lab server.

Let’s start with what the actual Python script looks like.

If you want to reuse this code to create your own bot, there are variables at the top for api_key, zip_code, and mastodon_access_token. The actual posting is done using Mastodon.py.

So, what would the Dockerfile look like?

You’ll notice that it also needs a requirements.txt and a crontab file. Lets see what those look like.

Just make sure that you have a newline at the end of your crontab file. At this point, you can run docker build -t gmmke-app . to build the docker image and then run docker run -d gmmke-app run the container.

https://i0.wp.com/jws.news/wp-content/uploads/2024/05/Screenshot-2024-05-03-at-3.24.33%E2%80%AFPM.png?resize=1024%2C856&ssl=1

With that, it is going to post once when you create the container and then daily at 6:00 AM (Milwaukee time).

Have any questions, comments, etc? Feel free to drop them, below.

https://jws.news/2024/i-rewrote-good-morning-milwaukee-in-python/

joe, to machinelearning

In yesterday’s post, we asked the basic question of what is machine learning. I hoped to illustrate the similarities and differences between artificial intelligence and machine learning. Lately, on this site, we have been spending a bit of time using Python and I wanted to take a moment today to look at a great library for machine learning in Python.

Scikit-learn is the go-to library for machine learning with an amazing ecosystem of plugins. It is open-source and supports supervised and unsupervised learning. It also provides various tools for model fitting, data preprocessing, model selection, model evaluation, and many other utilities. After you python3 -m venv EnvironmentName and source EnvironmentName/bin/activate, you can install it by running pip install scikit-learn. At that point, you can reference it in your code as sklearn.

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-26-at-2.37.12%E2%80%AFPM.png?resize=1024%2C374&ssl=1

The way that scikit-learn works is that you start with some data, you give it to a model, the model learns from it, and then you will be able to make predictions. The common notation is splitting up the data into a part called X (everything you are using to make a prediction) and another part called Y (the prediction you are interested in making). The X could be information about a house (square feet, number of bathrooms, etc) where Y is the house price, or X could be a patient’s health statistics where Y is whether or not they develop diabetes. The model then uses X to try to predict Y.

sklearn.datasets

Let’s take a look at the sklearn.datasets module, first. You can use https://scikit-learn.org/stable/modules/generated/sklearn.datasets.fetch_california_housing.html#sklearn.datasets.fetch_california_housing to get test data directly out of the library about the California housing market.

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-27-at-6.37.15%E2%80%AFPM.png?resize=1024%2C650&ssl=1

In the above code, we load the 20,640 records and 9 columns into the data variable and then we set the things that we are using to make a prediction to X and the prediction that we are interested in making to y. So, what are the feature (column) names for the data? If you print(data.feature_names), it will print them.

sklearn.model_selection

Once you have data, you can start working on creating a model. The model itself is nothing more than a Python object but the goal after you create it is to train it. You will want to split your data into a training set and a test set. Using <a href="https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.train_test_split.html#sklearn.model_selection.train_test_split">train_test_split</a> in sklearn.model_selection, you can split it into 70% of the data for training the model and 30% of the data for testing the model (or whatever split you want).

Let’s see what that looks like.

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-28-at-8.32.31%E2%80%AFPM.png?resize=1024%2C336&ssl=1

sklearn.impute

A dataset is rarely pristine. There are often missing data points or data points that are set to a value like 0. Imputing is the process of replacing missing or incomplete data with substituted values. https://scikit-learn.org/stable/modules/generated/sklearn.impute.SimpleImputer.html#sklearn.impute.SimpleImputer in sklearn.impute lets you replace missing values using a descriptive statistic (e.g. mean, median, or most frequent) along each column.

Let’s see what that looks like.

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-29-at-1.53.33%E2%80%AFPM.png?resize=1024%2C302&ssl=1

In the above example, we are taking any X values except num_preg (the number of pregnancies) that have the value 0 and setting it to the mean. That makes it so that missing values don’t scew things when you go to train the model.

Creating and training a model

Like I said above, the model itself is nothing more than a Python object. You can use sklearn to both create and train it, though. Let’s see what it looks like to create a model using sklearn.neighbors (for a regression based on k-nearest neighbors) and then https://scikit-learn.org/stable/modules/generated/sklearn.neighbors.KNeighborsRegressor.html#sklearn.neighbors.KNeighborsRegressor.fit to train the model.

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-29-at-3.46.17%E2%80%AFPM.png?resize=1024%2C246&ssl=1

The neat thing about .fit() is that if you want to swap out the KNeighborsRegressor model with a new one, .fit() still works just the same. Let’s look at what it would look like using a linear regression model.

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-29-at-3.48.42%E2%80%AFPM.png?resize=1024%2C250&ssl=1

That’s pretty easy.

How do you check the accuracy of the trained model?

Sklearn has a method for predicting using your chosen model and a library for performance metrics. Let’s take a look at what those look like.

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-29-at-4.02.57%E2%80%AFPM.png?resize=1024%2C228&ssl=1

In the above code, we are predicting the value for y and then comparing it against the actual value of y. Using just the training data, it is predicting the values with a 75.23% level of accuracy.

So, what is next?

In a future post, I want to step through the whole process of picking a statement to test, adjusting the data, building and training a model, testing, adjusting the model, and making predictions. Let’s save that for another day, though.

https://jws.news/2024/what-is-scikit-learn/

#MachineLearning #Python #scikitLearn

joe, to machinelearning

Last week, we went over some basics of Artificial Intelligence (AI) using Ollama, Llama3, and some custom code. Artificial intelligence (AI) encompasses a broad range of technologies designed to enable machines to perform tasks that typically require human intelligence. These tasks include understanding spoken or written language, recognizing visual patterns, making decisions, and providing recommendations. Machine learning (ML) is a specialized subset of AI that focuses on developing systems that improve their performance over time without being explicitly programmed. Instead, ML algorithms analyze and learn from large datasets to identify patterns and make decisions based on these insights. This learning process allows ML models to make increasingly accurate predictions or decisions as they are exposed to more data.

A few months ago, I added Liner to the resource page of my website. It allows you to easily train an ML model so that you can do image, text, audio, or video classification, object detection, image segmentation, or pose classification. I created “Is this Joe or Not Joe?” using that tool. TensorFlow.js is running client-side with a model that is trained on a half dozen examples of photos that are Joe and a half dozen examples of photos that are not Joe. You can supply a photo and get a prediction if Joe is in the image or not. You can always retrain the existing model with more examples. That is an example of machine learning.

So, you can think of ML as a subset of AI and Deep Learning (DL) as a subset of ML.

Have any questions, comments, etc? Please feel free to drop a comment, below.

https://jws.news/2024/what-is-machine-learning/

joe, to ai

Yesterday, we looked at how to write a JavaScript app that uses Ollama. Recently, we started to look at Python on this site and I figured that we better follow it up with how to write a Python app that uses Ollama. Just like with JavaScript, Ollama offers a Python library, so we are going to be using that for our examples. Also just like we did with the JavaScript demo, I am going to be using the generate endpoint instead of the chat endpoint. That keeps things simpler but I am going to explore the chat endpoint also at some point.

Install the Ollama Library

The first step is to run pip3 install ollama from the terminal. First, you need to create a virtual environment to isolate your project’s libraries from the global Python libraries.

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-22-at-5.58.34%E2%80%AFPM.png?resize=1024%2C647&ssl=1

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-22-at-5.59.03%E2%80%AFPM.png?resize=1024%2C647&ssl=1

Basic CLI example

At this point, we can start writing code. When we used the web service earlier this week, we used the generate endpoint and provided model, prompt, and stream as parameters. We set the stream parameter to false so that it would return a single response object instead of a stream of objects. When using the python library, the stream parameter isn’t necessary because it returns a single response object by default. We still provide it with a model and a prompt, though.

If you run it from the terminal, the response will look familiar.

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-22-at-8.05.20%E2%80%AFPM.png?resize=1024%2C647&ssl=1

If you replace print(output) with print(output['response']), you can more clearly see the important bits.

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-22-at-8.09.04%E2%80%AFPM.png?resize=1024%2C647&ssl=1

Basic Web Application Example

The output is very similar to the node-fetch example from earlier this week. Last week, when we looked at how to dockerize a node app, we output an array as an unordered list. Let’s see if we can replicate that result using the output from Ollama.

If you pip install flask to install flask, you can host a simple HTTP page at port 8080 and with the magic of json.loads() and a for loop, you can build your unordered list.

So, what does the output look like?

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-22-at-8.27.30%E2%80%AFPM.png?resize=1024%2C651&ssl=1

Every time you load the page, it makes a server-side API call to Ollama, gets a list of large cities in Wisconsin, and displays them on the website. The list is never the same (because of hallucinations) but that is another issue.

Have any questions, comments, etc? Please feel free to drop a comment, below.

https://jws.news/2024/how-to-write-a-python-app-that-uses-ollama/

joe, to ai

So far this week, we have looked at how to use Ollama from the CLI, how to use Ollama from the web service, and how to use Ollama from a phone or iPad. Today we are going to be using the Ollama JavaScript Library to write an application.

Install the Ollama Library

The first step is to run npm i ollama from the terminal.

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-21-at-8.30.04%E2%80%AFAM.png?resize=1024%2C728&ssl=1

That installs Ollama as a dependency in package.json.

Basic CLI example

At this point, we can start writing code. When we used the web service earlier this week, we used the generate endpoint and provided model, prompt, and stream as parameters. We set the stream parameter to false so that it would return a single response object instead of a stream of objects. When using the javascript library, the stream parameter isn’t necessary because it returns a single response object by default. We still provide it with a model and a prompt, though.

If you run it from the terminal, the response will look familiar.

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-21-at-9.19.38%E2%80%AFAM.png?resize=1024%2C728&ssl=1

Basic Web Application Example

The output is very similar to the node-fetch example from earlier this week. Last week, when we looked at how to dockerize a node app, we output an array as an unordered list. Let’s see if we can replicate that result using the output from Ollama.

If you npm install express to install express, you can host a simple HTTP page at port 8080 and with the magic of JSON.parse() and a for loop, you can build your unordered list.

So, what does the output look like?

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-21-at-8.03.57%E2%80%AFPM.png?resize=1024%2C796&ssl=1

Every time you load the page, it makes a server-side API call to Ollama, gets a list of large cities in Wisconsin, and displays them on the website. The list is never the same (because of hallucinations) but that is another issue.

Have any questions, comments, etc? Please feel free to drop a comment, below.

https://jws.news/2024/how-to-write-a-javascript-app-that-uses-ollama/

joe, to ai

Earlier this year, I started looking at how to run a fully on-prem AI. In February, I bought a machine to run the inference engine on and set up Tailscale (which works similarly to Hamachi) to connect to it remotely. If you want to use it remotely, there are a lot of options for native clients.

MacOS

My favorite client for MacOS is MindMac. You can buy it for under $30, it works with multiple models, servers, and server types, and it is easy to use.

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-20-at-2.34.12%E2%80%AFPM.png?resize=1024%2C690&ssl=1

If you want to look further into it, you can check it out at mindmac.app.

Android

My favorite client for Android is Amallo. It is $23 and like MindMac, it works with multiple models, servers, and server types. My only complaint would be that uploading a base64-encoded image to the model doesn’t seem to work well.

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot_20240420-143906.png?resize=461%2C1024&ssl=1

If you want to look further into it, you can check it out at doppeltilde.com.

ipadOS

There is a version of Amallo for iPadOS but I have been liking Enchanted LLM more. If you like it, there is a version for macOS as well. It has the added benefit of being free.

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/IMG_0088.jpg?resize=672%2C1024&ssl=1

If you want to look further into it, you can check it out at the project’s GitHub page.

Have any questions, comments, etc? Please feel free to drop a comment, below.

https://jws.news/2024/how-i-use-ai/

#AI #Amallo #Enchanted #LLM #MindMac #Ollama

joe,

A few months ago, I started trying to figure out how I could use AI without depending on Google, OpenAI, or Microsoft’s continued existence. The risk that Google would kill a product like Gemini is almost 100%. At work, I was asked to figure out embedding and the tools I used in the post are invaluable for the on-the-go use of both a stock model and something that you tinkered with.

If you like that, you are going to love the next dozen posts that I have planned. 🙂

joe, (edited ) to programming

Yesterday, we played with Llama 3 using the Ollama CLI client (or REPL). Today I figured that we would play with it using the Ollama API. The Ollama API is documented on their Github repo. Ollama has a client that runs when you run ollama run llama3 and a service that can be accessed from something like MindMac, Amallo, or Enchanted. The service is what starts when you run ollama serve.

In our first Llama 3 post, we asked the model for “a comma-delimited list of cities in Wisconsin with a population over 100,000 people”. Using Postman and the completion API endpoint, you can ask the same thing.

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-20-at-1.30.48%E2%80%AFPM.png?resize=1024%2C811&ssl=1

You will notice the stream parameter is set to false in the body. If the value is false, the response will be returned as a single response object, rather than a stream of objects. If you are using the API with a web application, you will want to ask the model for the answer as JSON and you will probably want to provide an example of how you want the answer formatted.

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-20-at-1.45.15%E2%80%AFPM.png?resize=1024%2C811&ssl=1

You can use Node and Node-fetch to do the same thing.

If you run it from the terminal, it will look like this:

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-20-at-2.01.19%E2%80%AFPM.png?resize=1024%2C932&ssl=1

Have any questions, comments, etc? Please feel free to drop a comment, below.

https://jws.news/2024/lets-play-more-with-llama-3/

joe, to ai

Last week, Meta announced Llama 3. Thanks to Ollama, you can run it pretty easily. There are 8b and 70b variants available. There are also pre-trained or instruction-tuned variants available. I am not seeing it on the Hugging Face Leader Board yet but the bit that I have played around with it has been promising.

Here are two basic test questions:

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-20-at-12.15.45%E2%80%AFPM.png?resize=989%2C1024&ssl=1

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-20-at-12.27.47%E2%80%AFPM.png?resize=989%2C1024&ssl=1

Have any questions, comments, etc? Please feel free to drop a comment, below.

https://jws.news/2024/lets-play-with-llama-3/

joe, to python

We have been looking at a lot of new things on the blog, lately (React, web components, etc). I figured that it was time to add was time to add Python to the list. Today’s post is going to go over the basics but you can expect a series of posts on the topic over the next few weeks. Python is a lot like Node. It is a general-purpose programming language that is not specialized for any specific problems. You can use it to build websites and software, automate tasks, and analyze data.

How to run a Python script

If you want to write Python, you will probably want to also run what you write. If you are developing on a Windows computer and don’t yet have Python installed, you can run the command python3 from PowerShell to install it from the Microsoft Store. If you don’t know if you have it installed, you can run python3 --version from the same place. If you are using MacOS, you can download the Python installer from the Python website and run it to install Python. If you are a MacOS user, Python3 is likely already there from previously using Homebrew.

With Python installed, you be able to open the Python shell and run simple commands.

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-17-at-12.01.36%E2%80%AFPM.png?resize=1024%2C856&ssl=1

Next, let’s install Jupyter. Jupyter Notebook is a popular way to write and run Python code, especially for data analysis, data science, and machine learning. Jupyter Notebooks are easy to use because they let you execute code and review the output quickly. From the MacOS terminal, you can install Jupyter by running brew install jupyterlab (assuming that you have Homebrew installed).

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-17-at-12.47.11%E2%80%AFPM.png?resize=1024%2C856&ssl=1

With Jupyter installed, you can now run Jupyter Notebook from the terminal.

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-17-at-12.55.32%E2%80%AFPM.png?resize=1024%2C856&ssl=1

You should see Jupyter open in a new browser window.

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-17-at-4.21.48%E2%80%AFPM.png?resize=1024%2C966&ssl=1

If you click on New and then Python 3, you can create a new notebook.

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-17-at-4.23.38%E2%80%AFPM.png?resize=1024%2C966&ssl=1

From within the notebook, you can run code like you can in the Python shell.

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-17-at-4.28.08%E2%80%AFPM.png?resize=1024%2C966&ssl=1

This is pretty useful if you are just trying to play around with Python.

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-17-at-4.36.56%E2%80%AFPM.png?resize=1024%2C966&ssl=1

Each cell in the notebook is going to be numbered, you can get as complex with it as you want, you can add markdown into cells, and you can use “Save and Export Notebook As…” to share your work. It is kind of cool.

Python Identifiers and Literals

When you name a variable, function, or class in Python, it can’t start with a number, be a reserved word, or contain special characters. It is also case-sensitive. The function type(x) (where x is an identifier) returns the data type for the object passed into it. Let’s take a look at a few data types.

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-17-at-5.08.06%E2%80%AFPM.png?resize=651%2C1024&ssl=1

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-17-at-5.08.29%E2%80%AFPM.png?resize=635%2C226&ssl=1

As you can see, you have a lot of options. Just remember that True and False values with booleans are case-sensitive.

Conditions and If Statements

Conditions are pretty easy with Python.

  • Equals: a == b
  • Not Equals: a != b
  • Less than: a < b
  • Less than or equal to: a <= b
  • Greater than: a > b
  • Greater than or equal to: a >= b

If statements are just if x > y: on the first line and what you want to conditionally run below it. Just remember to put an indentation after if x > y:.

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-17-at-5.26.50%E2%80%AFPM.png?resize=925%2C422&ssl=1

Loops

Loops are pretty easy as well. You just need to remember to indent, again.

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-17-at-5.38.32%E2%80%AFPM.png?resize=768%2C672&ssl=1

https://jws.news/2024/python-the-basics/

joe, to programming

We have talked about docker a few times in the past. Most recently, we talked about it in the context of running Ollama. For today’s post, I wanted to talk about how to turn your code into a docker container that you can run somewhere.

What is Docker

Docker provides the ability to package and run an application in a loosely isolated environment called a container. Docker containers can be deployed to just about any machine without any compatibility issues so your software stays system agnostic, making software simpler to use, less work to develop, and easier to maintain and deploy.

Once upon a time, a web application would be run on a physical piece of hardware that is running an operating system like Linux or Windows and then virtualization became a thing. Virtual machines access the hardware of a physical machine through a hypervisor. The host machine has an operating system (Ubuntu, Windows, MacOS, etc) and a hypervisor. Each virtual machine has an operating system of its own, binaries and libraries, and the actual web app. When using containers, the host machine has an operating system and a container engine but the containers only have binaries and libraries and the actual web app (no guest OS is necessary).

A dockerfile is needed to create an image and a container is the result of running an image. Today I am going to show how to go from a basic web app to a running docker container.

A Basic Node Example

If we are going to be dockerizing a web app, we need a web app to dockerize. In yesterday’s demo on how to pass an array as a property into a web component, we looked at three ways to turn an array into an unordered list. I figured that we could do the same with today’s demo.

In the above Node app, we are setting const items as being an array, using <a href="https://www.w3schools.com/nodejs/met_http_createserver.asp">createServer()</a> to create a new HTTP server, and then we are setting it to listen on port 8080. If you save the file locally as app.js, assuming that you have Node installed on your machine, you can run node app.js from the terminal to start the server.

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-15-at-12.09.13%E2%80%AFPM.png?resize=1024%2C764&ssl=1

Creating a Dockerfile

A Dockerfile isn’t anything special. It is just a file called Dockerfile. For our test app, the Dockerfile only needs three things:

  1. A base image
  2. What to copy from the host machine and where to copy it to in the container
  3. The command that you want to run when the container launches

Our Dockerfile for this demo looks like this:

You will notice that it also includes the line EXPOSE 8080, to expose port 8080 but as you will see below, it is more for documentation purposes than anything else.

Creating a Dockerignore

If you are familiar with git, you likely know what a .gitignore file is. A .dockerignore file does something similar. A .dockerignore is a configuration file that describes files and directories that you want to exclude when building a Docker image. Usually, you put the Dockerfile in the root directory of your project, but there may be many files in the root directory that are not related to the Docker image or that you do not want to include. .dockerignore is used to specify unwanted files and not include them in the Docker image.

Building a Docker Image

Now that you have what you are dockerizing, a Dockerfile, and a .dockerignore, you can simply build by running docker build . in the terminal.

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-15-at-3.44.17%E2%80%AFPM.png?resize=1024%2C856&ssl=1

If you run docker images, you can see the result.

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-15-at-5.37.20%E2%80%AFPM.png?resize=1024%2C806&ssl=1

If you want to aid in maintainability a little, you can add -t [image name] to the build command. When you run docker build -t node-app . in the terminal, it looks like this …

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-15-at-8.10.32%E2%80%AFPM.png?resize=1024%2C806&ssl=1

… and when you rerun docker images, it now looks like …

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-15-at-8.13.57%E2%80%AFPM.png?resize=1024%2C806&ssl=1

Running your Docker Container

As I said above, an image becomes a container when you execute it. You can execute it by running docker run -d -p 8080:8080 6cced9894e8c where -d runs it as a daemon (a background process) and -p [port number]:[port number] tells the container what port to give it on the host machine. The 6cced9894e8c hash is the “Image ID” value from when I ran docker images above. If you tagged the image in the above step, you can use that value instead of the hash, though.

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-15-at-9.20.55%E2%80%AFPM.png?resize=1024%2C742&ssl=1

If you run docker ps after starting the container, you can verify that it is running. Go to http://localhost:8080/ and witness the splendor (now running in a docker container).

https://i0.wp.com/jws.news/wp-content/uploads/2024/04/Screenshot-2024-04-15-at-9.24.06%E2%80%AFPM.png?resize=1024%2C729&ssl=1

https://jws.news/2024/how-to-dockerize-a-node-app/

joe, to javascript

In last week’s post, I said, “That is because you can not pass an array directly into a web component”. I said that I might take a moment at some point to talk about how you could do that. Well, today is the day we are doing that.

Let’s start with a basic Lit example.

See the Pen by Joe Steinbring (@steinbring)
on CodePen.

You will notice that the ArrayList class has an items property that is an array type. Lit won’t let you do something like <array-list items = ['Item 1', 'Item 2', 'Item 3']></array-list> but it is fine with you passing it in using javascript. That means that myList.items = ['Item 1', 'Item 2', 'Item 3']; does the job, fine.

So, how can we do that with a Vue.js array?

See the Pen by Joe Steinbring (@steinbring)
on CodePen.

It is the same thing except you need to set the value of the list in an onMounted() lifecycle hook.

What about if we want to do it with React?

See the Pen by Joe Steinbring (@steinbring)
on CodePen.

With React, you just set the value in a useEffect() React hook.

https://jws.news/2024/how-to-pass-an-array-as-a-property-into-a-web-component/

joe, (edited ) to javascript

Earlier this week, when I wrote about how to build an autocomplete using Vue.js, it was less about exploring how to do it and more about documenting recent work that used Vuetify. I wanted to use today’s post to go in the other direction. Recently, I discovered the value of using Lit when writing Web Components. I wanted to see if we could go from the HTML / CSS example to a proper web component.

First crack at it

Lit is powerful. You can do a lot with it. Let’s start with a rewrite of Tuesday’s final example to one that uses just Lit.

See the Pen by Joe Steinbring (@steinbring)
on CodePen.

The first thing that we do in this is to import LitElement, html, css from a CDN. Our CountySelector class extends LitElement and then customElements.define('county-selector', CountySelector) at the bottom of the page is what turns our class into a tag. The static styles definition is how you style the tag. You will notice that there aren’t any styles outside of that. The markup is all defined in render() near the bottom. The async fetchCounties() method gets the list of counties from the data.jws.app site that I created last week.

This works but web components are supposed to be reusable and this isn’t reusable enough, though.

How do we increase reusability?

As you might remember from last month’s post about web components, you can use properties with a web component. This means that the placeholder and the options for the autocomplete can be passed in as properties in the markup.

See the Pen by Joe Steinbring (@steinbring)
on CodePen.

You will notice that the big difference between this version and the first one is that we dropped the API call and replaced it with a countyList property that defines the options. We can do better, though.

See the Pen by Joe Steinbring (@steinbring)
on CodePen.

In this next version, we eliminate all explicit references to counties since a person might presumably want to use the component for something other than counties. You might want to use it to prompt a user for ice cream flavors or pizza toppings.

How do you use Vue with a web component?

Unfortunately, you aren’t going to be able to use something like v-model with a web component. There are other ways to bind to form inputs, though. Let’s take a look.

See the Pen by Joe Steinbring (@steinbring)
on CodePen.

In the above example, optionsList and selectedOption are defined as Refs. The ref object is mutable (you can assign new values to .value) and it is reactive (any read operations to .value are tracked, and write operations will trigger associated effects). The options list can be passed into the web component using the :optionsList property. You might notice, though that the example is using .join(', ') to convert the array to a comma-delimited list. That is because you can not pass an array directly into a web component. That is likely going to be the subject of a future article. You might also notice that it is triggering the when you click on a suggestion and onBlur. The dispatchEvent() method sends an event to the object, invoking the affected event listeners in the appropriate order. That should trigger updateSelectedOption when you select a county or finish typing one that isn’t in the list.

So, what do you think? Do you have any questions? Feel free to drop a comment, below.

https://jws.news/2024/how-to-implement-an-autocomplete-using-web-components/

joe, (edited ) to webdev

Have you ever stumbled upon those form fields that suggest options in a drop-down as you type, like when you’re entering a street address? It turns out, that making those are not as difficult as you would think! Today, I’m gonna walk you through three cool ways to pull it off using Vue.js. Let’s dive in!

Vuetify

If you are a Vue developer, you have likely used Vuetify at some point. It is an open-source UI library that offers Vue Components for all sorts of things. One of those things just happens to be Autocompletes.

See the Pen by Joe Steinbring (@steinbring)
on CodePen.

Last week, I spoke about creating a repository of data for coding examples. The first one is a list of counties in the state of Wisconsin. In this example, the values from the API are stored in a counties array, the value that you entered into the input is stored in a selectedCounty variable, and the fetchCounties method fetches the values from the API. Thanks to the v-autocomplete component, it is super easy using Vuetify.

Shoelace

Shoelace (now known as Web Awesome) doesn’t have a built-in autocomplete element but there is a stretch goal on their kickstarter to add one. That means that we need to build the functionality ourselves.

See the Pen by Joe Steinbring (@steinbring)
on CodePen.

Our Shoelace version has a filteredCounties variable so that we can control what is shown in the suggestions and a selectCounty method to let the user click on one of the suggestions.

Plain HTML and CSS

We have already established that Shoelace doesn’t have an autocomplete but neither does Bulma or Bootstrap. So, I figured that we would try a pure HTML and CSS autocomplete.

See the Pen by Joe Steinbring (@steinbring)
on CodePen.

This is very similar to our Shoelace example but with some extra CSS on the input. You might be wondering about that autocomplete attribute on the input. It is a different type of autocomplete. The autocomplete attribute specifies if browsers should try to predict the value of an input field or not. You still need to roll your own for the suggestions.

https://jws.news/2024/how-to-impliment-an-autocomplete-using-vue/

joe, to random

I am going to be at CypherCon today and tomorrow. You should come and say hi if you are there, too.

https://jws.news/2024/i-am-going-to-be-at-cyphercon-today-and-tomorrow/

joe, to random

I post a lot of sample code on this blog. My CodePen is full of little snippets of this and that. Quite often, these snippets need data to do something useful. A good example of that is my Lit example from this past week. Coming up with that data can be complicated, though. That is why I created a site for assorted test data. If you want to have a little rummage through it, I also made the git repository public for the site. While I was at it, I also put it behind a Cloudflare proxy to speed it up a little.

Have any questions, comments, etc? Please feel free to drop a comment below.

https://jws.news/2024/i-have-been-making-some-infrastructure-impovements/

#JSON #XML

joe, to bluesky

Four months ago, I created a Bluesky account to play around this the API and managed to create a simple node script to post a status to it. I wasn’t able to figure out how to get it to work with IFTTT, though. This week, I spun up a Pipedream workflow to try to post an announcement when a new blog post goes up.

https://i0.wp.com/jws.news/wp-content/uploads/2024/03/Screenshot-2024-03-27-at-7.33.56%E2%80%AFPM.png?resize=1024%2C522&ssl=1

If you wanted to replicate what I have so far, you should be able to set up your trigger like this and then the second step just looks like …

The only issue is that Bluesky requires you to specify exactly where in the string the URIs are and I don’t think that I can be bothered to figure out how to go about that at the moment. Until I figure that out, folks will need to copy and paste URLs instead of clicking on them.

https://jws.news/2024/this-blog-has-a-bluesky-account-with-a-few-issues/

joe, to javascript

Yesterday, we looked at how to define our own web components and how to use web components that were defined using Shoelace. Today, I figured that we should take a quick look at Lit. Lit is a simple library for building fast, lightweight web components.

Let’s see what yesterday’s “hello world” demo would look like with Lit.

See the Pen by Joe Steinbring (@steinbring)
on CodePen.

The syntax is a lot more pleasing in my humble opinion. Let’s see how to do something a little more complex, though.

See the Pen by Joe Steinbring (@steinbring)
on CodePen.

This example defines <blog-feed></blog-feed> with a json parameter. Lit has a <a href="https://lit.dev/docs/components/lifecycle/#connectedcallback">connectedCallback()</a> lifecycle hook that is invoked when a component is added to the document’s DOM. Using that, we are running this.fetchBlogFeed() which in turn running await fetch(). It is then using https://lit.dev/docs/components/rendering/ to render the list items.

I am kind of digging Lit.

https://jws.news/2024/playing-more-with-web-components/

joe, to javascript

We briefly played with web components once before on here but it has been a few years and I wanted to go a little deeper. Web components are a suite of different technologies that allow developers to create custom, reusable, encapsulated HTML tags for use in web pages and web apps. Essentially, they let you create your own HTML elements with their own functionality, independent of the rest of your codebase.

Let’s start by taking a look at a very basic example.

See the Pen by Joe Steinbring (@steinbring)
on CodePen.

In this example, the MyGreeting class extends HTMLElement to create a custom element. The constructor then creates a shadow DOM for encapsulation and adds a <span>element with a greeting message (which uses the name attribute for customization). The customElements.define method then registers the custom element with the browser, associating it with the tag <my-greeting>.

So, what can we do with this? You might have heard of Shoelace / Web Awesome. That is just a collection of cool web components. Let’s take a look at a quick example.

See the Pen by Joe Steinbring (@steinbring)
on CodePen.

As you can see above, you just include the activates Shoelace’s autoloader and then registers components on the fly as you use them. Let’s look at a slightly more complicated example.

See the Pen by Joe Steinbring (@steinbring)
on CodePen.

If you flip open the JavaScript panel, you will see that it still neeeds event listeners for the open and close buttons but it is not as complex as if you were writing this frome scratch.

https://jws.news/2024/playing-with-web-components/

joe, to transit

The gym I attend offers group fitness classes but I have never had enough confidence to sign up for one. Back in January, I saw the announcement of a six-week “Beginner Cycling” class and I immediately signed up for it. The pitch was that it was a cycling class for people who had never taken a cycling class before. I liked the idea of everyone in the class being in the same place as me. This past Sunday was the final week of the class and later that day, I signed up for a 6 pm Cycling class for later this week.

I enjoy the regular expectation that I need to be at the gym at a given time. It helps. I’m hoping that I can keep this up in the long term.

https://jws.news/2024/why-i-took-a-beginner-cycling-class-at-the-gym/

joe, to javascript

I have been spending a lot of the past month working on a Vue / Firebase side project, so this is going to be a fairly short post. I recently discovered that there are modifiers for v-model in Vue. I wanted to take a moment to cover what they do.

.lazy

Instead of the change being reflected the moment you make it, this modifier makes it so that the change syncs after change events.

See the Pen by Joe Steinbring (@steinbring)
on CodePen.

.number

This modifier uses parseFloat() to cast the value as a number. This is a good one to use with inputs that you are already using type=”number” with.

See the Pen by Joe Steinbring (@steinbring)
on CodePen.

.trim

This one is pretty straight-forward. It simply trims any extra whitespace off of the string.

See the Pen by Joe Steinbring (@steinbring)
on CodePen.

https://jws.news/2024/v-model-modifiers-in-vue/

joe, (edited ) to javascript

Earlier this week, we started looking at React and I figured that for today’s post, we should take a look at the https://react.dev/reference/react/useEffect and https://react.dev/reference/react/useMemo React Hooks. Hooks are functions that let you “hook into” React state and lifecycle features from function components. In yesterday’s post, we used https://codepen.io/steinbring/pen/GRLoGob/959ce699f499a7756cf6528eb3923f75. That is another React Hook. The useState Hook allows us to track state in a function component (not unlike how we used Pinia or Vuex with Vue.js).

The useEffect React hook lets you perform side effects in functional components, such as fetching data, subscribing to a service, or manually changing the DOM. It can be configured to run after every render or only when certain values change, by specifying dependencies in its second argument array. The useMemo React hook memoizes expensive calculations in your component, preventing them from being recomputed on every render unless specified dependencies change. This optimization technique can significantly improve performance in resource-intensive applications by caching computed values.

Let’s take a look at a quick useEffect, first. For the first demo, we will use useEffect and useState to tell the user what the current time is.

See the Pen by Joe Steinbring (@steinbring)
on CodePen.

Let’s walk through what we have going on here. The App() function is returning JSX containing <p>The current time is {currentTime}</p> and currentTime is defined by setCurrentTime. The code block useEffect(() => {}); executes whenever the state changes and can be used to do something like fetching data or talking to an authentication service. It also fires when the page first renders. So, what does that empty dependency array (,[]) do in useEffect(() => {},[]);? It makes sure that useEffect only runs one time instead of running whenever the state changes.

We can get a little crazier from here by incorporating the setInterval() method.

See the Pen by Joe Steinbring (@steinbring)
on CodePen.

In this example, it still runs useEffect(() => {},[]); only once (instead of whenever the state changes) but it uses setInterval() inside of useEffect to refresh the state once every 1000 milliseconds.

Let’s take a look at another example.

See the Pen by Joe Steinbring (@steinbring)
on CodePen.

In this one, we have three form elements: a number picker for “digits of pi”, a color picker for changing the background, and a read-only textarea field that shows the value of π to the precision specified in the “digits of pi” input. With no dependency array on useEffect(() => {});, whenever either “Digits of Pi” or the color picker change, useEffect is triggered. If you open the console and make a change, you can see how it is triggered once when you change the background color and twice when you change the digits of pi. Why? It does that because when you change the number of digits, it also changes the value of pi and you get one execution per state change.

So, how can we cut down on the number of executions? That is where useMemo() comes in. Let’s take a look at how it works.

See the Pen by Joe Steinbring (@steinbring)
on CodePen.

In this revision, instead of piValue having a state, it is “memoized” and the value of the variable only changes if the value of digits changes. In this version, we are also adding a dependency array to useEffect() so that it only executes if the value of color changes. Alternatively, you could also just have two . Let’s take a look at that.

See the Pen by Joe Steinbring (@steinbring)
on CodePen.

If you throw open your console and change the two input values, you will see that it is no longer triggering useEffect() twice when changing the number of digits.

Have any questions, comments, etc? Feel free to drop a comment, below.

https://jws.news/2024/exploring-useeffect-and-usememo-in-react/

joe,

The actual blog post is on a WordPress blog and it is publishing to the Fediverse from there. There is some sort of magic that that (first-party) wordpress plugin is doing, but I couldn’t tell you what it is.

  • All
  • Subscribed
  • Moderated
  • Favorites
  • anitta
  • ngwrru68w68
  • hgfsjryuu7
  • InstantRegret
  • Youngstown
  • rosin
  • slotface
  • everett
  • mdbf
  • ethstaker
  • kavyap
  • thenastyranch
  • DreamBathrooms
  • PowerRangers
  • Leos
  • magazineikmin
  • Durango
  • cubers
  • GTA5RPClips
  • cisconetworking
  • tacticalgear
  • osvaldo12
  • khanakhh
  • vwfavf
  • tester
  • modclub
  • normalnudes
  • provamag3
  • All magazines