Avatar

@stevekrouse

90 likes591 public vals
Joined July 11, 2022
mayor of val town
1
2
3
4
const whatIsValTown = @stevekrouse.karma.replaceAll(
/karma/gi,
"Val Town",
);
0
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const langchainEx = (async () => {
const { OpenAI } = await import("https://esm.sh/langchain/llms/openai");
const { PromptTemplate } = await import("https://esm.sh/langchain/prompts");
const { LLMChain } = await import("https://esm.sh/langchain/chains");
const model = new OpenAI({
temperature: 0.9,
openAIApiKey: @me.secrets.openai,
maxTokens: 100,
});
const template = "What is a good name for a company that makes {product}?";
const prompt = new PromptTemplate({
template: template,
inputVariables: ["product"],
});
const chain = new LLMChain({ llm: model, prompt: prompt });
const res = await chain.call({ product: "colorful socks" });
return res;
})();
0
0

dlock - free distributed lock as a service

https://dlock.univalent.net/

Usage

API

Acquire a lock.

The id path segment is the lock ID - choose your own.

https://dlock.univalent.net/lock/arbitrary-string/acquire?ttl=60

{"lease":1,"deadline":1655572186}

Another attempt to acquire the same lock within its TTL will fail with HTTP status code 409.

https://dlock.univalent.net/lock/01899dc0-2742-44f9-9c7b-01830851b299/acquire?ttl=60

{"error":"lock is acquired by another client","deadline":1655572186}

The previous lock can be renewed with its lease number, like a heartbeat

https://dlock.univalent.net/lock/01899dc0-2742-44f9-9c7b-01830851b299/acquire?ttl=60&lease=1

{"lease":1,"deadline":1655572824}

Release a lock

https://dlock.univalent.net/lock/01899dc0-2742-44f9-9c7b-01830851b299/release?lease=42

Readme
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
async function dlock({ id, ttl, release, lease }: {
id?: string;
ttl?: number;
release?: boolean;
lease?: number;
} = {}): Promise<{
lease?: number;
deadline: number;
error?: "string";
}> {
id = id ??
@stevekrouse.parentReference().userHandle + "-" +
@stevekrouse.parentReference().valName;
ttl = ttl ?? 3; // seconds
let method = release ? "release" : "acquire";
return @stevekrouse.fetchJSON(
`https://dlock.univalent.net/lock/${id}/${method}?${
@stevekrouse.searchParams({ ttl, lease })
}`,
);
}
0
2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
export const fetchJSON = async (
url: string,
options?: RequestInit & {
bearer?: string;
},
) => {
let f = await fetch(@stevekrouse.normalizeURL(url), {
redirect: "follow",
...options,
headers: {
"content-type": "application/json",
authorization: options?.bearer ? `Bearer ${options.bearer}` : undefined,
...(@stevekrouse.lowercaseKeys(options?.headers ?? {})),
},
});
let t = await f.text();
try {
return JSON.parse(t);
}
catch (e) {
throw new Error(`fetchJSON error: ${e.message} in ${url}\n\n"${t}"`);
}
};
2
1,055

Message yourself on Telegram

Inspired by console.email, this val lets you send yourself Telegram messages via the Val Town Telegram Bot. You can use it to make custom Telegram bots, such as this DallE one.

Usage

@stevekrouse.telegram(@me.secrets.telegram, "hi to me on telegram!")
@me.t("hello telegram!")

Installation

It takes less than a minute to set up!

  1. Start a conversation with ValTownBot

  2. Copy the secret it gives you

  3. Save it in your Val Town secrets under telegram

  4. Send a message!

@stevekrouse.telegram(@me.secrets.telegram, "hi to me on telegram!")

Example: https://www.val.town/v/stevekrouse.exampleTelegramMessage

  1. (Bonus) Make a helper function

If you want to make it even easier to message yourself on telegram, ie @me.t("hello!") then you can setup a helper function:

let t = (message, options) => @stevekrouse.telegram(@me.secrets.telegram, message, options);

Ensure you keep this function private otherwise anyone can message you on Telegram!

Commands

  • /roll - Roll your secret in case you accidentally leak it.
  • /webhook - Set a webhook to receive messages you send to @ValTownBot

Receiving Messages

If you send /webhook to @ValTownBot, it will let you specify a webhook URL. It will then forward on any messages (that aren't recognized @ValTownBot commands) to that webhook. It's particularly useful for creating personal chatbots, like my telegram <-> DallE bot.

How it works

Telegram has a lovely API.

  1. I created a @ValTownBot via Bot Father.
  2. I created a webhook and registered it with telegram
  3. Whenever someone new messages @ValTownBot, I generate a secret and save it along with their Chat Id in @stevekrouse.telegramValTownBotSecrets (a private val), and message it back to them
  4. Now whenever you call this val, it calls telegramValTownBot via the Run API (api is a helper), which looks up your Chat Id via your secret and sends you a message

Telegram Resources

Credits

This val was originally made by pomdtr.

Readme
1
2
3
4
async function telegram(secret: string, text: string, options?) {
return api(@stevekrouse.telegramValTownBot, secret, text, options);
}
// Forked from @pomdtr.telegram
0
12

☔️ Umbrella reminder if there's rain today

Screenshot 2023-09-14 at 12.31.32.png

Setup

  1. Fork this val 👉 https://val.town/v/stevekrouse.umbrellaReminder/fork
  2. Customize the location (line 2). You can supply any free-form description of a location.

⚠️ Only works for US-based locations (where weather.gov covers).

How it works

  1. Geocodes an free-form description of a location to latitude and longitude – @stevekrouse.nominatimSearch
  2. Converts a latitude and longitude to weather.gov grid – @stevekrouse.weatherGovGrid
  3. Gets the hourly forecast for that grid
  4. Filters the forecast for periods that are today and >30% chance of rain
  5. If there are any, it formats them appropriately, and sends me an email
Readme
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const umbrellaReminder = async () => {
let location = "prospect heights, brooklyn" // <---- customize this line
let [{ lat, lon }] = await @stevekrouse.nominatimSearch({ q: location })
let { properties: grid } = await @stevekrouse.weatherGovGrid({ lat, lon })
let { properties: { periods } } = await @stevekrouse.fetchJSON(grid.forecastHourly)
let { DateTime } = await import("npm:luxon")
let parse = iso => DateTime.fromISO(iso).setZone(grid.timeZone)
let today = periods.filter(x =>
parse(x.startTime).toLocaleString() ===
DateTime.now().setZone(grid.timeZone).toLocaleString()
);
if (today.every(x => x.probabilityOfPrecipitation.value < 30)) return today
let format = iso => parse(iso).toFormat("ha").toLowerCase()
let html = `The probabilities of rain in <b>${location}</b> today:<br><br>` + today.map(
({ startTime, endTime, probabilityOfPrecipitation: { value: p } }) =>
`${format(startTime)}-${format(endTime)}: ${p}%`
).join("<br>")
console.email({ html, subject: "☔️ Carry an umbrella today!" })
};
2
0

Planes Above Me

Inspired by https://louison.substack.com/p/i-built-a-plane-spotter-for-my-son

A little script that grabs that planes above you, just change line 4 to whatever location you want and it'll pull the lat/log for it and query.

Readme
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
let planesAboveMe = (async () => {
let [{ lat, lon, display_name }] = await @stevekrouse
.nominatimSearch({
q: "atlantic terminal", // <---- change me
});
let epsilon = .1;
let query = new URLSearchParams({
lamax: String(@stevekrouse.round(lat, 2) + epsilon),
lamin: String(@stevekrouse.round(lat, 2) - epsilon),
lomax: String(@stevekrouse.round(lon, 2) + epsilon),
lomin: String(@stevekrouse.round(lon, 2) - epsilon),
});
console.log({ lat, lon, display_name });
let url = `https://opensky-network.org/api/states/all?${query}`;
let data = await @stevekrouse.fetchJSON(url);
return data?.states?.map((f) => ({
icao24: f[0],
callsign: f[1],
origin_country: f[2],
time_position: f[3],
last_contact: f[4],
longitude: f[5],
latitude: f[6],
baro_altitude: f[7],
on_ground: f[8],
velocity: f[9],
true_track: f[10],
vertical_rate: f[11],
sensors: f[12],
geo_altitude: f[13],
squawk: f[14],
spi: f[15],
position_source: f[16],
category: f[17],
}));
})();
{"lat":"40.6846601","lon":"-73.9773109","display_name":"Atlantic Terminal, Flatbush Avenue, Fort Greene, Kings County, City of New York, New York, 11227, United States"}
0
0

Email with GPT-3

Send an email to stevekrouse.emailGPT3@valtown.email, it will forward it to gpt3, and email you back the response.

Readme
1
2
3
4
5
6
7
8
9
async function emailGPT3(email) {
let response = await api(@patrickjm.gpt3, { prompt: email.text });
return @me.mail({
to: email.from,
from: @stevekrouse.thisEmail(),
subject: "Re: " + email.subject,
text: response,
});
}
0
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const jsPython = (async () => {
const { jsPython } = await import("npm:jspython-interpreter");
const script = `
def mapFunction(r, i):
v = r * i
return v
x = [1, 2, 3, 4]
x
.map(mapFunction)
.filter(r => r * r)
.join(",")
`;
const interpreter = jsPython();
return interpreter.evaluate(script);
})();
0
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let xeval = async (req: Request) => {
let tweet, code, result;
try {
tweet = await @dpetrouk.fetchTweet(req.url);
code = tweet.text.split("```")[1]
.trim()
.replaceAll(/&lt;/g, "<")
.replaceAll(/&gt;/g, ">")
.replaceAll(/&amp;/g, "&");
result = await @stevekrouse.eval_(code, [req]);
return result;
}
catch (e) {
return Response.json({ code, tweet, result }, { status: 500 });
}
};
1
0