{"id":13695258,"url":"https://github.com/steven-tey/extrapolate","last_synced_at":"2025-05-15T11:05:56.992Z","repository":{"id":65386145,"uuid":"591312452","full_name":"steven-tey/extrapolate","owner":"steven-tey","description":"Age transformation AI app powered by Next.js, Vercel, Replicate, Upstash, and Cloudflare R2 + Workers.","archived":false,"fork":false,"pushed_at":"2024-12-15T18:24:02.000Z","size":955,"stargazers_count":675,"open_issues_count":3,"forks_count":112,"subscribers_count":13,"default_branch":"main","last_synced_at":"2025-04-07T13:01:49.587Z","etag":null,"topics":["cloudflare-r2","cloudflare-workers","nextjs","replicate","upstash","vercel"],"latest_commit_sha":null,"homepage":"https://extrapolate.app","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/steven-tey.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-01-20T13:02:00.000Z","updated_at":"2025-04-06T19:35:50.000Z","dependencies_parsed_at":"2023-02-14T11:32:00.467Z","dependency_job_id":"8bbc6694-f714-4a54-bca6-b1e0abc26cea","html_url":"https://github.com/steven-tey/extrapolate","commit_stats":{"total_commits":176,"total_committers":2,"mean_commits":88.0,"dds":"0.40340909090909094","last_synced_commit":"fb713e1f54a0abe24d49dbb3c4bf157cd0948cfa"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/steven-tey%2Fextrapolate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/steven-tey%2Fextrapolate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/steven-tey%2Fextrapolate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/steven-tey%2Fextrapolate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/steven-tey","download_url":"https://codeload.github.com/steven-tey/extrapolate/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248933340,"owners_count":21185460,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cloudflare-r2","cloudflare-workers","nextjs","replicate","upstash","vercel"],"created_at":"2024-08-02T18:00:20.363Z","updated_at":"2025-04-14T18:11:17.624Z","avatar_url":"https://github.com/steven-tey.png","language":"TypeScript","funding_links":[],"categories":["TypeScript","Built with Replicate","AI"],"sub_categories":[],"readme":"\u003ca href=\"https://extrapolate.app\"\u003e\n  \u003cimg alt=\"Extrapolate – See how well you age with AI\" src=\"https://extrapolate.app/api/og\"\u003e\n  \u003ch1 align=\"center\"\u003eExtrapolate\u003c/h1\u003e\n\u003c/a\u003e\n\n\u003cp align=\"center\"\u003e\n  See how well you age with AI\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://twitter.com/steventey\"\u003e\n    \u003cimg src=\"https://img.shields.io/twitter/follow/steventey?style=flat\u0026label=steventey\u0026logo=twitter\u0026color=0bf\u0026logoColor=fff\" alt=\"Steven Tey Twitter follower count\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/steven-tey/extrapolate\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/stars/steven-tey/extrapolate?label=steven-tey%2Fextrapolate\" alt=\"Extrapolate repo star count\" /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"#introduction\"\u003e\u003cstrong\u003eIntroduction\u003c/strong\u003e\u003c/a\u003e ·\n  \u003ca href=\"#features\"\u003e\u003cstrong\u003eFeatures\u003c/strong\u003e\u003c/a\u003e ·\n  \u003ca href=\"#deploy-your-own\"\u003e\u003cstrong\u003eDeploy Your Own\u003c/strong\u003e\u003c/a\u003e ·\n  \u003ca href=\"#author\"\u003e\u003cstrong\u003eAuthor\u003c/strong\u003e\u003c/a\u003e\n\u003c/p\u003e\n\u003cbr/\u003e\n\n--NEW README COMING SOON--\n\n## Introduction\n\nExtrapolate is an app for you to see how well you age by transforming your face with Artificial Intelligence.\n\nhttps://user-images.githubusercontent.com/28986134/213781048-d215894d-2286-4176-a200-f745b255ecbe.mp4\n\n## Features\n\n- 3s GIF of your face as it ages through time 🧓\n- Store \u0026 retrieve photos from [Cloudflare R2](https://www.cloudflare.com/lp/pg-r2/) using Workers\n\n## Deploy Your Own\n\nYou can deploy this template to Vercel with the button below:\n\n[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?demo-title=Extrapolate%20%E2%80%93%C2%A0See%20how%20well%20you%20age%20with%20AI\u0026demo-description=Age%20transformation%20AI%20app%20powered%20by%20Next.js%2C%20Replicate%2C%20Upstash%2C%20and%20Cloudflare%20R2%20%2B%20Workers.\u0026demo-url=https%3A%2F%2Fextrapolate.app%2F\u0026demo-image=%2F%2Fimages.ctfassets.net%2Fe5382hct74si%2F4B2RUQ7DTvPgpf3Ra9jSC2%2Fda2571b055081a670ac9649d3ac0ac7a%2FCleanShot_2023-01-20_at_12.04.08.png\u0026project-name=Extrapolate%20%E2%80%93%C2%A0See%20how%20well%20you%20age%20with%20AI\u0026repository-name=extrapolate\u0026repository-url=https%3A%2F%2Fgithub.com%2Fsteven-tey%2Fextrapolate\u0026from=templates\u0026integration-ids=oac_V3R1GIpkoJorr6fqyiwdhl17\u0026env=REPLICATE_API_TOKEN%2CREPLICATE_WEBHOOK_TOKEN%2CCLOUDFLARE_WORKER_SECRET%2CPOSTMARK_TOKEN\u0026envDescription=How%20to%20get%20these%20env%20variables%3A%20\u0026envLink=https%3A%2F%2Fgithub.com%2Fsteven-tey%2Fextrapolate%2Fblob%2Fmain%2F.env.example)\n\nNote that you'll need to:\n\n- Set up a [ReplicateHQ](https://replicate.com) account to get the `REPLICATE_API_TOKEN` env var.\n- Set up an [Upstash](https://upstash.com) account to get the Upstash Redis env vars.\n- Create a [Cloudflare R2 instance](https://www.cloudflare.com/lp/pg-r2/) and set up a [Cloudflare Worker](https://workers.cloudflare.com/) to handle uploads \u0026 reads (instructions below).\n\n### Cloudflare R2 setup instructions\n\n1. Go to Cloudflare and create an [R2 bucket](https://www.cloudflare.com/lp/pg-r2/).\n2. Create a [Cloudflare Worker](https://workers.cloudflare.com/) using the code snippet below.\n3. Bind your worker to your R2 instance under **Settings \u003e R2 Bucket Bindings**.\n4. For extra security, set an `AUTH_KEY_SECRET` variable under **Settings \u003e Environment Variables** (you can generate a random secret [here](https://generate-secret.vercel.app/)).\n5. Replace all instances of `images.extrapolate.workers.dev` in the codebase with your Cloudflare Worker endpoint.\n\n\u003cdetails\u003e\n\u003csummary\u003eCloudflare Worker Code\u003c/summary\u003e\n\n```ts\n// Check requests for a pre-shared secret\nconst hasValidHeader = (request, env) =\u003e {\n  return request.headers.get(\"X-CF-Secret\") === env.AUTH_KEY_SECRET;\n};\n\nfunction authorizeRequest(request, env, key) {\n  switch (request.method) {\n    case \"PUT\":\n    case \"DELETE\":\n      return hasValidHeader(request, env);\n    case \"GET\":\n      return true;\n    default:\n      return false;\n  }\n}\n\nexport default {\n  async fetch(request, env) {\n    const url = new URL(request.url);\n    const key = url.pathname.slice(1);\n\n    if (!authorizeRequest(request, env, key)) {\n      return new Response(\"Forbidden\", { status: 403 });\n    }\n\n    switch (request.method) {\n      case \"PUT\":\n        await env.MY_BUCKET.put(key, request.body);\n        return new Response(`Put ${key} successfully!`);\n      case \"GET\":\n        const object = await env.MY_BUCKET.get(key);\n\n        if (object === null) {\n          return new Response(\"Object Not Found\", { status: 404 });\n        }\n\n        const headers = new Headers();\n        object.writeHttpMetadata(headers);\n        headers.set(\"etag\", object.httpEtag);\n\n        return new Response(object.body, {\n          headers,\n        });\n      case \"DELETE\":\n        await env.MY_BUCKET.delete(key);\n        return new Response(\"Deleted!\");\n\n      default:\n        return new Response(\"Method Not Allowed\", {\n          status: 405,\n          headers: {\n            Allow: \"PUT, GET, DELETE\",\n          },\n        });\n    }\n  },\n};\n```\n\n\u003c/details\u003e\n\n## Author\n\n- Steven Tey ([@steventey](https://twitter.com/steventey))\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsteven-tey%2Fextrapolate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsteven-tey%2Fextrapolate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsteven-tey%2Fextrapolate/lists"}