C in CRUD in Plang language
Tags: plang, programming, ai, tutorial
Published: 2024-04-27 20:13:22

> This article explores Plang, an intent-based programming language designed to interpret natural language. For more information, visit [plang.is](https://plang.is)

How can you structure a input like this `ate sandwich with ham and cheese` to fit your database schema, that has 7 columns? That just doesn't add up, right?

## What is CRUD

Most developers are very familiar with CRUD (Create, Read, Update, Delete). 

The classic way we do this, is by creating a (web)form where we can create new data or update the data. We have list so we can see all the data, there we provide to either edit link to update or delete link to delete the data.

In Plang this can all be different. It is of course possible to provide the same form and list, but why not have it more natural. 

Instead of the human adjusting to the computer, having to fill in form according to the 7 column data structure that the required of the project, we allow the user to free form it and let the computer adjust to the user.

## Food diary
In this C in CRUD example, I am going to use Food diary app as an example. 

In general, Food diary apps are quite strict in their formatting, anyone that has used one has had a list of input to fill inn, selecting from multiple option, often difficult to decide which type of chicken I just ate, because there are 5 version to select from. We also are required to know the weight of what we eat. It's difficult.

## Data structure

The project dictates that we want this type of data structure. This of course can be anything that fits you app, in this case for Food diary.

```json
{
  date: datetime
  foods: [{
     name: string, quantity: number, protein: number, fat: number, carbs: number, calories: number
  }, 
  ....
  ]
  total_carbs: number
  total_fat:number,
  total_protein:number,
  total_calories:number
  total_quantity:number
}
```

The user would have to fill in the name of the food, and either we have a huge database, already defined with all the protein/fat/carbs/calories for every food available in the world or we make the user fill this in. 

It's not easy for the user or the service.

## LLM to the rescue

Plang has LLM integrated into the language (LLM is like ChatGPT if you don't know). Imagine having a person on the other end working for you, deciding how an input fits a data structure. 

So instead of having a form, with multiple fields, the user can simply say:

```
ate sandwich with ham and cheese
```

The LLM will take this statement, decide on the ingredients and return us a structured data, that fits our database.

## Create in CRUD

Let start on the create, where user inputs new data and we want to save into the database.

_If you like to code this on your computer, you need to [install Plang](https://github.com/PLangHQ/plang/blob/main/Documentation/Install.md)_

Lets start by setting up the database. Create Setup.goal file in your project folder.

```plang
Setup
- create table food_entries, columns:
    date(datetime, not null), foods(json, not null), total_quantity(number), total_carbs(number), total_fat(number), total_protein(number), total_calories(number)
```

We now have table food_entries, that contains those columns. The database is Sqlite database located on your computer, in your app folder under .db/data.sqlite. No need to setup database. It is simple.

Next lets do the Create part, I am calling this `Insert` in the plang code because we are going to insert new data into the database

I will start with the whole plang code and explain. 
Create `Insert.goal` file in the project folder

```plang
Insert
- read llm/insertSystem.txt, into %system%
- [llm] system: %system%
    user: %userInput%
    scheme: {
        "date": datetime, 
        "foods": [
                {"name": string, "quantity": number, "calories": number, "carbs": number, "fat": number, "protein": number}
            ], 
        "total_carbs": number, 
        "total_quantity": number, 
        "total_fat": number,
        "total_protein": number, 
        "total_calories": number
      }
    write to %foodEntry%
- insert into food_entries 
        %foodEntry.date%, %foodEntry.foods%, 
        %foodEntry.total_quantity%,  
        %foodEntry.total_carbs%, 
        %foodEntry.total_fat%, 
        %foodEntry.total_protein%,  
        %foodEntry.total_calories%
```

Notice that each `step` in the program starts with a dash(-).

Lets read the first `step` of the `Insert`
```
- read llm/insertSystem.txt, into %system%
```

In that first `step` we read a text file located in the `llm` folder, named `insertSystem.txt` and then load the content of that file into `%system%` variable.

We haven't created the `insertSystem.txt` file yet, so lets do that. Create a new folder called `llm`, and inside create `insertSystem.txt`

In the `insertSystem.txt` we setup the system command for the LLM. It goes something like this

```txt
Act as Nutritional specialist. 
Analyze the food entry from user input for a food diary and break down the macronutrients for each food. 

When user does not specify quantity or weight, always assume it is for one person that fits that meal type. Make up the missing numbers but be realistic.

Use your knowledge as LLM to figure out the macronutrients information about ingredients
```

Here we have setup the LLM to act as a specialist on food, to break up the user statement and give the macronutrients (protein, fat, carbs, calories). Notice we haven't defined the structure yet.

Next we call the the LLM in plang

```plang
- [llm] system: %system%
    user: %userInput%
    scheme: {
        "date": datetime, 
        "foods": [
                {"name": string, "quantity": number, "calories": number, "carbs": number, "fat": number, "protein": number}
            ], 
        "total_carbs": number, 
        "total_quantity": number, 
        "total_fat": number,
        "total_protein": number, 
        "total_calories": number
      }
    write to %foodEntry%
```
We start the the step with `[llm]`, this is to help the compiler of the plang language, telling it, we would like to use the `llm` for this step.

We then proceed to set the `system` variable and the `user` variable. The `system` variable is the content from the `insertSystem.txt` and the `user` is the input from the user, e.g. `ate sandwich with ham and cheese`.

Next part of the step, `scheme:` property, where we define what the response we would like back from the LLM. This means, we now have structured data from the user input

Last part of the step we tell it to load the response into the `%foodEntry%` variable.

Notice that this is all one `step`, even though it is multiple lines, because dash (-) defines a step

Now think of this step in this way:
> You have a person somewhere on the other end that gets the text sent to him: `ate sandwich with ham and cheese` and his job is to understand this statement, break down how much macronutrients is in each ingredient, and give us back a JSON response. This person is on the other end typing this in, sweating and working hard. Or it's just an LLM

Looking at it from that perspective, that there is another person on the other end, what can you do in your environment, that you could delegate for almost free? Just a thought.

Next step is easy, just insert into the database

```
- insert into food_entries 
        %foodEntry.date%, %foodEntry.foods%, 
        %foodEntry.total_quantity%,  
        %foodEntry.total_carbs%, 
        %foodEntry.total_fat%, 
        %foodEntry.total_protein%,  
        %foodEntry.total_calories%
```
Notice how we are not defining 100% correct SQL. No worries, this is not a new QL language. Plang will figure it out for you and construct 100% valid SQL. You are free to write 100% valid SQL, you just don't need to. 

## And that is how...

... you take user input `ate sandwich with ham and cheese` and convert into 7 column structured data. 

## Validity of data

Your suspicion will be if LLM can give you correct results, for this app, it is close enough. There are cases where it's is not correct, but so is manual input. LLM will only get better, humans will always have error rate. 

You can also adjust the `system` prompt, and tell him, you eat 50% more then a normal person if that is the case. You are very flexible without changing the logic of the program.

For critical data, where it must be correct, it all depends, but you can define exactly what data it can respond and you should validate response when you know what options are available, just like with humans

## U in CRUD

Please comment on this article if you are interested in the Update part, where you can say `actually, I had 2 sandwiches` and it figures it out. 

Just so I know there is interest.


Following example is of a Food diary app, available at https://github.com/ingig/FoodDiaryApp. This article is simplified version of it.