MVP - Phase One Complete
This commit is contained in:
@@ -5,11 +5,13 @@ const WS_URL = 'ws://localhost:8000';
|
||||
|
||||
function StorytellerView({ sessionId }) {
|
||||
const [characters, setCharacters] = useState({});
|
||||
const [publicMessages, setPublicMessages] = useState([]);
|
||||
const [selectedCharacter, setSelectedCharacter] = useState(null);
|
||||
const [responseText, setResponseText] = useState('');
|
||||
const [sceneText, setSceneText] = useState('');
|
||||
const [currentScene, setCurrentScene] = useState('');
|
||||
const [isConnected, setIsConnected] = useState(false);
|
||||
const [isGeneratingSuggestion, setIsGeneratingSuggestion] = useState(false);
|
||||
const wsRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -27,6 +29,7 @@ function StorytellerView({ sessionId }) {
|
||||
if (data.type === 'session_state') {
|
||||
setCharacters(data.characters || {});
|
||||
setCurrentScene(data.current_scene || '');
|
||||
setPublicMessages(data.public_messages || []);
|
||||
} else if (data.type === 'character_message') {
|
||||
// Update character with new message
|
||||
setCharacters(prev => ({
|
||||
@@ -110,6 +113,30 @@ function StorytellerView({ sessionId }) {
|
||||
setSceneText('');
|
||||
};
|
||||
|
||||
const getSuggestion = async () => {
|
||||
if (!selectedCharacter || isGeneratingSuggestion) return;
|
||||
|
||||
setIsGeneratingSuggestion(true);
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${API_URL}/sessions/${sessionId}/generate_suggestion?character_id=${selectedCharacter}`,
|
||||
{ method: 'POST' }
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to generate suggestion');
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
setResponseText(data.suggestion);
|
||||
} catch (error) {
|
||||
console.error('Error generating suggestion:', error);
|
||||
alert('Failed to generate AI suggestion. Please try again.');
|
||||
} finally {
|
||||
setIsGeneratingSuggestion(false);
|
||||
}
|
||||
};
|
||||
|
||||
const selectedChar = selectedCharacter ? characters[selectedCharacter] : null;
|
||||
const pendingCount = Object.values(characters).filter(c => c.pending_response).length;
|
||||
|
||||
@@ -150,6 +177,24 @@ function StorytellerView({ sessionId }) {
|
||||
Narrate Scene
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{publicMessages.length > 0 && (
|
||||
<div className="public-feed">
|
||||
<h4>📢 Public Actions Feed ({publicMessages.length})</h4>
|
||||
<div className="public-messages-list">
|
||||
{publicMessages.slice(-5).map((msg, idx) => (
|
||||
<div key={idx} className="public-message-item">
|
||||
<span className="public-msg-content">
|
||||
{msg.visibility === 'mixed' && msg.public_content ? msg.public_content : msg.content}
|
||||
</span>
|
||||
<span className="public-msg-time">
|
||||
{new Date(msg.timestamp).toLocaleTimeString()}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="storyteller-content">
|
||||
@@ -223,9 +268,18 @@ function StorytellerView({ sessionId }) {
|
||||
onChange={(e) => setResponseText(e.target.value)}
|
||||
rows="4"
|
||||
/>
|
||||
<button className="btn-primary" onClick={sendResponse} disabled={!isConnected}>
|
||||
Send Private Response
|
||||
</button>
|
||||
<div className="response-buttons">
|
||||
<button
|
||||
className="btn-secondary"
|
||||
onClick={getSuggestion}
|
||||
disabled={!isConnected || isGeneratingSuggestion}
|
||||
>
|
||||
{isGeneratingSuggestion ? '⏳ Generating...' : '✨ AI Suggest'}
|
||||
</button>
|
||||
<button className="btn-primary" onClick={sendResponse} disabled={!isConnected}>
|
||||
Send Private Response
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
|
||||
Reference in New Issue
Block a user