Skip to content

Commit e4975a9

Browse files
authored
haiku.html
1 parent ced25cd commit e4975a9

File tree

1 file changed

+204
-0
lines changed

1 file changed

+204
-0
lines changed

haiku.html

+204
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<title>Haiku</title>
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<style>
7+
body {
8+
margin: 0;
9+
padding: 0;
10+
overflow: hidden;
11+
}
12+
video {
13+
width: 100vw;
14+
height: 100vh;
15+
background-color: black;
16+
}
17+
.button-container {
18+
position: absolute;
19+
bottom: 20px;
20+
left: 50%;
21+
transform: translateX(-50%);
22+
text-align: center;
23+
}
24+
button {
25+
margin: 5px;
26+
}
27+
#response {
28+
position: absolute;
29+
top: 10px;
30+
left: 10px;
31+
color: white;
32+
background-color: rgba(0, 0, 0, 0.5);
33+
padding: 10px;
34+
font-size: 14px;
35+
max-width: 80%;
36+
max-height: 80%;
37+
overflow: auto;
38+
}
39+
</style>
40+
</head>
41+
<body>
42+
<video id="video" autoplay="" muted="" playsinline=""></video>
43+
<div class="button-container">
44+
<button
45+
id="captureBtn"
46+
style="background-color: transparent; border: none; cursor: pointer"
47+
>
48+
<svg
49+
viewBox="0 0 24.00 24.00"
50+
xmlns="http://www.w3.org/2000/svg"
51+
width="60px"
52+
height="60px"
53+
>
54+
<g>
55+
<path
56+
fill-rule="evenodd"
57+
clip-rule="evenodd"
58+
d="M3.46447 3.46447C2 4.92893 2 7.28595 2 12C2 16.714 2 19.0711 3.46447 20.5355C4.92893 22 7.28595 22 12 22C16.714 22 19.0711 22 20.5355 20.5355C22 19.0711 22 16.714 22 12C22 7.28595 22 4.92893 20.5355 3.46447C19.0711 2 16.714 2 12 2C7.28595 2 4.92893 2 3.46447 3.46447ZM7.25 12C7.25 9.37665 9.37665 7.25 12 7.25C14.6234 7.25 16.75 9.37665 16.75 12C16.75 14.6234 14.6234 16.75 12 16.75C9.37665 16.75 7.25 14.6234 7.25 12ZM8.75 12C8.75 10.2051 10.2051 8.75 12 8.75C13.7949 8.75 15.25 10.2051 15.25 12C15.25 13.7949 13.7949 15.25 12 15.25C10.2051 15.25 8.75 13.7949 8.75 12Z"
59+
fill="#ffffff"
60+
></path>
61+
</g>
62+
</svg></button
63+
><br />
64+
<button
65+
id="switchCameraBtn"
66+
style="background-color: transparent; border: none; cursor: pointer"
67+
>
68+
<svg
69+
xmlns="http://www.w3.org/2000/svg"
70+
style="width: 40px; height: 40px"
71+
height="24"
72+
viewBox="0 0 24 24"
73+
fill="none"
74+
stroke-width="2"
75+
stroke-linecap="round"
76+
stroke-linejoin="round"
77+
stroke="#ffffff"
78+
width="24"
79+
style="height: 40px; width: 40px"
80+
>
81+
<path d="M11 19H4a2 2 0 01-2-2V7a2 2 0 012-2h5"></path>
82+
<path d="M13 5h7a2 2 0 012 2v10a2 2 0 01-2 2h-5"></path>
83+
<circle cx="12" cy="12" r="3"></circle>
84+
<path d="M18 22l-3-3 3-3"></path>
85+
<path d="M6 2l3 3-3 3"></path>
86+
</svg>
87+
</button>
88+
</div>
89+
<pre id="response"></pre>
90+
<script>
91+
const video = document.getElementById("video");
92+
video.setAttribute("autoplay", "");
93+
video.setAttribute("muted", "");
94+
video.setAttribute("playsinline", "");
95+
const switchCameraBtn = document.getElementById("switchCameraBtn");
96+
const captureBtn = document.getElementById("captureBtn");
97+
switchCameraBtn.style.display = "none";
98+
const responseElement = document.getElementById("response");
99+
let currentStream;
100+
let currentCamera = "front";
101+
102+
// Request access to the webcam
103+
function startCamera() {
104+
const constraints = {
105+
video: {
106+
facingMode: currentCamera === "front" ? "user" : "environment",
107+
},
108+
};
109+
navigator.mediaDevices
110+
.getUserMedia(constraints)
111+
.then((stream) => {
112+
currentStream = stream;
113+
// Show switchCameraBtn if multiple cameras are available
114+
if (currentStream.getTracks().length > 1) {
115+
switchCameraBtn.style.display = "block";
116+
}
117+
video.srcObject = stream;
118+
})
119+
.catch((error) => {
120+
console.error("Error accessing the camera:", error);
121+
});
122+
}
123+
124+
// Switch between front and rear-facing cameras
125+
function switchCamera() {
126+
if (currentStream) {
127+
currentStream.getTracks().forEach((track) => track.stop());
128+
}
129+
currentCamera = currentCamera === "front" ? "rear" : "front";
130+
startCamera();
131+
}
132+
133+
switchCameraBtn.addEventListener("click", switchCamera);
134+
135+
// Get the API key from localStorage or prompt the user to enter it
136+
function getApiKey() {
137+
let apiKey = localStorage.getItem("ANTHROPIC_API_KEY");
138+
if (!apiKey) {
139+
apiKey = prompt("Please enter your Anthropic API key:");
140+
if (apiKey) {
141+
localStorage.setItem("ANTHROPIC_API_KEY", apiKey);
142+
}
143+
}
144+
return apiKey;
145+
}
146+
147+
// Capture the current image and send it to the Anthropic API
148+
captureBtn.addEventListener("click", () => {
149+
const apiKey = getApiKey();
150+
if (!apiKey) {
151+
alert("API key not found. Please enter your Anthropic API key.");
152+
return;
153+
}
154+
const canvas = document.createElement("canvas");
155+
canvas.width = video.videoWidth / 2;
156+
canvas.height = video.videoHeight / 2;
157+
const ctx = canvas.getContext("2d");
158+
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
159+
const imageData = canvas.toDataURL("image/jpeg");
160+
const base64Image = imageData.split(",")[1];
161+
const requestBody = {
162+
model: "claude-3-haiku-20240307",
163+
max_tokens: 1024,
164+
messages: [
165+
{
166+
role: "user",
167+
content: [
168+
{
169+
type: "image",
170+
source: {
171+
type: "base64",
172+
media_type: "image/jpeg",
173+
data: base64Image,
174+
},
175+
},
176+
{ type: "text", text: "Return a haiku inspired by this image" },
177+
],
178+
},
179+
],
180+
};
181+
fetch("https://anthropic-proxy.vercel.app/v1/messages", {
182+
method: "POST",
183+
headers: {
184+
"x-api-key": apiKey,
185+
"anthropic-version": "2023-06-01",
186+
"content-type": "application/json",
187+
},
188+
body: JSON.stringify(requestBody),
189+
})
190+
.then((response) => response.json())
191+
.then((data) => {
192+
console.log(JSON.stringify(data, null, 2));
193+
const haiku = data.content[0].text;
194+
responseElement.innerText += haiku + "\n\n";
195+
})
196+
.catch((error) => {
197+
console.error("Error sending image to the Anthropic API:", error);
198+
});
199+
});
200+
// Start the camera when the page loads
201+
startCamera();
202+
</script>
203+
</body>
204+
</html>

0 commit comments

Comments
 (0)