mirror of
https://github.com/QuantumNous/new-api.git
synced 2026-04-29 09:58:37 +00:00
✨ feat: Add custom request body editor with persistent message storage
- Add CustomRequestEditor component with JSON validation and real-time formatting - Implement bidirectional sync between chat messages and custom request body - Add persistent local storage for chat messages (separate from config) - Remove redundant System Prompt field in custom mode - Refactor configuration storage to separate messages and settings New Features: • Custom request body mode with JSON editor and syntax highlighting • Real-time bidirectional synchronization between chat UI and custom request body • Persistent message storage that survives page refresh • Enhanced configuration export/import including message data • Improved parameter organization with collapsible sections Technical Changes: • Add loadMessages/saveMessages functions in configStorage • Update usePlaygroundState hook to handle message persistence • Refactor SettingsPanel to remove System Prompt in custom mode • Add STORAGE_KEYS constants for better storage key management • Implement debounced auto-save for both config and messages • Add hash-based change detection to prevent unnecessary updates UI/UX Improvements: • Disabled state styling for parameters in custom mode • Warning banners and visual feedback for mode switching • Mobile-responsive design for custom request editor • Consistent styling with existing design system
This commit is contained in:
111
web/src/hooks/useSyncMessageAndCustomBody.js
Normal file
111
web/src/hooks/useSyncMessageAndCustomBody.js
Normal file
@@ -0,0 +1,111 @@
|
||||
import { useCallback, useRef } from 'react';
|
||||
import { MESSAGE_ROLES } from '../utils/constants';
|
||||
|
||||
export const useSyncMessageAndCustomBody = (
|
||||
customRequestMode,
|
||||
customRequestBody,
|
||||
message,
|
||||
inputs,
|
||||
setCustomRequestBody,
|
||||
setMessage,
|
||||
debouncedSaveConfig
|
||||
) => {
|
||||
const isUpdatingFromMessage = useRef(false);
|
||||
const isUpdatingFromCustomBody = useRef(false);
|
||||
const lastMessageHash = useRef('');
|
||||
const lastCustomBodyHash = useRef('');
|
||||
|
||||
const getMessageHash = useCallback((messages) => {
|
||||
return JSON.stringify(messages.map(msg => ({
|
||||
id: msg.id,
|
||||
role: msg.role,
|
||||
content: msg.content
|
||||
})));
|
||||
}, []);
|
||||
|
||||
const getCustomBodyHash = useCallback((customBody) => {
|
||||
try {
|
||||
const parsed = JSON.parse(customBody);
|
||||
return JSON.stringify(parsed.messages || []);
|
||||
} catch {
|
||||
return '';
|
||||
}
|
||||
}, []);
|
||||
|
||||
const syncMessageToCustomBody = useCallback(() => {
|
||||
if (!customRequestMode || isUpdatingFromCustomBody.current) return;
|
||||
|
||||
const currentMessageHash = getMessageHash(message);
|
||||
if (currentMessageHash === lastMessageHash.current) return;
|
||||
|
||||
try {
|
||||
isUpdatingFromMessage.current = true;
|
||||
let customPayload;
|
||||
|
||||
try {
|
||||
customPayload = JSON.parse(customRequestBody || '{}');
|
||||
} catch {
|
||||
customPayload = {
|
||||
model: inputs.model || 'gpt-4o',
|
||||
messages: [],
|
||||
temperature: inputs.temperature || 0.7,
|
||||
stream: inputs.stream !== false
|
||||
};
|
||||
}
|
||||
|
||||
customPayload.messages = message.map(msg => ({
|
||||
role: msg.role,
|
||||
content: msg.content
|
||||
}));
|
||||
|
||||
const newCustomBody = JSON.stringify(customPayload, null, 2);
|
||||
setCustomRequestBody(newCustomBody);
|
||||
lastMessageHash.current = currentMessageHash;
|
||||
lastCustomBodyHash.current = getCustomBodyHash(newCustomBody);
|
||||
|
||||
setTimeout(() => {
|
||||
debouncedSaveConfig();
|
||||
}, 0);
|
||||
} finally {
|
||||
isUpdatingFromMessage.current = false;
|
||||
}
|
||||
}, [customRequestMode, customRequestBody, message, inputs.model, inputs.temperature, inputs.stream, getMessageHash, getCustomBodyHash, setCustomRequestBody, debouncedSaveConfig]);
|
||||
|
||||
const syncCustomBodyToMessage = useCallback(() => {
|
||||
if (!customRequestMode || isUpdatingFromMessage.current) return;
|
||||
|
||||
const currentCustomBodyHash = getCustomBodyHash(customRequestBody);
|
||||
if (currentCustomBodyHash === lastCustomBodyHash.current) return;
|
||||
|
||||
try {
|
||||
isUpdatingFromCustomBody.current = true;
|
||||
const customPayload = JSON.parse(customRequestBody || '{}');
|
||||
|
||||
if (customPayload.messages && Array.isArray(customPayload.messages)) {
|
||||
const newMessages = customPayload.messages.map((msg, index) => ({
|
||||
id: msg.id || (index + 1).toString(),
|
||||
role: msg.role || MESSAGE_ROLES.USER,
|
||||
content: msg.content || '',
|
||||
createAt: Date.now(),
|
||||
...(msg.role === MESSAGE_ROLES.ASSISTANT && {
|
||||
reasoningContent: msg.reasoningContent || '',
|
||||
isReasoningExpanded: false
|
||||
})
|
||||
}));
|
||||
|
||||
setMessage(newMessages);
|
||||
lastCustomBodyHash.current = currentCustomBodyHash;
|
||||
lastMessageHash.current = getMessageHash(newMessages);
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('同步自定义请求体到消息失败:', error);
|
||||
} finally {
|
||||
isUpdatingFromCustomBody.current = false;
|
||||
}
|
||||
}, [customRequestMode, customRequestBody, getCustomBodyHash, getMessageHash, setMessage]);
|
||||
|
||||
return {
|
||||
syncMessageToCustomBody,
|
||||
syncCustomBodyToMessage
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user