Sends /quiz a word from your Google Sheet and marks your /answer against what the sheet says.
Uses
Google Sheets
OpenAI
Telegram
Drill your vocabulary list in Telegram
Keep your vocabulary in a Google Sheet, one row per word with a 'Term' column and an 'Answer' column, and drill yourself on it from Telegram. Whenever you send /quiz to your bot, it picks a word from the sheet at random and asks it. Send /answer followed by the word, an equals sign and what you think it means, and it marks you against what the sheet says.
Your sheet is the source of truth and nothing overrules it. An answer that matches the sheet word for word is marked correct straight away, before any AI is involved. Only an answer that does not match is passed to the AI, with a single question, whether it means the same thing, so a near miss can become a pass but a matching answer can never be marked wrong. If that check fails or comes back unclear, you are told the sheet's answer and the attempt is left unmarked. Messages that are not /quiz or /answer are ignored.
You need a Telegram bot in a private chat of your own.
message.When a new message is received. Save it as message.vocabSheetUrl to blank.Set vocabSheetUrl to blank.sheetName to blank.Set sheetName to blank.maxWordsRead to 500.Set maxWordsRead to 500.wordsToRead to maxWordsRead multiplied by 1.Set wordsToRead to maxWordsRead multiplied by 1.wordsToRead is less than 1If wordsToRead is less than 1chatId to message.chat_id.Set chatId to message.chat_id.messageText to blank.Set messageText to blank.noTextErrorIf a step below fails, save the error as noTextErrormessage.text and save it as messageText.Trim message.text and save it as messageText.This message carried no text, so there was nothing to mark..Show in the output: This message carried no text, so there was nothing to mark..messageText is emptyIf messageText is emptymessageText by a space and save it as words.Split messageText by a space and save it as words.words[0] split by @ lowercase and save it as command.Make the first item of words[0] split by @ lowercase and save it as command.words joined by a space and save it as rest.Trim the items from index 1 onward of words joined by a space and save it as rest.command is not /quiz and command is not /answerIf command is not /quiz and command is not /answermessageText starts with / (ignoring case)If messageText starts with / (ignoring case)chatId.Send a message to chat chatId.I drill you on the words in your vocabulary sheet.
/quiz - I pick a word from your sheet and ask it
/answer <word> = <what you think it means> - I mark it against your sheetsheetData to nothing.Set sheetData to nothing.readFailed to false.Set readFailed to false.readErrorIf a step below fails, save the error as readErrorvocabSheetUrl. Save it as sheetData.Read the rows of vocabSheetUrl. Save it as sheetData.readFailed to true.Change readFailed to true.readFailed is yesIf readFailed is yeschatId.Send a message to chat chatId.I could not read your vocabulary sheet just now, so nothing was asked or marked. Try again in a moment.vocabRows to sheetData.rows.Set vocabRows to sheetData.rows.command is /quizIf command is /quizaskable to an empty list.Set askable to an empty list.vocabRow in vocabRows:For each vocabRow in vocabRows:termError If a step below fails, save the error as termErrorvocabRow.Term and save it as term.Trim vocabRow.Term and save it as term.vocabRow.Answer and save it as meaning.Trim vocabRow.Answer and save it as meaning.term isn't empty and meaning isn't emptyIf term isn't empty and meaning isn't emptyterm to the end of askable and save it as askable.Add term to the end of askable and save it as askable.Skipped a row missing its Term or Answer column..Show in the output: Skipped a row missing its Term or Answer column..askable is emptyIf askable is emptychatId.Send a message to chat chatId.I could not find anything to ask you. The tab needs a Term column and an Answer column, with a heading row, and at least one row filled in on both.askable and save it as askedWord.Get the first item of 1 random items from askable and save it as askedWord.quizLine to Your word: askedWord.Set quizLine to Your word: askedWord.quizHow to Set quizHow to
When you have an answer, send:
/answer askedWord = your answer.chatId.Send a message to chat chatId.quizLine plus quizHowrest doesn't contain =If rest doesn't contain =chatId.Send a message to chat chatId.Send it as /answer <word> = <what you think it means>, for example: /answer ephemeral = lasting a very short timerest by = and save it as halves.Split rest by = and save it as halves.halves[0] and save it as askedTerm.Trim halves[0] and save it as askedTerm.halves joined by = and save it as learnerAnswer.Trim the items from index 1 onward of halves joined by = and save it as learnerAnswer.askedTerm is empty or learnerAnswer is emptyIf askedTerm is empty or learnerAnswer is emptychatId.Send a message to chat chatId.Send it as /answer <word> = <what you think it means>, for example: /answer ephemeral = lasting a very short timesheetAnswers to an empty list.Set sheetAnswers to an empty list.vocabRow in vocabRows:For each vocabRow in vocabRows:matchError If a step below fails, save the error as matchErrorvocabRow.Term and save it as term.Trim vocabRow.Term and save it as term.vocabRow.Answer and save it as meaning.Trim vocabRow.Answer and save it as meaning.term in lowercase is askedTerm in lowercase and meaning isn't emptyIf term in lowercase is askedTerm in lowercase and meaning isn't emptymeaning to the end of sheetAnswers and save it as sheetAnswers.Add meaning to the end of sheetAnswers and save it as sheetAnswers.Skipped a row missing its Term or Answer column..Show in the output: Skipped a row missing its Term or Answer column..sheetAnswers is emptyIf sheetAnswers is emptynotOnList to “@askedTerm” is not on your list, so I have nothing to mark it against. Send /quiz for a word that is.Set notOnList to “@askedTerm” is not on your list, so I have nothing to mark it against. Send /quiz for a word that is.chatId.Send a message to chat chatId.notOnListsheetAnswers and save it as statedAnswer.Get the first item of sheetAnswers and save it as statedAnswer.matchesTheSheet to false.Set matchesTheSheet to false.sheetAnswer in sheetAnswers:For each sheetAnswer in sheetAnswers:sheetAnswer in lowercase is learnerAnswer in lowercase If sheetAnswer in lowercase is learnerAnswer in lowercasematchesTheSheet to true.Change matchesTheSheet to true.matchesTheSheet is yesIf matchesTheSheet is yeschatId.Send a message to chat chatId.Correct. Your sheet gives that as the answer for “@askedTerm”.markPrompt to You are marking one vocabulary answer. Reply with exactly one word: SAME if the learner's answer means the same as the expected answer, or DIFFERENT if it does not. Do not explain and do not add anything else..Set markPrompt to You are marking one vocabulary answer. Reply with exactly one word: SAME if the learner's answer means the same as the expected answer, or DIFFERENT if it does not. Do not explain and do not add anything else..markDetail to Set markDetail to
Word: askedTerm
Expected answer: statedAnswer.markLearner to Set markLearner to
Learner's answer: learnerAnswer.verdict to blank.Set verdict to blank.markFailed to false.Set markFailed to false.markErrorIf a step below fails, save the error as markErrormarkDetail plus markLearner'. Save it as marking.Ask OpenAI: '@markPrompt plus markDetail plus markLearner'. Save it as marking.marking.response_text and save it as verdict.Trim marking.response_text and save it as verdict.markFailed to true.Change markFailed to true.sheetSays to Your sheet says: “@statedAnswer”.Set sheetSays to Your sheet says: “@statedAnswer”.markFailed is yesIf markFailed is yeschatId.Send a message to chat chatId.I could not check that one, so I am not marking it either way. sheetSaysverdict starts with same (ignoring case)If verdict starts with same (ignoring case)chatId.Send a message to chat chatId.Correct - not word for word, but it means the same. sheetSayschatId.Send a message to chat chatId.Not quite. sheetSayschatId.Send a message to chat chatId.I could not check that one, so I am not marking it either way. sheetSays