From afd6f81437ef5363ba6270e2e900bca16c67efeb Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 19 Jan 2026 03:45:14 +0000 Subject: [PATCH] feat: Add settings modal to customize AI system prompt This commit introduces a new feature that allows users to customize the AI's system prompt. - A new `SettingsModal` component has been created to provide the UI for editing the prompt. - A "Settings" button has been added to the header to open the modal. - The custom system prompt is saved to `localStorage` to persist the setting between sessions. - The AI generation logic now uses the custom prompt if it exists, otherwise it falls back to the default prompt. --- src/App.css | 48 ++++++++++++++++++++++++++++ src/App.jsx | 74 ++++++++++++++++++++++++++++++++++--------- src/SettingsModal.jsx | 29 +++++++++++++++++ 3 files changed, 136 insertions(+), 15 deletions(-) create mode 100644 src/SettingsModal.jsx diff --git a/src/App.css b/src/App.css index b9d355d..5191def 100644 --- a/src/App.css +++ b/src/App.css @@ -1,3 +1,51 @@ +.modal-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.7); + display: flex; + justify-content: center; + align-items: center; + z-index: 1000; +} + +.modal-content { + background-color: #2a2a2a; + padding: 2rem; + border-radius: 12px; + width: 500px; + max-width: 90%; + color: #fff; + box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3); +} + +.modal-content h2 { + margin-top: 0; +} + +.modal-content p { + color: #ccc; + line-height: 1.6; +} + +.modal-actions { + display: flex; + justify-content: flex-end; + gap: 1rem; + margin-top: 1.5rem; +} + +.modal-actions button { + padding: 10px 20px; + color: white; + border: none; + border-radius: 8px; + font-weight: bold; + cursor: pointer; +} + #root { max-width: 1280px; margin: 0 auto; diff --git a/src/App.jsx b/src/App.jsx index 5f3df15..68d68cd 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -11,12 +11,25 @@ import 'reactflow/dist/style.css'; import axios from 'axios'; import html2canvas from 'html2canvas'; import { saveAs } from 'file-saver'; +import SettingsModal from './SettingsModal'; // 🧠 Initial State & Helpers const initialNodes = []; const initialEdges = []; let nodeId = 1; +const defaultSystemPrompt = `You are an expert in cause-and-effect analysis. + +Given a news headline or event, break it down into a chain of consequences, like a domino effect. + +Each node must: +- Be short (max 15 words) +- Represent one specific consequence +- Be categorized as either: 'positive', 'neutral', or 'negative' +- Be logically linked to the prompt + +Return only 3 outputs: one of each type.`; + const getColor = (type) => { switch (type) { case 'positive': return '#00c853'; @@ -27,7 +40,7 @@ const getColor = (type) => { }; // 🤖 AI Logic with Domino Effect Thinking (Updated: Using Puter AI API) -const createAIChildren = async (text, parentId, setNodes, setEdges, stopGenerationRef) => { +const createAIChildren = async (text, parentId, setNodes, setEdges, stopGenerationRef, systemPrompt) => { try { if (stopGenerationRef.current) return; const res = await axios.post( @@ -37,17 +50,7 @@ const createAIChildren = async (text, parentId, setNodes, setEdges, stopGenerati messages: [ { role: 'system', - content: `You are an expert in cause-and-effect analysis. - -Given a news headline or event, break it down into a chain of consequences, like a domino effect. - -Each node must: -- Be short (max 15 words) -- Represent one specific consequence -- Be categorized as either: 'positive', 'neutral', or 'negative' -- Be logically linked to the prompt - -Return only 3 outputs: one of each type.` + content: systemPrompt }, { role: 'user', content: text } ] @@ -96,7 +99,7 @@ Return only 3 outputs: one of each type.` // Recursively expand each child one level deep for (const n of newNodes) { if (stopGenerationRef.current) break; - await createAIChildren(n.data.label, n.id, setNodes, setEdges, stopGenerationRef); + await createAIChildren(n.data.label, n.id, setNodes, setEdges, stopGenerationRef, systemPrompt); } } catch (err) { @@ -113,6 +116,11 @@ export default function App() { const [edges, setEdges] = useState(initialEdges); const [prompt, setPrompt] = useState(''); const [loading, setLoading] = useState(false); + const [isModalOpen, setIsModalOpen] = useState(false); + const [systemPrompt, setSystemPrompt] = useState( + localStorage.getItem('customSystemPrompt') || defaultSystemPrompt + ); + const [tempSystemPrompt, setTempSystemPrompt] = useState(systemPrompt); const stopGenerationRef = useRef(false); const reactFlowWrapper = useRef(null); @@ -150,7 +158,7 @@ export default function App() { setNodes([rootNode]); setEdges([]); - await createAIChildren(prompt, rootId, setNodes, setEdges, stopGenerationRef); + await createAIChildren(prompt, rootId, setNodes, setEdges, stopGenerationRef, systemPrompt); setPrompt(''); setLoading(false); @@ -164,12 +172,34 @@ export default function App() { const onNodeClick = async (_event, node) => { stopGenerationRef.current = false; setLoading(true); - await createAIChildren(node.data.label, node.id, setNodes, setEdges, stopGenerationRef); + await createAIChildren(node.data.label, node.id, setNodes, setEdges, stopGenerationRef, systemPrompt); setLoading(false); }; + const handleOpenModal = () => { + setTempSystemPrompt(systemPrompt); + setIsModalOpen(true); + }; + + const handleCloseModal = () => { + setIsModalOpen(false); + }; + + const handleSaveSettings = () => { + localStorage.setItem('customSystemPrompt', tempSystemPrompt); + setSystemPrompt(tempSystemPrompt); + setIsModalOpen(false); + }; + return (
+ {/* 🔝 Header */}
Export as PNG +
diff --git a/src/SettingsModal.jsx b/src/SettingsModal.jsx new file mode 100644 index 0000000..30ca085 --- /dev/null +++ b/src/SettingsModal.jsx @@ -0,0 +1,29 @@ +// ⚙️ SettingsModal.jsx +import React from 'react'; + +const SettingsModal = ({ isOpen, onClose, onSave, systemPrompt, setSystemPrompt }) => { + if (!isOpen) return null; + + return ( +
+
+

⚙️ AI Settings

+

Customize the AI's instructions to tailor its responses to your needs.

+ +