-
Notifications
You must be signed in to change notification settings - Fork 291
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
Iris
: Track token usage of iris requests
#9455
base: develop
Are you sure you want to change the base?
Changes from 11 commits
a5dfdbb
d0bdae3
2a08cb2
f85cf46
65fb259
188ff22
be85a3b
e974d59
6337162
84a60dc
5b0ab48
62dad8b
897d643
1d10860
8b27861
86294c1
56b20e7
8a29c82
abbd28f
8d34428
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package de.tum.cit.aet.artemis.core.domain; | ||
|
||
/** | ||
* Enum representing different types of LLM (Large Language Model) services used in the system. | ||
*/ | ||
public enum LLMServiceType { | ||
/** Athena service for preliminary feedback */ | ||
ATHENA_PRELIMINARY_FEEDBACK, | ||
/** Athena service for feedback suggestions */ | ||
ATHENA_FEEDBACK_SUGGESTION, | ||
/** Iris service for code feedback */ | ||
IRIS_CODE_FEEDBACK, | ||
/** Iris service for course chat messages */ | ||
IRIS_CHAT_COURSE_MESSAGE, | ||
/** Iris service for exercise chat messages */ | ||
IRIS_CHAT_EXERCISE_MESSAGE, | ||
/** Iris service for interaction suggestions */ | ||
IRIS_INTERACTION_SUGGESTION, | ||
/** Iris service for lecture chat messages */ | ||
IRIS_CHAT_LECTURE_MESSAGE, | ||
/** Iris service for competency generation */ | ||
IRIS_COMPETENCY_GENERATION, | ||
/** Iris service for citation pipeline */ | ||
IRIS_CITATION_PIPELINE, | ||
/** Iris service for lecture retrieval pipeline */ | ||
IRIS_LECTURE_RETRIEVAL_PIPELINE, | ||
/** Iris service for lecture ingestion */ | ||
IRIS_LECTURE_INGESTION, | ||
/** Default value when the service type is not set */ | ||
NOT_SET | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,177 @@ | ||||||||||||||||||||||||||
package de.tum.cit.aet.artemis.core.domain; | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
import java.time.ZonedDateTime; | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
import jakarta.annotation.Nullable; | ||||||||||||||||||||||||||
import jakarta.persistence.Column; | ||||||||||||||||||||||||||
import jakarta.persistence.Entity; | ||||||||||||||||||||||||||
import jakarta.persistence.EnumType; | ||||||||||||||||||||||||||
import jakarta.persistence.Enumerated; | ||||||||||||||||||||||||||
import jakarta.persistence.JoinColumn; | ||||||||||||||||||||||||||
import jakarta.persistence.ManyToOne; | ||||||||||||||||||||||||||
import jakarta.persistence.Table; | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
import org.hibernate.annotations.Cache; | ||||||||||||||||||||||||||
import org.hibernate.annotations.CacheConcurrencyStrategy; | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
import com.fasterxml.jackson.annotation.JsonIgnore; | ||||||||||||||||||||||||||
import com.fasterxml.jackson.annotation.JsonInclude; | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
import de.tum.cit.aet.artemis.exercise.domain.Exercise; | ||||||||||||||||||||||||||
import de.tum.cit.aet.artemis.iris.domain.message.IrisMessage; | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
@Entity | ||||||||||||||||||||||||||
@Table(name = "llm_token_usage") | ||||||||||||||||||||||||||
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) | ||||||||||||||||||||||||||
@JsonInclude(JsonInclude.Include.NON_EMPTY) | ||||||||||||||||||||||||||
public class LLMTokenUsage extends DomainObject { | ||||||||||||||||||||||||||
alexjoham marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) Consider adding JavaDoc comments for the class Adding a class-level JavaDoc comment can improve code readability and help other developers understand the purpose and usage of this entity. |
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
@Column(name = "service") | ||||||||||||||||||||||||||
@Enumerated(EnumType.STRING) | ||||||||||||||||||||||||||
private LLMServiceType serviceType; | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
@Column(name = "model") | ||||||||||||||||||||||||||
private String model; | ||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Consider Using an Enum for Similar to Apply these changes:
|
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
@Column(name = "num_input_tokens") | ||||||||||||||||||||||||||
private int numInputTokens; | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
@Column(name = "cost_per_million_input_tokens") | ||||||||||||||||||||||||||
private float costPerMillionInputTokens; | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
@Column(name = "num_output_tokens") | ||||||||||||||||||||||||||
private int numOutputTokens; | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
@Column(name = "cost_per_million_output_tokens") | ||||||||||||||||||||||||||
private float costPerMillionOutputTokens; | ||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use Using Apply these changes:
|
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
@Nullable | ||||||||||||||||||||||||||
@ManyToOne | ||||||||||||||||||||||||||
@JsonIgnore | ||||||||||||||||||||||||||
@JoinColumn(name = "course_id") | ||||||||||||||||||||||||||
private Course course; | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
@Nullable | ||||||||||||||||||||||||||
@ManyToOne | ||||||||||||||||||||||||||
@JsonIgnore | ||||||||||||||||||||||||||
@JoinColumn(name = "exercise_id") | ||||||||||||||||||||||||||
private Exercise exercise; | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
@Column(name = "user_id") | ||||||||||||||||||||||||||
private long userId; | ||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Consider Mapping Mapping the Apply these changes:
|
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
@Column(name = "time") | ||||||||||||||||||||||||||
private ZonedDateTime time = ZonedDateTime.now(); | ||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid using reserved SQL keywords for column names The column name Apply this change: - @Column(name = "time")
+ @Column(name = "\"time\"")
private ZonedDateTime time = ZonedDateTime.now(); Or rename the column: - @Column(name = "time")
+ @Column(name = "timestamp")
private ZonedDateTime time = ZonedDateTime.now(); Ensure that any database scripts or queries are updated to reflect this change. 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
@Column(name = "trace_id") | ||||||||||||||||||||||||||
private String traceId; | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
@Nullable | ||||||||||||||||||||||||||
@ManyToOne | ||||||||||||||||||||||||||
@JsonIgnore | ||||||||||||||||||||||||||
@JoinColumn(name = "iris_message_id") | ||||||||||||||||||||||||||
private IrisMessage irisMessage; | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
public LLMServiceType getServiceType() { | ||||||||||||||||||||||||||
return serviceType; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
public void setServiceType(LLMServiceType serviceType) { | ||||||||||||||||||||||||||
this.serviceType = serviceType; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
public String getModel() { | ||||||||||||||||||||||||||
return model; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
public void setModel(String model) { | ||||||||||||||||||||||||||
this.model = model; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
public float getCostPerMillionInputTokens() { | ||||||||||||||||||||||||||
return costPerMillionInputTokens; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
public void setCostPerMillionInputTokens(float costPerMillionInputToken) { | ||||||||||||||||||||||||||
this.costPerMillionInputTokens = costPerMillionInputToken; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) Synchronize Parameter Names in Setter Methods The parameter name in Apply this diff: - public void setCostPerMillionInputTokens(float costPerMillionInputToken) {
- this.costPerMillionInputTokens = costPerMillionInputToken;
+ public void setCostPerMillionInputTokens(float costPerMillionInputTokens) {
+ this.costPerMillionInputTokens = costPerMillionInputTokens;
} Similarly, update the - public void setCostPerMillionOutputTokens(float costPerMillionOutputToken) {
- this.costPerMillionOutputTokens = costPerMillionOutputToken;
+ public void setCostPerMillionOutputTokens(float costPerMillionOutputTokens) {
+ this.costPerMillionOutputTokens = costPerMillionOutputTokens;
} 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
public float getCostPerMillionOutputTokens() { | ||||||||||||||||||||||||||
return costPerMillionOutputTokens; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
public void setCostPerMillionOutputTokens(float costPerMillionOutputToken) { | ||||||||||||||||||||||||||
this.costPerMillionOutputTokens = costPerMillionOutputToken; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
public int getNumInputTokens() { | ||||||||||||||||||||||||||
return numInputTokens; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
public void setNumInputTokens(int numInputTokens) { | ||||||||||||||||||||||||||
this.numInputTokens = numInputTokens; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
public int getNumOutputTokens() { | ||||||||||||||||||||||||||
return numOutputTokens; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
public void setNumOutputTokens(int numOutputTokens) { | ||||||||||||||||||||||||||
this.numOutputTokens = numOutputTokens; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
public Course getCourse() { | ||||||||||||||||||||||||||
return course; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
public void setCourse(Course course) { | ||||||||||||||||||||||||||
this.course = course; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
public Exercise getExercise() { | ||||||||||||||||||||||||||
return exercise; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
public void setExercise(Exercise exercise) { | ||||||||||||||||||||||||||
this.exercise = exercise; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
public long getUserId() { | ||||||||||||||||||||||||||
return userId; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
public void setUserId(long userId) { | ||||||||||||||||||||||||||
this.userId = userId; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
public ZonedDateTime getTime() { | ||||||||||||||||||||||||||
return time; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
public void setTime(ZonedDateTime time) { | ||||||||||||||||||||||||||
this.time = time; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
public String getTraceId() { | ||||||||||||||||||||||||||
return traceId; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
public void setTraceId(String traceId) { | ||||||||||||||||||||||||||
this.traceId = traceId; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
public IrisMessage getIrisMessage() { | ||||||||||||||||||||||||||
return irisMessage; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
public void setIrisMessage(IrisMessage message) { | ||||||||||||||||||||||||||
this.irisMessage = message; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
@Override | ||||||||||||||||||||||||||
public String toString() { | ||||||||||||||||||||||||||
return "LLMTokenUsage{" + "serviceType=" + serviceType + ", model=" + model + ", numInputTokens=" + numInputTokens + ", costPerMillionInputTokens=" | ||||||||||||||||||||||||||
+ costPerMillionInputTokens + ", numOutputTokens=" + numOutputTokens + ", costPerMillionOutputTokens=" + costPerMillionOutputTokens + ", course=" + course | ||||||||||||||||||||||||||
+ ", exercise=" + exercise + ", userId=" + userId + ", timestamp=" + time + ", traceId=" + traceId + ", irisMessage=" + irisMessage + '}'; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) Inconsistent field label in In the Apply this diff to correct the label: - + ", exercise=" + exercise + ", userId=" + userId + ", timestamp=" + time + ", traceId=" + traceId + ", irisMessage=" + irisMessage + '}';
+ + ", exercise=" + exercise + ", userId=" + userId + ", time=" + time + ", traceId=" + traceId + ", irisMessage=" + irisMessage + '}'; 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package de.tum.cit.aet.artemis.core.repository; | ||
|
||
import static de.tum.cit.aet.artemis.core.config.Constants.PROFILE_IRIS; | ||
|
||
import org.springframework.context.annotation.Profile; | ||
import org.springframework.stereotype.Repository; | ||
|
||
import de.tum.cit.aet.artemis.core.domain.LLMTokenUsage; | ||
import de.tum.cit.aet.artemis.core.repository.base.ArtemisJpaRepository; | ||
|
||
@Repository | ||
@Profile(PROFILE_IRIS) | ||
public interface LLMTokenUsageRepository extends ArtemisJpaRepository<LLMTokenUsage, Long> { | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,110 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
package de.tum.cit.aet.artemis.core.service; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import static de.tum.cit.aet.artemis.core.config.Constants.PROFILE_IRIS; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import java.util.ArrayList; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import java.util.List; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import org.springframework.context.annotation.Profile; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import org.springframework.stereotype.Service; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import de.tum.cit.aet.artemis.core.domain.Course; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import de.tum.cit.aet.artemis.core.domain.LLMTokenUsage; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import de.tum.cit.aet.artemis.core.domain.User; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import de.tum.cit.aet.artemis.core.repository.LLMTokenUsageRepository; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import de.tum.cit.aet.artemis.exercise.domain.Exercise; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import de.tum.cit.aet.artemis.iris.domain.message.IrisMessage; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import de.tum.cit.aet.artemis.iris.service.pyris.dto.data.PyrisLLMCostDTO; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import de.tum.cit.aet.artemis.iris.service.pyris.job.PyrisJob; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* Service for managing the LLMTokenUsage by all LLMs in Artemis | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
@Service | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
@Profile(PROFILE_IRIS) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
public class LLMTokenUsageService { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
private final LLMTokenUsageRepository llmTokenUsageRepository; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
public LLMTokenUsageService(LLMTokenUsageRepository llmTokenUsageRepository) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
this.llmTokenUsageRepository = llmTokenUsageRepository; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* method saves the token usage to the database with a link to the IrisMessage | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* messages of the same job are grouped together by saving the job id as a trace id | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* @param job used to create a unique traceId to group multiple LLM calls | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* @param message IrisMessage to map the usage to an IrisMessage | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* @param exercise to map the token cost to an exercise | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* @param user to map the token cost to a user | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* @param course to map the token to a course | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* @param tokens token cost list of type PyrisLLMCostDTO | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* @return list of the saved data | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) Enhance JavaDoc comments for clarity and consistency While the JavaDoc provides useful information, improving the grammar and formatting would enhance readability and maintainability. Starting parameter descriptions with uppercase letters and ending sentences with periods can make the documentation more professional. Apply this diff to improve the JavaDoc comments: /**
- * method saves the token usage to the database with a link to the IrisMessage
- * messages of the same job are grouped together by saving the job id as a trace id
+ * Saves the token usage to the database with a link to the IrisMessage.
+ * Messages of the same job are grouped together by saving the job ID as a trace ID.
*
- * @param job used to create a unique traceId to group multiple LLM calls
- * @param message IrisMessage to map the usage to an IrisMessage
- * @param exercise to map the token cost to an exercise
- * @param user to map the token cost to a user
- * @param course to map the token to a course
- * @param tokens token cost list of type PyrisLLMCostDTO
+ * @param job Used to create a unique traceId to group multiple LLM calls.
+ * @param message IrisMessage to map the usage to an IrisMessage.
+ * @param exercise To map the token cost to an Exercise.
+ * @param user To map the token cost to a User.
+ * @param course To map the token to a Course.
+ * @param tokens Token cost list of type PyrisLLMCostDTO.
* @return List of the saved data.
*/ 📝 Committable suggestion
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) Improve JavaDoc comments for clarity and adherence to standards The JavaDoc comments can be enhanced for better readability and to conform with JavaDoc standards:
Apply this diff to improve the JavaDoc: /**
- * method saves the token usage to the database with a link to the IrisMessage
- * messages of the same job are grouped together by saving the job id as a trace id
+ * Saves the token usage to the database with a link to the IrisMessage.
+ * Messages of the same job are grouped together by saving the job ID as a trace ID.
*
- * @param job used to create a unique traceId to group multiple LLM calls
- * @param message IrisMessage to map the usage to an IrisMessage
- * @param exercise to map the token cost to an exercise
- * @param user to map the token cost to a user
- * @param course to map the token to a course
- * @param tokens token cost list of type PyrisLLMCostDTO
- * @return list of the saved data
+ * @param job Used to create a unique trace ID to group multiple LLM calls.
+ * @param message IrisMessage to map the usage to an IrisMessage.
+ * @param exercise To map the token cost to an Exercise.
+ * @param user To map the token cost to a User.
+ * @param course To map the token to a Course.
+ * @param tokens Token cost list of type PyrisLLMCostDTO.
+ * @return List of the saved data.
*/ 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
public List<LLMTokenUsage> saveIrisTokenUsage(PyrisJob job, IrisMessage message, Exercise exercise, User user, Course course, List<PyrisLLMCostDTO> tokens) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
alexjoham marked this conversation as resolved.
Show resolved
Hide resolved
alexjoham marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
List<LLMTokenUsage> tokenUsages = new ArrayList<>(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
for (PyrisLLMCostDTO cost : tokens) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add null check for In the Apply this diff to add a null check: public List<LLMTokenUsage> saveIrisTokenUsage(PyrisJob job, IrisMessage message, Exercise exercise, User user, Course course, List<PyrisLLMCostDTO> tokens) {
+ if (tokens == null || tokens.isEmpty()) {
+ return new ArrayList<>();
+ }
List<LLMTokenUsage> tokenUsages = new ArrayList<>(); 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
LLMTokenUsage llmTokenUsage = new LLMTokenUsage(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (message != null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
llmTokenUsage.setIrisMessage(message); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
llmTokenUsage.setTime(message.getSentAt()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
llmTokenUsage.setServiceType(cost.pipeline()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
llmTokenUsage.setExercise(exercise); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (user != null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
alexjoham marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
llmTokenUsage.setUserId(user.getId()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
llmTokenUsage.setCourse(course); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add null check before setting The Apply this diff to add the null check: llmTokenUsage.setServiceType(cost.pipeline());
-llmTokenUsage.setCourse(course);
+if (course != null) {
+ llmTokenUsage.setCourse(course);
+}
llmTokenUsage.setNumInputTokens(cost.numInputTokens()); 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
llmTokenUsage.setNumInputTokens(cost.numInputTokens()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
llmTokenUsage.setCostPerMillionInputTokens(cost.costPerInputToken()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
llmTokenUsage.setNumOutputTokens(cost.numOutputTokens()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
llmTokenUsage.setCostPerMillionOutputTokens(cost.costPerOutputToken()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
llmTokenUsage.setModel(cost.modelInfo()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
llmTokenUsage.setTraceId(job.jobId()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
tokenUsages.add(llmTokenUsage); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
llmTokenUsageRepository.saveAll(tokenUsages); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return tokenUsages; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
alexjoham marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* Overloaded method to save token usage without message and exercise. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* @param job used to create a unique traceId to group multiple LLM calls | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* @param user to map the token cost to a user | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* @param course to map the token to a course | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* @param tokens token cost list of type PyrisLLMCostDTO | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* @return list of the saved data | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
public List<LLMTokenUsage> saveIrisTokenUsage(PyrisJob job, User user, Course course, List<PyrisLLMCostDTO> tokens) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return saveIrisTokenUsage(job, null, null, user, course, tokens); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* Overloaded method to save token usage without exercise. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* @param job used to create a unique traceId to group multiple LLM calls | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* @param message IrisMessage to map the usage to an IrisMessage | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* @param user to map the token cost to a user | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* @param course to map the token to a course | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* @param tokens token cost list of type PyrisLLMCostDTO | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* @return list of the saved data | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
public List<LLMTokenUsage> saveIrisTokenUsage(PyrisJob job, IrisMessage message, User user, Course course, List<PyrisLLMCostDTO> tokens) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return saveIrisTokenUsage(job, message, null, user, course, tokens); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Refactor overloaded methods to reduce code duplication The overloaded For example, you could create a single method that accepts a builder or use method chaining to handle optional parameters more elegantly. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* Overloaded method to save token usage without message, exercise and user. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* @param job used to create a unique traceId to group multiple LLM calls | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* @param course to map the token to a course | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* @param tokens token cost list of type PyrisLLMCostDTO | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* @return list of the saved data | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
public List<LLMTokenUsage> saveIrisTokenUsage(PyrisJob job, Course course, List<PyrisLLMCostDTO> tokens) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return saveIrisTokenUsage(job, null, null, null, course, tokens); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Refactor Overloaded Methods to Reduce Code Duplication The overloaded |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick (assertive)
Enhance JavaDoc with details about enum constants.
The JavaDoc comment provides a good overview of the enum's purpose. However, consider adding more details about the enum constants to improve documentation.
Here's a suggested enhancement: