DEV Community

Cover image for Building a language learning tool with Supabase Edge functions + GPT3.5
Jack Bridger
Jack Bridger

Posted on • Edited on

Building a language learning tool with Supabase Edge functions + GPT3.5

I’m learning Japanese and I love News Web EASY from NHK - it features one news story every day written in Japanese that a beginner can understand.

Image description

So when I saw Supabase launched self hosted edge functions, I wanted to try building a simple version that translates and simplifies football news articles.

Image description
Easy Japanese - Football News

Here's the code https://github.com/jackbridger/japanese-simple-football-news

How it works:

  1. Grabs a football article written in English (now this is hard-coded but in future I'll use an API or scraper)
  2. Checks if the article has already been processed by checking the cache (Redis)
  3. If so, return the article to the client
  4. If not, translate the article
  5. Then convert the translation into simple Japanese using GPT 3.5
  6. Return to the client

Replicating it

For setup, we’re going to roughly follow this article from the Supabase team.

I added this into serve for main/index.ts and pretty much removed everything else.

I also recommend consulting the final code as you go through as I'm not covering everything I changed

    const supabaseClient = createClient(
      Deno.env.get('SUPABASE_API_URL'),
      Deno.env.get('SUPABASE_API_ANON_KEY'),
      { global: { headers: { Authorization: req.headers.get('Authorization')! } } }
    )
Enter fullscreen mode Exit fullscreen mode

Be sure to set

flyctl secrets set SUPABASE_API_ANON_KEY=

and

flyctl secrets set SUPABASE_API_URL=

Sign up for an Fly.io account and install flyctl

brew install flyctl
Enter fullscreen mode Exit fullscreen mode

Clone the demo repository to your machine

git clone https://github.com/supabase/self-hosted-edge-functions-demo.git && cd self-hosted-edge-functions-demo
Enter fullscreen mode Exit fullscreen mode

Install deno

We need to install deno to run our functions locally

brew install deno
Enter fullscreen mode Exit fullscreen mode

Then we can log into fly

flyctl auth login
Enter fullscreen mode Exit fullscreen mode

And then we can run

fly launch
Enter fullscreen mode Exit fullscreen mode

Here are the options I selected (make sure to select yes on redis/upstash)

➜  self-hosted-edge-functions-demo git:(main) ✗ fly launch
Creating app in /Users/Jack/programming/supa/self-hosted-edge-functions-demo
An existing fly.toml file was found for app supa-edge-demo
? Would you like to copy its configuration to the new app? Yes
Scanning source code
Detected a Dockerfile app
? Choose an app name (leaving blank will default to 'supa-edge-demo') easy-japanese-football
automatically selected personal organization: Jack Bridger
App will use 'syd' region as primary
Created app 'easy-japanese-football' in organization 'personal'
Admin URL: https://fly.io/apps/easy-japanese-football
Hostname: easy-japanese-football.fly.dev
? Would you like to set up a Postgresql database now? No
? Would you like to set up an Upstash Redis database now? Yes
? Select an Upstash Redis plan Free: 100 MB Max Data Size
Enter fullscreen mode Exit fullscreen mode

We need to add our supabase crednetials too:

Then add make the call to the deepL api - you’ll need to sign up for a free account and get an api key (it’s free but you need a credit card)

Set your DeepL API key

flyctl secrets set DEEPL_API_KEY=*YOUR_API_KEY*

async function translateTextToJapanese(text: string): Promise<string> {
  const response = await fetch(DEEPL_API_URL, {
    method: "POST",
    headers: {
      "Content-Type": "application/x-www-form-urlencoded",
      "Authorization": `DeepL-Auth-Key ${Deno.env.get('DEEPL_API_KEY')}`,
    },
    body: new URLSearchParams({
      text: text,
      target_lang: "JA",
    }),
  });
Enter fullscreen mode Exit fullscreen mode

Then make the call to openai, It’s not free but it should be cents per api call and I think there is a free trial.

Set your API key

flyctl secrets set OPENAI_API_KEY=*API_KEY*

    async function rewriteToN5Japanese(text) {
      try {
const openAI = new OpenAI(Deno.env.get('OPENAI_API_KEY'));
        const response = await openAI.createChatCompletion({
          model: "gpt-3.5-turbo",
          messages: [
            {
              role: "system",
              content: "わかりやすい日本語を書くのが得意な親切なアシスタントさんですね。特にn-5レベルの外国人向けの文章を得意としています。", // You are a helpful assistant that is great at writing easy-to-understand Japanese. You are especially good at writing for n-5 level foreigners.
            },
            {
              role: "user",
              content: `以下の文章を、N5レベルの簡単な文章に書き換える。: ${text}`, // Rewrite the following text into simple N5 level text
            },
          ],
          max_tokens: 200, // Limit the response length
        });


        const translatedText = response.choices[0].message.content.trim();
        return translatedText;
      } catch (error) {
        console.error('Error translating text:', error);
        return '';
      }
    }
Enter fullscreen mode Exit fullscreen mode

Then we need to get our redis crednetials from upstassh and

We import redis and initialise it like this.

import {
  connect as redisConnect
} from 'https://deno.land/x/redis/mod.ts';
...
      const redisClient = await redisConnect({
        hostname: "fly-easy-japanese-football-redis.upstash.io",
        port: 6379,
        password: Deno.env.get('REDIS_PW'),
        maxRetryCount: 10,
        retryInterval: 100000,
      });      
Enter fullscreen mode Exit fullscreen mode

Then to check the cache we use this code:

      if (translatedAlr){
        console.log("already exists")
        translatedAndSimplified = translatedAlr
        return new Response(JSON.stringify(translatedAndSimplified), {
          headers,
          status: 200,
        })
      }
Enter fullscreen mode Exit fullscreen mode

Notice how redis is really just a key value look up.

Now we can do fly deploy

fly deploy

And then we can check it out by going to the dashboard at fly.io

Then, I went to chat.opneai.com and used gpt 4 to generate some basic html using this prompt:

Make a html page for me that queries this api https://jp-football.fly.dev/

"リバプールは、サラー選手とイオタ選手が得点し、リーズ・ユナイテッドを2-1で破りました。これで、リバプールはプレミアリーグで5試合ぶりの勝利となりました。前の試合では、5失点しましたが、今回は攻撃面で優位に立ちました。"

It gets back an article like the above.

It should be a single page with a random unsplash football image.

The text should be nice to read, in the style of Medium (the blogging site).

The title is "Easy Japanese Football News"

Use only html css and js
Enter fullscreen mode Exit fullscreen mode

I copy paste this into an index.html file And it looks pretty decent.

Deploying the html page

Finally. I deployed the one page site on Tiiny - which was simply a case of dragging my index.html

https://easy-japanese-news-football.tiiny.site/

The next step is to set this up to work with a news api or do some scraping. And to refine my gpt prompt as the Japanese translation isn't perfect yet.

Here's the full code again https://github.com/jackbridger/japanese-simple-football-news

If you like this article, I also host a podcast on developer tools.

Top comments (0)