SarahXia0405 commited on
Commit
9f08e41
·
verified ·
1 Parent(s): 129e5c1

Update web/src/App.tsx

Browse files
Files changed (1) hide show
  1. web/src/App.tsx +46 -26
web/src/App.tsx CHANGED
@@ -611,42 +611,62 @@ function App() {
611
  return "Syllabus";
612
  };
613
 
614
- const handleSendMessage = async (content: string) => {
615
- if (!content.trim() || !user) return;
616
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
617
  const sender: GroupMember = {
618
  id: user.email,
619
  name: user.name,
620
  email: user.email,
621
  avatar: `https://api.dicebear.com/7.x/avataaars/svg?seed=${encodeURIComponent(user.email)}`,
622
  };
623
-
 
 
 
 
 
624
  const userMessage: Message = {
625
  id: Date.now().toString(),
626
  role: "user",
627
- content,
628
  timestamp: new Date(),
629
  sender,
630
  };
631
-
632
  if (chatMode === "ask") setAskMessages((prev) => [...prev, userMessage]);
633
  else if (chatMode === "review") setReviewMessages((prev) => [...prev, userMessage]);
634
  else setQuizMessages((prev) => [...prev, userMessage]);
635
-
636
  if (chatMode === "quiz") {
637
  setIsTyping(true);
638
-
639
  try {
640
  const docType = getCurrentDocTypeForChat();
641
-
642
  const r = await apiChat({
643
  user_id: user.email,
644
- message: content,
645
  learning_mode: "quiz",
646
  language_preference: mapLanguagePref(language),
647
  doc_type: docType,
648
  });
649
-
650
  const refs = (r.refs || [])
651
  .map((x) => {
652
  const a = x?.source_file ? String(x.source_file) : "";
@@ -655,7 +675,7 @@ function App() {
655
  return s || null;
656
  })
657
  .filter(Boolean) as string[];
658
-
659
  const assistantMessage: Message = {
660
  id: (Date.now() + 1).toString(),
661
  role: "assistant",
@@ -665,9 +685,9 @@ function App() {
665
  sender: spaceType === "group" ? groupMembers.find((m) => m.isAI) : undefined,
666
  showNextButton: false,
667
  };
668
-
669
  setIsTyping(false);
670
-
671
  setTimeout(() => {
672
  setQuizMessages((prev) => [...prev, assistantMessage]);
673
  setQuizState((prev) => ({ ...prev, waitingForAnswer: true, showNextButton: false }));
@@ -675,7 +695,7 @@ function App() {
675
  } catch (e: any) {
676
  setIsTyping(false);
677
  toast.error(e?.message || "Quiz failed");
678
-
679
  const assistantMessage: Message = {
680
  id: (Date.now() + 1).toString(),
681
  role: "assistant",
@@ -683,27 +703,27 @@ function App() {
683
  timestamp: new Date(),
684
  sender: spaceType === "group" ? groupMembers.find((m) => m.isAI) : undefined,
685
  };
686
-
687
  setTimeout(() => {
688
  setQuizMessages((prev) => [...prev, assistantMessage]);
689
  }, 50);
690
  }
691
-
692
  return;
693
  }
694
-
695
  setIsTyping(true);
696
  try {
697
  const docType = getCurrentDocTypeForChat();
698
-
699
  const r = await apiChat({
700
  user_id: user.email,
701
- message: content,
702
  learning_mode: learningMode,
703
  language_preference: mapLanguagePref(language),
704
  doc_type: docType,
705
  });
706
-
707
  const refs = (r.refs || [])
708
  .map((x) => {
709
  const a = x?.source_file ? String(x.source_file) : "";
@@ -712,7 +732,7 @@ function App() {
712
  return s || null;
713
  })
714
  .filter(Boolean) as string[];
715
-
716
  const assistantMessage: Message = {
717
  id: (Date.now() + 1).toString(),
718
  role: "assistant",
@@ -721,14 +741,14 @@ function App() {
721
  references: refs.length ? refs : undefined,
722
  sender: spaceType === "group" ? groupMembers.find((m) => m.isAI) : undefined,
723
  };
724
-
725
  setIsTyping(false);
726
-
727
  setTimeout(() => {
728
  if (chatMode === "ask") setAskMessages((prev) => [...prev, assistantMessage]);
729
  else if (chatMode === "review") setReviewMessages((prev) => [...prev, assistantMessage]);
730
  }, 50);
731
-
732
  try {
733
  const ml = await apiMemoryline(user.email);
734
  setMemoryProgress(Math.round((ml.progress_pct ?? 0) * 100));
@@ -738,7 +758,7 @@ function App() {
738
  } catch (e: any) {
739
  setIsTyping(false);
740
  toast.error(e?.message || "Chat failed");
741
-
742
  const assistantMessage: Message = {
743
  id: (Date.now() + 1).toString(),
744
  role: "assistant",
@@ -746,7 +766,7 @@ function App() {
746
  timestamp: new Date(),
747
  sender: spaceType === "group" ? groupMembers.find((m) => m.isAI) : undefined,
748
  };
749
-
750
  setTimeout(() => {
751
  if (chatMode === "ask") setAskMessages((prev) => [...prev, assistantMessage]);
752
  if (chatMode === "review") setReviewMessages((prev) => [...prev, assistantMessage]);
 
611
  return "Syllabus";
612
  };
613
 
 
 
614
 
615
+ const handleSendMessage = async (content: string) => {
616
+ if (!user) return;
617
+
618
+ const hasText = !!content.trim();
619
+ const hasFiles = uploadedFiles.length > 0;
620
+
621
+ // ✅ 允许“只发文件不发文字”
622
+ if (!hasText && !hasFiles) return;
623
+
624
+ // ✅ 如果用户没写字,但上传了文件:构造一条后端可用的 message
625
+ const fileNames = hasFiles ? uploadedFiles.map((f) => f.file.name) : [];
626
+ const fileLine = fileNames.length ? `Uploaded files: ${fileNames.join(", ")}` : "";
627
+
628
+ const effectiveContent = hasText
629
+ ? content
630
+ : `I've uploaded file(s). Please read them and help me based on their content.\n${fileLine}`.trim();
631
+
632
  const sender: GroupMember = {
633
  id: user.email,
634
  name: user.name,
635
  email: user.email,
636
  avatar: `https://api.dicebear.com/7.x/avataaars/svg?seed=${encodeURIComponent(user.email)}`,
637
  };
638
+
639
+ // ✅ 用户消息在 UI 里也要可见(否则会出现空白气泡)
640
+ const userVisibleContent = hasText
641
+ ? content
642
+ : `📎 Sent ${fileNames.length} file(s)\n${fileNames.map((n) => `- ${n}`).join("\n")}`;
643
+
644
  const userMessage: Message = {
645
  id: Date.now().toString(),
646
  role: "user",
647
+ content: userVisibleContent,
648
  timestamp: new Date(),
649
  sender,
650
  };
651
+
652
  if (chatMode === "ask") setAskMessages((prev) => [...prev, userMessage]);
653
  else if (chatMode === "review") setReviewMessages((prev) => [...prev, userMessage]);
654
  else setQuizMessages((prev) => [...prev, userMessage]);
655
+
656
  if (chatMode === "quiz") {
657
  setIsTyping(true);
658
+
659
  try {
660
  const docType = getCurrentDocTypeForChat();
661
+
662
  const r = await apiChat({
663
  user_id: user.email,
664
+ message: effectiveContent,
665
  learning_mode: "quiz",
666
  language_preference: mapLanguagePref(language),
667
  doc_type: docType,
668
  });
669
+
670
  const refs = (r.refs || [])
671
  .map((x) => {
672
  const a = x?.source_file ? String(x.source_file) : "";
 
675
  return s || null;
676
  })
677
  .filter(Boolean) as string[];
678
+
679
  const assistantMessage: Message = {
680
  id: (Date.now() + 1).toString(),
681
  role: "assistant",
 
685
  sender: spaceType === "group" ? groupMembers.find((m) => m.isAI) : undefined,
686
  showNextButton: false,
687
  };
688
+
689
  setIsTyping(false);
690
+
691
  setTimeout(() => {
692
  setQuizMessages((prev) => [...prev, assistantMessage]);
693
  setQuizState((prev) => ({ ...prev, waitingForAnswer: true, showNextButton: false }));
 
695
  } catch (e: any) {
696
  setIsTyping(false);
697
  toast.error(e?.message || "Quiz failed");
698
+
699
  const assistantMessage: Message = {
700
  id: (Date.now() + 1).toString(),
701
  role: "assistant",
 
703
  timestamp: new Date(),
704
  sender: spaceType === "group" ? groupMembers.find((m) => m.isAI) : undefined,
705
  };
706
+
707
  setTimeout(() => {
708
  setQuizMessages((prev) => [...prev, assistantMessage]);
709
  }, 50);
710
  }
711
+
712
  return;
713
  }
714
+
715
  setIsTyping(true);
716
  try {
717
  const docType = getCurrentDocTypeForChat();
718
+
719
  const r = await apiChat({
720
  user_id: user.email,
721
+ message: effectiveContent,
722
  learning_mode: learningMode,
723
  language_preference: mapLanguagePref(language),
724
  doc_type: docType,
725
  });
726
+
727
  const refs = (r.refs || [])
728
  .map((x) => {
729
  const a = x?.source_file ? String(x.source_file) : "";
 
732
  return s || null;
733
  })
734
  .filter(Boolean) as string[];
735
+
736
  const assistantMessage: Message = {
737
  id: (Date.now() + 1).toString(),
738
  role: "assistant",
 
741
  references: refs.length ? refs : undefined,
742
  sender: spaceType === "group" ? groupMembers.find((m) => m.isAI) : undefined,
743
  };
744
+
745
  setIsTyping(false);
746
+
747
  setTimeout(() => {
748
  if (chatMode === "ask") setAskMessages((prev) => [...prev, assistantMessage]);
749
  else if (chatMode === "review") setReviewMessages((prev) => [...prev, assistantMessage]);
750
  }, 50);
751
+
752
  try {
753
  const ml = await apiMemoryline(user.email);
754
  setMemoryProgress(Math.round((ml.progress_pct ?? 0) * 100));
 
758
  } catch (e: any) {
759
  setIsTyping(false);
760
  toast.error(e?.message || "Chat failed");
761
+
762
  const assistantMessage: Message = {
763
  id: (Date.now() + 1).toString(),
764
  role: "assistant",
 
766
  timestamp: new Date(),
767
  sender: spaceType === "group" ? groupMembers.find((m) => m.isAI) : undefined,
768
  };
769
+
770
  setTimeout(() => {
771
  if (chatMode === "ask") setAskMessages((prev) => [...prev, assistantMessage]);
772
  if (chatMode === "review") setReviewMessages((prev) => [...prev, assistantMessage]);