diff --git a/src/App.js b/src/App.js index 30e7fd6..e10fea7 100644 --- a/src/App.js +++ b/src/App.js @@ -23,6 +23,8 @@ export default function App() { const [isSending, setIsSending] = useState(false); const [isBotTyping, setIsBotTyping] = useState(false); + const [rethinkTargetIdx, setRethinkTargetIdx] = useState(null); + const bottomRef = useRef(null); useEffect(() => { @@ -67,6 +69,49 @@ export default function App() { setIsSending(false); } + async function handleRethink(targetIdx) { + if (isSending || isBotTyping) return; + const target = messages[targetIdx]; + if (!target || target.role !== "assistant") return; + + setRethinkTargetIdx(targetIdx); + setIsBotTyping(true); + + // 把目标消息内容替换成占位文本 + setMessages((prev) => { + const next = [...prev]; + next[targetIdx] = { ...next[targetIdx], content: "正在重新思考…" }; + return next; + }); + + // 用“该条 assistant 之前的历史” + 重新思考指令 + const before = messages.slice(0, targetIdx); + const historyForModel = [ + { role: "system", content: "你是一个简洁的助手,用中文回答。" }, + ...before.map(({ role, content }) => ({ role, content })), + { + role: "user", + content: "我对你刚才的回答不满意。请重新思考并改进:更准确、更有条理;如有错误请纠正;尽量避免重复原句。", + }, + ]; + + let newReply = ""; + try { + newReply = await requestBotReply(historyForModel); + } catch (e) { + newReply = "重新思考失败了,请稍后再试。"; + } + + // 覆盖原来的那条 assistant 内容 + setMessages((prev) => { + const next = [...prev]; + next[targetIdx] = { ...next[targetIdx], content: newReply }; + return next; + }); + setIsBotTyping(false); + setRethinkTargetIdx(null); + } + function handleKeyDown(e) { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); @@ -78,26 +123,29 @@ export default function App() {
- {/* 顶部 */} - -
- Chatbot Demo - - -
+ + Chatbot Demo - {/* 聊天区域 */} -
- {messages.map((m) => { +
+ {messages.map((m, idx) => { const isUser = m.role === "user"; + const isAssistant = m.role === "assistant"; + const isInitialGreeting = idx === 0; + const canRethink = isAssistant && !isInitialGreeting; + return ( -
-
+
+ {/* 以气泡为参照:按钮放在气泡“下面的右侧” */} +
+ {/* 气泡 */}
{m.content}
+ + {/* 在气泡下方*/} + {canRethink && ( + + )}
); })} - {isBotTyping && ( + + {/* 全局“正在回复…” */} + {isBotTyping && rethinkTargetIdx === null && (
-
-
- - 正在回复… -
+
+ + 正在回复…
)} @@ -130,35 +211,32 @@ export default function App() { {/* 输入区 */}
- {/* 这个容器视觉上就是“一个输入框” */}
- {/* 上半部分:真正可滚动/可拖拉的 textarea */}