AI development course #novice A2

The AI Development Course #novice A2 builds on A1, where we set up VS Code, Git, and Docker to prepare for AI-driven development. If you’ve completed A1, you’re ready to move on. If you’re just joining, make sure you have these tools installed—no coding experience needed (but it sure helps if you have it anyways), just some basic logic (or the ability to follow along, even if you’re a bit drunk).

Now, we’re looking at how to extend AI conversations, but with a trade-off: the longer the chat, the more the AI forgets. The key is that we can control what gets forgotten instead of letting the model decide randomly.

We’ll dive into three techniques: summarization, which compresses past messages into a shorter form; token compression, which removes parts of older messages to save space; and topic-based retrieval, which picks past messages based on relevance. By the end, you’ll understand how to stretch AI conversations while deciding what gets lost along the way.

happy coding

6 Likes

By the way: we can use git now to save the code that we made in A1.

Ask chatgpt

how to commit a couple files and how to create a new branch?
And wth hell does that mean?

And also while we are not really writing code manually you should still be able to at least read the code that is produced by ChatGPT.

That’s why I would like to talk about the print command in this course.

PRINT or WRITE was used in early FORTRAN or BASIC programs already and was at first meant to actually print/write something.

Early computers had no screens—only punch cards, teletypes (TTYs), or line printers.

Unix (1969) introduced standard output (stdout) in the late 60’s so it was possible to select where to print something.

so a

PRINT *, "Hello, World!"

in FORTRAN was most likely printed onto a paper strip (* = in default formatting).

Let’s have a look at C code which makes it a little bit clearer

#include <stdio.h>
int main() {
    printf("Hello, World!\n");
    return 0;
}

#include <stdio.h> << here we are importing some code - a so called header file which gives us standard functionality

stdio.h stands for “Standard Input/Output Header”.

int main() { << this starts a so called function (and since it is called main it is the standard entry point for a C program).

the “int” at the beginning is a so called data type (integer = which are numbers like 0,1,2,3,4,5,… - there are multiple otehr data types - but we will talk about them later - same as with return and the "closing bracket } ")

printf("Hello, World!\n"); << means formatted (hence the f) printing of what ever is inside the two double quotes.

So it prints “Hello, World! and then \n which is translated into a line break” onto the terminal on your screen - where you run the compiled program.

There is no need to look into data types just yet. Just need to understand the print command and, then after some sleep we will continue with the next step. It perfectly makes sense to sleep after each lesson before continuing with the next lesson. That has to do with how the brain stores information.

I would not recommend to take more than one task per day but be consistent! We are getting there faster than you think :wink:

1 Like

Alright, then let’s dive into some theoretical stuff about data.

Let’s say we have a sentence “The red dog jumps over the green fence”.
And then let us think about what this sentence makes it different to other sentences like “The red tomato is very delicious” and how they are connected.

A normal human would automatically say “red” - the connection is “red”.

An english teacher would likely also say they are both in the “present tense” and follow a basic subject-verb-object structure (“The red dog jumps” / “The red tomato is”).

A programmer would likely point out they are both strings.

A gardener might say something like “tomatoes can be either red or green”…

Other cultures might say it is both delicious.

Let that sink in for some time and then ask ChatGPT for more things like that and what techniques exist to find similarity and differences (or likelyhood of similarity).


Understanding Similarity in Sentences

You’re hitting on something deep here—how different perspectives shape what we consider “similar.” This is the essence of semantic similarity, and there are various ways to measure and model it.


:one: Lexical Similarity (Words & Structure)

  • Bag of Words (BoW): Counts word occurrences but ignores word order.
  • Jaccard Similarity: Measures overlap in unique words between sentences.
  • TF-IDF (Term Frequency - Inverse Document Frequency): Weighs important words based on how common they are across documents.
  • n-grams: Looks at sequences of words (like “The red” vs. “red tomato”).

:two: Syntactic Similarity (Grammar & Structure)

  • Parse Trees: Break down the sentence structure (e.g., Subject-Verb-Object) and compare tree similarity.
  • POS Tagging (Parts of Speech): Identifies nouns, verbs, adjectives, etc., to compare sentence structure.
  • Dependency Parsing: Examines relationships between words (e.g., “red” describes “dog” vs. “red” describes “tomato”).

:three: Semantic Similarity (Meaning)

  • Word Embeddings (Word2Vec, GloVe, FastText): Turns words into high-dimensional vectors, where similar meanings are closer in space.
  • Sentence Embeddings (BERT, SBERT, GPT-based models): Converts whole sentences into meaning-rich vectors.
  • Cosine Similarity: Measures angle similarity between vectorized sentences.

:four: Contextual & Cultural Similarity

  • Knowledge Graphs (e.g., WordNet, ConceptNet, Wikipedia links): Find conceptual links (like “tomato is a fruit” or “dog is an animal”).
  • Topic Modeling (LDA, Latent Semantic Analysis): Clusters sentences based on themes (e.g., food vs. animals).
  • Commonsense Reasoning (GPT-like models): Uses vast datasets to infer relationships.

:five: Human Perspective Differences

  • Personal Experiences & Domains: A chef vs. a programmer vs. a child will all interpret “red” differently.
  • Association Bias: Different people highlight different similarities (like a gardener noticing plant colors).
  • Cultural & Linguistic Variations: Some languages make distinctions others don’t (e.g., Russian has separate words for “light blue” and “dark blue”).

How do we find “likely” similarities?

  1. Statistical Models: NLP models predict probabilities of words appearing in similar contexts.
  2. Neural Networks: Deep learning models (like transformers) learn complex relationships.
  3. Human-in-the-loop Learning: Leveraging feedback from humans to refine similarity scores.

Want to try a specific similarity technique on example sentences? :rocket:


We don’t really need to understand all this stuff in detail. But we will pick a few of them and you should solve how to build it in human language.
For example how can we make ChatGPT create a programm that finds similarity with one of the methods in pure code (no need to use vector databases and models for this. We can do that purely with code - at least a binary “it has similarity” or “it has no similarity” should be possible)

2 Likes

We learned about the print command. Which prints “something”.

Let’s dive a little deeper into it.

print "hello"

will print the so called “string” (the sequence of single characters defined inside double quotes) to whereever the default output is redirected to.
In python if you run the program on your local terminal it would do that on your terminal.

we are using docker which means it happens in the virtual environment of that container.

Let’s try that.

1. Project Setup

Create your Python file:

# main.py
print("Hello from inside the Docker container!")

2. Dockerfile

Create a file named Dockerfile in the same directory with the following content:

FROM python:3.9-slim
WORKDIR /app
COPY main.py .
CMD ["tail", "-f", "/dev/null"]

when you type

ls -l

In your terminal you should see the two files:

Screenshot from 2025-03-14 23-13-10

3. Build the Docker Image

Open your terminal, navigate to your project directory, and build the image with:

docker build -t my-python-app .

4. Run the Docker Container

Start the container in detached mode so that it remains running:

docker run -d --name my-python-container my-python-app

5. Log into the Running Container

Open an interactive shell in your container:

docker exec -it my-python-container /bin/bash

6. Run Your Python Script Inside the Container

Once inside the container’s shell, run:

python main.py

which should show something like this:

Screenshot from 2025-03-14 22-37-19


But when we update the code in our IDE

print("Hello from inside the Docker container - with some changes!")

and then run it inside our docker container the output remains the same.

That’s because the docker container was build from the definition in our Dockerfile:

FROM python:3.9-slim
WORKDIR /app
COPY main.py .   <<<<<<<<<<<<<<< the main.py was copied into the docker instance
CMD ["tail", "-f", "/dev/null"]

Let’s change that.

  1. we exit the docker container by typing:
exit

and pressing enter

  1. then we stop the running docker container with
docker stop my-python-container

and let’s also delete the build

docker rm my-python-container

Using Docker Bind Mount for Live Code Updates

To immediately reflect changes made in your IDE, use a bind mount to link your local directory to the container. This way, any updates to your code will be instantly available in the container.

1. Dockerfile

FROM python:3.9-slim
WORKDIR /app
COPY main.py .
CMD ["tail", "-f", "/dev/null"]

2. Running the Container with a Bind Mount

Run the container using a bind mount to attach your current directory to /app inside the container:

docker run -d --name my-python-container -v "$(pwd)":/app my-python-app

3. Testing Your Code

After updating your code in your IDE, for example:

print("Hello from inside the Docker container - with some changes!")

Log into the container and run the Python script:

docker exec -it my-python-container /bin/bash
python main.py

Screenshot from 2025-03-14 22-56-55

Now you can change some code in your ide and run it inside the docker container and see the changes instantly.

Since this time we havn’t imported a webserver (flask) this only works on the terminal.

Your next task is to create a simple script on that command line that will ask you for a firstname and lastname and print that as a json.

This time you should not ask chatgpt how to do that. Try to find a solution using a search engine.

3 Likes

No GPT were harmed during this task.

1 Like

The next step is petty easy again.

We put a text file (file extension .txt) next to the main.py

Then add a so called function (think of it like an own command - similar to the print command)

This here is pseudo code though (not python - we just want to talk about the pattern):

function name_of_the_function(a_parameter)
  print "hey"
  print "another print"
  print a_parameter

The word “function” defines that we want to group some functionality.
We can call the function by the name

name_of_the_function("we can put any string here and the function will print it")

In python we don’t use the word “function” to define a function / subroutine.
Instead we use def

def name_of_the_function(a_parameter: str)
  print ("hey")
  print ("another print")
  print (f"{a_parameter}")

call it like this:

name_of_the_function("something to print out - must be in quotes / be a string as you can see after a_parameter: str ")

It is not really important to remember the correct syntax for that. ChatGPT will write the code anyways. But you need to remember that there is a way to group functionality into a function.

This allows us to organize our code better.

Your next task is to prompt a function that takes a “prompt” and returns a json

The user prompt is “I have 3 apple and 2 dogs”

And the function should output a json like this: {“fruit”: “apple”}

And then the function should also read the content from the text file into a variable and then run the gpt chat completion with that.

And then add the user prompt to the text file and run the program and see if it outputs a json.

1 Like

I’m not sure I got it right. Should the function work with just this template “I have 3 xxx and 2 yyy” or should it scan the text file for all the objects like fruits and animals and put them into json?

So the function should read the text file and return a json, but what does “then run the gpt chat completion with that” mean? Do you mean use gpt to write the function?

So, I’ve wrote about organizing code better.
But the way I’ve wrote it was not easily understandable.

Let’s try to make that task better understandable using pseudo code:

content = 'I have 3 apple and 2 dogs'
file_name = 'prompt.txt'

create_new_text_file(content, file_name)

file_content = read_content_from_text_file(file_name)

expected_json_format = {“fruit”: “....”}

json = ask_openai_model_to_extract_data(expected_json_format, file_content)

print(json)

Thanks. I first thought that the prompt should be processed locally.
Ok, I did it. It sends a request with the prompt via API and receives a json.

1 Like

Great!

Now instead of asking for a fruit ask for a summary of the content of the txt file.

And put a longer text into the txt file and run it.

I sent a short story and got a summary.

1 Like

Now the next step would be to use this technique on the chat.

In a chat we have a so called chat history.

We got a message sent by the user and a message sent by the assistant.

which kind of looks like this:

{
  "messages": [
     {"role": "user", "message": "Hi" },
     {"role": "assistant", "message": "Hello, how may I assist you today?" }
   ]
}

The next message in this chat requires us to send the chat history together with the next user message

{
  "messages": [
     {"role": "user", "message": "Hi" },
     {"role": "assistant", "message": "Hello, how may I assist you today?" },
     {"role": "user", "message": "I want to talk about my hobby: plants. I grow some stuff over here." }
   ]
}

Over time this chat history becomes too big to be processed by the model because it has a limit in tokens.

So what we can do is - we summarize older messages.

The next task would be to create a skeleton of the functionality that is needed for that (not the whole code).

2 Likes

So the task is to create a test JSON of this format with messages and summarize it?
When I manually export the chat history, there is a conversations.json with messages, but a more complex structure. Do we need to simplify it to this format? What do you mean by a skeleton of functionality without code?

Simplifying the code. Try to use pseudo code.

Write it like a list of commands. You are free to name them however you like.

We want to summarize older chat messages in a program.

So when user sends a message and chat history has reached a certain size we need to let the program simulate “forgetting”.

Maybe you need to learn a concept for that.

Something like that?

history_format =   { "messages": [
     {"role": "...", "message": "..." }
   ]
}
chat_history = retrieve_chat_history()
chat_history_json = convert_history_to_json(chat_history, history_format)
chat_summary = summarize(chat_history_json)

That could be done when we assume the summarize function handles a lot.

Try to go deeper into the logic of that function.

What exactly makes the most sense to summarize?

Ok, I did some googling and gpting and this looks promising. Though I don’t know yet how exactly this TextRank or BERT stuff works.

# 1 Preprocess Messages
def preprocess_messages(chat_history) -> list:
    pass  # Extracts role and message from JSON and returns a cleaned list

# 2 Segment Messages by Topics
def segment_by_topics(messages) -> list:
    """Groups messages into topics using NLP-based topic detection."""
    pass  # Uses topic modeling to detect shifts and group messages

# 3 Extract Key Sentences
def extract_key_sentences(topic_segments) -> list:
    """Selects the most important sentences from each topic segment."""
    pass  # Uses TextRank or BERT-based ranking to extract key points

# 4 Detect Emotional Tone
def detect_emotion(topic_summaries) -> list:
    """Analyzes sentiment of messages to track emotional tone for each topic."""
    pass  # Uses sentiment analysis to assign an emotion label

# 5 Generate Final Summary
def generate_summary(final_data) -> str:
    """Creates a coherent, readable summary of the chat."""
    pass  # Uses GPT-4 or T5 to generate a natural summary
Step 1: Preprocess Messages
  • Extracts role (user / assistant) and message text from JSON.
  • Returns a structured list for easier processing.

Input:

{
  "messages": [
    {"role": "user", "message": "Hey! Guess what? I finally went skiing this weekend!"},
    {"role": "assistant", "message": "That sounds amazing! How was it?"},
    {"role": "user", "message": "Incredible. The fresh snow, the speed, the wind in my face... I felt so free."},
    {"role": "assistant", "message": "That’s the best feeling! Did anything exciting happen?"},
    {"role": "user", "message": "Well, I almost crashed into someone, but I managed to turn at the last second!"},
    {"role": "assistant", "message": "Wow, that must have been intense!"},
    {"role": "user", "message": "Also, I wanted to ask you something. I was thinking about AI learning methods today."},
    {"role": "assistant", "message": "Oh? What specifically?"},
    {"role": "user", "message": "Like how reinforcement learning works in training AI."},
    {"role": "assistant", "message": "That’s a fascinating topic! AI learns by trial and error, improving with feedback."}
  ]
}

Output:

[
    {"role": "user", "text": "Hey! Guess what? I finally went skiing this weekend!"},
    {"role": "assistant", "text": "That sounds amazing! How was it?"},
    {"role": "user", "text": "Incredible. The fresh snow, the speed, the wind in my face... I felt so free."},
    {"role": "assistant", "text": "That’s the best feeling! Did anything exciting happen?"},
    {"role": "user", "text": "Well, I almost crashed into someone, but I managed to turn at the last second!"},
    {"role": "assistant", "text": "Wow, that must have been intense!"},
    {"role": "user", "text": "Also, I wanted to ask you something. I was thinking about AI learning methods today."},
    {"role": "assistant", "text": "Oh? What specifically?"},
    {"role": "user", "text": "Like how reinforcement learning works in training AI."},
    {"role": "assistant", "text": "That’s a fascinating topic! AI learns by trial and error, improving with feedback."}
]
Step 2: Segment Messages by Topics
  • Uses BERT-based topic modeling (or another method) to detect topic changes.
  • Groups messages into topic-based segments.

Input:

[
    {"role": "user", "text": "Hey! Guess what? I finally went skiing this weekend!"},
    {"role": "assistant", "text": "That sounds amazing! How was it?"},
    {"role": "user", "text": "Incredible. The fresh snow, the speed, the wind in my face... I felt so free."},
    {"role": "assistant", "text": "That’s the best feeling! Did anything exciting happen?"},
    {"role": "user", "text": "Well, I almost crashed into someone, but I managed to turn at the last second!"},
    {"role": "assistant", "text": "Wow, that must have been intense!"},
    {"role": "user", "text": "Also, I wanted to ask you something. I was thinking about AI learning methods today."},
    {"role": "assistant", "text": "Oh? What specifically?"},
    {"role": "user", "text": "Like how reinforcement learning works in training AI."},
    {"role": "assistant", "text": "That’s a fascinating topic! AI learns by trial and error, improving with feedback."}
]

Output:

[
    {"topic": "Skiing Experience", "messages": [
        {"role": "user", "text": "Hey! Guess what? I finally went skiing this weekend!"},
        {"role": "assistant", "text": "That sounds amazing! How was it?"},
        {"role": "user", "text": "Incredible. The fresh snow, the speed, the wind in my face... I felt so free."},
        {"role": "assistant", "text": "That’s the best feeling! Did anything exciting happen?"},
        {"role": "user", "text": "Well, I almost crashed into someone, but I managed to turn at the last second!"},
        {"role": "assistant", "text": "Wow, that must have been intense!"}
    ]},
    {"topic": "AI Learning", "messages": [
        {"role": "user", "text": "Also, I wanted to ask you something. I was thinking about AI learning methods today."},
        {"role": "assistant", "text": "Oh? What specifically?"},
        {"role": "user", "text": "Like how reinforcement learning works in training AI."},
        {"role": "assistant", "text": "That’s a fascinating topic! AI learns by trial and error, improving with feedback."}
    ]}
]
Step 3: Extract Key Sentences
  • Uses TextRank or BERT-based ranking to select the most important messages.
  • Filters out redundant or minor details.

Input:

[
    {"topic": "Skiing Experience", "messages": [
        {"role": "user", "text": "Hey! Guess what? I finally went skiing this weekend!"},
        {"role": "assistant", "text": "That sounds amazing! How was it?"},
        {"role": "user", "text": "Incredible. The fresh snow, the speed, the wind in my face... I felt so free."},
        {"role": "assistant", "text": "That’s the best feeling! Did anything exciting happen?"},
        {"role": "user", "text": "Well, I almost crashed into someone, but I managed to turn at the last second!"}
    ]}
]

Output:

[
    {"topic": "Skiing Experience", "summary": [
        "Went skiing this weekend for the first time!",
        "The fresh snow, the speed, and the wind made me feel free.",
        "I almost crashed into someone but managed to turn at the last second!"
    ]},
    {"topic": "AI Learning", "summary": [
        "Discussed reinforcement learning in AI.",
        "AI improves through trial and error with feedback."
    ]}
]
Step 4: Detect Emotional Tone
  • Uses sentiment analysis (e.g., BERT, VADER) to detect emotion/tone.
  • Assigns a dominant emotion to each topic.
  • Other keys like user_intent and assistant_intent can also be added here if needed.

Input:

[
    {"topic": "Skiing Experience", "summary": [
        "Went skiing this weekend for the first time!",
        "The fresh snow, the speed, and the wind made me feel free.",
        "I almost crashed into someone but managed to turn at the last second!"
    ]},
    {"topic": "AI Learning", "summary": [
        "Discussed reinforcement learning in AI.",
        "AI improves through trial and error with feedback."
    ]}
]

Output:

[
    {"topic": "Skiing Experience", "summary": [
        "Went skiing this weekend for the first time!",
        "The fresh snow, the speed, and the wind made me feel free.",
        "I almost crashed into someone but managed to turn at the last second!"
    ], "emotion": "excitement"},
    
    {"topic": "AI Learning", "summary": [
        "Discussed reinforcement learning in AI.",
        "AI improves through trial and error with feedback."
    ], "emotion": "curiosity"}
]
Step 5: Generate Final Summary
  • Uses GPT-4, T5, or another model to rewrite extracted points into a natural summary.
  • Ensures clarity, fluency, and emotional accuracy.

Input:

[
    {"topic": "Skiing Experience", "summary": [
        "Went skiing this weekend for the first time!",
        "The fresh snow, the speed, and the wind made me feel free.",
        "I almost crashed into someone but managed to turn at the last second!"
    ], "emotion": "excitement"},
    
    {"topic": "AI Learning", "summary": [
        "Discussed reinforcement learning in AI.",
        "AI improves through trial and error with feedback."
    ], "emotion": "curiosity"}
]

Output:

Skiing Experience: Went skiing this weekend for the first time! The fresh snow, the speed, and the wind made me feel free. I almost crashed into someone but managed to turn at the last second! (Excitement)

AI Learning: Discussed reinforcement learning in AI. AI improves through trial and error with feedback. (Curiosity)

Note for step 5:

  • In this example, the output is not very different from the input because the extracted summaries are already short and well-structured.
  • For longer conversations, this step would:
    1. Merge or rewrite overlapping ideas for conciseness.
    2. Ensure the summary flows naturally, avoiding repetition.
    3. Generate a more narrative or fluid summary if needed.
  • The emotional tone is kept in the final summary to maintain context.
1 Like

That’s amazing.

Keep going.

Try to make it work.

2 Likes

Maybe this might help for a more basic understanding of what Bert / Topic extraction does (generalized).

But let’s get back to this in the B1 course.
First we just use summarization on older messages.

1 Like

Here is a prompt for that:

Build a simple chat that uses OpenAI API.

We use python and import the openai lib v. 1.6.*

We also want to store the chat in a database.

Let's use sqlite - and we only store one chat. No need to overcomplicate things.
A database table that stores datetime of the message, role (assistant/user), message, and a summary of that.

We want to send a user message, store that in the database as one data entry.

Then call the model and create a summary of the user message and add that to that entry.

Then create a chathistory

Then call the model with that and ask for a json that gives us a response and a summary of the response.

Then save the result into the database table
with role assistant.

For the following chat initialisations by the user we will use the last 4 messages of user and assistant in full and for the older messages we use the summaries to fill the chathistory.

I want a darkmode chat - modern design - one file python, one file html/javascript/css and a requirements.txt.

you can enhance the prompt using this technique

1 Like