Skip to content

Enhance ChatMessage with timing metrics for message processing #51

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,131 @@
*/
public class ChatMessage {

public String mMessage;
public int mLength;
private String mMessage;
private int mLength;
public MessageSender mSender;
private double msToFirstToken;
private double msToLastToken;
private boolean isFirstTokenTimeSet = false;

public ChatMessage(String msg, MessageSender sender) {
mMessage = msg;
mSender = sender;
mLength = msg.length();
}

/**
* ChatMessage: Constructor for a message from the user
* @param msg: the message
* @param sender: the sender of the message
* @param timeUntilFirstToken: the time it took to generate the first token
*/
public ChatMessage(String msg, MessageSender sender, double timeUntilFirstToken) {
mMessage = msg;
mLength = msg.length();
mSender = sender;
msToFirstToken = timeUntilFirstToken;
isFirstTokenTimeSet = timeUntilFirstToken > 0;
}

/**
* isMessageFromUser: Check if the message is from the user
*
* @return true if the message is from the user, false otherwise
*/
public boolean isMessageFromUser() {
return mSender == MessageSender.USER;
}

/**
* getMessage: Get the message
*
* @return the message
*/
public String getMessage() {
return mMessage;
}

/**
* getLength: Get the length of the message
*
* @return the length of the message
*/
public int getLength() {
return mLength;
}

/**
* setMessage: Set the message and update the length
* @param message: the message to set
*/
public void setMessage(String message) {
mMessage = message;
mLength = message.length();
}

/**
* getMsToFirstToken: Get the time it took to generate the first token
*
* @return time in milliseconds
*/
public double getMsToFirstToken() {
return msToFirstToken;
}

/**
* setMsToFirstToken: Set the time it took to generate the first token
*/
public void setMsToFirstToken() {
if (!isFirstTokenTimeSet) {
msToFirstToken = System.currentTimeMillis();
isFirstTokenTimeSet = true;
}
}

/**
* getMsToLastToken: Get the time it took to generate the last token
*
* @return time in milliseconds
*/
public double getMsToLastToken() {
return msToLastToken;
}

/**
* setMsToLastToken: Set the time it took to generate the last token
* @param origin: the time the message was sent
*/
public void setMsToLastToken(long origin) {
msToLastToken = System.currentTimeMillis() - origin;
}

/**
* timeBetweenTokens: Get the time it took to generate the last token
*
* @return time in milliseconds
*/
public double timeBetweenTokens() {
if (!isFirstTokenTimeSet || msToLastToken == 0) {
return 0;
}
return msToLastToken - msToFirstToken;
}

/**
* getTimeToFirstTokenSeconds: Get the time it took to generate the first token
*
* @return time in seconds
*/
public double getTimeToFirstTokenSeconds() {
return msToFirstToken / 1000.0;
}

/**
* Returns total generation time in seconds
*/
public double getTotalTimeSeconds() {
return timeBetweenTokens() / 1000.0;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,15 @@ public void onClick(View view) {
service.execute(new Runnable() {
@Override
public void run() {
final long startTime = System.currentTimeMillis();

genieWrapper.getResponseForPrompt(userInputMsg, new StringCallback() {
@Override
public void onNewString(String response) {
runOnUiThread(() -> {
// Update the last item in the adapter
adapter.updateBotMessage(response);
adapter.notifyItemChanged(botResponseMsgIndex);
adapter.updateBotMessage(response, startTime);
adapter.notifyItemChanged(messages.size() - 1);
});
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import androidx.recyclerview.widget.RecyclerView;

import java.util.ArrayList;
import java.util.Locale;

public class Message_RecyclerViewAdapter extends RecyclerView.Adapter<Message_RecyclerViewAdapter.MyViewHolder> {

Expand Down Expand Up @@ -42,13 +43,40 @@ public void onBindViewHolder(@NonNull Message_RecyclerViewAdapter.MyViewHolder h
holder.mUserMessage.setText(msg.getMessage());
holder.mLeftChatLayout.setVisibility(View.GONE);
holder.mRightChatLayout.setVisibility(View.VISIBLE);
holder.mTokenTimingView.setVisibility(View.GONE);
} else {
holder.mBotMessage.setText(msg.getMessage());
holder.mLeftChatLayout.setVisibility(View.VISIBLE);
holder.mRightChatLayout.setVisibility(View.GONE);

// Show timing information for messages that have started generating
if (msg.getTimeToFirstTokenSeconds() > 0) {
holder.mTokenTimingView.setVisibility(View.VISIBLE);
String timingText = formatTimingText(msg);
holder.mTokenTimingView.setText(timingText);

// Style the timing view differently if message is still generating
if (msg.getTotalTimeSeconds() == 0) {
holder.mTokenTimingView.setAlpha(0.7f);
} else {
holder.mTokenTimingView.setAlpha(1.0f);
}
} else {
holder.mTokenTimingView.setVisibility(View.GONE);
}
}
}

private String formatTimingText(ChatMessage msg) {
double firstTokenTime = msg.getTimeToFirstTokenSeconds();
double totalTime = msg.getTotalTimeSeconds();
double tokenRate = msg.getLength() / (totalTime > 0 ? totalTime : 1);

return String.format(Locale.ENGLISH, "First token: %.1fs", firstTokenTime) +
" • Total: " + String.format(Locale.ENGLISH, "%.1fs", totalTime) +
" • " + String.format(Locale.ENGLISH, "%.0f chars/sec", tokenRate);
}

@Override
public int getItemCount() {
return messages.size();
Expand All @@ -62,9 +90,9 @@ public void addMessage(ChatMessage msg) {
* updateBotMessage: updates / inserts message on behalf of Bot
*
* @param bot_message message to update or insert
* @return newly added message
* @param startTime the time the message was sent
*/
public String updateBotMessage(String bot_message) {
public void updateBotMessage(String bot_message, long startTime) {
boolean lastMessageFromBot = false;
ChatMessage lastMessage;

Expand All @@ -74,15 +102,16 @@ public String updateBotMessage(String bot_message) {
lastMessageFromBot = true;
}
} else {
addMessage(new ChatMessage(bot_message, MessageSender.BOT));
addMessage(new ChatMessage(bot_message, MessageSender.BOT, System.currentTimeMillis() - startTime));
}

if (lastMessageFromBot) {
messages.get(messages.size() - 1).mMessage = messages.get(messages.size() - 1).mMessage + bot_message;
ChatMessage msg = messages.get(messages.size() - 1);
msg.setMessage(msg.getMessage() + bot_message);
msg.setMsToLastToken(startTime);
} else {
addMessage(new ChatMessage(bot_message, MessageSender.BOT));
addMessage(new ChatMessage(bot_message, MessageSender.BOT, System.currentTimeMillis() - startTime));
}
return messages.get(messages.size() - 1).mMessage;
}

public static class MyViewHolder extends RecyclerView.ViewHolder {
Expand All @@ -91,6 +120,7 @@ public static class MyViewHolder extends RecyclerView.ViewHolder {
TextView mBotMessage;
LinearLayout mLeftChatLayout;
LinearLayout mRightChatLayout;
TextView mTokenTimingView;

public MyViewHolder(@NonNull View itemView) {
super(itemView);
Expand All @@ -99,6 +129,7 @@ public MyViewHolder(@NonNull View itemView) {
mUserMessage = itemView.findViewById(R.id.user_message);
mLeftChatLayout = itemView.findViewById(R.id.left_chat_layout);
mRightChatLayout = itemView.findViewById(R.id.right_chat_layout);
mTokenTimingView = itemView.findViewById(R.id.token_timing_view);
}
}
}
11 changes: 11 additions & 0 deletions apps/android/ChatApp/src/main/res/layout/chat_row.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@
android:paddingRight="10dp"
android:paddingBottom="6dp"
android:textSize="20sp" />

<TextView
android:id="@+id/token_timing_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="4dp"
android:textSize="11sp"
android:textColor="#757575"
android:visibility="gone"
android:text="Generated in 0.0s" />
</LinearLayout>

<LinearLayout
Expand Down