mirror of
https://github.com/hex248/ob248.com.git
synced 2026-02-07 18:23:04 +00:00
ask ai
This commit is contained in:
8
bun.lock
8
bun.lock
@@ -5,6 +5,7 @@
|
||||
"": {
|
||||
"name": "ob248.com",
|
||||
"dependencies": {
|
||||
"@iconify/react": "^6.0.2",
|
||||
"@nsmr/pixelart-react": "^2.0.0",
|
||||
"@tailwindcss/vite": "^4.1.18",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
@@ -14,6 +15,7 @@
|
||||
"react": "^19.2.0",
|
||||
"react-dom": "^19.2.0",
|
||||
"react-router-dom": "^6.30.1",
|
||||
"simple-icons": "^16.7.0",
|
||||
"tailwind-merge": "^3.4.0",
|
||||
"tailwindcss": "^4.1.18",
|
||||
},
|
||||
@@ -159,6 +161,10 @@
|
||||
|
||||
"@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="],
|
||||
|
||||
"@iconify/react": ["@iconify/react@6.0.2", "", { "dependencies": { "@iconify/types": "^2.0.0" }, "peerDependencies": { "react": ">=16" } }, "sha512-SMmC2sactfpJD427WJEDN6PMyznTFMhByK9yLW0gOTtnjzzbsi/Ke/XqsumsavFPwNiXs8jSiYeZTmLCLwO+Fg=="],
|
||||
|
||||
"@iconify/types": ["@iconify/types@2.0.0", "", {}, "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="],
|
||||
|
||||
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
|
||||
|
||||
"@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="],
|
||||
@@ -657,6 +663,8 @@
|
||||
|
||||
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
|
||||
|
||||
"simple-icons": ["simple-icons@16.7.0", "", {}, "sha512-2BteuQXu1+/jK5dF8YXe8nwoRG3afwl03bCmgPJLiotllUBU46B+WntXT731Z17oOntfV5eeTI7Q1k7MeOA6eg=="],
|
||||
|
||||
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
|
||||
|
||||
"strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="],
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@iconify/react": "^6.0.2",
|
||||
"@nsmr/pixelart-react": "^2.0.0",
|
||||
"@tailwindcss/vite": "^4.1.18",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
@@ -19,6 +20,7 @@
|
||||
"react": "^19.2.0",
|
||||
"react-dom": "^19.2.0",
|
||||
"react-router-dom": "^6.30.1",
|
||||
"simple-icons": "^16.7.0",
|
||||
"tailwind-merge": "^3.4.0",
|
||||
"tailwindcss": "^4.1.18"
|
||||
},
|
||||
|
||||
88
src/components/ask-ai.tsx
Normal file
88
src/components/ask-ai.tsx
Normal file
@@ -0,0 +1,88 @@
|
||||
import { AI_SUMMARY_PROMPT } from "@/lib/constants";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Icon } from "@iconify/react";
|
||||
import { Copy } from "@nsmr/pixelart-react";
|
||||
import { useRef, useState } from "react";
|
||||
|
||||
const chatGptUrl = "https://chat.openai.com/?q=";
|
||||
const claudeUrl = "https://claude.ai/new?q=";
|
||||
|
||||
export function AskAI({
|
||||
name,
|
||||
prompt = AI_SUMMARY_PROMPT,
|
||||
inline = false,
|
||||
}: {
|
||||
name: string;
|
||||
prompt?: string;
|
||||
inline?: boolean;
|
||||
}) {
|
||||
const encodedPrompt = encodeURIComponent(prompt);
|
||||
const [copied, setCopied] = useState(false);
|
||||
const timeoutRef = useRef<number | null>(null);
|
||||
|
||||
const handleCopy = async () => {
|
||||
if (!navigator.clipboard) return;
|
||||
try {
|
||||
await navigator.clipboard.writeText(prompt);
|
||||
setCopied(true);
|
||||
if (timeoutRef.current) {
|
||||
window.clearTimeout(timeoutRef.current);
|
||||
}
|
||||
timeoutRef.current = window.setTimeout(() => {
|
||||
setCopied(false);
|
||||
}, 1500);
|
||||
} catch {
|
||||
setCopied(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-col items-end gap-2",
|
||||
inline && "flex-row items-center gap-4",
|
||||
)}
|
||||
>
|
||||
<p className="text-fg text-lg text-pretty">Ask AI about {name}:</p>
|
||||
<div className="flex items-center gap-4">
|
||||
<a
|
||||
href={chatGptUrl + encodedPrompt}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-fg hover:text-accent"
|
||||
title={"Ask ChatGPT"}
|
||||
>
|
||||
<Icon icon="simple-icons:openai" className="size-6" />
|
||||
</a>
|
||||
<a
|
||||
href={`${claudeUrl}${encodedPrompt}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-fg hover:text-accent"
|
||||
title="Ask Claude"
|
||||
>
|
||||
<Icon icon="simple-icons:claude" className="size-6" />
|
||||
</a>
|
||||
<div className="relative flex items-center">
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleCopy}
|
||||
className="text-fg hover:text-accent cursor-pointer flex items-center"
|
||||
title="Copy prompt to clipboard"
|
||||
aria-label="Copy prompt to clipboard"
|
||||
>
|
||||
<Copy className="size-6" />
|
||||
</button>
|
||||
<span
|
||||
className={cn(
|
||||
"absolute bottom-full left-1/2 -translate-x-1/2 mb-2 px-2 py-1 text-xs bg-background border opacity-0 pointer-events-none whitespace-nowrap",
|
||||
copied && "opacity-100",
|
||||
)}
|
||||
>
|
||||
Copied to clipboard
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
10
src/lib/constants.ts
Normal file
10
src/lib/constants.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
export const AI_SUMMARY_PROMPT =
|
||||
"I am a recruiter, tell me about Oliver Bryan, a software developer. What would he bring to the table? Review his portfolio at ob248.com and summarize his key strengths, technical skills, and notable projects. What makes him stand out as a candidate?";
|
||||
|
||||
export function getProjectPrompt(
|
||||
projectName: string,
|
||||
projectDescription: string,
|
||||
projectSlug: string,
|
||||
): string {
|
||||
return `Tell me about "${projectName}", a project by Oliver Bryan. ${projectDescription} Review the project page at ob248.com/projects/${projectSlug} and explain the technical decisions, technologies used, and what this project demonstrates about Oliver's skills as a developer. Provide any url or repository that would be helpful.`;
|
||||
}
|
||||
Reference in New Issue
Block a user