needware-cli 1.7.3 → 1.7.5
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 +1 -1
- package/skills/ai-integration/SKILL.md +44 -91
package/package.json
CHANGED
|
@@ -590,107 +590,60 @@ Requirements:
|
|
|
590
590
|
}),
|
|
591
591
|
});
|
|
592
592
|
|
|
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
|
-
}
|
|
603
|
-
|
|
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
|
-
}
|
|
593
|
+
// 非流式响应
|
|
594
|
+
const result = await response.json();
|
|
610
595
|
|
|
611
|
-
let errorMessage = "AI service temporarily unavailable";
|
|
612
|
-
try {
|
|
613
|
-
const errorJson = JSON.parse(errorText);
|
|
614
|
-
errorMessage = errorJson.error?.message || errorJson.message || errorMessage;
|
|
615
|
-
} catch {
|
|
616
|
-
if (errorText) errorMessage = errorText.slice(0, 200);
|
|
617
|
-
}
|
|
618
596
|
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
);
|
|
623
|
-
}
|
|
597
|
+
// 解析响应,提取生成的图片
|
|
598
|
+
let generatedImageUrl: string | null = null;
|
|
599
|
+
let textContent: string | null = null;
|
|
624
600
|
|
|
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
601
|
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
if (
|
|
651
|
-
|
|
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;
|
|
602
|
+
const messageContent = result.choices?.[0]?.message?.content;
|
|
603
|
+
|
|
604
|
+
// 检查是否有图片内容
|
|
605
|
+
if (Array.isArray(messageContent)) {
|
|
606
|
+
for (const part of messageContent) {
|
|
607
|
+
if (part.type === 'image_url' && part.image_url?.url) {
|
|
608
|
+
generatedImageUrl = part.image_url.url;
|
|
609
|
+
} else if (part.type === 'text') {
|
|
610
|
+
textContent = part.text;
|
|
658
611
|
}
|
|
659
612
|
}
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
613
|
+
} else if (typeof messageContent === 'string') {
|
|
614
|
+
// 检查是否包含 base64 图片或图片 URL
|
|
615
|
+
const base64Match = messageContent.match(/data:image\/[^;]+;base64,[A-Za-z0-9+/=]+/);
|
|
616
|
+
const urlMatch = messageContent.match(/https?:\/\/[^\s"']+\.(jpg|jpeg|png|gif|webp)/i);
|
|
617
|
+
|
|
618
|
+
if (base64Match) {
|
|
619
|
+
generatedImageUrl = base64Match[0];
|
|
620
|
+
} else if (urlMatch) {
|
|
621
|
+
generatedImageUrl = urlMatch[0];
|
|
669
622
|
}
|
|
623
|
+
textContent = messageContent;
|
|
670
624
|
}
|
|
671
625
|
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
console.log("Virtual try-on completed successfully");
|
|
626
|
+
// 包装响应
|
|
627
|
+
const virtualTryOnResponse = {
|
|
628
|
+
success: response.ok,
|
|
629
|
+
data: {
|
|
630
|
+
generatedImageUrl,
|
|
631
|
+
textContent,
|
|
632
|
+
personImageUrl: body.personImageUrl,
|
|
633
|
+
garmentImageUrl: body.garmentImageUrl,
|
|
634
|
+
model: body.model || 'google/gemini-3-pro-image-preview',
|
|
635
|
+
usage: result.usage || null,
|
|
636
|
+
},
|
|
637
|
+
rawResponse: result,
|
|
638
|
+
};
|
|
686
639
|
|
|
687
|
-
return new Response(
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
);
|
|
640
|
+
return new Response(JSON.stringify(virtualTryOnResponse), {
|
|
641
|
+
status: response.status,
|
|
642
|
+
headers: {
|
|
643
|
+
"Content-Type": "application/json",
|
|
644
|
+
...corsHeaders
|
|
645
|
+
},
|
|
646
|
+
});
|
|
694
647
|
|
|
695
648
|
} catch (error: any) {
|
|
696
649
|
console.error("Virtual try-on error:", error);
|