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.
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.
Here's the code https://github.com/jackbridger/japanese-simple-football-news
How it works:
- Grabs a football article written in English (now this is hard-coded but in future I'll use an API or scraper)
- Checks if the article has already been processed by checking the cache (Redis)
- If so, return the article to the client
- If not, translate the article
- Then convert the translation into simple Japanese using GPT 3.5
- 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')! } } }
)
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
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
Install deno
We need to install deno to run our functions locally
brew install deno
Then we can log into fly
flyctl auth login
And then we can run
fly launch
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
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",
}),
});
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 '';
}
}
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,
});
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,
})
}
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
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)