This article explores Plang, an intent-based programming language designed to interpret natural language. For more information, visit 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.
{ 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
Lets start by setting up the database. Create Setup.goal file in your project folder.
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
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
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
- [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.