3hi sophieee
45ok so i only edited `frontend_card`, you can see where im directly grabbing a public url i have in my blob storage aka: https://charmaine-blob_admin.web.val.run/api/public/public%2F1738957543311_Red_Happy_Valentine's_Day_PNG_Clip-Art_Image.png
67i would love to be able to make get requests to a url like that instead of hard coding them :p
blob_admin_migratedmain.tsx25 matches
73const menuRef = useRef(null);
74const isPublic = blob.key.startsWith("__public/");
75const publicUrl = isPublic ? `${window.location.origin}/api/public/${encodeURIComponent(blob.key.slice(9))}` : null;
7677useEffect(() => {
237setLoading(true);
238try {
239const response = await fetch(`/api/blobs?prefix=${encodeKey(searchPrefix)}&limit=${limit}`);
240const data = await response.json();
241setBlobs(data);
264setBlobContentLoading(true);
265try {
266const response = await fetch(`/api/blob?key=${encodeKey(clickedBlob.key)}`);
267const content = await response.text();
268setSelectedBlob({ ...clickedBlob, key: decodeKey(clickedBlob.key) });
278const handleSave = async () => {
279try {
280await fetch(`/api/blob?key=${encodeKey(selectedBlob.key)}`, {
281method: "PUT",
282body: editContent,
290const handleDelete = async (key) => {
291try {
292await fetch(`/api/blob?key=${encodeKey(key)}`, { method: "DELETE" });
293setBlobs(blobs.filter(b => b.key !== key));
294if (selectedBlob && selectedBlob.key === key) {
307const key = `${searchPrefix}${file.name}`;
308formData.append("key", encodeKey(key));
309await fetch("/api/blob", { method: "POST", body: formData });
310const newBlob = { key, size: file.size, lastModified: new Date().toISOString() };
311setBlobs([newBlob, ...blobs]);
329try {
330const fullKey = `${searchPrefix}${key}`;
331await fetch(`/api/blob?key=${encodeKey(fullKey)}`, {
332method: "PUT",
333body: "",
344const handleDownload = async (key) => {
345try {
346const response = await fetch(`/api/blob?key=${encodeKey(key)}`);
347const blob = await response.blob();
348const url = window.URL.createObjectURL(blob);
363if (newKey && newKey !== oldKey) {
364try {
365const response = await fetch(`/api/blob?key=${encodeKey(oldKey)}`);
366const content = await response.blob();
367await fetch(`/api/blob?key=${encodeKey(newKey)}`, {
368method: "PUT",
369body: content,
370});
371await fetch(`/api/blob?key=${encodeKey(oldKey)}`, { method: "DELETE" });
372setBlobs(blobs.map(b => b.key === oldKey ? { ...b, key: newKey } : b));
373if (selectedBlob && selectedBlob.key === oldKey) {
383const newKey = `__public/${key}`;
384try {
385const response = await fetch(`/api/blob?key=${encodeKey(key)}`);
386const content = await response.blob();
387await fetch(`/api/blob?key=${encodeKey(newKey)}`, {
388method: "PUT",
389body: content,
390});
391await fetch(`/api/blob?key=${encodeKey(key)}`, { method: "DELETE" });
392setBlobs(blobs.map(b => b.key === key ? { ...b, key: newKey } : b));
393if (selectedBlob && selectedBlob.key === key) {
402const newKey = key.slice(9); // Remove "__public/" prefix
403try {
404const response = await fetch(`/api/blob?key=${encodeKey(key)}`);
405const content = await response.blob();
406await fetch(`/api/blob?key=${encodeKey(newKey)}`, {
407method: "PUT",
408body: content,
409});
410await fetch(`/api/blob?key=${encodeKey(key)}`, { method: "DELETE" });
411setBlobs(blobs.map(b => b.key === key ? { ...b, key: newKey } : b));
412if (selectedBlob && selectedBlob.key === key) {
557onClick={() =>
558copyToClipboard(
559`${window.location.origin}/api/public/${encodeURIComponent(selectedBlob.key.slice(9))}`,
560)}
561className="text-blue-400 hover:text-blue-300 text-sm"
580>
581<img
582src={`/api/blob?key=${encodeKey(selectedBlob.key)}`}
583alt="Blob content"
584className="max-w-full h-auto"
660661// Public route without authentication
662app.get("/api/public/:id", async (c) => {
663const key = `__public/${c.req.param("id")}`;
664const { blob } = await import("https://esm.town/v/std/blob");
766};
767768app.get("/api/blobs", checkAuth, async (c) => {
769const prefix = c.req.query("prefix") || "";
770const limit = parseInt(c.req.query("limit") || "20", 10);
775});
776777app.get("/api/blob", checkAuth, async (c) => {
778const key = c.req.query("key");
779if (!key) return c.text("Missing key parameter", 400);
783});
784785app.put("/api/blob", checkAuth, async (c) => {
786const key = c.req.query("key");
787if (!key) return c.text("Missing key parameter", 400);
792});
793794app.delete("/api/blob", checkAuth, async (c) => {
795const key = c.req.query("key");
796if (!key) return c.text("Missing key parameter", 400);
800});
801802app.post("/api/blob", checkAuth, async (c) => {
803const { file, key } = await c.req.parseBody();
804if (!file || !key) return c.text("Missing file or key", 400);
42<title>Log Me In</title>
43<meta name="viewport" content="width=device-width, initial-scale=1" />
44<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap" rel="stylesheet" />
45<style>{css}</style>
46</head>
2526async login(email: string, config: Config | undefined): Promise<string> {
27const resp = await fetch("https://api.val.town/v1/me", {
28headers: {
29"Authorization": `Bearer ${Deno.env.get("valtown")}`,
gptMemoryManagerREADME.md20 matches
1A simple Rest API that allows for you GPT to save and recall snippets of data (memories). You can read my blog post explaining it in detail here: [xkonti.tech](https://xkonti.tech/blog/giving-gpt-memory/)
23# Demonstration
7
89What GPT sent do the API:
1011```json
24# Setup
2526There are several steps to set up the API:
27- deploy and configure the API
28- create the API key for your GPT
29- add an action for the API in you GPT
30- add prompt section to your GPT so that it can use it properly
3132## Deploying the API on Val Town
3334Deploy your own memory API. You can fork the following Val to do it: https://www.val.town/v/xkonti/memoryApiExample
3536In the code configure the appropriate values:
3738- `apiName` the name of your API - used in the Privacy Policy (eg. `Memory API`)
39- `contactEmail` - the email to provide for contact in the Privacy Policy (eg. `some@email.com`)
40- `lastPolicyUpdate` - the date the Privacy Policy was last updated (eg. `2023-11-28`)
41- `blobKeyPrefix` - the prefix for the blob storage keys used by your API - more info below (eg. `gpt:memories:`)
42- `apiKeyPrefix` - the prefix for you API Keys secrets - more info below (eg. `GPTMEMORYAPI_KEY_`)
4344## Create API keys
4546The Memory API is designed to serve multiple GPTs at the same time. Each GPT should have it's own unique **name** and **API key**.
4748The **name** is used for identifying the specific GPT and appended to both:
49- `blobKeyPrefix`- to maintain separate memory storage from other GPTs
50- `apiKeyPrefix` - to maintain separate API key for each GPT
51521. Please pick a unique alphanumeric name for your GPT. For example `personaltrainer`.
532. Generate some alphanumeric API key for your GPT. For example `Wrangle-Chapped-Monkhood4-Domain-Suspend`
543. Add a new secret to your Val.town secrets storage. The Key should be the picked name prefixed by `apiKeyPrefix`. Using the default it would be `GPTMEMORYAPI_KEY_personaltrainer`. The value of the secret should be the API key itself.
5556The memories of the GPT will be stored in the blob storage under the key `blobKeyPrefix + name`, for example: `gpt:memories:personaltrainer`.
59601. Add a new action in your GPT.
612. Get the OpenAPI spefication by calling the `/openapi` endpoint of your API
623. Change all `<APIURL>` instances within the specification to the url of your deployed API. For example `https://xkonti-memoryapiexample.web.val.run`
634. Set the authentication method to basic and provide a [base64 encoded](https://www.base64encode.org/) version of the `<name>:<apiKey>`. For example: `personaltrainer:Wrangle-Chapped-Monkhood4-Domain-Suspend` -> `cGVyc29uYWx0cmFpbmVyOldyYW5nbGUtQ2hhcHBlZC1Nb25raG9vZDQtRG9tYWluLVN1c3BlbmQ=`
645. Add the link to the privacy policy, which is the `/privacy` endpoint of your API. For example: `https://xkonti-memoryapiexample.web.val.run/privacy`
6566## Adding the prompt section
gptMemoryManagermain.tsx24 matches
1import * as uuid from "https://deno.land/std/uuid/mod.ts";
2import { blob } from "https://esm.town/v/std/blob";
3import { getPolicy } from "https://esm.town/v/xkonti/memoryApiPolicy";
4import { Hono } from "npm:hono@3";
56export const handleMemoryApiRequest = async (
7req: Request,
8apiName: string,
9contactEmail: string,
10lastPolicyUpdate: string,
11blobKeyPrefix: string,
12apiKeyPrefix: string,
13) => {
14// ==== HELPERS ====
2728const verifyRequest = (c): { memoriesKey: string; error: any } => {
29// Verify API key coming as a Bearer header
30const authHeader = c.req.headers.get("Authorization");
31if (!authHeader || !authHeader.startsWith("Basic ")) {
43return { memoriesKey: "", error: c.text("Forbidden", 403) };
44}
45const expectedKey = Deno.env.get(apiKeyPrefix + key) ?? null;
46if (token !== expectedKey) {
47console.error("Invalid API KEY header");
48return { memoriesKey: "", error: c.text("Forbidden", 403) };
49}
51};
5253// API
5455const app = new Hono();
209// PRIVACY POLICY
210app.get("/privacy", async (c) => {
211const policy = getPolicy(apiName, contactEmail, lastPolicyUpdate);
212c.header("Content-Type", "text/html");
213return c.html(policy);
214});
215216app.get("/openapi", async (c) => {
217const specification = `
218{
219"openapi": "3.1.0",
220"info": {
221"title": "Memories API",
222"description": "API for managing and storing long-term memories.",
223"version": "1.0.0"
224},
225"servers": [
226{
227"url": "<APIURL>"
228}
229],
238},
239"401": {
240"description": "Unauthorized - Missing or invalid API key."
241},
242"403": {
243"description": "Forbidden - Invalid API key."
244}
245},
272},
273"401": {
274"description": "Unauthorized - Missing or invalid API key."
275},
276"403": {
277"description": "Forbidden - Invalid API key."
278}
279},
328},
329"401": {
330"description": "Unauthorized - Missing or invalid API key."
331},
332"403": {
333"description": "Forbidden - Invalid API key."
334}
335},
375},
376"401": {
377"description": "Unauthorized - Missing or invalid API key."
378},
379"403": {
380"description": "Forbidden - Invalid API key."
381}
382},
406},
407"401": {
408"description": "Unauthorized - Missing or invalid API key."
409},
410"403": {
411"description": "Forbidden - Invalid API key."
412}
413},
1A simple Rest API that allows for you GPT to save and recall snippets of data (memories). You can read my blog post explaining it in detail here: [xkonti.tech](https://xkonti.tech/blog/giving-gpt-memory/)
23# Demonstration
7
89What GPT sent do the API:
1011```json
24# Setup
2526There are several steps to set up the API:
27- deploy and configure the API
28- create the API key for your GPT
29- add an action for the API in you GPT
30- add prompt section to your GPT so that it can use it properly
3132## Deploying the API on Val Town
3334Deploy your own memory API. You can fork the following Val to do it: https://www.val.town/v/xkonti/memoryApiExample
3536In the code configure the appropriate values:
3738- `apiName` the name of your API - used in the Privacy Policy (eg. `Memory API`)
39- `contactEmail` - the email to provide for contact in the Privacy Policy (eg. `some@email.com`)
40- `lastPolicyUpdate` - the date the Privacy Policy was last updated (eg. `2023-11-28`)
41- `blobKeyPrefix` - the prefix for the blob storage keys used by your API - more info below (eg. `gpt:memories:`)
42- `apiKeyPrefix` - the prefix for you API Keys secrets - more info below (eg. `GPTMEMORYAPI_KEY_`)
4344## Create API keys
4546The Memory API is designed to serve multiple GPTs at the same time. Each GPT should have it's own unique **name** and **API key**.
4748The **name** is used for identifying the specific GPT and appended to both:
49- `blobKeyPrefix`- to maintain separate memory storage from other GPTs
50- `apiKeyPrefix` - to maintain separate API key for each GPT
51521. Please pick a unique alphanumeric name for your GPT. For example `personaltrainer`.
532. Generate some alphanumeric API key for your GPT. For example `Wrangle-Chapped-Monkhood4-Domain-Suspend`
543. Add a new secret to your Val.town secrets storage. The Key should be the picked name prefixed by `apiKeyPrefix`. Using the default it would be `GPTMEMORYAPI_KEY_personaltrainer`. The value of the secret should be the API key itself.
5556The memories of the GPT will be stored in the blob storage under the key `blobKeyPrefix + name`, for example: `gpt:memories:personaltrainer`.
59601. Add a new action in your GPT.
612. Get the OpenAPI spefication by calling the `/openapi` endpoint of your API
623. Change all `<APIURL>` instances within the specification to the url of your deployed API. For example `https://xkonti-memoryapiexample.web.val.run`
634. Set the authentication method to basic and provide a [base64 encoded](https://www.base64encode.org/) version of the `<name>:<apiKey>`. For example: `personaltrainer:Wrangle-Chapped-Monkhood4-Domain-Suspend` -> `cGVyc29uYWx0cmFpbmVyOldyYW5nbGUtQ2hhcHBlZC1Nb25raG9vZDQtRG9tYWluLVN1c3BlbmQ=`
645. Add the link to the privacy policy, which is the `/privacy` endpoint of your API. For example: `https://xkonti-memoryapiexample.web.val.run/privacy`
6566## Adding the prompt section
1import * as uuid from "https://deno.land/std/uuid/mod.ts";
2import { blob } from "https://esm.town/v/std/blob";
3import { getPolicy } from "https://esm.town/v/xkonti/memoryApiPolicy";
4import { Hono } from "npm:hono@3";
56export const handleMemoryApiRequest = async (
7req: Request,
8apiName: string,
9contactEmail: string,
10lastPolicyUpdate: string,
11blobKeyPrefix: string,
12apiKeyPrefix: string,
13) => {
14// ==== HELPERS ====
5152const verifyRequest = (c): { memoriesKey: string; error: any } => {
53// Verify API key coming as a Bearer header
54const authHeader = c.req.headers.get("Authorization");
55if (!authHeader || !authHeader.startsWith("Basic ")) {
67return { memoriesKey: "", error: c.text("Forbidden", 403) };
68}
69const expectedKey = Deno.env.get(apiKeyPrefix + key) ?? null;
70if (token !== expectedKey) {
71console.error("Invalid API KEY header");
72return { memoriesKey: "", error: c.text("Forbidden", 403) };
73}
75};
7677// API
7879const app = new Hono();
405// PRIVACY POLICY
406app.get("/privacy", async (c) => {
407const policy = getPolicy(apiName, contactEmail, lastPolicyUpdate);
408c.header("Content-Type", "text/html");
409return c.html(policy);
410});
411412app.get("/openapi", async (c) => {
413const specification = `
414{
415"openapi": "3.1.0",
416"info": {
417"title": "Memories and Conversations API",
418"description": "API for managing and storing long-term memories, AI conversations, and file attachments.",
419"version": "1.2.0"
420},
421"servers": [
422{
423"url": "<APIURL>"
424}
425],
434},
435"401": {
436"description": "Unauthorized - Missing or invalid API key."
437},
438"403": {
439"description": "Forbidden - Invalid API key."
440}
441},
468},
469"401": {
470"description": "Unauthorized - Missing or invalid API key."
471},
472"403": {
473"description": "Forbidden - Invalid API key."
474}
475},
524},
525"401": {
526"description": "Unauthorized - Missing or invalid API key."
527},
528"403": {
529"description": "Forbidden - Invalid API key."
530}
531},
571},
572"401": {
573"description": "Unauthorized - Missing or invalid API key."
574},
575"403": {
576"description": "Forbidden - Invalid API key."
577}
578},
602},
603"401": {
604"description": "Unauthorized - Missing or invalid API key."
605},
606"403": {
607"description": "Forbidden - Invalid API key."
608},
609"404": {
641},
642"401": {
643"description": "Unauthorized - Missing or invalid API key."
644},
645"403": {
646"description": "Forbidden - Invalid API key."
647}
648},
674},
675"401": {
676"description": "Unauthorized - Missing or invalid API key."
677},
678"403": {
679"description": "Forbidden - Invalid API key."
680},
681"404": {
728},
729"401": {
730"description": "Unauthorized - Missing or invalid API key."
731},
732"403": {
733"description": "Forbidden - Invalid API key."
734},
735"404": {
781},
782"401": {
783"description": "Unauthorized - Missing or invalid API key."
784},
785"403": {
786"description": "Forbidden - Invalid API key."
787},
788"404": {
handleMemoryApiRequestREADME.md20 matches
1A simple Rest API that allows for you GPT to save and recall snippets of data (memories). You can read my blog post explaining it in detail here: [xkonti.tech](https://xkonti.tech/blog/giving-gpt-memory/)
23# Demonstration
7
89What GPT sent do the API:
1011```json
24# Setup
2526There are several steps to set up the API:
27- deploy and configure the API
28- create the API key for your GPT
29- add an action for the API in you GPT
30- add prompt section to your GPT so that it can use it properly
3132## Deploying the API on Val Town
3334Deploy your own memory API. You can fork the following Val to do it: https://www.val.town/v/xkonti/memoryApiExample
3536In the code configure the appropriate values:
3738- `apiName` the name of your API - used in the Privacy Policy (eg. `Memory API`)
39- `contactEmail` - the email to provide for contact in the Privacy Policy (eg. `some@email.com`)
40- `lastPolicyUpdate` - the date the Privacy Policy was last updated (eg. `2023-11-28`)
41- `blobKeyPrefix` - the prefix for the blob storage keys used by your API - more info below (eg. `gpt:memories:`)
42- `apiKeyPrefix` - the prefix for you API Keys secrets - more info below (eg. `GPTMEMORYAPI_KEY_`)
4344## Create API keys
4546The Memory API is designed to serve multiple GPTs at the same time. Each GPT should have it's own unique **name** and **API key**.
4748The **name** is used for identifying the specific GPT and appended to both:
49- `blobKeyPrefix`- to maintain separate memory storage from other GPTs
50- `apiKeyPrefix` - to maintain separate API key for each GPT
51521. Please pick a unique alphanumeric name for your GPT. For example `personaltrainer`.
532. Generate some alphanumeric API key for your GPT. For example `Wrangle-Chapped-Monkhood4-Domain-Suspend`
543. Add a new secret to your Val.town secrets storage. The Key should be the picked name prefixed by `apiKeyPrefix`. Using the default it would be `GPTMEMORYAPI_KEY_personaltrainer`. The value of the secret should be the API key itself.
5556The memories of the GPT will be stored in the blob storage under the key `blobKeyPrefix + name`, for example: `gpt:memories:personaltrainer`.
59601. Add a new action in your GPT.
612. Get the OpenAPI spefication by calling the `/openapi` endpoint of your API
623. Change all `<APIURL>` instances within the specification to the url of your deployed API. For example `https://xkonti-memoryapiexample.web.val.run`
634. Set the authentication method to basic and provide a [base64 encoded](https://www.base64encode.org/) version of the `<name>:<apiKey>`. For example: `personaltrainer:Wrangle-Chapped-Monkhood4-Domain-Suspend` -> `cGVyc29uYWx0cmFpbmVyOldyYW5nbGUtQ2hhcHBlZC1Nb25raG9vZDQtRG9tYWluLVN1c3BlbmQ=`
645. Add the link to the privacy policy, which is the `/privacy` endpoint of your API. For example: `https://xkonti-memoryapiexample.web.val.run/privacy`
6566## Adding the prompt section
handleMemoryApiRequestmain.tsx24 matches
1import * as uuid from "https://deno.land/std/uuid/mod.ts";
2import { blob } from "https://esm.town/v/std/blob";
3import { getPolicy } from "https://esm.town/v/xkonti/memoryApiPolicy";
4import { Hono } from "npm:hono@3";
56export const handleMemoryApiRequest = async (
7req: Request,
8apiName: string,
9contactEmail: string,
10lastPolicyUpdate: string,
11blobKeyPrefix: string,
12apiKeyPrefix: string,
13) => {
14// ==== HELPERS ====
2728const verifyRequest = (c): { memoriesKey: string; error: any } => {
29// Verify API key coming as a Bearer header
30const authHeader = c.req.headers.get("Authorization");
31if (!authHeader || !authHeader.startsWith("Basic ")) {
43return { memoriesKey: "", error: c.text("Forbidden", 403) };
44}
45const expectedKey = Deno.env.get(apiKeyPrefix + key) ?? null;
46if (token !== expectedKey) {
47console.error("Invalid API KEY header");
48return { memoriesKey: "", error: c.text("Forbidden", 403) };
49}
51};
5253// API
5455const app = new Hono();
209// PRIVACY POLICY
210app.get("/privacy", async (c) => {
211const policy = getPolicy(apiName, contactEmail, lastPolicyUpdate);
212c.header("Content-Type", "text/html");
213return c.html(policy);
214});
215216app.get("/openapi", async (c) => {
217const specification = `
218{
219"openapi": "3.1.0",
220"info": {
221"title": "Memories API",
222"description": "API for managing and storing long-term memories.",
223"version": "1.0.0"
224},
225"servers": [
226{
227"url": "<APIURL>"
228}
229],
238},
239"401": {
240"description": "Unauthorized - Missing or invalid API key."
241},
242"403": {
243"description": "Forbidden - Invalid API key."
244}
245},
272},
273"401": {
274"description": "Unauthorized - Missing or invalid API key."
275},
276"403": {
277"description": "Forbidden - Invalid API key."
278}
279},
328},
329"401": {
330"description": "Unauthorized - Missing or invalid API key."
331},
332"403": {
333"description": "Forbidden - Invalid API key."
334}
335},
375},
376"401": {
377"description": "Unauthorized - Missing or invalid API key."
378},
379"403": {
380"description": "Forbidden - Invalid API key."
381}
382},
406},
407"401": {
408"description": "Unauthorized - Missing or invalid API key."
409},
410"403": {
411"description": "Forbidden - Invalid API key."
412}
413},