Storyweavermain.tsx28 matches
24parts: []
25});
26const [imagePreview, setImagePreview] = useState<string | null>(null);
27const [isLoading, setIsLoading] = useState(false);
28const [error, setError] = useState<string | null>(null);
29const fileInputRef = useRef<HTMLInputElement>(null);
3031const handleImageUpload = async (event: React.ChangeEvent<HTMLInputElement>) => {
32const file = event.target.files?.[0];
33if (file) {
34const reader = new FileReader();
35reader.onloadend = () => {
36setImagePreview(reader.result as string);
37};
38reader.readAsDataURL(file);
42try {
43const formData = new FormData();
44formData.append('image', file);
45formData.append('previousStory', JSON.stringify(storyParts.parts));
46
62title: cleanText(result.chapterTitle),
63content: cleanText(result.story),
64imageBase64: result.imageBase64
65}
66]
67}));
68setImagePreview(null);
69}
70} catch (error) {
89type="file"
90ref={fileInputRef}
91onChange={handleImageUpload}
92accept="image/*"
93style={{display: 'none'}}
94/>
115<div key={index} className="story-section">
116<h3>Chapter {index + 1}: {part.title}</h3>
117{part.imageBase64 && (
118<div className="story-image">
119<img
120src={part.imageBase64}
121alt={`Illustration for Chapter ${index + 1}`}
122/>
155if (request.method === 'POST' && new URL(request.url).pathname === '/generate-story') {
156const formData = await request.formData();
157const imageFile = formData.get('image') as File;
158const previousStoryStr = formData.get('previousStory') as string || '[]';
159const previousStory = JSON.parse(previousStoryStr);
160161if (!imageFile) {
162return new Response(JSON.stringify({ error: 'No image uploaded' }), { status: 400 });
163}
164165const arrayBuffer = await imageFile.arrayBuffer();
166const base64Image = btoa(
167new Uint8Array(arrayBuffer).reduce((data, byte) => data + String.fromCharCode(byte), '')
168);
172173try {
174const imageAnalysis = await withTimeout(openai.chat.completions.create({
175model: "gpt-4o",
176messages: [
180{
181type: "text",
182text: "Describe this image briefly, focusing on the main characters and key elements. Be concise."
183},
184{
185type: "image_url",
186image_url: { url: `data:image/jpeg;base64,${base64Image}` }
187}
188]
192}), 15000); // 15 seconds timeout
193194const imageDescription = imageAnalysis.choices[0].message.content || "A magical drawing";
195
196// Optimize previous story context
204{
205role: "system",
206content: "You are a children's storyteller. Continue the story or start a new one based on the image. Use 3 short, simple sentences. Be exciting and brief. Provide a chapter title."
207},
208{
209role: "user",
210content: `Image: ${imageDescription}\n${previousStoryContext}\n\nCreate a chapter title and a 3-sentence story continuation.`
211}
212],
235chapterTitle: chapterTitle,
236story: storyContent,
237imageBase64: `data:image/jpeg;base64,${base64Image}`
238}), {
239headers: { 'Content-Type': 'application/json' }
243console.error('Story generation error:', error);
244return new Response(JSON.stringify({
245error: 'Story generation timed out. Please try again with a simpler image or shorter previous story.'
246}), {
247status: 500,
325}
326327.story-image {
328max-width: 100%;
329margin-bottom: 15px;
332}
333334.story-image img {
335max-width: 100%;
336max-height: 300px;
343}
344345.image-preview {
346display: none;
347}
blob_adminREADME.md1 match
3This is a lightweight Blob Admin interface to view and debug your Blob data.
45
67Versions 0-17 of this val were done with Hono and server-rendering.
blob_adminmain.tsx3 matches
440{profile && (
441<div className="flex items-center space-x-4">
442<img src={profile.profileImageUrl} alt="Profile" className="w-8 h-8 rounded-full" />
443<span>{profile.username}</span>
444<a href="/auth/logout" className="text-blue-400 hover:text-blue-300">Logout</a>
583alt="Blob content"
584className="max-w-full h-auto"
585onError={() => console.error("Error loading image")}
586/>
587</div>
635<li>Create public shareable links for blobs</li>
636<li>View and manage public folder</li>
637<li>Preview images directly in the interface</li>
638</ul>
639</div>
blob_adminREADME.md1 match
3This is a lightweight Blob Admin interface to view and debug your Blob data.
45
67Versions 0-17 of this val were done with Hono and server-rendering.
blob_adminmain.tsx3 matches
439{profile && (
440<div className="flex items-center space-x-4">
441<img src={profile.profileImageUrl} alt="Profile" className="w-8 h-8 rounded-full" />
442<span>{profile.username}</span>
443<a href="/auth/logout" className="text-blue-400 hover:text-blue-300">Logout</a>
582alt="Blob content"
583className="max-w-full h-auto"
584onError={() => console.error("Error loading image")}
585/>
586</div>
634<li>Create public shareable links for blobs</li>
635<li>View and manage public folder</li>
636<li>Preview images directly in the interface</li>
637</ul>
638</div>
78"headers": {
79"accept":
80"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
81"accept-encoding": "gzip, deflate, br, zstd",
82"referer": "https://workers.cloudflare.com/",
immaculateTanMooseREADME.md1 match
3This is a lightweight Blob Admin interface to view and debug your Blob data.
45
67## Installation
11let html = `<h1>${valTownInspo.title}</h1>
12<p>${valTownInspo.description}</p>
13<a href="https://val.town/${valTownInspo.val}"><img src="${valTownInspo.image}" style="max-width:576px"/></a>
14<p><a href="https://www.val.town/settings/intervals">Unsubscribe here</a></p>`;
15
sqlite_adminREADME.md1 match
3This is a lightweight SQLite Admin interface to view and debug your SQLite data.
45
67It's currently super limited (no pagination, editing data, data-type specific viewers), and is just a couple dozens lines of code over a couple different vals. Forks encouraged! Just comment on the val if you add any features that you want to share.
is_omnico_upREADME.md1 match
89<div align="center">
10<img src="https://imagedelivery.net/iHX6Ovru0O7AjmyT5yZRoA/67a1d35e-c37c-41a4-0e5a-03a9ba585d00/public" width="500px"/>
11</div>