Compare commits
No commits in common. "d8f40500bbe0c1f188b60961ca900a480f2476ab" and "979627ca2a3960d85f284beb3e560066291d9e22" have entirely different histories.
d8f40500bb
...
979627ca2a
1
.gitignore
vendored
1
.gitignore
vendored
@ -9,4 +9,3 @@ data/
|
|||||||
data-dev/
|
data-dev/
|
||||||
_fresh/
|
_fresh/
|
||||||
node_modules/
|
node_modules/
|
||||||
mise.toml
|
|
||||||
|
@ -110,7 +110,7 @@ function Subline(
|
|||||||
const ctx = useContext(HeroContext);
|
const ctx = useContext(HeroContext);
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
class={`relative flex items-center z-10 flex gap-5 font-sm text-light mt-3`}
|
class={`relative flex items-center z-50 flex gap-5 font-sm text-light mt-3`}
|
||||||
style={{ color: ctx.image ? "#1F1F1F" : "white" }}
|
style={{ color: ctx.image ? "#1F1F1F" : "white" }}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
{
|
{
|
||||||
"lock": false,
|
"lock": false,
|
||||||
"nodeModulesDir": "auto",
|
"nodeModulesDir": "auto",
|
||||||
"unstable": [
|
|
||||||
"cron"
|
|
||||||
],
|
|
||||||
"tasks": {
|
"tasks": {
|
||||||
"check": "deno fmt --check && deno lint && deno check **/*.ts && deno check **/*.tsx",
|
"check": "deno fmt --check && deno lint && deno check **/*.ts && deno check **/*.tsx",
|
||||||
"start": "deno run --env-file -A --watch=static/,routes/ dev.ts",
|
"start": "deno run --env-file -A --watch=static/,routes/ dev.ts",
|
||||||
|
@ -6,7 +6,6 @@ import * as $_404 from "./routes/_404.tsx";
|
|||||||
import * as $_app from "./routes/_app.tsx";
|
import * as $_app from "./routes/_app.tsx";
|
||||||
import * as $_layout from "./routes/_layout.tsx";
|
import * as $_layout from "./routes/_layout.tsx";
|
||||||
import * as $_middleware from "./routes/_middleware.ts";
|
import * as $_middleware from "./routes/_middleware.ts";
|
||||||
import * as $admin_cache_index from "./routes/admin/cache/index.tsx";
|
|
||||||
import * as $admin_log_index from "./routes/admin/log/index.tsx";
|
import * as $admin_log_index from "./routes/admin/log/index.tsx";
|
||||||
import * as $admin_performance_index from "./routes/admin/performance/index.tsx";
|
import * as $admin_performance_index from "./routes/admin/performance/index.tsx";
|
||||||
import * as $api_articles_name_ from "./routes/api/articles/[name].ts";
|
import * as $api_articles_name_ from "./routes/api/articles/[name].ts";
|
||||||
@ -69,7 +68,6 @@ const manifest = {
|
|||||||
"./routes/_app.tsx": $_app,
|
"./routes/_app.tsx": $_app,
|
||||||
"./routes/_layout.tsx": $_layout,
|
"./routes/_layout.tsx": $_layout,
|
||||||
"./routes/_middleware.ts": $_middleware,
|
"./routes/_middleware.ts": $_middleware,
|
||||||
"./routes/admin/cache/index.tsx": $admin_cache_index,
|
|
||||||
"./routes/admin/log/index.tsx": $admin_log_index,
|
"./routes/admin/log/index.tsx": $admin_log_index,
|
||||||
"./routes/admin/performance/index.tsx": $admin_performance_index,
|
"./routes/admin/performance/index.tsx": $admin_performance_index,
|
||||||
"./routes/api/articles/[name].ts": $api_articles_name_,
|
"./routes/api/articles/[name].ts": $api_articles_name_,
|
||||||
|
@ -191,7 +191,7 @@ export const KMenu = (
|
|||||||
}}
|
}}
|
||||||
style={{ outline: "none !important" }}
|
style={{ outline: "none !important" }}
|
||||||
placeholder="Command"
|
placeholder="Command"
|
||||||
class="bg-transparent color pl-4 outline-none"
|
class="bg-transparent color pl-4 outline outline outline-2 outline-offset-2"
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
15
lib/cache.ts
15
lib/cache.ts
@ -6,9 +6,9 @@ interface SetCacheOptions {
|
|||||||
expires?: number; // Override expiration for individual cache entries
|
expires?: number; // Override expiration for individual cache entries
|
||||||
}
|
}
|
||||||
|
|
||||||
const caches = new Map<
|
export const caches = new Map<
|
||||||
string,
|
string,
|
||||||
{ info: () => { name: string; count: number; sizeInKB: number } }
|
{ info: () => { count: number; sizeInKB: number } }
|
||||||
>();
|
>();
|
||||||
|
|
||||||
export function createCache<T>(
|
export function createCache<T>(
|
||||||
@ -48,7 +48,7 @@ export function createCache<T>(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
info() {
|
info(): { count: number; sizeInKB: number } {
|
||||||
// Cleanup expired entries before calculating info
|
// Cleanup expired entries before calculating info
|
||||||
this.cleanup();
|
this.cleanup();
|
||||||
|
|
||||||
@ -65,8 +65,8 @@ export function createCache<T>(
|
|||||||
totalBytes += keySize + valueSize;
|
totalBytes += keySize + valueSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
const sizeInKB = Math.floor(totalBytes / 1024); // Convert bytes to kilobytes
|
const sizeInKB = totalBytes / 1024; // Convert bytes to kilobytes
|
||||||
return { name: cacheName, count, sizeInKB };
|
return { count, sizeInKB };
|
||||||
},
|
},
|
||||||
|
|
||||||
has(key: string): boolean {
|
has(key: string): boolean {
|
||||||
@ -96,10 +96,5 @@ export function createCache<T>(
|
|||||||
caches.set(cacheName, {
|
caches.set(cacheName, {
|
||||||
info: api.info.bind(api),
|
info: api.info.bind(api),
|
||||||
});
|
});
|
||||||
|
|
||||||
return api;
|
return api;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getCacheInfo() {
|
|
||||||
return [...caches.values().map((c) => c.info())];
|
|
||||||
}
|
|
||||||
|
@ -89,10 +89,10 @@ export function createCrud<T extends GenericResource>(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let parsed = parse(content, id);
|
const parsed = parse(content, id);
|
||||||
|
|
||||||
if (hasThumbnails) {
|
if (hasThumbnails) {
|
||||||
parsed = await addThumbnailToResource(parsed);
|
return addThumbnailToResource(parsed);
|
||||||
}
|
}
|
||||||
const doc = { ...parsed, content };
|
const doc = { ...parsed, content };
|
||||||
cache.set(path, doc, { expires: 10 * 1000 });
|
cache.set(path, doc, { expires: 10 * 1000 });
|
||||||
@ -124,6 +124,7 @@ export function createCrud<T extends GenericResource>(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const newDoc = transformDocument(content, updater);
|
const newDoc = transformDocument(content, updater);
|
||||||
|
cache.set("all", undefined);
|
||||||
await createDocument(path, newDoc);
|
await createDocument(path, newDoc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,4 +172,3 @@ export function getTextOfChild(child: DocumentChild): string | undefined {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import { zodResponseFormat } from "https://deno.land/x/openai@v4.69.0/helpers/zo
|
|||||||
import { OPENAI_API_KEY } from "@lib/env.ts";
|
import { OPENAI_API_KEY } from "@lib/env.ts";
|
||||||
import { hashString } from "@lib/helpers.ts";
|
import { hashString } from "@lib/helpers.ts";
|
||||||
import { createCache } from "@lib/cache.ts";
|
import { createCache } from "@lib/cache.ts";
|
||||||
import { recipeResponseSchema } from "@lib/recipeSchema.ts";
|
import recipeSchema, { recipeResponseSchema } from "@lib/recipeSchema.ts";
|
||||||
|
|
||||||
const openAI = OPENAI_API_KEY && new OpenAI({ apiKey: OPENAI_API_KEY });
|
const openAI = OPENAI_API_KEY && new OpenAI({ apiKey: OPENAI_API_KEY });
|
||||||
|
|
||||||
|
@ -13,15 +13,6 @@ export function safeFileName(inputString: string): string {
|
|||||||
return fileName;
|
return fileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function toUrlSafeString(input: string): string {
|
|
||||||
return input
|
|
||||||
.trim() // Remove leading and trailing whitespace
|
|
||||||
.toLowerCase() // Convert to lowercase
|
|
||||||
.replace(/[^a-z0-9\s-]/g, "") // Remove non-alphanumeric characters except spaces and hyphens
|
|
||||||
.replace(/\s+/g, "-") // Replace spaces with hyphens
|
|
||||||
.replace(/-+/g, "-"); // Remove consecutive hyphens
|
|
||||||
}
|
|
||||||
|
|
||||||
export function extractHashTags(inputString: string) {
|
export function extractHashTags(inputString: string) {
|
||||||
const hashtags = [];
|
const hashtags = [];
|
||||||
|
|
||||||
|
@ -19,7 +19,6 @@ export default function App({ Component }: PageProps) {
|
|||||||
/>
|
/>
|
||||||
<link rel="manifest" href="/site.webmanifest" />
|
<link rel="manifest" href="/site.webmanifest" />
|
||||||
<meta name="msapplication-TileColor" content="#da532c" />
|
<meta name="msapplication-TileColor" content="#da532c" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<meta name="theme-color" content="#141218" />
|
<meta name="theme-color" content="#141218" />
|
||||||
<style>{globalCss}</style>
|
<style>{globalCss}</style>
|
||||||
<title>Memorium</title>
|
<title>Memorium</title>
|
||||||
|
32
routes/admin/cache/index.tsx
vendored
32
routes/admin/cache/index.tsx
vendored
@ -1,32 +0,0 @@
|
|||||||
import { MainLayout } from "@components/layouts/main.tsx";
|
|
||||||
import { Handlers, PageProps } from "$fresh/server.ts";
|
|
||||||
import { getCacheInfo } from "@lib/cache.ts";
|
|
||||||
|
|
||||||
export const handler: Handlers<
|
|
||||||
{ cacheInfo: ReturnType<typeof getCacheInfo> }
|
|
||||||
> = {
|
|
||||||
GET(_, ctx) {
|
|
||||||
return ctx.render({ cacheInfo: getCacheInfo() });
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function Greet(
|
|
||||||
props: PageProps<
|
|
||||||
{ cacheInfo: ReturnType<typeof getCacheInfo> }
|
|
||||||
>,
|
|
||||||
) {
|
|
||||||
const { cacheInfo } = props.data;
|
|
||||||
return (
|
|
||||||
<MainLayout
|
|
||||||
url={props.url}
|
|
||||||
title="Recipes"
|
|
||||||
context={{ type: "recipe" }}
|
|
||||||
>
|
|
||||||
<code>
|
|
||||||
<pre class="text-white">
|
|
||||||
{JSON.stringify(cacheInfo, null, 2)}
|
|
||||||
</pre>
|
|
||||||
</code>
|
|
||||||
</MainLayout>
|
|
||||||
);
|
|
||||||
}
|
|
@ -8,11 +8,7 @@ import * as openai from "@lib/openai.ts";
|
|||||||
import tds from "https://cdn.skypack.dev/turndown@7.2.0";
|
import tds from "https://cdn.skypack.dev/turndown@7.2.0";
|
||||||
import { Article, createArticle } from "@lib/resource/articles.ts";
|
import { Article, createArticle } from "@lib/resource/articles.ts";
|
||||||
import { getYoutubeVideoDetails } from "@lib/youtube.ts";
|
import { getYoutubeVideoDetails } from "@lib/youtube.ts";
|
||||||
import {
|
import { extractYoutubeId, isYoutubeLink } from "@lib/string.ts";
|
||||||
extractYoutubeId,
|
|
||||||
isYoutubeLink,
|
|
||||||
toUrlSafeString,
|
|
||||||
} from "@lib/string.ts";
|
|
||||||
import { createLogger } from "@lib/log/index.ts";
|
import { createLogger } from "@lib/log/index.ts";
|
||||||
|
|
||||||
const parser = new DOMParser();
|
const parser = new DOMParser();
|
||||||
@ -73,10 +69,6 @@ async function processCreateArticle(
|
|||||||
const url = new URL(fetchUrl);
|
const url = new URL(fetchUrl);
|
||||||
|
|
||||||
function makeUrlAbsolute(src: string) {
|
function makeUrlAbsolute(src: string) {
|
||||||
if (src.startsWith("//")) {
|
|
||||||
return "https:" + src;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (src.startsWith("/")) {
|
if (src.startsWith("/")) {
|
||||||
return `${url.origin}${src.replace(/$\//, "")}`;
|
return `${url.origin}${src.replace(/$\//, "")}`;
|
||||||
}
|
}
|
||||||
@ -106,16 +98,20 @@ async function processCreateArticle(
|
|||||||
|
|
||||||
if (href.startsWith("/")) {
|
if (href.startsWith("/")) {
|
||||||
return `[${content}](${url.origin}${href.replace(/$\//, "")})`;
|
return `[${content}](${url.origin}${href.replace(/$\//, "")})`;
|
||||||
} else if (href.startsWith("//")) {
|
}
|
||||||
return `[${content}](https:${href})`;
|
|
||||||
} else if (href.startsWith("#")) {
|
if (href.startsWith("#")) {
|
||||||
if (content.length < 2) return "";
|
if (content.length < 2) return "";
|
||||||
return `[${content}](${url.href}#${href})`.replace("##", "#");
|
return `[${content}](${url.href}#${href})`.replace("##", "#");
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
if (!href.startsWith("https://") && !href.startsWith("http://")) {
|
||||||
return `[${content}](${url.origin.replace(/\/$/, "")}/${
|
return `[${content}](${url.origin.replace(/\/$/, "")}/${
|
||||||
href.replace(/^\//, "")
|
href.replace(/^\//, "")
|
||||||
})`;
|
})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return `[${content}](${href})`;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -129,10 +125,7 @@ async function processCreateArticle(
|
|||||||
metaAuthor || openai.extractAuthorName(markdown),
|
metaAuthor || openai.extractAuthorName(markdown),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
console.log({ tags, shortTitle, author });
|
const id = shortTitle || title || "";
|
||||||
streamResponse.enqueue("postprocessing article");
|
|
||||||
|
|
||||||
const id = toUrlSafeString(shortTitle || title || "");
|
|
||||||
|
|
||||||
const meta: Article["meta"] = {
|
const meta: Article["meta"] = {
|
||||||
author: (author || "").replace("@", "twitter:"),
|
author: (author || "").replace("@", "twitter:"),
|
||||||
@ -168,7 +161,7 @@ async function processCreateArticle(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
streamResponse.enqueue("writing to disk");
|
streamResponse.enqueue("finished processing");
|
||||||
|
|
||||||
await createArticle(newArticle.id, newArticle);
|
await createArticle(newArticle.id, newArticle);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user