Skip to content

Commit

Permalink
First steps in a redo of #42
Browse files Browse the repository at this point in the history
(llm-chat-take-2), since the codebase had a major refactor.
  • Loading branch information
mcjustin committed Nov 29, 2024
1 parent e822f30 commit 2c39396
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 1 deletion.
109 changes: 109 additions & 0 deletions src/lib/utils/llmChat.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
let fhirResources = null;
let messages = [];

function initLLMChat(resources) {
fhirResources = resources;
const llmChatContent = document.getElementById('llm-chat-content');
const chatInput = document.getElementById('chat-input');
const sendMessageButton = document.getElementById('send-message');

sendMessageButton.addEventListener('click', sendMessage);
chatInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') sendMessage();
});
}

function insertMessageIntoUi(role, userMessage) {
const chatMessages = document.getElementById('chat-messages');

// Create a new table row for the user message
const row = document.createElement('tr');

// Create cells for the request
const requestCell = document.createElement('td');
requestCell.textContent = userMessage;

// Create empty cells for response and tokens
const responseCell = document.createElement('td');
const promptTokensCell = document.createElement('td');
const completionTokensCell = document.createElement('td');
const costCell = document.createElement('td');

// Append cells to the row
row.appendChild(requestCell);
row.appendChild(responseCell);
row.appendChild(promptTokensCell);
row.appendChild(completionTokensCell);
row.appendChild(costCell);

// Append the row to the chat messages table
chatMessages.appendChild(row);

// Return the row for later updates
return row;
}

// Update the sendMessage function to use the new insertMessageIntoUi
async function sendMessage() {
const chatInput = document.getElementById('chat-input');
const userMessage = chatInput.value.trim();
if (userMessage.length === 0) return;

// Append the FHIR resources as the first message
if (messages.length === 0) {
messages.push({
role: "user",
content: [{ type: "text", text: JSON.stringify(fhirResources) }]
});
}

// Append the user message
messages.push({
role: "user",
content: [{ type: "text", text: userMessage }]
});

// Insert the user message into the UI and get the row reference
const row = insertMessageIntoUi('user', userMessage);

chatInput.value = '';

try {
// FIXME config for this url...
const response = await fetch('https://llm-service.fl.mcjustin.dev.cirg.uw.edu/api/chat', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ messages: messages }), // Send the messages array
});

if (!response.ok) {
throw new Error('Failed to get LLM response');
}

const data = await response.json();
// Append the assistant's response
messages.push({
role: "assistant",
content: [{ type: "text", text: data.content }]
});

const promptTokens = data.prompt_tokens;
const completionTokens = data.completion_tokens;
const costInput = parseInt(promptTokens) * 0.15 / 1000000;
const costOutput = parseInt(completionTokens) * 0.6 / 1000000;
const cost = costInput + costOutput;

// Update the existing row with the response and token counts
row.cells[1].textContent = data.content; // Response
row.cells[2].textContent = promptTokens; // Prompt Tokens
row.cells[3].textContent = completionTokens; // Completion Tokens
row.cells[4].textContent = costInput.toString().substring(0,7) + " + " + costOutput.toString().substring(0,7) + " = " + cost.toString().substring(0,7);
} catch (error) {
console.error('Error sending message to LLM:', error);
row.cells[1].textContent = 'Failed to get a response. Please try again.'; // Update response cell with error message
}
}

export { initLLMChat };
30 changes: 29 additions & 1 deletion src/routes/(viewer)/ips/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,15 @@
text: {
buttonText: "Generated Text",
dropdownText: "Display text generated by IPS source"
},
llmchat: {
buttonText: "LLM Chat (experimental)",
dropdownText: "Chat with a large language model (LLM) about your health"
}
}
let showLlmChat = false;
let displayModeText:string;
$: {
if ($displayMode) {
Expand All @@ -63,6 +69,7 @@
function setMode(mode:string) {
$displayMode = mode;
showLlmChat = mode === "llmchat";
}
// End display mode logic
Expand Down Expand Up @@ -245,6 +252,27 @@
<IPSContent content={shlContents[0]} mode={$displayMode} />
{/if}

{#if showLlmChat} <!-- Conditional rendering for LLM chat content -->
<div id="llm-chat-content" style="display: block; margin: 30px;"> <!-- Changed display to block -->
<table id="chat-messages" style="width: 100%; border-collapse: collapse;">
<thead>
<tr>
<th>Your request</th>
<th>LLM Chat Response</th>
<th>Prompt Tokens</th>
<th>Response Tokens</th>
<th>Cost in US$ (prompt + response = total)</th>
</tr>
</thead>
<tbody>
<!-- Messages will be appended here -->
</tbody>
</table>
<input type="text" id="chat-input" placeholder="Ask a large language model about your health...">
<button id="send-message">Send to LLM</button>
</div>
{/if}

<style lang="css">
:global(.loader) {
width: 100%;
Expand Down Expand Up @@ -289,4 +317,4 @@
background-position: 150% 0, 0 0, 70px 5px, 70px 38px, 0px 66px;
}
}
</style>
</style>

0 comments on commit 2c39396

Please sign in to comment.