Spaces:
Sleeping
Sleeping
| <html> | |
| <head> | |
| <title>Chat System with LLM Proxy</title> | |
| <style> | |
| body { | |
| font-family: Arial, sans-serif; | |
| margin: 0; | |
| padding: 20px; | |
| } | |
| .container { | |
| display: flex; | |
| gap: 20px; | |
| height: 90vh; | |
| } | |
| .panel { | |
| flex: 1; | |
| border: 1px solid #ddd; | |
| border-radius: 8px; | |
| padding: 15px; | |
| display: flex; | |
| flex-direction: column; | |
| } | |
| h2 { | |
| margin-top: 0; | |
| border-bottom: 1px solid #eee; | |
| padding-bottom: 10px; | |
| } | |
| .chat-container { | |
| height: 300px; | |
| overflow-y: scroll; | |
| border: 1px solid #eee; | |
| padding: 10px; | |
| margin-bottom: 10px; | |
| flex: 1; | |
| } | |
| .input-container { | |
| display: flex; | |
| gap: 10px; | |
| } | |
| input[type="text"], | |
| input[type="password"] { | |
| flex: 1; | |
| padding: 8px; | |
| border: 1px solid #ddd; | |
| border-radius: 4px; | |
| } | |
| button { | |
| padding: 8px 15px; | |
| background-color: #4CAF50; | |
| color: white; | |
| border: none; | |
| border-radius: 4px; | |
| cursor: pointer; | |
| } | |
| button:hover { | |
| background-color: #45a049; | |
| } | |
| .message { | |
| margin-bottom: 10px; | |
| padding: 8px; | |
| border-radius: 8px; | |
| } | |
| .user-message { | |
| background-color: #e1f5fe; | |
| align-self: flex-end; | |
| } | |
| .assistant-message { | |
| background-color: #f1f1f1; | |
| } | |
| .connection-status { | |
| color: #666; | |
| font-size: 0.9em; | |
| margin-top: 10px; | |
| } | |
| .message-entry { | |
| margin: 5px 0; | |
| padding: 8px; | |
| border-radius: 8px; | |
| background: white; | |
| box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); | |
| font-family: monospace; | |
| } | |
| .incoming { | |
| border-left: 4px solid #4CAF50; | |
| } | |
| .outgoing { | |
| border-left: 4px solid #2196F3; | |
| } | |
| .system { | |
| border-left: 4px solid #9C27B0; | |
| } | |
| .error { | |
| border-left: 4px solid #F44336; | |
| } | |
| .message-header { | |
| display: flex; | |
| justify-content: space-between; | |
| font-size: 0.8em; | |
| color: #666; | |
| margin-bottom: 4px; | |
| } | |
| .tabs { | |
| display: flex; | |
| margin-bottom: 15px; | |
| } | |
| .tab { | |
| padding: 10px 20px; | |
| cursor: pointer; | |
| border: 1px solid #ddd; | |
| border-radius: 4px 4px 0 0; | |
| margin-right: 5px; | |
| } | |
| .tab.active { | |
| background-color: #f1f1f1; | |
| border-bottom: none; | |
| } | |
| .tab-content { | |
| display: none; | |
| } | |
| .tab-content.active { | |
| display: block; | |
| flex: 1; | |
| display: flex; | |
| flex-direction: column; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="tabs"> | |
| <div class="tab active" onclick="switchTab('chat')">Chat Client</div> | |
| <div class="tab" onclick="switchTab('proxy')">Proxy Configuration</div> | |
| </div> | |
| <div class="container"> | |
| <!-- Chat Client Panel --> | |
| <div id="chat-tab" class="tab-content active panel"> | |
| <h2>Chat Client</h2> | |
| <div id="chat" class="chat-container"></div> | |
| <div class="input-container"> | |
| <input id="msg" type="text" placeholder="Type your message here..."> | |
| <button onclick="sendMessage()">Send</button> | |
| </div> | |
| <div id="client-status" class="connection-status">Connecting...</div> | |
| </div> | |
| <!-- Proxy Configuration Panel --> | |
| <div id="proxy-tab" class="tab-content panel"> | |
| <h2>LLM Proxy Configuration</h2> | |
| <div style="margin-bottom: 20px;"> | |
| <input type="password" id="apiKey" placeholder="Enter API Key" style="width: 100%;"> | |
| <button onclick="initializeClient()" style="margin-top: 10px;">Fetch Models</button> | |
| </div> | |
| <select id="modelSelect" style="width: 100%; margin-bottom: 20px;"></select> | |
| <div id="systemStatus" class="connection-status"></div> | |
| <h3>Message Flow</h3> | |
| <div id="messageFlow" | |
| style="flex: 1; border: 1px solid #eee; padding: 10px; overflow-y: auto; background: #f9f9f9;"> | |
| <div style="text-align: center; color: #999; margin-bottom: 10px;">Message Flow</div> | |
| </div> | |
| <div id="detailedStatus" class="connection-status"></div> | |
| </div> | |
| </div> | |
| <script> | |
| function showStatus(message, type = 'info') { | |
| const statusDiv = document.getElementById('systemStatus'); | |
| statusDiv.innerHTML = `<div style="color: ${type === 'error' ? '#F44336' : '#4CAF50'}">${message}</div>`; | |
| addMessageEntry('system', 'system', 'proxy', message); | |
| } | |
| // Tab switching functionality | |
| function switchTab(tabName) { | |
| document.querySelectorAll('.tab').forEach(tab => tab.classList.remove('active')); | |
| document.querySelectorAll('.tab-content').forEach(content => content.classList.remove('active')); | |
| document.querySelector(`.tab[onclick="switchTab('${tabName}')"]`).classList.add('active'); | |
| document.getElementById(`${tabName}-tab`).classList.add('active'); | |
| } | |
| // Client WebSocket | |
| const clientWs = new WebSocket('wss://' + window.location.host + '/ws'); | |
| clientWs.onopen = () => { | |
| clientWs.send(JSON.stringify({ | |
| source: 'user' | |
| })); | |
| document.getElementById('client-status').textContent = 'Connected'; | |
| }; | |
| clientWs.onclose = () => { | |
| document.getElementById('client-status').textContent = 'Disconnected'; | |
| }; | |
| clientWs.onmessage = e => { | |
| const msg = JSON.parse(e.data); | |
| const chatDiv = document.getElementById('chat'); | |
| chatDiv.innerHTML += `<div class="message assistant-message">${msg.content}</div>`; | |
| chatDiv.scrollTop = chatDiv.scrollHeight; | |
| }; | |
| function sendMessage() { | |
| const input = document.getElementById('msg'); | |
| const content = input.value.trim(); | |
| if (content) { | |
| const message = { | |
| content: content, | |
| source: 'user', | |
| destination: 'proxy', | |
| request_id: generateUUID() | |
| }; | |
| clientWs.send(JSON.stringify(message)); | |
| const chatDiv = document.getElementById('chat'); | |
| chatDiv.innerHTML += `<div class="message user-message">${content}</div>`; | |
| chatDiv.scrollTop = chatDiv.scrollHeight; | |
| input.value = ''; | |
| } | |
| } | |
| document.getElementById('msg').addEventListener('keypress', function (e) { | |
| if (e.key === 'Enter') { | |
| sendMessage(); | |
| } | |
| }); | |
| // Proxy WebSocket | |
| let proxyWs = new WebSocket('wss://' + window.location.host + '/ws'); | |
| proxyWs.onopen = () => { | |
| proxyWs.send(JSON.stringify({ | |
| source: 'proxy' | |
| })); | |
| showStatus('Connected to server'); | |
| }; | |
| proxyWs.onclose = () => { | |
| showStatus('Disconnected from server', 'error'); | |
| }; | |
| proxyWs.onmessage = async e => { | |
| const msg = JSON.parse(e.data); | |
| // Display incoming messages | |
| if (msg.destination === 'proxy') { | |
| let tools = null | |
| addMessageEntry('incoming', msg.source, 'proxy', msg.content); | |
| document.getElementById('detailedStatus').textContent = `Processing ${msg.source} request...`; | |
| try { | |
| const response = await fetch("/list-tools"); | |
| tools = await response.json(); | |
| } catch (error) { | |
| console.log(`Failed to fetch tools : ${error}`); | |
| tools = null; | |
| } | |
| try { | |
| if (!agentClient) { | |
| throw new Error( | |
| "LLM client not initialized. Please enter API key and fetch models first."); | |
| } | |
| if (!currentModel) { | |
| throw new Error("No model selected. Please select a model first."); | |
| } | |
| let llmResponse = await agentClient.call( | |
| currentModel, | |
| msg.content, | |
| conversationHistory, | |
| tools | |
| ); | |
| conversationHistory = llmResponse.history | |
| // Display outgoing response | |
| addMessageEntry('outgoing', 'proxy', msg.source, llmResponse.response); | |
| if(llmResponse.response.tool_calls != null){ | |
| try { | |
| console.log("Calling ....") | |
| const toolCalls = await fetch("/call-tools", { | |
| method: "POST", | |
| headers: { | |
| "Content-Type": "application/json" | |
| }, | |
| body: JSON.stringify({tool_calls: llmResponse.response.tool_calls}) | |
| }) | |
| const toolCallsJson = await toolCalls.json() | |
| console.log("Succeed !") | |
| for(const toolCall of toolCallsJson){ | |
| conversationHistory.push(toolCall) | |
| } | |
| llmResponse = await agentClient.call( | |
| currentModel, | |
| null, | |
| conversationHistory, | |
| null | |
| ) | |
| conversationHistory = llmResponse.history | |
| } catch (error) { | |
| throw new Error("Error on calling tools " + error) | |
| } | |
| } | |
| const responseMsg = { | |
| request_id: msg.request_id, | |
| content: llmResponse.response.content, | |
| source: 'proxy', | |
| destination: msg.source | |
| }; | |
| proxyWs.send(JSON.stringify(responseMsg)); | |
| document.getElementById('detailedStatus').textContent = `Response sent to ${msg.source}`; | |
| } catch (error) { | |
| addMessageEntry('error', 'system', 'proxy', `Error: ${error.message}`); | |
| const errorResponse = { | |
| request_id: msg.request_id, | |
| content: `Error: ${error.message}`, | |
| source: 'proxy', | |
| destination: msg.source | |
| }; | |
| proxyWs.send(JSON.stringify(errorResponse)); | |
| } | |
| } | |
| }; | |
| function generateUUID() { | |
| return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { | |
| var r = Math.random() * 16 | 0, | |
| v = c == 'x' ? r : (r & 0x3 | 0x8); | |
| return v.toString(16); | |
| }); | |
| } | |
| </script> | |
| <script src="/static/proxy_llm.js"></script> | |
| </body> | |
| </html> | |