error handling
Browse files
src/lib/components/MonsterGenerator/MonsterGenerator.svelte
CHANGED
@@ -83,12 +83,49 @@ Assistant:`;
|
|
83 |
state.currentStep = 'complete';
|
84 |
} catch (err) {
|
85 |
console.error('Workflow error:', err);
|
86 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
87 |
} finally {
|
88 |
state.isProcessing = false;
|
89 |
}
|
90 |
}
|
91 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
92 |
async function captionImage() {
|
93 |
state.currentStep = 'captioning';
|
94 |
|
@@ -96,18 +133,22 @@ Assistant:`;
|
|
96 |
throw new Error('Caption service not available or no image provided');
|
97 |
}
|
98 |
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
|
|
|
|
|
|
|
|
111 |
}
|
112 |
|
113 |
async function generateMonsterConcept() {
|
@@ -121,21 +162,25 @@ Assistant:`;
|
|
121 |
|
122 |
console.log('Generating monster concept with prompt:', conceptPrompt);
|
123 |
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
|
|
|
|
|
|
|
|
139 |
}
|
140 |
}
|
141 |
|
@@ -150,21 +195,25 @@ Assistant:`;
|
|
150 |
|
151 |
console.log('Generating image prompt from concept');
|
152 |
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
|
|
|
|
|
|
|
|
168 |
}
|
169 |
}
|
170 |
|
@@ -175,30 +224,34 @@ Assistant:`;
|
|
175 |
throw new Error('Image generation service not available or no prompt');
|
176 |
}
|
177 |
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
|
|
|
|
|
|
|
|
202 |
}
|
203 |
}
|
204 |
|
|
|
83 |
state.currentStep = 'complete';
|
84 |
} catch (err) {
|
85 |
console.error('Workflow error:', err);
|
86 |
+
|
87 |
+
// Check for GPU quota error
|
88 |
+
if (err && typeof err === 'object' && 'message' in err) {
|
89 |
+
const errorMessage = String(err.message);
|
90 |
+
if (errorMessage.includes('exceeded your GPU quota') || errorMessage.includes('GPU quota')) {
|
91 |
+
state.error = 'GPU quota exceeded! You need to sign in with Hugging Face for free GPU time, or upgrade to Hugging Face Pro for more quota.';
|
92 |
+
} else {
|
93 |
+
state.error = errorMessage;
|
94 |
+
}
|
95 |
+
} else if (err instanceof Error) {
|
96 |
+
state.error = err.message;
|
97 |
+
} else {
|
98 |
+
state.error = 'An unknown error occurred';
|
99 |
+
}
|
100 |
} finally {
|
101 |
state.isProcessing = false;
|
102 |
}
|
103 |
}
|
104 |
|
105 |
+
function handleAPIError(error: any): never {
|
106 |
+
console.error('API Error:', error);
|
107 |
+
|
108 |
+
// Check if it's a GPU quota error
|
109 |
+
if (error && typeof error === 'object' && 'message' in error) {
|
110 |
+
const errorMessage = String(error.message);
|
111 |
+
if (errorMessage.includes('exceeded your GPU quota') || errorMessage.includes('GPU quota')) {
|
112 |
+
throw new Error('GPU quota exceeded! You need to sign in with Hugging Face for free GPU time, or upgrade to Hugging Face Pro for more quota.');
|
113 |
+
}
|
114 |
+
throw new Error(errorMessage);
|
115 |
+
}
|
116 |
+
|
117 |
+
// Check if error has a different structure (like the status object from the logs)
|
118 |
+
if (error && typeof error === 'object' && 'type' in error && error.type === 'status') {
|
119 |
+
const statusError = error as any;
|
120 |
+
if (statusError.message && statusError.message.includes('GPU quota')) {
|
121 |
+
throw new Error('GPU quota exceeded! You need to sign in with Hugging Face for free GPU time, or upgrade to Hugging Face Pro for more quota.');
|
122 |
+
}
|
123 |
+
throw new Error(statusError.message || 'API request failed');
|
124 |
+
}
|
125 |
+
|
126 |
+
throw error;
|
127 |
+
}
|
128 |
+
|
129 |
async function captionImage() {
|
130 |
state.currentStep = 'captioning';
|
131 |
|
|
|
133 |
throw new Error('Caption service not available or no image provided');
|
134 |
}
|
135 |
|
136 |
+
try {
|
137 |
+
const output = await joyCaptionClient.predict("/stream_chat", [
|
138 |
+
state.userImage,
|
139 |
+
"Descriptive" as CaptionType,
|
140 |
+
"very long" as CaptionLength,
|
141 |
+
[], // extra_options
|
142 |
+
"", // name_input
|
143 |
+
"" // custom_prompt
|
144 |
+
]);
|
145 |
+
|
146 |
+
const [prompt, caption] = output.data;
|
147 |
+
state.imageCaption = caption;
|
148 |
+
console.log('Caption generated:', caption);
|
149 |
+
} catch (error) {
|
150 |
+
handleAPIError(error);
|
151 |
+
}
|
152 |
}
|
153 |
|
154 |
async function generateMonsterConcept() {
|
|
|
162 |
|
163 |
console.log('Generating monster concept with prompt:', conceptPrompt);
|
164 |
|
165 |
+
try {
|
166 |
+
const output = await rwkvClient.predict(0, [
|
167 |
+
conceptPrompt,
|
168 |
+
300, // maxTokens
|
169 |
+
0.7, // temperature
|
170 |
+
0.8, // topP
|
171 |
+
0.1, // presencePenalty
|
172 |
+
0.1 // countPenalty
|
173 |
+
]);
|
174 |
+
|
175 |
+
console.log('RWKV output:', output);
|
176 |
+
state.monsterConcept = output.data[0];
|
177 |
+
console.log('Monster concept generated:', state.monsterConcept);
|
178 |
+
|
179 |
+
if (!state.monsterConcept || state.monsterConcept.trim() === '') {
|
180 |
+
throw new Error('Failed to generate monster concept - received empty response');
|
181 |
+
}
|
182 |
+
} catch (error) {
|
183 |
+
handleAPIError(error);
|
184 |
}
|
185 |
}
|
186 |
|
|
|
195 |
|
196 |
console.log('Generating image prompt from concept');
|
197 |
|
198 |
+
try {
|
199 |
+
const output = await rwkvClient.predict(0, [
|
200 |
+
promptGenerationPrompt,
|
201 |
+
300, // maxTokens
|
202 |
+
0.7, // temperature
|
203 |
+
0.8, // topP
|
204 |
+
0.1, // presencePenalty
|
205 |
+
0.1 // countPenalty
|
206 |
+
]);
|
207 |
+
|
208 |
+
console.log('Image prompt output:', output);
|
209 |
+
state.imagePrompt = output.data[0];
|
210 |
+
console.log('Image prompt generated:', state.imagePrompt);
|
211 |
+
|
212 |
+
if (!state.imagePrompt || state.imagePrompt.trim() === '') {
|
213 |
+
throw new Error('Failed to generate image prompt - received empty response');
|
214 |
+
}
|
215 |
+
} catch (error) {
|
216 |
+
handleAPIError(error);
|
217 |
}
|
218 |
}
|
219 |
|
|
|
224 |
throw new Error('Image generation service not available or no prompt');
|
225 |
}
|
226 |
|
227 |
+
try {
|
228 |
+
const output = await fluxClient.predict("/infer", [
|
229 |
+
`${state.imagePrompt}\nNow generate an Anime-style image of the monster in an idle pose with a white background. The monster should not be attacking or in motion. The full monster must be visible within the frame.`,
|
230 |
+
0, // seed
|
231 |
+
true, // randomizeSeed
|
232 |
+
1024, // width
|
233 |
+
1024, // height
|
234 |
+
4 // steps
|
235 |
+
]);
|
236 |
+
|
237 |
+
const [image, usedSeed] = output.data;
|
238 |
+
let url: string | undefined;
|
239 |
+
|
240 |
+
if (typeof image === "string") url = image;
|
241 |
+
else if (image && image.url) url = image.url;
|
242 |
+
else if (image && image.path) url = image.path;
|
243 |
+
|
244 |
+
if (url) {
|
245 |
+
state.monsterImage = {
|
246 |
+
imageUrl: url,
|
247 |
+
seed: usedSeed,
|
248 |
+
prompt: state.imagePrompt
|
249 |
+
};
|
250 |
+
} else {
|
251 |
+
throw new Error('Failed to generate monster image');
|
252 |
+
}
|
253 |
+
} catch (error) {
|
254 |
+
handleAPIError(error);
|
255 |
}
|
256 |
}
|
257 |
|