edge lab LIVE! starts Tuesday in Munich. Grab a workshop seat and take home the board you build on. Code FRIEND-HACKSTER saves 20%. () Learn more!
esferatec
Published © GPL3+

Math Toucan Core – Train Your Brain, Anytime

A tiny offline LLM device that generates simple math challenges and solutions to keep your brain sharp anytime.

AdvancedShowcase (no instructions)Over 1 day48
Math Toucan Core – Train Your Brain, Anytime

Things used in this project

Hardware components

Core2 v1.3
M5Stack Core2 v1.3
×1
M5Stack LLM (large language model) Module Kit (AX630C)
M5Stack LLM (large language model) Module Kit (AX630C)
×1
Lego Wild Animals: Tropical Toucan
×1

Software apps and online services

M5Stack UIFlow 2.0

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)

Story

Read more

Schematics

Setup

Say Functions

Model Response

Read Text

Problem Functions

Solution Functions

Explanation Function

Code

math-toucan-core.py

MicroPython
MicroPython code generated by UIFlow
import os, sys, io
import M5
from M5 import *
import m5ui
import lvgl as lv
from module import LlmModule
import time



page_start = None
page_problem = None
page_menu = None
page_start_spinner = None
page_menu_buttonmatrix = None
page_problem_textarea = None
page_start_label_title = None
page_start_label_load = None
page_start_label_name = None
llm_0 = None


saytext = None
question = None
is_answer_finish = None
answer = None
operation = None
k = None

# say a welcome message during setup
def Say_Welcome_Text():
  global saytext, question, is_answer_finish, answer, operation, k, page_start, page_problem, page_menu, page_start_spinner, page_menu_buttonmatrix, page_problem_textarea, page_start_label_title, page_start_label_load, page_start_label_name, llm_0
  saytext = 'Welcome to the Math Jungle. I am Dietmar, your colorful math toucan. Together, we will practice addition and subtraction at your own pace.'
  print(saytext)
  llm_0.melotts_inference(llm_0.get_latest_melotts_work_id(), saytext, 0, 'melotts_inference')
  page_start_label_load.set_flag(lv.obj.FLAG.HIDDEN, True)
  page_start_label_name.set_flag(lv.obj.FLAG.HIDDEN, False)
  time.sleep(10)

# generate a maths problem if the button labelled "1 to 100 s" is pressed.
def Generate_Category1_Problem():
  global saytext, question, is_answer_finish, answer, operation, k, page_start, page_problem, page_menu, page_start_spinner, page_menu_buttonmatrix, page_problem_textarea, page_start_label_title, page_start_label_load, page_start_label_name, llm_0
  question = 'Write a very simple math problem using only addition or subtraction. Use numbers between 1 and 100. Make the problem short and easy to read. Only write the problem, not the answer.'
  print(question)
  llm_0.clear_response_msg_list()
  llm_0.llm_inference(llm_0.get_latest_llm_work_id(), question, 'llm_inference')
  page_problem_textarea.set_text(str(get_model_response()))
  Read_Textarea_Text()

# get the larg language model response
def get_model_response():
  global saytext, question, is_answer_finish, answer, operation, k, page_start, page_problem, page_menu, page_start_spinner, page_menu_buttonmatrix, page_problem_textarea, page_start_label_title, page_start_label_load, page_start_label_name, llm_0
  is_answer_finish = False
  answer = ''
  while not is_answer_finish:
    llm_0.update()
    for k in (llm_0.get_response_msg_list()):
      if (k['work_id']) == (llm_0.get_latest_llm_work_id()):
        answer = (str(answer) + str(((k['data'])['delta'])))
        is_answer_finish = (k['data'])['finish']
    llm_0.clear_response_msg_list()
  return str(answer)

# say an instruction message during setup
def Say_Instructions_Text():
  global saytext, question, is_answer_finish, answer, operation, k, page_start, page_problem, page_menu, page_start_spinner, page_menu_buttonmatrix, page_problem_textarea, page_start_label_title, page_start_label_load, page_start_label_name, llm_0
  saytext = 'I will pick out the right problems for you and show you just how much fun numbers can be. If something does not work out, we will just flutter on until we get it right.'
  print(saytext)
  llm_0.melotts_inference(llm_0.get_latest_melotts_work_id(), saytext, 0, 'melotts_inference')
  time.sleep(9)

# say a message to start the game during setup.
def Say_Start_Text():
  global saytext, question, is_answer_finish, answer, operation, k, page_start, page_problem, page_menu, page_start_spinner, page_menu_buttonmatrix, page_problem_textarea, page_start_label_title, page_start_label_load, page_start_label_name, llm_0
  saytext = 'Listen carefully, choose a category, and our adventure will begin. But sometimes I get confused.'
  print(saytext)
  llm_0.melotts_inference(llm_0.get_latest_melotts_work_id(), saytext, 0, 'melotts_inference')
  time.sleep(6)

# generate a maths problem if the button labelled "1 to 100 w & d" is pressed.
def Generate_Category2_Problem():
  global saytext, question, is_answer_finish, answer, operation, k, page_start, page_problem, page_menu, page_start_spinner, page_menu_buttonmatrix, page_problem_textarea, page_start_label_title, page_start_label_load, page_start_label_name, llm_0
  question = 'Write a very simple math problem using only addition or subtraction. Use everyday objects and numbers between 1 and 100. Make the problem short and easy to read. Only write the problem, not the answer.'
  print(question)
  llm_0.clear_response_msg_list()
  llm_0.llm_inference(llm_0.get_latest_llm_work_id(), question, 'llm_inference')
  page_problem_textarea.set_text(str(get_model_response()))
  Read_Textarea_Text()

# read aloud the problem or solution
def Read_Textarea_Text():
  global saytext, question, is_answer_finish, answer, operation, k, page_start, page_problem, page_menu, page_start_spinner, page_menu_buttonmatrix, page_problem_textarea, page_start_label_title, page_start_label_load, page_start_label_name, llm_0
  if not not len(page_problem_textarea.get_text()):
    llm_0.melotts_inference(llm_0.get_latest_melotts_work_id(), page_problem_textarea.get_text(), 500, 'melotts_inference')

# generate a maths problem if the button labelled "1 to 100 d" is pressed.
def Generate_Category3_Problem():
  global saytext, question, is_answer_finish, answer, operation, k, page_start, page_problem, page_menu, page_start_spinner, page_menu_buttonmatrix, page_problem_textarea, page_start_label_title, page_start_label_load, page_start_label_name, llm_0
  question = 'Write a very simple math problem using only addition or subtraction. Use numbers between 1 and 100. Make the problem short and easy to read. Only write the problem, not the answer.'
  print(question)
  llm_0.clear_response_msg_list()
  llm_0.llm_inference(llm_0.get_latest_llm_work_id(), question, 'llm_inference')
  page_problem_textarea.set_text(str(get_model_response()))
  Read_Textarea_Text()

# generate a maths problem if the button labelled "1 to 100 s" is pressed.
def Generate_Simple_Solution():
  global saytext, question, is_answer_finish, answer, operation, k, page_start, page_problem, page_menu, page_start_spinner, page_menu_buttonmatrix, page_problem_textarea, page_start_label_title, page_start_label_load, page_start_label_name, llm_0
  llm_0.llm_inference(llm_0.get_latest_llm_work_id(), (str((page_problem_textarea.get_text())) + str('Develop a simple solution for an elementary school student. Provide only the solution.')), 'llm_inference')
  page_problem_textarea.set_text(str(get_model_response()))
  Read_Textarea_Text()

# generate a maths problem if the button labelled "1 to 100 w & d" is pressed.
def Generate_Category4_Problem():
  global saytext, question, is_answer_finish, answer, operation, k, page_start, page_problem, page_menu, page_start_spinner, page_menu_buttonmatrix, page_problem_textarea, page_start_label_title, page_start_label_load, page_start_label_name, llm_0
  question = 'Write a very simple math problem using only addition or subtraction. Use everyday objects and numbers between 1 and 100. Make the problem short and easy to read. Only write the problem, not the answer.'
  print(question)
  llm_0.clear_response_msg_list()
  llm_0.llm_inference(llm_0.get_latest_llm_work_id(), question, 'llm_inference')
  page_problem_textarea.set_text(str(get_model_response()))
  Read_Textarea_Text()

# Describe this function...
def Generate_Detailed_Solution():
  global saytext, question, is_answer_finish, answer, operation, k, page_start, page_problem, page_menu, page_start_spinner, page_menu_buttonmatrix, page_problem_textarea, page_start_label_title, page_start_label_load, page_start_label_name, llm_0
  llm_0.llm_inference(llm_0.get_latest_llm_work_id(), (str((page_problem_textarea.get_text())) + str('Develop a simple solution for an elementary school student. The solution should consist of one to four sentences. Provide the solution.')), 'llm_inference')
  page_problem_textarea.set_text(str(get_model_response()))
  Read_Textarea_Text()

# Describe this function...
def Generate_Operation_Explanation():
  global saytext, question, is_answer_finish, answer, operation, k, page_start, page_problem, page_menu, page_start_spinner, page_menu_buttonmatrix, page_problem_textarea, page_start_label_title, page_start_label_load, page_start_label_name, llm_0
  saytext = 'One jungle moment, please! I’m flapping around to find the right definitions.'
  print(saytext)
  llm_0.melotts_inference(llm_0.get_latest_melotts_work_id(), saytext, 0, 'melotts_inference')
  question = 'Explain in a short and simple way what addition and subtraction is, so that an elementary school student can easily understand it. The explanation should consist of one to four sentences.'
  print(question)
  llm_0.llm_inference(llm_0.get_latest_llm_work_id(), question, 'llm_inference')
  saytext = get_model_response()
  print(saytext)
  llm_0.melotts_inference(llm_0.get_latest_melotts_work_id(), saytext, 0, 'melotts_inference')


def btnA_wasClicked_event(state):
  global page_start, page_problem, page_menu, page_start_spinner, page_menu_buttonmatrix, page_problem_textarea, page_start_label_title, page_start_label_load, page_start_label_name, llm_0, saytext, question, is_answer_finish, answer, operation, k
  print('BtnA')
  Speaker.tone(2000, 50)
  if operation == 4:
    Say_Instructions_Text()
    Say_Start_Text()
  if operation < 4:
    operation = 4
    page_menu.screen_load()
  print(operation)


def btnB_wasClicked_event(state):
  global page_start, page_problem, page_menu, page_start_spinner, page_menu_buttonmatrix, page_problem_textarea, page_start_label_title, page_start_label_load, page_start_label_name, llm_0, saytext, question, is_answer_finish, answer, operation, k
  print('BtnB')
  Speaker.tone(2000, 50)
  if operation==0:
    Generate_Simple_Solution()
  elif operation==1:
    Generate_Simple_Solution()
  elif operation==2:
    Generate_Detailed_Solution()
  elif operation==3:
    Generate_Detailed_Solution()
  else:
    Generate_Operation_Explanation()


# call the problem function and page
def page_menu_buttonmatrix_value_changed_event(event_struct):
  global page_start, page_problem, page_menu, page_start_spinner, page_menu_buttonmatrix, page_problem_textarea, page_start_label_title, page_start_label_load, page_start_label_name, llm_0, saytext, question, is_answer_finish, answer, operation, k
  Speaker.tone(2000, 50)
  print(page_menu_buttonmatrix.get_selected_button())
  if page_menu_buttonmatrix.get_selected_button()==0:
    operation = 0
    page_problem.screen_load()
    Generate_Category1_Problem()
  elif page_menu_buttonmatrix.get_selected_button()==1:
    operation = 1
    page_problem.screen_load()
    Generate_Category2_Problem()
  elif page_menu_buttonmatrix.get_selected_button()==2:
    operation = 2
    page_problem.screen_load()
    Generate_Category3_Problem()
  elif page_menu_buttonmatrix.get_selected_button()==3:
    operation = 3
    page_problem.screen_load()
    Generate_Category4_Problem()
  else:
    operation = 4
    page_menu.screen_load()
  print(operation)


def btnC_wasClicked_event(state):
  global page_start, page_problem, page_menu, page_start_spinner, page_menu_buttonmatrix, page_problem_textarea, page_start_label_title, page_start_label_load, page_start_label_name, llm_0, saytext, question, is_answer_finish, answer, operation, k
  print('BtnC')
  Speaker.tone(2000, 50)
  if operation == 0:
    operation = 0
    page_problem.screen_load()
    Generate_Category1_Problem()
  if operation == 1:
    operation = 1
    page_problem.screen_load()
    Generate_Category2_Problem()
  if operation == 2:
    operation = 2
    page_problem.screen_load()
    Generate_Category3_Problem()
  if operation == 3:
    operation = 3
    page_problem.screen_load()
    Generate_Category4_Problem()
  print(operation)


def page_menu_buttonmatrix_event_handler(event_struct):
  global page_start, page_problem, page_menu, page_start_spinner, page_menu_buttonmatrix, page_problem_textarea, page_start_label_title, page_start_label_load, page_start_label_name, llm_0, saytext, question, is_answer_finish, answer, operation, k
  event = event_struct.code
  if event == lv.EVENT.VALUE_CHANGED and True:
    page_menu_buttonmatrix_value_changed_event(event_struct)
  return

def setup():
  global page_start, page_problem, page_menu, page_start_spinner, page_menu_buttonmatrix, page_problem_textarea, page_start_label_title, page_start_label_load, page_start_label_name, llm_0, saytext, question, is_answer_finish, answer, operation, k

  M5.begin()
  Widgets.setRotation(1)
  m5ui.init()
  page_start = m5ui.M5Page(bg_c=0xffffff)
  page_problem = m5ui.M5Page(bg_c=0xffffff)
  page_menu = m5ui.M5Page(bg_c=0xffffff)
  page_problem_textarea = m5ui.M5TextArea(text="Text", placeholder="Placeholder...", x=2, y=2, w=316, h=236, font=lv.font_montserrat_14, bg_c=0xffffff, border_c=0xe0e0e0, text_c=0x212121, parent=page_problem)
  page_start_spinner = m5ui.M5Spinner(x=110, y=70, w=100, h=100, anim_t=10000, angle=180, bg_c=0xe7e3e7, bg_c_indicator=0x2193f3, parent=page_start)
  page_menu_buttonmatrix = m5ui.M5ButtonMatrix(["1 to 100 s","1 to 100 w & s","\n","1 to 100 d","1 to 100 w & d"], x=1, y=1, w=318, h=237, target_textarea=None, parent=page_menu)
  page_start_label_title = m5ui.M5Label("Math Toucan Core", x=48, y=20, text_c=0x000000, bg_c=0xffffff, bg_opa=0, font=lv.font_montserrat_24, parent=page_start)
  page_start_label_load = m5ui.M5Label("loading", x=10, y=200, text_c=0x000000, bg_c=0xffffff, bg_opa=0, font=lv.font_montserrat_12, parent=page_start)
  page_start_label_name = m5ui.M5Label(" I am Dietmar, your colorful math toucan. ", x=11, y=200, text_c=0x000000, bg_c=0xffffff, bg_opa=0, font=lv.font_montserrat_14, parent=page_start)

  BtnA.setCallback(type=BtnA.CB_TYPE.WAS_CLICKED, cb=btnA_wasClicked_event)
  BtnB.setCallback(type=BtnB.CB_TYPE.WAS_CLICKED, cb=btnB_wasClicked_event)
  page_menu_buttonmatrix.add_event_cb(page_menu_buttonmatrix_event_handler, lv.EVENT.ALL, None)
  BtnC.setCallback(type=BtnC.CB_TYPE.WAS_CLICKED, cb=btnC_wasClicked_event)

  page_start_label_name.set_flag(lv.obj.FLAG.HIDDEN, True)
  page_start_label_load.set_text(str((str('loading ') + str('openbuddy-llama3.2-1B-ax630c'))))
  page_start.screen_load()
  llm_0 = LlmModule(2, tx=14, rx=13)
  while not (llm_0.check_connection()):
    time.sleep(1)
  llm_0.sys_reset(True)
  llm_0.audio_setup(cap_volume=0.5, play_volume=0.15, request_id='audio_setup')
  # llama3.2-1B-p256-ax630c
  llm_0.llm_setup(prompt='You are a math teacher for elementary school students.', model='openbuddy-llama3.2-1B-ax630c', enoutput=True, enkws='', max_token_len=254, request_id='llm_setup')
  llm_0.melotts_setup(model='melotts-en-default', input='tts.utf-8.stream', enoutput=False, enkws='', request_id='melotts_setup')
  time.sleep_ms(500)
  Say_Welcome_Text()
  Say_Instructions_Text()
  Say_Start_Text()
  operation = 4
  page_menu.screen_load()


def loop():
  global page_start, page_problem, page_menu, page_start_spinner, page_menu_buttonmatrix, page_problem_textarea, page_start_label_title, page_start_label_load, page_start_label_name, llm_0, saytext, question, is_answer_finish, answer, operation, k
  M5.update()


if __name__ == '__main__':
  try:
    setup()
    while True:
      loop()
  except (Exception, KeyboardInterrupt) as e:
    try:
      m5ui.deinit()
      from utility import print_error_msg
      print_error_msg(e)
    except ImportError:
      print("please update to latest firmware")

Credits

esferatec
2 projects • 0 followers

Comments