needware-cli 1.7.3 → 1.7.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -361,14 +361,6 @@ export async function streamChat({
|
|
|
361
361
|
|
|
362
362
|
if (!resp.ok) {
|
|
363
363
|
const errorData = await resp.json().catch(() => ({}));
|
|
364
|
-
if (resp.status === 429) {
|
|
365
|
-
onError(errorData.error || "Request rate too high, please try again later");
|
|
366
|
-
return;
|
|
367
|
-
}
|
|
368
|
-
if (resp.status === 402) {
|
|
369
|
-
onError(errorData.error || "Insufficient quota, please recharge to continue");
|
|
370
|
-
return;
|
|
371
|
-
}
|
|
372
364
|
onError(errorData.error || "Connection failed, please retry");
|
|
373
365
|
return;
|
|
374
366
|
}
|
|
@@ -590,107 +582,39 @@ Requirements:
|
|
|
590
582
|
}),
|
|
591
583
|
});
|
|
592
584
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
console.error("AI service error:", response.status, errorText);
|
|
596
|
-
|
|
597
|
-
if (response.status === 429) {
|
|
598
|
-
return new Response(
|
|
599
|
-
JSON.stringify({ error: "Request rate too high, please try again later" }),
|
|
600
|
-
{ status: 429, headers: { "Content-Type": "application/json", ...corsHeaders } }
|
|
601
|
-
);
|
|
602
|
-
}
|
|
585
|
+
// 非流式响应
|
|
586
|
+
const result = await response.json();
|
|
603
587
|
|
|
604
|
-
if (response.status === 402) {
|
|
605
|
-
return new Response(
|
|
606
|
-
JSON.stringify({ error: "AI service quota exhausted" }),
|
|
607
|
-
{ status: 402, headers: { "Content-Type": "application/json", ...corsHeaders } }
|
|
608
|
-
);
|
|
609
|
-
}
|
|
610
588
|
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
errorMessage = errorJson.error?.message || errorJson.message || errorMessage;
|
|
615
|
-
} catch {
|
|
616
|
-
if (errorText) errorMessage = errorText.slice(0, 200);
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
return new Response(
|
|
620
|
-
JSON.stringify({ error: errorMessage }),
|
|
621
|
-
{ status: 500, headers: { "Content-Type": "application/json", ...corsHeaders } }
|
|
622
|
-
);
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
const data = await response.json();
|
|
626
|
-
console.log("AI response:", JSON.stringify(data, null, 2));
|
|
627
|
-
|
|
628
|
-
// ⚠️ IMPORTANT: Parse image from multiple possible response formats
|
|
629
|
-
let generatedImage: string | null = null;
|
|
630
|
-
const message = data.choices?.[0]?.message;
|
|
631
|
-
|
|
632
|
-
// Format 1: content_parts (Gemini native format)
|
|
633
|
-
if (message?.content_parts && Array.isArray(message.content_parts)) {
|
|
634
|
-
for (const part of message.content_parts) {
|
|
635
|
-
if (part.inline_data?.data) {
|
|
636
|
-
const mimeType = part.inline_data.mime_type || "image/png";
|
|
637
|
-
generatedImage = `data:${mimeType};base64,${part.inline_data.data}`;
|
|
638
|
-
break;
|
|
639
|
-
}
|
|
640
|
-
}
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
// Format 2: content array with various structures
|
|
644
|
-
if (!generatedImage && Array.isArray(message?.content)) {
|
|
645
|
-
for (const item of message.content) {
|
|
646
|
-
if (item.type === "image_url" && item.image_url?.url) {
|
|
647
|
-
generatedImage = item.image_url.url;
|
|
648
|
-
break;
|
|
649
|
-
}
|
|
650
|
-
if (item.type === "image" && item.data) {
|
|
651
|
-
generatedImage = `data:image/png;base64,${item.data}`;
|
|
652
|
-
break;
|
|
653
|
-
}
|
|
654
|
-
if (item.inline_data?.data) {
|
|
655
|
-
const mimeType = item.inline_data.mime_type || "image/png";
|
|
656
|
-
generatedImage = `data:${mimeType};base64,${item.inline_data.data}`;
|
|
657
|
-
break;
|
|
658
|
-
}
|
|
659
|
-
}
|
|
660
|
-
}
|
|
589
|
+
// 解析响应,提取生成的图片
|
|
590
|
+
let generatedImageUrl: string | null = null;
|
|
591
|
+
let textContent: string | null = null;
|
|
661
592
|
|
|
662
|
-
//
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
} else if (message.content.length > 1000 && /^[A-Za-z0-9+/=\s]+$/.test(message.content)) {
|
|
667
|
-
// Looks like raw base64 data
|
|
668
|
-
generatedImage = `data:image/png;base64,${message.content.replace(/\s/g, '')}`;
|
|
669
|
-
}
|
|
593
|
+
// 从正确的路径获取图片 URL
|
|
594
|
+
const images = result.choices?.[0]?.message?.images;
|
|
595
|
+
if (images && images.length > 0 && images[0].image_url?.url) {
|
|
596
|
+
generatedImageUrl = images[0].image_url.url;
|
|
670
597
|
}
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
return new Response(
|
|
677
|
-
JSON.stringify({
|
|
678
|
-
error: "AI failed to generate try-on image, please retry or use a different photo",
|
|
679
|
-
debug: reasoning ? reasoning.slice(0, 100) : "Unable to extract image"
|
|
680
|
-
}),
|
|
681
|
-
{ status: 500, headers: { "Content-Type": "application/json", ...corsHeaders } }
|
|
682
|
-
);
|
|
598
|
+
|
|
599
|
+
// 获取文本内容
|
|
600
|
+
const messageContent = result.choices?.[0]?.message?.content;
|
|
601
|
+
if (typeof messageContent === 'string') {
|
|
602
|
+
textContent = messageContent;
|
|
683
603
|
}
|
|
684
604
|
|
|
685
|
-
|
|
605
|
+
// 包装响应 - 返回简洁的格式
|
|
606
|
+
const virtualTryOnResponse = {
|
|
607
|
+
resultImage: generatedImageUrl,
|
|
608
|
+
message: generatedImageUrl ? "换装效果生成成功" : "未能生成图片,请重试",
|
|
609
|
+
};
|
|
686
610
|
|
|
687
|
-
return new Response(
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
);
|
|
611
|
+
return new Response(JSON.stringify(virtualTryOnResponse), {
|
|
612
|
+
status: response.ok ? 200 : response.status,
|
|
613
|
+
headers: {
|
|
614
|
+
"Content-Type": "application/json",
|
|
615
|
+
...corsHeaders
|
|
616
|
+
},
|
|
617
|
+
});
|
|
694
618
|
|
|
695
619
|
} catch (error: any) {
|
|
696
620
|
console.error("Virtual try-on error:", error);
|
|
@@ -945,30 +869,6 @@ pnpm add @supabase/supabase-js
|
|
|
945
869
|
- ✅ Implement usage monitoring and alerts
|
|
946
870
|
- ✅ Consider using batch processing to reduce costs
|
|
947
871
|
|
|
948
|
-
## Error Handling Checklist
|
|
949
|
-
|
|
950
|
-
```typescript
|
|
951
|
-
// Standard error handling pattern
|
|
952
|
-
const handleAIError = (error: any, statusCode: number) => {
|
|
953
|
-
const errorMap: Record<number, string> = {
|
|
954
|
-
400: "Invalid request parameters",
|
|
955
|
-
401: "Authentication failed",
|
|
956
|
-
402: "Insufficient account balance or quota exhausted",
|
|
957
|
-
403: "No permission to access this API",
|
|
958
|
-
404: "API endpoint does not exist",
|
|
959
|
-
429: "Too many requests, please try again later",
|
|
960
|
-
500: "AI service internal error",
|
|
961
|
-
503: "AI service temporarily unavailable",
|
|
962
|
-
};
|
|
963
|
-
|
|
964
|
-
return {
|
|
965
|
-
error: errorMap[statusCode] || "Unknown error",
|
|
966
|
-
statusCode,
|
|
967
|
-
originalError: error?.message,
|
|
968
|
-
timestamp: new Date().toISOString(),
|
|
969
|
-
};
|
|
970
|
-
};
|
|
971
|
-
```
|
|
972
872
|
|
|
973
873
|
## When NOT to Use This Skill
|
|
974
874
|
|
|
@@ -977,15 +877,3 @@ const handleAIError = (error: any, statusCode: number) => {
|
|
|
977
877
|
- Pure data processing logic (no AI inference needed)
|
|
978
878
|
- Static content display
|
|
979
879
|
- User is just asking about AI concepts (just provide explanation)
|
|
980
|
-
|
|
981
|
-
## Final Reminders
|
|
982
|
-
|
|
983
|
-
**After completing AI integration, must:**
|
|
984
|
-
1. ✅ Test all error scenarios
|
|
985
|
-
2. ✅ Check response format correctness
|
|
986
|
-
3. ✅ Test edge cases (extra-long input, special characters, etc.)
|
|
987
|
-
4. ✅ Confirm smooth user experience
|
|
988
|
-
5. ✅ Add usage documentation and examples
|
|
989
|
-
|
|
990
|
-
**Remember: AI integration is not "set it and forget it", requires continuous monitoring and optimization.**
|
|
991
|
-
|
|
File without changes
|