needware-cli 1.7.2 → 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.
@@ -358,7 +358,7 @@ Since the codebase is a template, you should not assume they have set up anythin
358
358
 
359
359
  - Then list what features you'll implement in this first version. It's a first version so the user will be able to iterate on it. Don't do too much, but make it look good.
360
360
 
361
- - List possible colors, gradients, animations, fonts and styles you'll use if relevant. Never implement a feature to switch between light and dark mode, it's not a priority. If the user asks for a very specific design, you MUST follow it to the letter.
361
+ - List possible colors, gradients, animations, fonts and styles you'll use if relevant. Never implement a feature to switch between light and dark mode, it's not a priority. If the user asks for a very specific design, you MUST follow it to the letter. IMPORTANT: Do NOT use purple as the primary color theme unless explicitly requested by the user.
362
362
 
363
363
  - When implementing:
364
364
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "needware-cli",
3
- "version": "1.7.2",
3
+ "version": "1.7.5",
4
4
  "description": "一个功能强大的 Node.js 命令行工具",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -590,107 +590,60 @@ Requirements:
590
590
  }),
591
591
  });
592
592
 
593
- if (!response.ok) {
594
- const errorText = await response.text();
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
- return new Response(
620
- JSON.stringify({ error: errorMessage }),
621
- { status: 500, headers: { "Content-Type": "application/json", ...corsHeaders } }
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
- // 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;
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
- // Format 3: Direct base64 string in content
663
- if (!generatedImage && typeof message?.content === "string" && message.content) {
664
- if (message.content.startsWith("data:image")) {
665
- generatedImage = message.content;
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, '')}`;
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
- if (!generatedImage) {
673
- const reasoning = message?.reasoning;
674
- console.error("No image in response. Full response:", JSON.stringify(data));
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
- );
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
- JSON.stringify({
689
- success: true,
690
- image: generatedImage
691
- }),
692
- { status: 200, headers: { "Content-Type": "application/json", ...corsHeaders } }
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);