Skip to content
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

Track token usage of iris requests #165

Merged
merged 20 commits into from
Oct 23, 2024
Merged

Conversation

alexjoham
Copy link
Member

@alexjoham alexjoham commented Oct 11, 2024

Track usage of iris requests

All Pipelines now have a tokens argument that is set by langchain. The tokens have a new type called LLMTokenCount, where an Enum is also added to set the pipeline in which the specified cost was created. Pyris sends now with an status update the tokens to Artemis.

New class LLMTokenCount with the following attributes:

    model_info: str
    num_input_tokens: int
    cost_per_input_token: float
    num_output_tokens: int
    cost_per_output_token: float
    pipeline: PipelineEnum

Every LLM call has those attributes set by langchain to track the usage. pipeline is an enum with all the important pipelines that Pyris has:

class PipelineEnum(str, Enum):
    IRIS_CODE_FEEDBACK = "IRIS_CODE_FEEDBACK"
    IRIS_CHAT_COURSE_MESSAGE = "IRIS_CHAT_COURSE_MESSAGE"
    IRIS_CHAT_EXERCISE_MESSAGE = "IRIS_CHAT_EXERCISE_MESSAGE"
    IRIS_INTERACTION_SUGGESTION = "IRIS_INTERACTION_SUGGESTION"
    IRIS_CHAT_LECTURE_MESSAGE = "IRIS_CHAT_LECTURE_MESSAGE"
    IRIS_COMPETENCY_GENERATION = "IRIS_COMPETENCY_GENERATION"
    IRIS_CITATION_PIPELINE = "IRIS_CITATION_PIPELINE"
    IRIS_RERANKER_PIPELINE = "IRIS_RERANKER_PIPELINE"
    IRIS_SUMMARY_PIPELINE = "IRIS_SUMMARY_PIPELINE"
    IRIS_LECTURE_RETRIEVAL_PIPELINE = "IRIS_LECTURE_RETRIEVAL_PIPELINE"
    NOT_SET = "NOT_SET"

Langchain sets the enum to not_set and the pipeline edits the variable and sets it to their value.

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Introduced TokenUsageDTO for tracking token usage information.
    • Enhanced PyrisMessage to include token counts and model info.
    • Implemented PipelineEnum for managing different processing stages.
    • Enhanced CapabilityRequestHandler to return messages with cost information for input and output tokens.
    • Updated IrisLangchainChatModel to incorporate token counting functionality.
    • Integrated token tracking across multiple pipelines, including CodeFeedbackPipeline, ExerciseChatPipeline, and LectureChatPipeline.
    • Added new attributes for token tracking in various classes, including LectureRetrieval, CitationPipeline, and CompetencyExtractionPipeline.
    • Updated the StatusUpdateDTO to include token usage information.
    • Modified the done and error methods in the StatusCallback class to accept token usage parameters.
  • Bug Fixes

    • Adjusted method signatures across various classes to accommodate new parameters for token management.
  • Documentation

    • Updated method signatures and class attributes to reflect new token management features.

@alexjoham alexjoham self-assigned this Oct 11, 2024
@alexjoham alexjoham marked this pull request as ready for review October 11, 2024 17:55
@alexjoham alexjoham requested a review from Hialus October 11, 2024 18:00
Copy link
Contributor

coderabbitai bot commented Oct 11, 2024

Walkthrough

This pull request introduces the PipelineEnum class for enumerating string constants representing various pipeline stages related to the IRIS system. It also adds the TokenUsageDTO class to encapsulate token-related information, which is integrated into the PyrisMessage class. Several pipeline classes are modified to include token tracking capabilities, enhancing the ability to monitor token usage throughout the application. Import paths for PyrisMessage are updated to reflect a new organizational structure, and various classes are updated to utilize the new token management features.

Changes

File Path Change Summary
app/common/PipelineEnum.py Added PipelineEnum class with constants for various pipeline stages.
app/common/token_usage_dto.py Added TokenUsageDTO class with fields for token usage information.
app/common/pyris_message.py Updated PyrisMessage class to include token_usage: TokenUsageDTO.
app/domain/init.py Removed import of PyrisMessage and IrisMessageRole from app.domain.pyris_message.
app/domain/chat/chat_pipeline_execution_base_data_dto.py Updated import for PyrisMessage from app.common.pyris_message.
app/domain/chat/chat_pipeline_execution_dto.py Updated import for PyrisMessage from app.common.pyris_message.
app/domain/chat/interaction_suggestion_dto.py Updated import for PyrisMessage from app.common.pyris_message.
app/domain/status/status_update_dto.py Added tokens: List[TokenUsageDTO] to StatusUpdateDTO.
app/llm/external/model.py Updated import for PyrisMessage from app.common.pyris_message.
app/llm/external/openai_chat.py Updated convert_to_iris_message function to include new parameters for token usage.
app/llm/langchain/iris_langchain_chat_model.py Added tokens: TokenUsageDTO to IrisLangchainChatModel.
app/llm/request_handler/basic_request_handler.py Updated import for PyrisMessage from app.common.pyris_message.
app/llm/request_handler/capability_request_handler.py Added CapabilityRequestHandlerSelectionMode enum and updated chat method for token costs.
app/pipeline/chat/code_feedback_pipeline.py Added tokens: TokenUsageDTO to CodeFeedbackPipeline and updated __call__ method.
app/pipeline/chat/course_chat_pipeline.py Added self.tokens: List[int] to CourseChatPipeline.
app/pipeline/chat/exercise_chat_pipeline.py Added self.tokens to ExerciseChatPipeline for tracking token information.
app/pipeline/chat/interaction_suggestion_pipeline.py Added tokens: TokenUsageDTO to InteractionSuggestionPipeline.
app/pipeline/chat/lecture_chat_pipeline.py Added self.tokens to LectureChatPipeline for tracking token usage.
app/pipeline/competency_extraction_pipeline.py Added self.tokens to CompetencyExtractionPipeline for token tracking.
app/pipeline/lecture_ingestion_pipeline.py Added self.tokens to LectureIngestionPipeline for tracking token usage.
app/pipeline/pipeline.py Added tokens: List[TokenUsageDTO] to Pipeline class for managing token counts.
app/pipeline/shared/citation_pipeline.py Added self.tokens to CitationPipeline for token tracking.
app/pipeline/shared/reranker_pipeline.py Added self.tokens to RerankerPipeline for token tracking.
app/retrieval/lecture_retrieval.py Added tokens: List[TokenUsageDTO] to LectureRetrieval for logging token usage.
app/web/status/status_update.py Updated done and error methods in StatusCallback to include optional tokens parameter.
app/domain/text_exercise_chat_pipeline_execution_dto.py Updated import for PyrisMessage from app.common.pyris_message.
app/pipeline/text_exercise_chat_pipeline.py Updated import for PyrisMessage and IrisMessageRole from app.common.

Possibly related PRs

  • Tutor Chat Pipeline with Lecture content.  #104: Tutor Chat Pipeline with Lecture content.
    This PR introduces functionality for handling lecture content in the Tutor Chat Pipeline, which may utilize the new PipelineEnum constants defined in the main PR.

  • Course Chat Agent Version #107: Course Chat Agent Version.
    This PR involves updates to chat pipeline execution DTOs, which may interact with the PipelineEnum class introduced in the main PR for managing different pipeline stages.

  • Fix competency extraction feature #145: Fix competency extraction feature.
    This PR enhances the competency extraction functionality, potentially leveraging the PipelineEnum for defining pipeline stages related to competency extraction processes.


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

🧹 Outside diff range and nitpick comments (21)
app/domain/data/token_usage_dto.py (1)

6-10: LGTM: Well-structured DTO with a minor suggestion.

The TokenUsageDTO class is well-defined and aligns with the PR objectives:

  • Inherits from pydantic.BaseModel for robust data validation.
  • Clear and descriptive attribute names with appropriate type annotations.
  • The pipeline attribute using PipelineEnum supports tracking token usage across different pipelines.

Consider adding a docstring to the class to provide more context and usage information. For example:

class TokenUsageDTO(BaseModel):
    """
    Data Transfer Object for token usage information.

    Attributes:
        model_info (str): Information about the model used.
        num_input_tokens (int): Number of input tokens processed.
        num_output_tokens (int): Number of output tokens generated.
        pipeline (PipelineEnum): The pipeline associated with this token usage.
    """
    # ... (rest of the class definition)
app/llm/external/PipelineEnum.py (1)

5-14: LGTM: Well-structured enum members with a minor suggestion.

The enum members are well-defined and consistently named. They cover various aspects of the IRIS system, which aligns with the PR objectives. The inclusion of a NOT_SET member is a good practice for handling undefined cases.

Consider adding a brief docstring to the PipelineEnum class to describe its purpose and the meaning of each member. This would enhance the code's self-documentation. For example:

class PipelineEnum(str, Enum):
    """
    Enumeration of pipeline types in the IRIS system.
    
    Each member represents a specific pipeline or processing stage
    used for tracking token usage and other metrics.
    """
    # ... enum members ...
app/llm/external/LLMTokenCount.py (1)

23-24: LGTM with a minor suggestion: Consider enhancing the __str__ method.

The __str__ method provides a clear and informative string representation of the object, which is great. However, to improve consistency and readability, consider using f-string's formatting options for better alignment. Here's a suggested improvement:

def __str__(self):
    return (f"{self.model_info}: "
            f"input_tokens={self.num_input_tokens:<6} "
            f"output_tokens={self.num_output_tokens:<6} "
            f"pipeline={self.pipeline.name}")

This format aligns the values and uses the enum's name for better readability. It also separates the information more clearly, which can be helpful when logging or debugging.

app/domain/pyris_message.py (1)

19-22: LGTM! Consider reordering fields for better readability.

The new fields num_input_tokens, num_output_tokens, and model_info are well-implemented and align with the PR objectives for tracking token usage. The use of aliases and default values is a good practice for serialization and backward compatibility.

Consider reordering the fields to group related attributes together, improving readability. For example:

class PyrisMessage(BaseModel):
    model_config = ConfigDict(populate_by_name=True)

    sent_at: datetime | None = Field(alias="sentAt", default=None)
    sender: IrisMessageRole
    contents: List[MessageContentDTO] = []

    num_input_tokens: int = Field(alias="numInputTokens", default=0)
    num_output_tokens: int = Field(alias="numOutputTokens", default=0)
    model_info: str = Field(alias="modelInfo", default="")

This groups the message-related fields together, followed by the token and model information fields.

app/pipeline/pipeline.py (1)

11-11: Consider initializing tokens in __init__ method.

The addition of the tokens attribute aligns with the PR objectives for tracking token usage. However, there are a couple of points to consider:

  1. The attribute is defined as a class attribute rather than an instance attribute. This might lead to unexpected behavior if shared across instances.
  2. The __init__ method hasn't been updated to initialize this attribute.

Consider modifying the __init__ method to initialize tokens as an instance attribute:

 class Pipeline(metaclass=ABCMeta):
     """Abstract class for all pipelines"""
 
     implementation_id: str
-    tokens: List[LLMTokenCount]
 
-    def __init__(self, implementation_id=None, **kwargs):
+    def __init__(self, implementation_id=None, tokens: List[LLMTokenCount] = None, **kwargs):
         self.implementation_id = implementation_id
+        self.tokens = tokens if tokens is not None else []

This change ensures that each instance has its own tokens list and allows for optional initialization.

app/llm/langchain/iris_langchain_chat_model.py (1)

Line range hint 19-20: Consider updating the class docstring.

The class has been enhanced with token tracking functionality. It would be beneficial to update the class docstring to reflect this new capability. This will help maintain clear and up-to-date documentation.

Here's a suggested addition to the docstring:

class IrisLangchainChatModel(BaseChatModel):
    """Custom langchain chat model for our own request handler.
    
    This class now includes token tracking functionality, storing token usage
    information in the `tokens` attribute after each generation.
    """
app/pipeline/shared/reranker_pipeline.py (1)

60-60: Consider adding a type hint for self.tokens

While the initialization of self.tokens is correct and aligns with the PR objectives, adding a type hint would improve code clarity and maintainability.

Consider updating the line as follows:

self.tokens: List[LLMTokenCount] = []

Don't forget to import List from typing if not already imported.

app/web/status/status_update.py (2)

Line range hint 101-113: LGTM: Enhanced done method with token tracking

The changes to the done method successfully incorporate token tracking and provide more control over the next stage. The implementation looks correct and aligns with the PR objectives.

Consider adding a brief comment explaining the purpose of the new parameters, especially tokens, to improve code documentation.


Issue: Some StatusCallback.done() calls are missing the tokens argument

Several instances of StatusCallback.done() do not include the tokens parameter, which may lead to inconsistent token tracking.

Affected files:

  • app/pipeline/lecture_ingestion_pipeline.py
    • Line 123
    • Line 142
    • Line 145
  • app/pipeline/chat/exercise_chat_pipeline.py
    • Line 102
    • Line 119
    • Line 245
    • Line 270
  • app/pipeline/chat/course_chat_pipeline.py
    • Line 422

Please update these calls to include the tokens parameter as necessary to ensure consistent token tracking across the codebase.

🔗 Analysis chain

Line range hint 22-113: Overall: Successfully implemented token tracking

The changes successfully add token tracking functionality to the StatusCallback class, aligning with the PR objectives. The implementation is backward-compatible and minimally invasive.

To ensure full utilization of this new feature:

  1. Verify that other parts of the codebase that use the StatusCallback class are updated to pass token information when available.
  2. Consider adding unit tests to cover the new token tracking functionality.
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for usages of StatusCallback.done() method that might need updating

# Test: Search for calls to StatusCallback.done() or its subclasses
echo "Searching for StatusCallback.done() calls:"
rg --type python -n "\.done\(" --glob '!app/web/status/status_update.py'

echo "Searching for potential subclasses of StatusCallback:"
rg --type python -n "class.*\(.*StatusCallback.*\):"

Length of output: 403


Script:

#!/bin/bash
# Description: Check for usages of StatusCallback.done() method that might need updating

# Test: Search for calls to StatusCallback.done() or its subclasses
echo "Searching for StatusCallback.done() calls:"
rg "\.done\(" --glob '*.py' -n --ignore-file '!app/web/status/status_update.py'

echo "Searching for potential subclasses of StatusCallback:"
rg "class\s+\w+\s*\(.*StatusCallback.*\):" --glob '*.py' -n

Length of output: 1841


Script:

#!/bin/bash
# Description: Verify that all StatusCallback.done() method calls include the 'tokens' argument

# Search for calls to StatusCallback.done() excluding the status_update.py file
echo "Searching for StatusCallback.done() calls excluding app/web/status/status_update.py:"
rg "\.done\(" --glob '*.py' --glob '!app/web/status/status_update.py' -n

# Extract the arguments of each done() call to check for 'tokens'
echo "Extracting arguments of StatusCallback.done() calls to verify 'tokens' parameter inclusion:"
rg "\.done\(" --glob '*.py' --glob '!app/web/status/status_update.py' -n -o "done\(([^)]*)\)"

Length of output: 1667

app/pipeline/chat/course_chat_pipeline.py (1)

420-422: LGTM: Comprehensive token tracking and reporting

The implementation successfully:

  1. Includes tokens from the citation pipeline in the total count.
  2. Sends token usage data to Artemis as part of the status update.

These changes align well with the PR objectives. However, consider adding a comment explaining the purpose of extending self.tokens with self.citation_pipeline.tokens for better code readability.

Consider adding a comment above line 420 to explain the purpose of including citation pipeline tokens:

# Include tokens from citation pipeline in the total count
self.tokens.extend(self.citation_pipeline.tokens)
app/pipeline/shared/citation_pipeline.py (3)

Line range hint 2-2: Incorrect import of logger

The import statement from asyncio.log import logger is incorrect because the asyncio module does not have a log submodule that provides logger. Instead, you should use Python's built-in logging module. Replace the import statement with:

-from asyncio.log import logger
+import logging
+logger = logging.getLogger(__name__)

92-92: Use logging instead of print statements

The use of print(response) is not recommended in production code. It is better to use a logger for controlled and configurable output. Replace the print statement with a logging call:

-            print(response)
+            logger.info(f"Citation pipeline response: {response}")

Line range hint 100-102: Improve exception handling and logging

In the exception block, the statement logger.error("citation pipeline failed", e) may not correctly log the exception details. Use logger.exception to include the traceback automatically:

-        except Exception as e:
-            logger.error("citation pipeline failed", e)
+        except Exception:
+            logger.exception("Citation pipeline failed")

This will provide more detailed information about the exception, aiding in debugging.

app/llm/external/ollama.py (1)

Line range hint 60-73: Ensure 'message' supports attribute access instead of subscriptable access

In the convert_to_iris_message function, you're accessing message using message["content"] and message["role"]. If message is an instance of the Message class, it may not support subscriptable access (__getitem__). Instead, use attribute access like message.content and message.role.

Apply this diff to correct the attribute access:

def convert_to_iris_message(
    message: Message, num_input_tokens: int, num_output_tokens: int, model: str
) -> PyrisMessage:
    """
    Convert a Message to a PyrisMessage
    """
-    contents = [TextMessageContentDTO(text_content=message["content"])]
+    contents = [TextMessageContentDTO(text_content=message.content)]
    return PyrisMessage(
-        sender=map_str_to_role(message["role"]),
+        sender=map_str_to_role(message.role),
        contents=contents,
        send_at=datetime.now(),
        num_input_tokens=num_input_tokens,
        num_output_tokens=num_output_tokens,
        model_info=model,
    )
app/pipeline/chat/code_feedback_pipeline.py (1)

45-45: Consider initializing tokens in the __init__ method

While declaring tokens: LLMTokenCount at the class level defines its type, initializing self.tokens in the __init__ method ensures that the attribute is instantiated when an object is created.

You may apply this change:

def __init__(self, callback: Optional[StatusCallback] = None):
    super().__init__(implementation_id="code_feedback_pipeline_reference_impl")
    # existing code...
+   self.tokens = LLMTokenCount()
app/llm/external/openai_chat.py (3)

71-72: Consider defaulting token counts to zero instead of -1

When usage does not include prompt_tokens or completion_tokens, the default value is set to -1. This might lead to confusion when interpreting token counts, as negative values may not be expected in token usage metrics.

Consider setting the default values to zero to accurately represent the absence of token usage:

-num_input_tokens = getattr(usage, "prompt_tokens", -1)
-num_output_tokens = getattr(usage, "completion_tokens", -1)
+num_input_tokens = getattr(usage, "prompt_tokens", 0)
+num_output_tokens = getattr(usage, "completion_tokens", 0)

Line range hint 105-105: Use logging instead of print for logging messages

The use of print statements is not recommended for logging purposes in a production environment. Utilizing the logging module provides better control over logging levels and formats.

Replace the print statement with a logging.info call to align with the logging practices used elsewhere in the code:

-print("Sending messages to OpenAI", messages)
+logging.info("Sending messages to OpenAI: %s", messages)

Line range hint 125-125: Correct the error message in exception handling

The error message states "Failed to interpret image after several attempts," which is not relevant to the chat functionality. This appears to be a copy-paste error and could cause confusion during debugging.

Update the error message to accurately reflect the operation being performed:

-logging.error("Failed to interpret image after several attempts.")
+logging.error("Failed to receive a response from OpenAI after several attempts.")
app/pipeline/chat/interaction_suggestion_pipeline.py (1)

Line range hint 57-171: Consider adding unit tests for the new token tracking functionality.

To ensure the robustness of the token tracking feature, please add unit tests that verify:

  • self.tokens is correctly assigned after pipeline execution.
  • self.tokens.pipeline is set to the appropriate PipelineEnum value.
  • The token counts reflect the actual usage during the pipeline run.
app/pipeline/lecture_ingestion_pipeline.py (2)

9-9: Potential naming conflict between imported module and variable tokens

You've imported tokens from sipbuild.generator.parser.tokens, and later used tokens as a variable name (self.tokens). This could lead to confusion or unintended behavior if the imported tokens is used elsewhere in the code. Consider renaming either the import or the variable to avoid naming conflicts.


282-282: Address the TODO: Implement sending token usage data to Artemis

There's a TODO comment indicating that the implementation for sending token usage data to Artemis is pending. Completing this functionality is crucial for tracking and reporting token usage as intended by the PR objectives.

Would you like assistance in generating the code to send self.tokens to Artemis? I can help draft the necessary implementation or open a new GitHub issue to track this task.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 9e19d18 and 6bcb002.

📒 Files selected for processing (21)
  • app/domain/data/token_usage_dto.py (1 hunks)
  • app/domain/pyris_message.py (1 hunks)
  • app/domain/status/status_update_dto.py (1 hunks)
  • app/llm/external/LLMTokenCount.py (1 hunks)
  • app/llm/external/PipelineEnum.py (1 hunks)
  • app/llm/external/ollama.py (3 hunks)
  • app/llm/external/openai_chat.py (3 hunks)
  • app/llm/langchain/iris_langchain_chat_model.py (3 hunks)
  • app/pipeline/chat/code_feedback_pipeline.py (3 hunks)
  • app/pipeline/chat/course_chat_pipeline.py (3 hunks)
  • app/pipeline/chat/exercise_chat_pipeline.py (8 hunks)
  • app/pipeline/chat/interaction_suggestion_pipeline.py (3 hunks)
  • app/pipeline/chat/lecture_chat_pipeline.py (3 hunks)
  • app/pipeline/competency_extraction_pipeline.py (4 hunks)
  • app/pipeline/lecture_ingestion_pipeline.py (4 hunks)
  • app/pipeline/pipeline.py (1 hunks)
  • app/pipeline/shared/citation_pipeline.py (3 hunks)
  • app/pipeline/shared/reranker_pipeline.py (3 hunks)
  • app/pipeline/shared/summary_pipeline.py (1 hunks)
  • app/retrieval/lecture_retrieval.py (3 hunks)
  • app/web/status/status_update.py (3 hunks)
🧰 Additional context used
🔇 Additional comments (47)
app/domain/data/token_usage_dto.py (2)

1-3: LGTM: Imports are appropriate and concise.

The imports are well-chosen for the purpose of this DTO:

  • pydantic.BaseModel provides robust data validation and serialization capabilities.
  • PipelineEnum is imported from a local module, which is good for maintaining a clear project structure.

1-10: Overall assessment: Well-implemented DTO for token usage tracking.

This new file introduces a clean and well-structured TokenUsageDTO that aligns perfectly with the PR objectives of tracking token usage across different pipelines. The use of Pydantic for the DTO provides robust data validation and serialization capabilities, which is a good practice.

The only minor suggestion is to add a docstring to the class for improved documentation.

Great job on implementing this crucial component for enhancing the tracking of iris request usage!

app/domain/status/status_update_dto.py (3)

5-5: LGTM: New import for TokenUsageDTO

The import of TokenUsageDTO is correctly placed and necessary for the new tokens attribute in the StatusUpdateDTO class. This change aligns with the PR objective of tracking token usage.


11-11: LGTM: New tokens attribute added to StatusUpdateDTO

The new tokens attribute in the StatusUpdateDTO class is well-implemented:

  1. It uses a clear and descriptive name.
  2. The type annotation (List[TokenUsageDTO]) is correct and matches the imported type.
  3. The default value of an empty list is a good practice for optional attributes.

This addition aligns with the PR objective of tracking token usage and sending it to Artemis as part of the status update.


Line range hint 1-11: Summary: Changes effectively support token usage tracking

The modifications to StatusUpdateDTO are minimal, focused, and directly support the PR objectives:

  1. The new tokens attribute allows for the inclusion of token usage data in status updates.
  2. This change enables Pyris to track and report token usage to Artemis, as mentioned in the PR objectives.

The implementation is clean, follows good practices, and integrates well with the existing code structure. These changes lay the groundwork for improved monitoring and management of token usage across different pipelines.

app/llm/external/PipelineEnum.py (3)

1-1: LGTM: Import statement is correct.

The import of Enum from the enum module is appropriate for defining an enumeration class.


4-4: LGTM: Well-defined enum class.

The PipelineEnum class is well-defined, inheriting from both str and Enum. This approach creates a string-based enum, which allows for easy string comparison and serialization while maintaining the benefits of an enumeration.


1-14: Summary: PipelineEnum aligns well with PR objectives.

The introduction of PipelineEnum is a solid foundation for tracking token usage across different pipeline types in the IRIS system. This enum class directly supports the PR's objective of enhancing the tracking of usage related to iris requests.

The implementation is clean, follows best practices for string-based enums in Python, and provides a comprehensive list of pipeline types. This will likely be used in conjunction with the LLMTokenCount type mentioned in the PR description to facilitate detailed token usage tracking.

Great job on laying the groundwork for improved usage monitoring!

app/llm/external/LLMTokenCount.py (4)

1-1: LGTM: Import statement is correct and necessary.

The import of PipelineEnum is properly done and is required for the class implementation.


4-9: LGTM: Class definition and attributes are well-structured.

The LLMTokenCount class is well-defined with clear and appropriate attributes. The use of type hints enhances code readability and aligns with Python best practices. The attributes effectively capture the necessary information for token usage tracking, which is in line with the PR objectives.


11-21: LGTM: Constructor is well-implemented.

The __init__ method is correctly implemented, initializing all attributes with the provided values. The use of type hints in the method signature is consistent with the attribute definitions, which is good practice.


1-24: Overall, excellent implementation of LLMTokenCount class.

The LLMTokenCount class is well-designed and implemented, providing a solid foundation for token usage tracking across different pipelines. It aligns perfectly with the PR objectives and integrates well with the existing system (e.g., using PipelineEnum). The use of type hints, clear attribute definitions, and informative string representation contribute to code readability and maintainability.

A few key strengths:

  1. Clear and appropriate attribute definitions
  2. Well-structured __init__ method
  3. Informative __str__ method

The class forms a crucial part of the token usage tracking system, which will be valuable for monitoring and managing resources across different pipelines.

app/domain/pyris_message.py (1)

19-21: Verify usage of new token and model info fields.

The new fields num_input_tokens, num_output_tokens, and model_info have been added to the PyrisMessage class. To ensure these changes are fully integrated:

  1. Verify that these fields are being populated correctly where PyrisMessage objects are created or updated.
  2. Check if any existing code needs to be updated to handle these new fields.
  3. Ensure that any serialization/deserialization logic elsewhere in the codebase is updated to include these new fields.

Run the following script to check for usage of the PyrisMessage class and the new fields:

This will help identify areas of the codebase that might need updates to fully utilize these new fields.

✅ Verification successful

New token and model info fields are properly utilized across the codebase.

All usages of num_input_tokens, num_output_tokens, and model_info in the PyrisMessage class have been verified and correctly implemented in the relevant files.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check usage of PyrisMessage and new fields

# Search for PyrisMessage usage
echo "PyrisMessage usage:"
rg --type python -A 5 "PyrisMessage"

# Search for the new field names (both snake_case and camelCase)
echo "\nNew field usage:"
rg --type python -A 5 -e "num_input_tokens" -e "numInputTokens" -e "num_output_tokens" -e "numOutputTokens" -e "model_info" -e "modelInfo"

Length of output: 323


Script:

#!/bin/bash
# Description: Check usage of PyrisMessage and new fields by targeting .py files

# Search for PyrisMessage usage
echo "PyrisMessage usage:"
rg -g "*.py" -A 5 "PyrisMessage"

# Search for the new field names (both snake_case and camelCase)
echo "\nNew field usage:"
rg -g "*.py" -A 5 -e "num_input_tokens" -e "numInputTokens" -e "num_output_tokens" -e "numOutputTokens" -e "model_info" -e "modelInfo"

Length of output: 33101

app/pipeline/pipeline.py (2)

2-2: LGTM: Import of List is correct and necessary.

The addition of from typing import List is appropriate for type hinting the new tokens attribute. This follows Python best practices for type annotations.


Line range hint 1-35: Clarify token tracking usage in pipeline execution.

The changes to add token tracking capability are consistent with the PR objectives. However, it's not clear from this file how the tokens attribute will be populated or used during pipeline execution.

To understand how token tracking is integrated into the pipeline execution, please run the following verification script:

#!/bin/bash
# Search for usage of 'tokens' attribute in pipeline execution
rg --type python -g '!app/pipeline/pipeline.py' 'self\.tokens' app/pipeline

Consider adding a comment or documentation to explain how subclasses should interact with the tokens attribute during execution.

app/llm/langchain/iris_langchain_chat_model.py (2)

10-11: LGTM: New imports for token counting.

The new imports for LLMTokenCount and PipelineEnum are correctly placed and align with the PR objectives to track token usage.


24-24: LGTM: New class attribute for token tracking.

The tokens attribute of type LLMTokenCount is correctly added and initialized. This aligns with the PR objectives and follows good practices for type hinting.

app/pipeline/shared/summary_pipeline.py (1)

Line range hint 1-72: Review other pipeline classes for consistency

While we've addressed the token tracking implementation in the SummaryPipeline class, it's important to ensure that these changes are applied consistently across all pipeline classes in the project. This will ensure that the PR objectives of adding token tracking to all Pipelines are fully met.

To verify the consistency of implementation across other pipeline classes, you can run the following script:

This script will help identify any inconsistencies in the implementation of token tracking across different pipeline classes.

✅ Verification successful

Run Updated Verification Scripts

To ensure consistent implementation of token tracking across all pipeline classes, please execute the following scripts:


Token Tracking Implementation Verified Across Pipeline Classes

The token tracking functionality has been consistently implemented across all pipeline classes in the project. All relevant classes initialize and utilize self.tokens, and LLMTokenCount is properly imported where necessary.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for consistent implementation of token tracking across pipeline classes

# Search for pipeline classes and their __init__ methods
echo "Checking pipeline classes for token tracking implementation:"
rg --type python -A 10 "class \w+Pipeline\(Pipeline\):" | rg -A 10 "def __init__"

# Search for usage of self.tokens in pipeline classes
echo "\nChecking usage of self.tokens in pipeline classes:"
rg --type python "self\.tokens" --glob "*pipeline.py"

# Search for LLMTokenCount import in pipeline files
echo "\nChecking for LLMTokenCount import in pipeline files:"
rg --type python "from .+import.+LLMTokenCount" --glob "*pipeline.py"

Length of output: 669


Script:

#!/bin/bash
# Description: Check for consistent implementation of token tracking across pipeline classes

# Search for pipeline classes and their __init__ methods
echo "Checking pipeline classes for token tracking implementation:"
rg "class \w+Pipeline\(Pipeline\):" --glob "*.py" -A 10 | rg "def __init__"

# Search for usage of self.tokens in pipeline classes
echo "\nChecking usage of self.tokens in pipeline classes:"
rg "self\.tokens" --glob "*pipeline.py"

# Search for LLMTokenCount import in pipeline files
echo "\nChecking for LLMTokenCount import in pipeline files:"
rg "from .+import.+LLMTokenCount" --glob "*pipeline.py"

Length of output: 3877

app/pipeline/shared/reranker_pipeline.py (2)

12-12: LGTM: New import for PipelineEnum

The import of PipelineEnum aligns with the PR objectives and is correctly placed within the import section.


Line range hint 1-115: Overall assessment: Changes align well with PR objectives

The modifications to the RerankerPipeline class successfully implement token usage tracking as outlined in the PR objectives. The changes are well-integrated and maintain the existing functionality of the pipeline.

Key points:

  1. The new import and use of PipelineEnum are appropriate.
  2. Token tracking is correctly implemented in the __call__ method.
  3. The self.tokens list is properly initialized to store token usage data.

Consider implementing the suggested improvements:

  1. Add a type hint for self.tokens.
  2. Implement error handling for self.llm.tokens in the __call__ method.

These enhancements will further improve code clarity and robustness.

app/web/status/status_update.py (1)

22-22: LGTM: New import for LLMTokenCount

The new import for LLMTokenCount is correctly added and aligns with the PR objectives of tracking token usage.

app/pipeline/chat/course_chat_pipeline.py (4)

44-44: LGTM: New import for token tracking

The addition of PipelineEnum import is consistent with the PR objectives for tracking token usage across different pipelines.


111-111: LGTM: New attribute for token tracking

The addition of self.tokens as a list to store token counts is in line with the PR objectives for tracking token usage during pipeline execution.


411-413: LGTM: Token tracking implementation

The implementation of token tracking is well-executed:

  1. Retrieves the token count from self.llm.tokens.
  2. Sets the pipeline type using PipelineEnum.IRIS_CHAT_COURSE_MESSAGE.
  3. Appends the token count to self.tokens list.

This is consistent with the PR objectives for tracking token usage across different pipelines.


Line range hint 1-489: Overall assessment: Well-implemented token tracking

The changes in this file successfully implement token tracking for the CourseChatPipeline, aligning with the PR objectives. Key points:

  1. New import and attribute for token tracking.
  2. Token count collection during pipeline execution.
  3. Integration with citation pipeline tokens.
  4. Reporting of token usage to Artemis.

The implementation is clean and consistent. A minor suggestion for improved readability has been made, but overall, the changes are approved and ready for merging.

app/pipeline/shared/citation_pipeline.py (2)

10-10: Verify the import path for PipelineEnum

Please ensure that PipelineEnum is correctly imported from app.llm.external.PipelineEnum. Confirm that this module path is accurate and that PipelineEnum is accessible from this location.


88-90: ⚠️ Potential issue

Assigning pipeline attribute to token_count may cause errors

Ensure that self.llm.tokens returns an object that allows setting the pipeline attribute. If token_count is an instance of a class without a predefined pipeline attribute (e.g., an immutable dataclass), this assignment could raise an AttributeError. Verify that the LLMTokenCount class is designed to have a mutable pipeline attribute.

app/pipeline/competency_extraction_pipeline.py (4)

17-18: Imports added for token tracking

The addition of LLMTokenCount and PipelineEnum imports is appropriate for implementing token usage tracking.


43-43: Initialization of self.tokens

Initializing self.tokens as an empty list to store token usage data is correct.


111-111: Confirm self.callback.done accepts the tokens parameter

Ensure that the done method of self.callback is updated to accept the tokens parameter to handle token usage data.

You can verify this by running:

#!/bin/bash
# Description: Verify that 'done' method accepts 'tokens' parameter.

# Test: Search for the 'done' method definition in 'CompetencyExtractionCallback'.
rg --type python 'def done' -A 5

# Expected: The method signature includes 'tokens' as a parameter.

82-88: Verify that response contains required token attributes

Ensure that the response object from self.request_handler.chat includes model_info, num_input_tokens, and num_output_tokens attributes necessary for LLMTokenCount.

To confirm, you can run the following script:

app/pipeline/chat/code_feedback_pipeline.py (2)

16-17: Imports for token tracking added correctly

The imports for LLMTokenCount and PipelineEnum have been properly added to support token usage tracking in the pipeline.


147-149: Verify that LLMTokenCount has a pipeline attribute

Ensure that the LLMTokenCount class includes a pipeline attribute to store the pipeline type. This prevents potential AttributeError when setting num_tokens.pipeline.

You can run the following script to verify if the pipeline attribute exists in LLMTokenCount:

✅ Verification successful

Verified: LLMTokenCount class includes the pipeline attribute

The LLMTokenCount class correctly defines and initializes the pipeline attribute, ensuring that setting num_tokens.pipeline will not cause an AttributeError.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that 'LLMTokenCount' class has a 'pipeline' attribute.

# Search for the 'LLMTokenCount' class definition with a 'pipeline' attribute
ast-grep --lang python --pattern $'class LLMTokenCount:
    $$$
    pipeline: $_
    $$$'

Length of output: 1457

app/llm/external/openai_chat.py (2)

74-74: ⚠️ Potential issue

Fix parameter name inconsistency in TextMessageContentDTO

The parameter textContent is inconsistent with the naming convention used elsewhere, where text_content is preferred. This inconsistency might cause errors if the TextMessageContentDTO class expects text_content.

Update the parameter name to maintain consistency and prevent potential attribute errors:

-contents=[TextMessageContentDTO(textContent=message.content)],
+contents=[TextMessageContentDTO(text_content=message.content)],

Likely invalid or redundant comment.


116-118: Ensure response.usage and response.model are always available

While the code assumes that response.usage and response.model are present, there could be cases where these attributes are missing. This might lead to AttributeError exceptions.

Run the following script to verify that all responses from OpenAI include the usage and model attributes:

Ensure that the output includes the usage and model fields. If these fields can be absent, consider adding checks in the code to handle such cases gracefully.

app/pipeline/chat/interaction_suggestion_pipeline.py (3)

37-38: Import statements added for token tracking.

The additions of LLMTokenCount and PipelineEnum imports are appropriate for token usage tracking.


57-57: Introduced tokens attribute to InteractionSuggestionPipeline.

Adding the tokens attribute to the class enables tracking of token usage, aligning with the goal of monitoring resource utilization.


170-171: Token usage data correctly assigned after pipeline invocation.

Assigning self.tokens = self.llm.tokens and setting self.tokens.pipeline after invoking the pipeline correctly updates the token usage information.

app/pipeline/chat/lecture_chat_pipeline.py (3)

19-19: LGTM!

The import statement correctly includes PipelineEnum, which is necessary for assigning the pipeline attribute to the token usage data.


78-78: LGTM!

Initializing self.tokens as an empty list prepares the pipeline to collect and store token usage data effectively.


125-125: LGTM!

Extending self.tokens with tokens from the citation_pipeline effectively aggregates token usage from both pipelines.

app/pipeline/chat/exercise_chat_pipeline.py (5)

37-37: Importing PipelineEnum

The import statement correctly adds PipelineEnum from the external module. This is necessary for specifying pipeline types in token tracking.


82-82: Initialize self.tokens for token tracking

Initializing self.tokens as an empty list allows for collecting token usage data throughout the pipeline execution.


103-105: Pass token usage to callback

The tokens parameter is appropriately added to self.callback.done() to transmit the collected token usage data.


211-212: Append tokens from code_feedback_pipeline

Tokens from code_feedback_pipeline are correctly appended to self.tokens when available.


233-234: Append tokens from retriever

Tokens from self.retriever are correctly appended to self.tokens when available.

app/retrieval/lecture_retrieval.py (1)

9-9: Importing LLMTokenCount

The import statement for LLMTokenCount is appropriate and aligns with the integration of token counting functionality.

app/pipeline/pipeline.py Outdated Show resolved Hide resolved
app/llm/langchain/iris_langchain_chat_model.py Outdated Show resolved Hide resolved
@@ -45,6 +45,7 @@ def __init__(self):
)
# Create the pipeline
self.pipeline = self.prompt | self.llm | StrOutputParser()
self.tokens = []
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Incomplete implementation of token tracking functionality

The addition of self.tokens = [] is a step towards implementing token tracking, but it falls short of the PR objectives. Consider the following points:

  1. The PR objectives mention adding a tokens argument to all Pipelines, which is not implemented in the __init__ method.
  2. The self.tokens list is initialized but never used in the class methods, particularly in the __call__ method where token usage should likely be tracked.
  3. There's no implementation of sending token usage data to Artemis as mentioned in the PR objectives.
  4. The LLMTokenCount type mentioned in the PR objectives is not used or imported.

To fully implement the token tracking functionality, consider the following changes:

  1. Update the __init__ method to accept a tokens argument:
def __init__(self, tokens: Optional[List[LLMTokenCount]] = None):
    super().__init__(implementation_id="summary_pipeline")
    self.tokens = tokens or []
  1. Implement token usage tracking in the __call__ method:
def __call__(self, query: str, **kwargs) -> str:
    # ... existing code ...
    response: str = self.pipeline.invoke({"text": query})
    # Track token usage
    token_count = self.llm.get_num_tokens(response)  # Assuming this method exists
    self.tokens.append(LLMTokenCount(count=token_count, pipeline=PipelineEnum.SUMMARY))
    # ... rest of the method ...
  1. Add a method to send token usage to Artemis (this might require additional dependencies):
def send_token_usage_to_artemis(self):
    # Implementation to send self.tokens to Artemis
    pass
  1. Import necessary types and enums at the top of the file:
from typing import List, Optional
from .token_types import LLMTokenCount, PipelineEnum

Would you like me to provide a more detailed implementation or open a GitHub issue to track these changes?

Comment on lines 113 to 115
num_tokens = self.llm.tokens
num_tokens.pipeline = PipelineEnum.IRIS_RERANKER_PIPELINE
self.tokens.append(num_tokens)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Potential Missing Error Handling for self.llm.tokens Across Codebase

The recent addition of error handling for self.llm.tokens in app/pipeline/shared/reranker_pipeline.py is a positive step towards ensuring robustness. However, the usage of self.llm.tokens has been identified in multiple other files without similar checks. It's recommended to implement appropriate error handling in all instances where self.llm.tokens is accessed to prevent potential NoneType errors.

Affected Files:

  • app/retrieval/lecture_retrieval.py
  • app/pipeline/lecture_ingestion_pipeline.py
  • app/pipeline/shared/citation_pipeline.py
  • app/pipeline/chat/course_chat_pipeline.py
  • app/pipeline/chat/interaction_suggestion_pipeline.py
  • app/pipeline/chat/lecture_chat_pipeline.py
  • app/pipeline/chat/exercise_chat_pipeline.py
  • app/pipeline/chat/code_feedback_pipeline.py
🔗 Analysis chain

LGTM: Token tracking logic added

The new token tracking logic aligns well with the PR objectives. It correctly captures the token usage and associates it with the specific pipeline type.

However, consider adding error handling to ensure self.llm.tokens is not None before accessing it. Here's a suggested improvement:

if hasattr(self.llm, 'tokens') and self.llm.tokens is not None:
    num_tokens = self.llm.tokens
    num_tokens.pipeline = PipelineEnum.IRIS_RERANKER_PIPELINE
    self.tokens.append(num_tokens)
else:
    logger.warning("Token usage information is not available for this LLM.")

To verify the usage of self.llm.tokens across the codebase, you can run the following script:

This will help ensure consistent handling of token usage across different parts of the application.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the usage of self.llm.tokens across the codebase

# Test: Search for occurrences of self.llm.tokens
rg --type python -A 5 'self\.llm\.tokens'

Length of output: 74


Script:

#!/bin/bash
# Description: Verify the usage of self.llm.tokens across the codebase by searching Python files

# Test: Search for occurrences of self.llm.tokens in .py files
rg --glob '*.py' -A 5 'self\.llm\.tokens'

Length of output: 5311

@@ -38,6 +39,7 @@ def __init__(self):
with open(prompt_file_path, "r") as file:
self.prompt_str = file.read()
self.pipeline = self.llm | StrOutputParser()
self.tokens = []
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Potential concurrency issues with self.tokens

Initializing self.tokens as a list may lead to concurrency issues if instances of CitationPipeline are used across multiple threads or asynchronous tasks. Appending to a shared list without proper synchronization can cause race conditions. Consider using thread-safe data structures or handling token counts in a way that avoids shared mutable state.

app/pipeline/lecture_ingestion_pipeline.py Outdated Show resolved Hide resolved
app/pipeline/chat/exercise_chat_pipeline.py Outdated Show resolved Hide resolved
app/pipeline/chat/exercise_chat_pipeline.py Outdated Show resolved Hide resolved
Comment on lines 85 to 86
tokens: LLMTokenCount

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Initialize tokens in the __init__ method

The tokens attribute is declared but not initialized in the constructor. This could lead to an AttributeError if accessed before assignment. It is recommended to initialize tokens in the __init__ method.

Apply this diff to initialize tokens:

 def __init__(self, client: WeaviateClient, **kwargs):
     super().__init__(implementation_id="lecture_retrieval_pipeline")
+    self.tokens = LLMTokenCount()
     request_handler = CapabilityRequestHandler(
         requirements=RequirementList(
             gpt_version_equivalent=3.5,

Committable suggestion was skipped due to low confidence.

app/retrieval/lecture_retrieval.py Outdated Show resolved Hide resolved
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (5)
app/domain/data/token_usage_dto.py (1)

6-12: LGTM: Well-structured DTO for token usage tracking.

The TokenUsageDTO class is well-designed and aligns perfectly with the PR objectives:

  • It includes all necessary attributes for tracking token usage and associated costs.
  • The use of specific types (str, int, float) enhances data validation.
  • The pipeline attribute using PipelineEnum allows for categorization of token usage by pipeline.

Consider adding a class-level docstring to provide a brief description of the DTO's purpose and its attributes. This would enhance code readability and maintainability. For example:

class TokenUsageDTO(BaseModel):
    """
    Data Transfer Object for token usage information.

    Attributes:
        model_info (str): Information about the model used.
        num_input_tokens (int): Number of input tokens.
        cost_per_input_token (float): Cost per input token.
        num_output_tokens (int): Number of output tokens.
        cost_per_output_token (float): Cost per output token.
        pipeline (PipelineEnum): The pipeline associated with this token usage.
    """
    # ... (rest of the class definition)
app/domain/pyris_message.py (3)

20-20: LGTM: Well-defined field for cost per input token.

The cost_per_input_token field is correctly implemented with the appropriate type, default value, and alias. It supports the PR objective of tracking usage costs.

Consider adding a comment explaining the unit of cost (e.g., USD, EUR) to improve clarity:

cost_per_input_token: float = Field(alias="costPerInputToken", default=0)  # Cost in USD per input token

22-22: LGTM: Well-defined field for cost per output token.

The cost_per_output_token field is correctly implemented with the appropriate type, default value, and alias. It complements the cost_per_input_token field and supports comprehensive cost tracking.

For consistency with the cost_per_input_token field, consider adding a comment explaining the unit of cost:

cost_per_output_token: float = Field(alias="costPerOutputToken", default=0)  # Cost in USD per output token

23-23: LGTM: Useful field for storing model information.

The model_info field is well-defined and provides valuable context about the model used in token generation. This aligns with the PR objective of enhanced tracking for iris requests.

To improve clarity, consider adding a comment explaining the expected format or content of the model_info field:

model_info: str = Field(alias="modelInfo", default="")  # Format: "model_name:version" (e.g., "gpt-3.5-turbo:1")
app/llm/external/LLMTokenCount.py (1)

29-33: Consider using a multi-line f-string for improved readability.

The __str__ method provides a comprehensive string representation of the object. However, the readability could be improved by using a multi-line f-string.

Here's a suggested improvement:

def __str__(self):
    return f"""\
{self.model_info}:
    Input: {self.num_input_tokens} tokens, cost {self.cost_per_input_token}
    Output: {self.num_output_tokens} tokens, cost {self.cost_per_output_token}
    Pipeline: {self.pipeline}"""

This format improves readability and makes it easier to add or modify fields in the future.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 6bcb002 and 4324180.

📒 Files selected for processing (5)
  • app/domain/data/token_usage_dto.py (1 hunks)
  • app/domain/pyris_message.py (1 hunks)
  • app/llm/external/LLMTokenCount.py (1 hunks)
  • app/llm/langchain/iris_langchain_chat_model.py (3 hunks)
  • app/llm/request_handler/capability_request_handler.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/llm/langchain/iris_langchain_chat_model.py
🧰 Additional context used
🔇 Additional comments (9)
app/domain/data/token_usage_dto.py (2)

1-3: LGTM: Appropriate imports for the DTO.

The imports are well-chosen:

  1. BaseModel from pydantic provides robust data validation for the DTO.
  2. PipelineEnum import aligns with the PR objective of tracking token usage across different pipelines.

1-12: Overall: Excellent implementation of TokenUsageDTO

This new file introduces a well-structured DTO for token usage tracking, which aligns perfectly with the PR objectives. The use of pydantic's BaseModel and specific types for attributes ensures robust data validation. The inclusion of the PipelineEnum allows for effective categorization of token usage across different pipelines.

A minor suggestion for adding a class-level docstring was made to enhance code documentation, but this is not critical for functionality.

Great job on implementing this crucial component for tracking token usage in the Pyris project!

app/domain/pyris_message.py (2)

19-19: LGTM: Appropriate field for tracking input tokens.

The num_input_tokens field is well-defined with the correct type, default value, and alias. It aligns with the PR objective of tracking token usage for iris requests.


21-21: LGTM: Appropriate field for tracking output tokens.

The num_output_tokens field is well-defined with the correct type, default value, and alias. It complements the num_input_tokens field and supports the PR objective of comprehensive token usage tracking.

app/llm/external/LLMTokenCount.py (4)

1-1: LGTM: Import statement is correct and follows best practices.

The import statement is well-structured, importing only the specific enum needed from the correct module path.


4-11: LGTM: Well-structured class definition with appropriate attributes.

The LLMTokenCount class is well-defined with clear and descriptive attribute names. The use of type hints for all attributes is commendable, enhancing code readability and type safety. The inclusion of the PipelineEnum for the pipeline attribute ensures consistency in pipeline identification.


13-27: LGTM: Well-implemented __init__ method.

The __init__ method is correctly implemented with:

  • Parameters matching class attributes
  • Consistent use of type hints
  • Proper initialization of all attributes

This implementation ensures that all necessary data is provided when creating an instance of LLMTokenCount.


1-33: Overall, excellent implementation of the LLMTokenCount class.

This new class aligns well with the PR objectives of tracking token usage for iris requests. The code is clean, well-organized, and follows Python best practices. The consistent use of type hints throughout the file is commendable.

A few key strengths:

  1. Clear and descriptive attribute names
  2. Proper use of type hints
  3. Well-structured __init__ method
  4. Informative __str__ method

The only suggestion for improvement is to consider using a multi-line f-string in the __str__ method for better readability.

Great job on implementing this crucial component for token usage tracking!

app/llm/request_handler/capability_request_handler.py (1)

47-50: ⚠️ Potential issue

Ensure 'cost_per_input_token' and 'cost_per_output_token' are defined in 'PyrisMessage'

Assigning cost_per_input_token and cost_per_output_token directly to the message object assumes that these attributes exist in the PyrisMessage class. If not, this could lead to an AttributeError at runtime. It's important to verify that these attributes are properly defined within PyrisMessage.

Run the following script to verify that these attributes are defined:

If these attributes are not defined, consider adding them to the PyrisMessage class:

+ class PyrisMessage:
+     # Existing attributes...
+     cost_per_input_token: float = 0.0
+     cost_per_output_token: float = 0.0

app/domain/pyris_message.py Outdated Show resolved Hide resolved
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (5)
app/llm/external/ollama.py (1)

Line range hint 60-73: LGTM! Consider enhancing the function documentation.

The changes to convert_to_iris_message align well with the PR objectives of tracking token usage. The new parameters allow for more detailed message conversion, including token counts and model information.

Consider updating the function's docstring to reflect the new parameters and their purpose. For example:

def convert_to_iris_message(
    message: Message, num_input_tokens: int, num_output_tokens: int, model: str
) -> PyrisMessage:
    """
    Convert a Message to a PyrisMessage

    Args:
        message (Message): The message to convert
        num_input_tokens (int): The number of input tokens used
        num_output_tokens (int): The number of output tokens generated
        model (str): The model used for generation

    Returns:
        PyrisMessage: The converted message with token usage information
    """
app/pipeline/competency_extraction_pipeline.py (1)

111-111: Consider passing only the current execution's token usage.

The addition of tokens=self.tokens to the callback is good for providing token usage data. However, self.tokens accumulates data across multiple pipeline executions. For status updates, it might be more appropriate to pass only the token usage from the current execution.

Consider modifying the line as follows:

self.callback.done(final_result=generated_competencies, tokens=[self.tokens[-1]])

This ensures that only the most recent token usage is sent with each status update.

app/pipeline/chat/code_feedback_pipeline.py (1)

147-149: LGTM: Token usage tracking implemented.

The implementation of token usage tracking is correct and aligns with the PR objectives. The token count is retrieved from the LLM, the pipeline type is set, and the information is stored in the self.tokens attribute.

Consider adding a comment explaining the purpose of these lines for better code readability:

# Track token usage for this pipeline
token_usage = self.llm.tokens
token_usage.pipeline = PipelineEnum.IRIS_CODE_FEEDBACK
self.tokens = token_usage
app/pipeline/lecture_ingestion_pipeline.py (2)

278-285: Token usage tracking implemented, but TODO remains

The implementation of token usage tracking is good. However, there's a TODO comment indicating that sending this data to Artemis is still pending.

  1. The clean function application improves the quality of the merged content.
  2. Token usage is correctly captured and categorized for the IRIS_LECTURE_INGESTION pipeline.
  3. The token usage is properly appended to self.tokens.

Would you like assistance in implementing the logic to send this data to Artemis, or should we create a GitHub issue to track this TODO?


Line range hint 1-339: Summary: Token usage tracking successfully implemented

The changes in this file successfully implement token usage tracking for the lecture ingestion pipeline, aligning well with the PR objectives. Key points:

  1. The PipelineEnum import and self.tokens initialization set up the foundation for token tracking.
  2. Token usage is captured and categorized correctly in the merge_page_content_and_image_interpretation method.
  3. The previous issue with variable reference has been resolved.

However, there's still a pending TODO to send this data to Artemis. Consider addressing this in a follow-up task or PR to fully complete the token usage tracking feature.

To fully realize the benefits of this token tracking implementation, ensure that the data sent to Artemis is structured in a way that allows for easy analysis and reporting of token usage across different pipelines. This will provide valuable insights into resource utilization and help in optimizing the system's performance.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 4324180 and c9e89be.

📒 Files selected for processing (10)
  • app/llm/external/PipelineEnum.py (1 hunks)
  • app/llm/external/ollama.py (3 hunks)
  • app/pipeline/chat/code_feedback_pipeline.py (3 hunks)
  • app/pipeline/chat/exercise_chat_pipeline.py (9 hunks)
  • app/pipeline/chat/lecture_chat_pipeline.py (3 hunks)
  • app/pipeline/competency_extraction_pipeline.py (4 hunks)
  • app/pipeline/lecture_ingestion_pipeline.py (3 hunks)
  • app/pipeline/pipeline.py (1 hunks)
  • app/pipeline/shared/reranker_pipeline.py (3 hunks)
  • app/retrieval/lecture_retrieval.py (7 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • app/llm/external/PipelineEnum.py
  • app/pipeline/chat/lecture_chat_pipeline.py
  • app/pipeline/pipeline.py
  • app/pipeline/shared/reranker_pipeline.py
🧰 Additional context used
🔇 Additional comments (22)
app/llm/external/ollama.py (2)

116-121: LGTM! Good job addressing the previous review comment.

The changes to the chat method effectively implement token usage tracking and address the concerns raised in the previous review about error handling for missing keys. Using the get method with default values is a robust approach to handle potential missing data.

This implementation successfully addresses the previous review comment about adding error handling for missing keys in the 'response' dictionary.


Line range hint 60-121: Overall, excellent implementation of token usage tracking!

The changes in this file successfully implement token usage tracking and address previous concerns about error handling. The modifications align well with the PR objectives and enhance the robustness of the code. Great job on improving both functionality and code quality!

app/pipeline/competency_extraction_pipeline.py (4)

17-18: LGTM: New imports for token tracking.

The new imports for LLMTokenCount and PipelineEnum are correctly added and necessary for the token tracking functionality being implemented.


43-43: LGTM: New instance variable for token tracking.

The addition of self.tokens as an empty list is appropriate for accumulating token usage data across multiple pipeline executions.


82-88: LGTM: Token tracking implementation.

The implementation of token tracking is well-structured:

  1. Correctly creates an LLMTokenCount object with relevant data.
  2. Uses the appropriate PipelineEnum to identify this pipeline.
  3. Appends the token usage to self.tokens for accumulation.

This aligns well with the PR objectives for tracking token usage across different pipelines.


Line range hint 1-111: Overall implementation looks good.

The changes made to implement token tracking in the CompetencyExtractionPipeline are well-structured and align with the PR objectives. The token usage is correctly captured and stored. The only suggestion for improvement is to consider passing only the current execution's token usage to the callback for more accurate status updates.

app/pipeline/chat/code_feedback_pipeline.py (3)

16-17: LGTM: New imports for token tracking.

The new imports for LLMTokenCount and PipelineEnum are correctly added and align with the PR objectives of tracking token usage across different pipelines.


45-45: LGTM: New attribute for token tracking.

The addition of the tokens attribute of type LLMTokenCount is appropriate for storing token usage information in the CodeFeedbackPipeline class.


Line range hint 1-149: Summary: Token usage tracking successfully implemented.

The changes in this file successfully implement token usage tracking for the CodeFeedbackPipeline class. The new imports, attribute, and logic in the __call__ method all contribute to achieving the PR objective of enhancing the tracking of usage related to iris requests.

The implementation allows for:

  1. Storing token usage information specific to this pipeline.
  2. Setting the correct pipeline type for accurate tracking.
  3. Preparing the data to be sent to Artemis as part of a status update.

These changes lay the groundwork for improved monitoring and management of token usage across different pipelines in the Pyris project.

app/pipeline/lecture_ingestion_pipeline.py (3)

21-21: LGTM: New import for PipelineEnum

The addition of PipelineEnum import is appropriate and aligns with the PR objectives of tracking token usage across different pipelines.


116-116: LGTM: Initialization of self.tokens

The initialization of self.tokens as an empty list is appropriate for storing token usage information during the pipeline's execution.


284-284: Fixed: Correct usage of self.tokens

The previous issue of using tokens instead of self.tokens has been addressed. The code now correctly uses self.tokens.append(token_usage), resolving the variable reference problem.

app/pipeline/chat/exercise_chat_pipeline.py (6)

37-37: LGTM: Import statement for PipelineEnum added

The import statement for PipelineEnum is correctly placed and aligns with the PR objectives of enhancing token usage tracking across different pipelines.


82-82: LGTM: self.tokens initialized for token tracking

The addition of self.tokens = [] in the __init__ method is appropriate for accumulating token usage data throughout the pipeline execution, which aligns with the PR objectives.


103-105: LGTM: Token handling improved in call method

The changes in the __call__ method effectively incorporate token tracking:

  1. Tokens are now included in the callback.done() method.
  2. Suggestion pipeline tokens are handled with a null check before being passed to the callback.

These modifications align with the PR objectives and address a previous review comment about null checking self.suggestion_pipeline.tokens.

Also applies to: 119-127


215-216: LGTM: Token collection improved in _run_exercise_chat_pipeline method

The changes in the _run_exercise_chat_pipeline method enhance token tracking:

  1. Tokens from code_feedback_pipeline and retriever are now appended to self.tokens with null checks.
  2. The new _collect_llm_tokens() method is called at appropriate points in the pipeline execution.

These modifications align with the PR objectives and address a previous review comment about refactoring duplicated code for collecting LLM tokens.

Also applies to: 237-238, 271-271, 286-286


389-392: LGTM: _collect_llm_tokens method added for centralized token collection

The new _collect_llm_tokens method effectively centralizes the logic for collecting LLM tokens:

  1. It includes a null check before appending tokens, which is good practice.
  2. The method sets the pipeline attribute of the tokens to PipelineEnum.IRIS_CHAT_EXERCISE_MESSAGE, aligning with the PR objectives.

This addition addresses a previous review comment about refactoring duplicated code for collecting LLM tokens, improving code maintainability.


Line range hint 37-392: Overall LGTM: Token tracking successfully implemented

The changes in this file effectively implement token tracking across the ExerciseChatPipeline:

  1. Token collection is consistently implemented for various pipeline components (LLM, code feedback, retriever, suggestion pipeline).
  2. Proper null checks and error handling have been added where necessary.
  3. Code structure has been improved by refactoring duplicated logic into the _collect_llm_tokens method.

These modifications align well with the PR objectives of enhancing the tracking of usage related to iris requests. The implementation will provide better insights into resource utilization across different pipelines.

app/retrieval/lecture_retrieval.py (4)

284-286: Ensure consistent thread-safe token usage tracking

The token usage tracking implementation in this method is consistent with rewrite_student_query, which is good for maintainability. However, it has the same potential thread safety issue.

Please apply the same solution as suggested for the rewrite_student_query method to ensure thread safety.


322-324: Ensure consistent thread-safe token usage tracking and fix typo

The token usage tracking implementation in this method is consistent with previous methods, which is good for maintainability. However, it has the same potential thread safety issue.

Please apply the same solution as suggested for the rewrite_student_query method to ensure thread safety.

There's a typo in the logging message:

-    logger.info(f"Response from retirval pipeline: {response}")
+    logger.info(f"Response from retrieval pipeline: {response}")

364-366: Ensure consistent thread-safe token usage tracking

The token usage tracking implementation in this method is consistent with previous methods, which is good for maintainability. However, it has the same potential thread safety issue.

Please apply the same solution as suggested for the rewrite_student_query method to ensure thread safety.


Line range hint 1-524: Summary of changes and recommendations

The implementation of token usage tracking aligns well with the PR objectives. The changes are consistent across multiple methods, which is good for maintainability. However, there are a few important points to address:

  1. Initialize the tokens attribute in the constructor to prevent potential AttributeErrors.
  2. Implement a thread-safe solution for token usage tracking, as suggested in the previous comments, to avoid race conditions when methods are invoked concurrently.
  3. Fix the typo in the logging message in the rewrite_elaborated_query method.

Addressing these points will significantly improve the reliability and correctness of the token tracking feature. Overall, the changes are a good step towards enhancing the monitoring and management of token usage across different pipelines.

Comment on lines 9 to 10
from ..llm.external.LLMTokenCount import LLMTokenCount
from ..llm.external.PipelineEnum import PipelineEnum
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Initialize tokens attribute in the constructor

The new imports and the tokens attribute declaration align with the PR objectives for token usage tracking. However, the tokens attribute is not initialized in the constructor, which could lead to AttributeError if accessed before assignment.

To fix this, initialize the tokens attribute in the __init__ method:

 def __init__(self, client: WeaviateClient, **kwargs):
     super().__init__(implementation_id="lecture_retrieval_pipeline")
+    self.tokens: List[LLMTokenCount] = []
     request_handler = CapabilityRequestHandler(
         requirements=RequirementList(
             gpt_version_equivalent=3.5,
             context_length=16385,
             privacy_compliance=True,
         )
     )
     # ... rest of the constructor ...

Also applies to: 86-87

@alexjoham alexjoham changed the title Track usage of iris requests Track token usage of iris requests Oct 12, 2024
app/domain/pyris_message.py Outdated Show resolved Hide resolved
app/llm/external/LLMTokenCount.py Outdated Show resolved Hide resolved
Comment on lines 48 to 55
self.tokens = LLMTokenCount(
model_info=iris_message.model_info,
num_input_tokens=iris_message.num_input_tokens,
cost_per_input_token=iris_message.cost_per_input_token,
num_output_tokens=iris_message.num_output_tokens,
cost_per_output_token=iris_message.cost_per_output_token,
pipeline=PipelineEnum.NOT_SET,
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't this overwrite existing any token counts when this wrapper is used a second time?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The token information is saved in every pipeline as soon as the LLM call is done, so the token counts can be overwritten without any loss

app/pipeline/lecture_ingestion_pipeline.py Outdated Show resolved Hide resolved
app/retrieval/lecture_retrieval.py Show resolved Hide resolved
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Outside diff range and nitpick comments (12)
app/common/PipelineEnum.py (1)

5-16: LGTM: Comprehensive and well-structured enum members.

The enum members are consistently named and cover a wide range of pipeline types, which aligns well with the PR objectives of tracking usage for various IRIS requests. The inclusion of a NOT_SET member is a good practice for handling undefined cases.

Consider adding a brief class-level docstring to explain the purpose of this enum and how it relates to the IRIS system. This would enhance the code's self-documentation. For example:

class PipelineEnum(str, Enum):
    """
    Enumeration of pipeline types used in the IRIS system.
    These constants represent various stages or types of pipelines
    for tracking and managing different IRIS requests.
    """
    # ... (enum members)
app/common/token_usage_dto.py (2)

6-12: LGTM: Well-structured DTO with appropriate field definitions.

The TokenUsageDTO class is well-defined using Pydantic's BaseModel. The fields are correctly typed and aliased for JSON compatibility, with sensible default values. The use of PipelineEnum for the pipeline field aligns well with the PR objectives.

Consider adding a class-level docstring to describe the purpose and usage of this DTO. For example:

class TokenUsageDTO(BaseModel):
    """
    Data Transfer Object for token usage information.
    
    This class encapsulates information about token usage, including input and output
    token counts, associated costs, and the pipeline in which the tokens were used.
    """
    # ... existing field definitions ...

14-18: LGTM: Comprehensive string representation.

The __str__ method provides a clear and informative string representation of the TokenUsageDTO object, including all relevant field values. The use of an f-string and multi-line formatting enhances readability.

Consider adding .value when referencing self.pipeline in the string representation to ensure you're displaying the enum's value rather than potentially its string representation:

f"... pipeline: {self.pipeline.value} "

This change would ensure consistency in how the pipeline is represented as a string.

app/pipeline/pipeline.py (1)

36-38: LGTM with a suggestion: Initialize self.tokens in the constructor.

The _append_tokens method is well-implemented and aligns with the PR objectives. It correctly sets the pipeline attribute of the tokens object before appending it to the list.

However, to prevent potential AttributeErrors, consider initializing self.tokens in the constructor:

def __init__(self, implementation_id=None, **kwargs):
    self.implementation_id = implementation_id
+   self.tokens = []

This ensures that self.tokens is always initialized as an empty list when a new Pipeline object is created.

app/llm/request_handler/request_handler_interface.py (2)

Line range hint 33-35: Consider using a more specific type for chat messages.

The chat method currently uses list[any] for the messages parameter. To improve type safety and code clarity, consider using a more specific type that represents the structure of chat messages.

You could define a ChatMessage type or use PyrisMessage if it's suitable. For example:

from typing import List

def chat(self, messages: List[PyrisMessage], arguments: CompletionArguments) -> PyrisMessage:
    """Create a completion from the chat messages"""
    raise NotImplementedError

Line range hint 24-29: Add return type hint for the complete method.

The complete method is missing a return type hint. Adding it would improve code readability and type checking.

Consider updating the method signature as follows:

def complete(
    self,
    prompt: str,
    arguments: CompletionArguments,
    image: Optional[ImageMessageContentDTO] = None,
) -> str:
    """Create a completion from the prompt"""
    raise NotImplementedError
app/pipeline/chat/code_feedback_pipeline.py (1)

147-149: LGTM: Token usage tracking implemented correctly.

The implementation of token usage tracking aligns well with the PR objectives. The pipeline type is correctly set, and the token usage is retrieved and stored appropriately.

Consider adding error handling to ensure self.llm.tokens exists before accessing it:

if hasattr(self.llm, 'tokens'):
    token_usage = self.llm.tokens
    token_usage.pipeline = PipelineEnum.IRIS_CODE_FEEDBACK
    self.tokens = token_usage
else:
    logger.warning("Token usage information not available")

This addition would make the code more robust against potential changes in the IrisLangchainChatModel implementation.

app/pipeline/lecture_ingestion_pipeline.py (4)

254-256: Token tracking for image interpretation

The _append_tokens method is called after image interpretation. This is good for tracking token usage for this specific operation.

However, consider adding error handling around this call to ensure it doesn't break the main flow if there's an issue with token tracking.

 response = self.llm_vision.chat(
     [iris_message], CompletionArguments(temperature=0, max_tokens=512)
 )
-self._append_tokens(
-    response.token_usage, PipelineEnum.IRIS_LECTURE_INGESTION
-)
+try:
+    self._append_tokens(
+        response.token_usage, PipelineEnum.IRIS_LECTURE_INGESTION
+    )
+except Exception as e:
+    logger.warning(f"Failed to append tokens: {e}")

285-289: Token tracking for content merging

Token tracking is added for the content merging operation. The use of clean function is good for maintaining consistent output.

However, similar to the previous suggestion, consider adding error handling for the token tracking call.

 clean_output = clean(
     (prompt | self.pipeline).invoke({}), bullets=True, extra_whitespace=True
 )
-self._append_tokens(self.llm.tokens, PipelineEnum.IRIS_LECTURE_INGESTION)
+try:
+    self._append_tokens(self.llm.tokens, PipelineEnum.IRIS_LECTURE_INGESTION)
+except Exception as e:
+    logger.warning(f"Failed to append tokens: {e}")
 return clean_output

306-306: Token tracking for language detection

Token usage is tracked for the language detection operation. This is consistent with the token tracking implemented in other methods.

As before, consider adding error handling for robustness.

-self._append_tokens(response.token_usage, PipelineEnum.IRIS_LECTURE_INGESTION)
+try:
+    self._append_tokens(response.token_usage, PipelineEnum.IRIS_LECTURE_INGESTION)
+except Exception as e:
+    logger.warning(f"Failed to append tokens: {e}")

Line range hint 1-346: Overall assessment: Token tracking well-implemented with minor improvement suggestions

The implementation of token tracking in the LectureIngestionPipeline class is thorough and consistent. It aligns well with the PR objectives of enhancing the tracking of usage related to iris requests. The token usage is captured for various operations including image interpretation, content merging, and language detection.

Key points:

  1. Token tracking is initialized properly in the constructor.
  2. Token usage is included in both success and error callbacks.
  3. The _append_tokens method is used consistently across different operations.

Suggestions for improvement:

  1. Consider adding error handling around the token tracking calls to ensure they don't disrupt the main flow of the program if there's an issue.
  2. The _append_tokens method is not visible in this file. Ensure it's properly implemented and documented in the appropriate location.

Overall, the changes are well-structured and effectively implement the new token tracking feature.

app/retrieval/lecture_retrieval.py (1)

244-246: Consider appending token_usage instead of self.llm.tokens

After assigning token_usage = self.llm.tokens and updating token_usage.pipeline, you append self.llm.tokens to self.tokens. Since token_usage and self.llm.tokens refer to the same object, appending token_usage improves code clarity.

Apply this diff:

-        self.tokens.append(self.llm.tokens)
+        self.tokens.append(token_usage)

Also applies to: 284-286, 322-324, 364-366

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between c9e89be and 4c92900.

📒 Files selected for processing (28)
  • app/common/PipelineEnum.py (1 hunks)
  • app/common/message_converters.py (1 hunks)
  • app/common/pyris_message.py (2 hunks)
  • app/common/token_usage_dto.py (1 hunks)
  • app/domain/init.py (0 hunks)
  • app/domain/chat/chat_pipeline_execution_base_data_dto.py (1 hunks)
  • app/domain/chat/chat_pipeline_execution_dto.py (1 hunks)
  • app/domain/chat/interaction_suggestion_dto.py (1 hunks)
  • app/domain/status/status_update_dto.py (1 hunks)
  • app/llm/external/model.py (1 hunks)
  • app/llm/external/ollama.py (3 hunks)
  • app/llm/external/openai_chat.py (3 hunks)
  • app/llm/langchain/iris_langchain_chat_model.py (3 hunks)
  • app/llm/request_handler/basic_request_handler.py (1 hunks)
  • app/llm/request_handler/capability_request_handler.py (2 hunks)
  • app/llm/request_handler/request_handler_interface.py (1 hunks)
  • app/pipeline/chat/code_feedback_pipeline.py (3 hunks)
  • app/pipeline/chat/course_chat_pipeline.py (5 hunks)
  • app/pipeline/chat/exercise_chat_pipeline.py (11 hunks)
  • app/pipeline/chat/interaction_suggestion_pipeline.py (4 hunks)
  • app/pipeline/chat/lecture_chat_pipeline.py (3 hunks)
  • app/pipeline/competency_extraction_pipeline.py (4 hunks)
  • app/pipeline/lecture_ingestion_pipeline.py (8 hunks)
  • app/pipeline/pipeline.py (2 hunks)
  • app/pipeline/shared/citation_pipeline.py (3 hunks)
  • app/pipeline/shared/reranker_pipeline.py (3 hunks)
  • app/retrieval/lecture_retrieval.py (7 hunks)
  • app/web/status/status_update.py (4 hunks)
💤 Files with no reviewable changes (1)
  • app/domain/init.py
✅ Files skipped from review due to trivial changes (2)
  • app/common/message_converters.py
  • app/domain/chat/chat_pipeline_execution_dto.py
🚧 Files skipped from review as they are similar to previous changes (9)
  • app/domain/status/status_update_dto.py
  • app/llm/request_handler/capability_request_handler.py
  • app/pipeline/chat/course_chat_pipeline.py
  • app/pipeline/chat/interaction_suggestion_pipeline.py
  • app/pipeline/chat/lecture_chat_pipeline.py
  • app/pipeline/competency_extraction_pipeline.py
  • app/pipeline/shared/citation_pipeline.py
  • app/pipeline/shared/reranker_pipeline.py
  • app/web/status/status_update.py
🧰 Additional context used
🔇 Additional comments (49)
app/domain/chat/interaction_suggestion_dto.py (2)

Line range hint 9-12: LGTM! Consider verifying PyrisMessage's new capabilities.

The InteractionSuggestionPipelineExecutionDTO class remains unchanged and correctly uses the imported PyrisMessage. This is good as it maintains backwards compatibility.

Given the PR's focus on token usage tracking, it might be beneficial to verify if PyrisMessage now includes new token-related attributes or methods. You can use the following script to inspect the PyrisMessage class:

#!/bin/bash
# Description: Inspect the PyrisMessage class for new token-related attributes or methods

# Test: Search for the PyrisMessage class definition and its contents. Expect: New token-related attributes or methods.
ast-grep --lang python --pattern $'class PyrisMessage($_):
  $$$
'

If PyrisMessage has new capabilities, consider whether InteractionSuggestionPipelineExecutionDTO should be updated to utilize these new features.


5-5: LGTM! Verify other imports for consistency.

The import statement for PyrisMessage has been correctly updated to reflect its new location in the app.common.pyris_message module. This change aligns with good practices for code organization.

To ensure consistency across the codebase, please verify that all other imports of PyrisMessage have been updated similarly. You can use the following script to check for any remaining old imports:

✅ Verification successful

Verification Successful!

All old import statements for PyrisMessage have been successfully updated. No remaining old imports found.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any remaining old imports of PyrisMessage

# Test: Search for old import statements. Expect: No results.
rg --type python 'from app\.domain import PyrisMessage'

Length of output: 783

app/domain/chat/chat_pipeline_execution_base_data_dto.py (2)

Line range hint 1-20: LGTM: Rest of the file is unchanged and consistent

The ChatPipelineExecutionBaseDataDTO class and its structure remain unchanged. The usage of PyrisMessage in the chat_history field is still valid after the import change. No further modifications are necessary in this file.


6-6: Verify the new import path for PyrisMessage

The import statement for PyrisMessage has been updated from app.domain.pyris_message to app.common.pyris_message. This change aligns with the PR objectives of enhancing token usage tracking and suggests a reorganization of the project structure.

To ensure this change is consistent across the codebase and doesn't introduce any issues, please run the following verification script:

This script will help ensure that:

  1. There are no remaining imports from the old path.
  2. The new import is used consistently across the codebase.
  3. The PyrisMessage class is actually defined in the new location.
  4. There are no potential circular imports introduced by this change.
✅ Verification successful

Import path for PyrisMessage has been correctly updated and verified.

All checks confirm that:

  • There are no remaining imports from the old path.
  • The new import is used consistently across the codebase.
  • PyrisMessage is properly defined in the new location.
  • No circular imports have been introduced.
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the consistency of PyrisMessage import across the codebase

# Test 1: Check for any remaining imports from the old path
echo "Checking for any remaining old imports:"
rg --type python "from app.domain.pyris_message import PyrisMessage"

# Test 2: Verify the new import is used consistently
echo "Verifying the new import usage:"
rg --type python "from app.common.pyris_message import PyrisMessage"

# Test 3: Check if PyrisMessage is defined in the new location
echo "Checking if PyrisMessage is defined in the new location:"
rg --type python "class PyrisMessage" app/common/pyris_message.py

# Test 4: Look for any potential circular imports
echo "Checking for potential circular imports:"
rg --type python "from app.domain" app/common/pyris_message.py

Length of output: 774


Script:

#!/bin/bash
# Description: Re-verify the consistency of PyrisMessage import across the codebase without using --type flag

# Test 1: Check for any remaining imports from the old path
echo "Checking for any remaining old imports:"
fd --extension py --exec rg "from app.domain.pyris_message import PyrisMessage"

# Test 2: Verify the new import is used consistently
echo "Verifying the new import usage:"
fd --extension py --exec rg "from app.common.pyris_message import PyrisMessage"

# Test 3: Check if PyrisMessage is defined in the new location
echo "Checking if PyrisMessage is defined in the new location:"
rg "class PyrisMessage" app/common/pyris_message.py

# Test 4: Look for any potential circular imports
echo "Checking for potential circular imports:"
rg "from app.domain" app/common/pyris_message.py

Length of output: 1175


Script:

#!/bin/bash
# Description: Check if app/domain/data/message_content_dto.py imports from app.common.pyris_message to detect circular imports

echo "Checking if app/domain/data/message_content_dto.py imports from app.common.pyris_message:"
rg "from app\.common\.pyris_message import" app/domain/data/message_content_dto.py

Length of output: 273

app/common/pyris_message.py (3)

8-8: LGTM: New import for TokenUsageDTO

The import statement for TokenUsageDTO is correctly placed and necessary for the new token_usage field. This change aligns with the PR objectives of enhancing token usage tracking.


Line range hint 1-28: Overall assessment: Changes align with PR objectives

The modifications to PyrisMessage class successfully introduce token usage tracking, which is the main goal of this PR. The implementation is clean and follows good practices. The suggested minor improvements (field ordering) and the verification script will help ensure smooth integration of these changes across the codebase.


20-21: LGTM: New token_usage field added

The addition of the token_usage field of type TokenUsageDTO aligns well with the PR objectives for tracking token usage in iris requests. The use of a default factory is a good practice for mutable default values.

Consider moving the token_usage field after the existing fields to maintain consistency with the current field order. This would help preserve the existing JSON structure:

class PyrisMessage(BaseModel):
    model_config = ConfigDict(populate_by_name=True)

    sent_at: datetime | None = Field(alias="sentAt", default=None)
    sender: IrisMessageRole
    contents: List[MessageContentDTO] = []
    token_usage: TokenUsageDTO = Field(default_factory=TokenUsageDTO)

To ensure that all usages of PyrisMessage are updated to handle the new token_usage field, we can run the following script:

This script will help identify areas where PyrisMessage is used, allowing us to verify if any updates are needed to accommodate the new token_usage field.

✅ Verification successful

Verification Successful: token_usage field is properly integrated and utilized consistently across the codebase. No issues found.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for PyrisMessage instantiations and usages

# Search for PyrisMessage instantiations
echo "PyrisMessage instantiations:"
rg --type python -n "PyrisMessage\s*\(" -A 5

# Search for PyrisMessage attribute accesses
echo "\nPyrisMessage attribute accesses:"
rg --type python -n "\.token_usage" -C 2

Length of output: 297


Script:

#!/bin/bash
# Description: Check for PyrisMessage instantiations and usages in Python files

# Search for PyrisMessage instantiations
echo "PyrisMessage instantiations:"
rg "PyrisMessage\s*\(" --type py -n -A 5

# Search for PyrisMessage attribute accesses
echo "\nPyrisMessage attribute accesses:"
rg "\.token_usage" --type py -n -C 2

Length of output: 10279

app/common/PipelineEnum.py (3)

1-1: LGTM: Import statement is correct and concise.

The import of Enum from the enum module is appropriate for defining an Enum class.


4-4: LGTM: Well-designed class inheritance for string-based enum.

The PipelineEnum class inherits from both str and Enum, which is a good practice for creating string-based enumerations. This approach allows enum members to be used as strings while retaining the benefits of an enumeration, such as type safety and iteration capabilities.


1-16: Overall assessment: Well-implemented PipelineEnum class.

This new PipelineEnum class is a solid addition that aligns perfectly with the PR objectives of enhancing the tracking of usage related to IRIS requests. The implementation follows best practices for string-based enums in Python, and the comprehensive list of pipeline types will facilitate better management of token usage across different pipelines.

The code is clean, concise, and ready for integration into the Pyris project. It provides a strong foundation for the token usage tracking feature described in the PR summary.

app/common/token_usage_dto.py (2)

1-3: LGTM: Imports are appropriate and well-organized.

The necessary imports from Pydantic and the custom PipelineEnum are correctly included. The empty line between different import sources improves readability.


1-18: Great implementation of TokenUsageDTO for enhanced token tracking.

This new TokenUsageDTO class aligns perfectly with the PR objectives of enhancing token usage tracking for iris requests. The use of Pydantic's BaseModel ensures robust data validation and easy serialization, which will be beneficial when sending token usage data to Artemis as mentioned in the PR summary.

The implementation covers all necessary fields for comprehensive token usage tracking, including model information, input/output token counts, associated costs, and the pipeline enum. This structure will provide valuable insights into resource utilization across different pipelines.

Overall, this is a well-structured and thoughtful addition to the project that should significantly improve the monitoring and management of token usage.

app/llm/request_handler/basic_request_handler.py (2)

3-3: LGTM! Verify consistent import usage across the codebase.

The import change for PyrisMessage looks good and aligns with the restructuring mentioned in the summary. This change doesn't affect the functionality of the BasicRequestHandler class.

To ensure consistency, let's verify that this import change has been applied across the entire codebase:

✅ Verification successful

Import consistency verified across the codebase. All old imports of PyrisMessage have been removed, and new imports are correctly in place.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any remaining old imports of PyrisMessage and new imports

echo "Checking for old imports:"
rg --type python "from app.domain import PyrisMessage"

echo "Checking for new imports:"
rg --type python "from app.common.pyris_message import PyrisMessage"

Length of output: 311


Script:

#!/bin/bash
# Description: Check for any remaining old imports of PyrisMessage and verify new imports using fd and grep

echo "Checking for old imports:"
fd --extension py --type f | xargs grep "from app.domain import PyrisMessage"

echo "Checking for new imports:"
fd --extension py --type f | xargs grep "from app.common.pyris_message import PyrisMessage"

Length of output: 1103


Line range hint 10-38: Verify if BasicRequestHandler needs updates for token tracking.

The PR objectives mention adding a new tokens argument to all Pipelines, which is not reflected in this class. While this class might not directly handle token usage tracking, it's worth verifying if any updates are needed here to support the new feature.

Let's check if similar request handler classes have been updated with token tracking:

app/pipeline/pipeline.py (3)

2-2: LGTM: Import statement is correct and necessary.

The addition of from typing import List is appropriate for type hinting the new tokens attribute. This follows Python best practices for type hinting.


4-5: LGTM: New imports and class attribute are correctly implemented.

The new imports for TokenUsageDTO and PipelineEnum are necessary for the token tracking feature. The tokens attribute is correctly type hinted as List[TokenUsageDTO], which aligns with the PR objectives of tracking token usage across different pipelines.

Also applies to: 12-12


Line range hint 1-38: Overall assessment: Changes are well-implemented and align with PR objectives.

The modifications to the Pipeline class effectively introduce token usage tracking, which aligns with the PR objectives. The new imports, class attribute, and _append_tokens method are correctly implemented. The only suggestion for improvement is to initialize self.tokens in the constructor for added robustness.

These changes provide a solid foundation for tracking token usage across different pipelines in the Pyris project.

app/llm/langchain/iris_langchain_chat_model.py (4)

1-1: LGTM: New imports added correctly.

The new imports for logging, PipelineEnum, and TokenUsageDTO are correctly added and necessary for the new functionality introduced in this update.

Also applies to: 11-11, 16-16


25-26: LGTM: New class attributes added correctly.

The new tokens attribute of type TokenUsageDTO and the logger instantiation are correctly implemented. These additions align with the PR objectives for token usage tracking and logging capabilities.


Line range hint 1-64: Summary: Good implementation with a minor consideration.

The changes in this file successfully implement token usage tracking as per the PR objectives. The new imports, class attributes, and modifications to the _generate method are well-integrated and correctly implemented.

However, there's a potential issue with overwriting token counts when the _generate method is called multiple times. Consider addressing this by either:

  1. Accumulating token usage across multiple calls.
  2. Resetting token usage at an appropriate point in the workflow.
  3. Documenting the current behavior if it's intentional.

Once this consideration is addressed, the implementation will be robust and fully aligned with the PR objectives.


50-57: LGTM with a consideration: Token usage tracking implementation.

The implementation of token usage tracking looks good and aligns with the PR objectives. The tokens attribute is correctly populated with relevant information from iris_message.token_usage.

However, as pointed out in a previous review comment, there's a potential issue:

If the _generate method is called multiple times on the same instance, the existing token counts would be overwritten. Consider accumulating the token usage instead of overwriting it, or resetting it at an appropriate point in the workflow.

app/llm/external/ollama.py (4)

9-10: LGTM: New imports align with PR objectives

The addition of PyrisMessage and TokenUsageDTO imports is consistent with the PR's goal of enhancing token usage tracking. These imports are necessary for the subsequent changes in the file.


61-63: LGTM: Function signature update enhances token tracking

The updated signature of convert_to_iris_message now includes num_input_tokens, num_output_tokens, and model parameters. This change aligns well with the PR's objective of enhancing token usage tracking for iris requests.


68-77: LGTM: Token usage tracking implemented correctly

The changes to the convert_to_iris_message function body effectively implement token usage tracking. The creation of a TokenUsageDTO instance and its inclusion in the PyrisMessage align perfectly with the PR's objectives.


120-125: LGTM: Safe key access implemented and token tracking enhanced

The changes to the chat method effectively address the previous review comment about potential KeyErrors. The use of response.get() with default values is a safe approach to handle potentially missing keys. Additionally, these changes align with the PR objectives by passing token usage information to convert_to_iris_message.

app/pipeline/chat/code_feedback_pipeline.py (4)

11-17: LGTM: Import changes align with new token tracking functionality.

The updated import for PyrisMessage and the new imports for TokenUsageDTO and PipelineEnum are consistent with the PR objectives of introducing token usage tracking.


45-45: LGTM: New tokens attribute added for token usage tracking.

The addition of the tokens attribute of type TokenUsageDTO is consistent with the PR objectives and enables token usage tracking within the pipeline.


47-47: LGTM: Improved method signature with explicit optional parameter.

The updated __init__ method signature now explicitly defines the callback parameter as optional, enhancing code clarity and type hinting without changing functionality.


Line range hint 1-151: Overall assessment: Changes successfully implement token usage tracking.

The modifications to the CodeFeedbackPipeline class effectively introduce token usage tracking as per the PR objectives. The changes are well-integrated, maintaining code consistency and enhancing functionality. The new tokens attribute, updated method signatures, and token usage handling in the __call__ method all contribute to achieving the goal of tracking and categorizing token usage in the IRIS system.

A minor suggestion for error handling has been provided to improve robustness. Otherwise, the implementation looks solid and ready for integration.

app/pipeline/lecture_ingestion_pipeline.py (4)

13-13: New imports added for token tracking

The new imports for PyrisMessage, IrisMessageRole, and PipelineEnum are related to the token tracking feature. This is a good practice as it keeps the dependencies clear and localized.

Also applies to: 21-21


116-116: Token tracking attribute added

The self.tokens list is initialized in the constructor. This is a good place to initialize it, ensuring it's ready for use throughout the class's lifecycle.


144-144: Token usage included in callback

The tokens parameter is now included in both successful and error callbacks. This is consistent and allows for proper tracking of token usage regardless of the outcome.

Also applies to: 153-155


177-179: Token usage included in error callback

Similar to the previous comment, tokens are included in the error callback here. This maintains consistency in error reporting.

app/pipeline/chat/exercise_chat_pipeline.py (14)

27-27: Import PyrisMessage for message handling

The import of PyrisMessage ensures proper handling of message types within the pipeline, which is essential for processing chat interactions.


37-37: Introduce PipelineEnum for pipeline tracking

Importing PipelineEnum allows for better enumeration and tracking of different pipeline stages, enhancing clarity and maintainability.


82-82: Initialize self.tokens for token aggregation

Initializing self.tokens as an empty list in the constructor correctly sets up the aggregation of token usage data throughout the pipeline execution.


103-105: Pass aggregated tokens to callback

Including tokens=self.tokens in the self.callback.done method ensures that token usage data is properly passed back for tracking and monitoring purposes.


119-127: Handle suggestion_pipeline.tokens safely

The code now checks if self.suggestion_pipeline.tokens is not None before using it, preventing potential errors by avoiding passing None values. This addresses previous concerns about potential None values being passed.


140-142: Include tokens in error callback for suggestions

Passing tokens=self.tokens in the error handling of interaction suggestions provides additional context, aiding in debugging and monitoring token usage even when errors occur.


146-148: Enhance error reporting with token data

Including tokens=self.tokens in the error callback improves error reporting by providing token usage information, which can be valuable for diagnosing issues.


219-220: Collect tokens from code_feedback_pipeline

Properly checking if self.code_feedback_pipeline.tokens is not None before appending ensures that only valid token data is collected, preventing potential NoneType errors.


233-235: Provide tokens in error callback for code feedback

Including tokens=self.tokens in the error handling when retrieving code feedback enhances the ability to debug and trace token usage during failures.


243-244: Aggregate tokens from retriever component

The code correctly checks for None before appending self.retriever.tokens to self.tokens, ensuring robust handling of token data from the retrieval process.


251-253: Token-inclusive error handling for lecture retrieval

Passing tokens=self.tokens in the error callback when lecture retrieval fails adds valuable context for debugging and monitoring.


279-281: Refactor LLM token collection with _append_tokens

By using the _append_tokens method to collect tokens from self.llm, the code eliminates duplication and adheres to the DRY principle, addressing previous refactoring suggestions.


296-298: Consistent use of _append_tokens for LLM tokens

The consistent application of _append_tokens for collecting tokens from self.llm enhances code maintainability and readability.


307-309: Enhance response creation error handling with tokens

Including tokens=self.tokens when handling exceptions during response creation provides comprehensive debugging information for token usage.

app/retrieval/lecture_retrieval.py (2)

9-11: Imports added align with PR objectives

The new imports of TokenUsageDTO and PipelineEnum are appropriate for token usage tracking and pipeline enumeration as described in the PR objectives.


105-105: Initialization of tokens attribute approved

The tokens attribute is properly initialized in the constructor.

@@ -1,7 +1,7 @@
from abc import ABCMeta, abstractmethod
from typing import Optional

from ...domain import PyrisMessage
from ...common.pyris_message import PyrisMessage
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Inconsistent import paths for PyrisMessage detected.

  • app/pipeline/lecture_ingestion_pipeline.py uses from ..common.pyris_message import PyrisMessage, IrisMessageRole
  • app/retrieval/lecture_retrieval.py uses from ..common.pyris_message import PyrisMessage

Please update these import statements to match the standardized patterns:

  • Relative: from ...common.pyris_message import PyrisMessage
  • Absolute: from app.common.pyris_message import PyrisMessage

This will ensure consistency across the codebase and prevent potential import issues.

🔗 Analysis chain

Import path update looks good.

The import statement for PyrisMessage has been updated from a relative import from the domain module to a relative import from the common.pyris_message module. This change is consistent with the PR objectives and the AI-generated summary, which mentioned updates to import paths for PyrisMessage to reflect a new organizational structure.

To ensure this change is consistent across the codebase, let's verify the usage of PyrisMessage:


[/run_scripts]


[/run_scripts]


[/run_scripts]

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the import path for PyrisMessage across the codebase

# Test: Search for PyrisMessage imports
rg --type python "from.*import.*PyrisMessage"

# Test: Search for PyrisMessage usage
rg --type python "PyrisMessage"

Length of output: 141


Script:

#!/bin/bash
# Description: Verify the import path for PyrisMessage across the codebase

# Test: Search for PyrisMessage imports
rg --glob "*.py" "from.*import.*PyrisMessage"

# Test: Search for PyrisMessage usage
rg --glob "*.py" "PyrisMessage"

Length of output: 8395


Script:

#!/bin/bash
# Description: Identify inconsistent import paths for PyrisMessage

# Define acceptable import patterns
acceptable_patterns="from ...common.pyris_message import PyrisMessage|from app.common.pyris_message import PyrisMessage"

# Search for PyrisMessage imports that do NOT match the acceptable patterns
rg --glob "*.py" "from\s+(?!\.\.\.common\.pyris_message|app\.common\.pyris_message)\w+.*import\s+PyrisMessage"

Length of output: 537


Script:

#!/bin/bash
# Description: Identify inconsistent import paths for PyrisMessage without using look-around

# Step 1: Find all PyrisMessage import statements
rg --glob "*.py" "from.*import.*PyrisMessage" > all_pyris_imports.txt

# Step 2: Exclude acceptable import patterns
rg -v -e "from \.\.\.common\.pyris_message import PyrisMessage" -e "from app\.common\.pyris_message import PyrisMessage" all_pyris_imports.txt

Length of output: 383

@@ -1,7 +1,7 @@
from abc import ABCMeta, abstractmethod
from pydantic import BaseModel

from ...domain import PyrisMessage
from ...common.pyris_message import PyrisMessage
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Issues Found: Inconsistent Import Paths for PyrisMessage

The import statements for PyrisMessage are not fully consistent across the codebase:

  • Relative imports still exist:
    • from ..common.pyris_message import PyrisMessage
  • Absolute imports are used in some files:
    • from app.common.pyris_message import PyrisMessage

Please standardize all import paths to from ...common.pyris_message import PyrisMessage to ensure consistency and prevent potential issues.

🔗 Analysis chain

LGTM! Verify import consistency across the codebase.

The import statement for PyrisMessage has been updated to reflect the new module structure. This change is in line with the PR objectives.

To ensure consistency across the codebase, please run the following script:

This script will help identify any inconsistencies in the import statements across the project.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the consistency of PyrisMessage import across the codebase.

# Test 1: Check for any remaining imports from the old path
echo "Checking for any remaining old imports:"
rg --type python "from \.\.\.domain import PyrisMessage"

# Test 2: Verify the new import is used consistently
echo "Verifying the new import usage:"
rg --type python "from \.\.\.common\.pyris_message import PyrisMessage"

# Test 3: Check for any other variations of PyrisMessage import
echo "Checking for any other variations of PyrisMessage import:"
rg --type python "import.*PyrisMessage" | grep -v "from ...common.pyris_message import PyrisMessage"

Length of output: 615


Script:

#!/bin/bash
# Description: Verify the consistency of PyrisMessage import across the codebase.

# Test 1: Check for any remaining imports from the old path
echo "Checking for any remaining old imports:"
rg --type py "from \.\.\.domain import PyrisMessage"

# Test 2: Verify the new import is used consistently
echo "Verifying the new import usage:"
rg --type py "from \.\.\.common\.pyris_message import PyrisMessage"

# Test 3: Check for any other variations of PyrisMessage import
echo "Checking for any other variations of PyrisMessage import:"
rg --type py "import.*PyrisMessage" | grep -v "from ...common.pyris_message import PyrisMessage"

Length of output: 2314

sender=map_str_to_role(message.role),
contents=[TextMessageContentDTO(textContent=message.content)],
send_at=datetime.now(),
sentAt=datetime.now(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Use UTC timestamps to ensure consistency across time zones

In the construction of PyrisMessage, consider using datetime.utcnow() instead of datetime.now() to ensure that the timestamp is in UTC. This helps prevent issues related to timezone differences and ensures consistency across different environments.

Apply this diff to update the timestamp:

-            sentAt=datetime.now(),
+            sentAt=datetime.utcnow(),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
sentAt=datetime.now(),
sentAt=datetime.utcnow(),

Comment on lines +66 to +68
def convert_to_iris_message(
message: ChatCompletionMessage, usage: Optional[CompletionUsage], model: str
) -> PyrisMessage:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Calls to convert_to_iris_message in app/llm/external/ollama.py do not match the updated function signature. Please update these calls to include all required parameters: message, num_input_tokens, num_output_tokens, and model.

  • app/llm/external/ollama.py:
    • Line where convert_to_iris_message is called with insufficient arguments.
🔗 Analysis chain

Ensure all calls to convert_to_iris_message are updated with new parameters

Since the function convert_to_iris_message now includes additional parameters usage: Optional[CompletionUsage] and model: str, please verify that all calls to this function across the codebase have been updated to match the new signature to prevent any potential errors.

You can run the following script to identify any calls that may need to be updated:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find all usages of `convert_to_iris_message` and check if they match the new signature.

# Expected: All calls should include three parameters: message, usage, and model.

rg --type python $'convert_to_iris_message\s*\(' -A 1

Length of output: 85


Script:

#!/bin/bash
# Description: Find all usages of `convert_to_iris_message` in Python files and check if they match the new signature.

# Expected: All calls should include three parameters: message, usage, and model.

rg --glob "*.py" 'convert_to_iris_message\s*\(' -A 1

Length of output: 723

Comment on lines 86 to 87
tokens: [TokenUsageDTO]

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Correct the type annotation for tokens attribute

The type annotation tokens: [TokenUsageDTO] is incorrect. It should use List[TokenUsageDTO] from the typing module.

Apply this diff to fix the type annotation:

-        tokens: [TokenUsageDTO]
+        tokens: List[TokenUsageDTO]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
tokens: [TokenUsageDTO]
tokens: List[TokenUsageDTO]
```
Note: This suggestion assumes that the `List` type is imported from the `typing` module elsewhere in the file. If it's not already imported, you would need to add the following import at the top of the file:
```python
from typing import List

@alexjoham alexjoham requested a review from kaancayli October 16, 2024 09:19
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (1)
app/llm/external/ollama.py (1)

61-77: LGTM with a minor suggestion: Function update aligns with PR objectives

The changes to convert_to_iris_message correctly implement token usage tracking, which aligns with the PR objectives. The new parameters are used appropriately to create a TokenUsageDTO object.

For consistency, consider updating the TokenUsageDTO field names to use snake_case:

tokens = TokenUsageDTO(
-    numInputTokens=num_input_tokens,
-    numOutputTokens=num_output_tokens,
+    num_input_tokens=num_input_tokens,
+    num_output_tokens=num_output_tokens,
    modelInfo=model,
)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 4d61c85 and 3253c46.

📒 Files selected for processing (1)
  • app/llm/external/ollama.py (3 hunks)
🧰 Additional context used
🔇 Additional comments (3)
app/llm/external/ollama.py (3)

9-10: LGTM: New imports align with PR objectives

The addition of PyrisMessage and TokenUsageDTO imports is consistent with the PR's goal of enhancing token usage tracking.


120-125: LGTM: Improved error handling and consistency with other implementations

The changes to the chat method effectively implement token usage tracking and address previous concerns:

  1. Using get with default values mitigates potential KeyError issues.
  2. The default value for token counts is now -1, consistent with the OpenAI implementation as mentioned in the past review comments.

These updates align well with the PR objectives and improve the overall robustness of the code.


Line range hint 1-135: Overall assessment: Well-implemented token usage tracking

The changes in this file successfully implement token usage tracking for the Ollama integration, aligning well with the PR objectives. The code quality is good, with only minor consistency suggestions. The implementation addresses previous concerns and improves error handling.

Great job on enhancing the Ollama integration with token usage tracking!

kaancayli
kaancayli previously approved these changes Oct 16, 2024
Copy link
Contributor

@kaancayli kaancayli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes look good

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (1)
app/llm/external/ollama.py (1)

61-77: LGTM: Token usage tracking implemented correctly

The changes to the convert_to_iris_message function successfully implement token usage tracking, aligning with the PR objectives. The new parameters are correctly used to create a TokenUsageDTO object, which is then included in the PyrisMessage.

Minor suggestion:
Consider using snake_case for consistency in the TokenUsageDTO initialization:

tokens = TokenUsageDTO(
    num_input_tokens=num_input_tokens,
    num_output_tokens=num_output_tokens,
    model=model,
)

This would align with Python's naming conventions and the style used in the rest of the code.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 3253c46 and 9fe9e0a.

📒 Files selected for processing (4)
  • app/common/token_usage_dto.py (1 hunks)
  • app/llm/external/ollama.py (3 hunks)
  • app/llm/external/openai_chat.py (4 hunks)
  • app/llm/langchain/iris_langchain_chat_model.py (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • app/common/token_usage_dto.py
  • app/llm/langchain/iris_langchain_chat_model.py
🧰 Additional context used
🔇 Additional comments (9)
app/llm/external/ollama.py (3)

9-10: LGTM: New imports align with PR objectives

The addition of PyrisMessage and TokenUsageDTO imports is consistent with the PR's goal of introducing token usage tracking. These imports are necessary for the subsequent changes in the file.


120-125: LGTM: Safe key access and consistent default values

The changes to the chat method effectively implement token usage tracking and address previous review comments:

  1. The use of the get method with default values prevents potential KeyError issues, as suggested in a past review.
  2. The default value of -1 for token counts is now consistent with other models, addressing the concern raised in another past comment.

These modifications align well with the PR objectives and improve the robustness of the code.


Line range hint 1-135: Summary: Successful implementation of token usage tracking

The changes in this file effectively implement token usage tracking for the Ollama model, aligning well with the PR objectives. Key improvements include:

  1. Addition of necessary imports for PyrisMessage and TokenUsageDTO.
  2. Update of the convert_to_iris_message function to include token usage information.
  3. Modification of the chat method to safely retrieve and pass token usage data.

These changes enhance the functionality of the Ollama model integration while addressing previous review comments. The code is now more robust and consistent with other parts of the system.

Great job on implementing these features and addressing the feedback from previous reviews!

app/llm/external/openai_chat.py (6)

4-4: LGTM: Import statements updated correctly

The new import statements for Optional, CompletionUsage, PyrisMessage, and TokenUsageDTO are consistent with the PR objectives and support the implementation of token usage tracking.

Also applies to: 15-15, 21-22


72-74: LGTM: Function signature updated appropriately

The convert_to_iris_message function signature has been correctly updated to include usage: Optional[CompletionUsage] and model: str parameters. This change aligns with the PR objectives and enables token usage tracking.


81-85: LGTM: TokenUsageDTO creation implemented correctly

The creation of the TokenUsageDTO object with model information and token counts is implemented correctly. This change aligns with the PR objectives of enhancing token usage tracking.


87-91: LGTM with a suggestion: Use UTC time for consistency

The addition of token_usage to the PyrisMessage creation is correct and aligns with the PR objectives. However, as previously suggested, consider using datetime.utcnow() instead of datetime.now() for the sentAt attribute to ensure consistency across different time zones.

Apply this diff to update the timestamp:

- sentAt=datetime.now(),
+ sentAt=datetime.utcnow(),

131-132: LGTM: Correct extraction of usage and model information

The extraction of usage and model information from the response is implemented correctly. These changes support the updated convert_to_iris_message function and align with the PR objectives of enhancing token usage tracking.


139-139: LGTM: Correct usage of updated convert_to_iris_message function

The convert_to_iris_message function call has been correctly updated to include the usage and model parameters. This change is consistent with the updated function signature and ensures that token usage information is properly passed to the PyrisMessage creation.

Comment on lines 78 to 79
num_input_tokens = getattr(usage, "prompt_tokens", -1)
num_output_tokens = getattr(usage, "completion_tokens", -1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Consider using 0 as the default value for token counts

The current implementation uses -1 as the default value for num_input_tokens and num_output_tokens. However, this might be confusing as it's not a valid token count. For consistency with other parts of the codebase (e.g., ollama) and improved clarity, consider using 0 as the default value.

Suggested change:

- num_input_tokens = getattr(usage, "prompt_tokens", -1)
- num_output_tokens = getattr(usage, "completion_tokens", -1)
+ num_input_tokens = getattr(usage, "prompt_tokens", 0)
+ num_output_tokens = getattr(usage, "completion_tokens", 0)

This change would make the default values more intuitive and consistent with other parts of the codebase.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
num_input_tokens = getattr(usage, "prompt_tokens", -1)
num_output_tokens = getattr(usage, "completion_tokens", -1)
num_input_tokens = getattr(usage, "prompt_tokens", 0)
num_output_tokens = getattr(usage, "completion_tokens", 0)

kaancayli
kaancayli previously approved these changes Oct 22, 2024
Copy link
Contributor

@kaancayli kaancayli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reapprove

yassinsws
yassinsws previously approved these changes Oct 22, 2024
Copy link
Contributor

@yassinsws yassinsws left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tested locally works as expected

@alexjoham alexjoham dismissed stale reviews from yassinsws and kaancayli via 13c5db1 October 23, 2024 14:32
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (1)
app/llm/external/ollama.py (1)

61-63: Add type hints for token count parameters.

The function parameters num_input_tokens and num_output_tokens should have explicit type hints for better code maintainability and IDE support.

 def convert_to_iris_message(
-    message: Message, num_input_tokens: int, num_output_tokens: int, model: str
+    message: Message, num_input_tokens: Optional[int], num_output_tokens: Optional[int], model: str
 ) -> PyrisMessage:
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 9fe9e0a and 13c5db1.

📒 Files selected for processing (2)
  • app/llm/external/ollama.py (3 hunks)
  • app/llm/external/openai_chat.py (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/llm/external/openai_chat.py
🧰 Additional context used
🔇 Additional comments (1)
app/llm/external/ollama.py (1)

9-10: LGTM: New imports align with token tracking requirements.

The added imports for PyrisMessage and TokenUsageDTO are appropriately placed and necessary for the token tracking implementation.

Comment on lines +68 to +72
tokens = TokenUsageDTO(
numInputTokens=num_input_tokens,
numOutputTokens=num_output_tokens,
model=model,
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add validation for token count parameters.

The token counts should be validated to ensure they are not negative values before creating the TokenUsageDTO.

+    if num_input_tokens is not None and num_input_tokens < -1:
+        raise ValueError("Input token count cannot be less than -1")
+    if num_output_tokens is not None and num_output_tokens < -1:
+        raise ValueError("Output token count cannot be less than -1")
     tokens = TokenUsageDTO(
         numInputTokens=num_input_tokens,
         numOutputTokens=num_output_tokens,
         model=model,
     )

Committable suggestion was skipped due to low confidence.

Comment on lines +120 to +125
return convert_to_iris_message(
response.get("message"),
response.get("prompt_eval_count", 0),
response.get("eval_count", 0),
response.get("model", self.model),
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Update default token counts to -1 for consistency.

As discussed in previous comments and confirmed by you, the default token count values should be -1 to maintain consistency with the OpenAI implementation.

     return convert_to_iris_message(
         response.get("message"),
-        response.get("prompt_eval_count", 0),
-        response.get("eval_count", 0),
+        response.get("prompt_eval_count", -1),
+        response.get("eval_count", -1),
         response.get("model", self.model),
     )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return convert_to_iris_message(
response.get("message"),
response.get("prompt_eval_count", 0),
response.get("eval_count", 0),
response.get("model", self.model),
)
return convert_to_iris_message(
response.get("message"),
response.get("prompt_eval_count", -1),
response.get("eval_count", -1),
response.get("model", self.model),
)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (1)
app/pipeline/chat/exercise_chat_pipeline.py (1)

82-82: Consider adding debug logging for token tracking

To aid in debugging token-related issues, consider adding debug logging when tokens are collected or appended.

Add logging statements like:

 def _append_tokens(self, tokens, source):
+    logger.debug(f"Appending {len(tokens)} tokens from {source}")
     # existing implementation
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 13c5db1 and 043264a.

📒 Files selected for processing (2)
  • app/pipeline/chat/exercise_chat_pipeline.py (11 hunks)
  • app/retrieval/lecture_retrieval.py (7 hunks)
🧰 Additional context used
🔇 Additional comments (5)
app/pipeline/chat/exercise_chat_pipeline.py (4)

37-37: LGTM: Token tracking initialization

The initialization of token tracking is properly implemented with the required import and class variable setup.

Also applies to: 82-82


103-105: LGTM: Token tracking in callback

The token tracking is properly integrated into the callback mechanism.


140-142: LGTM: Comprehensive error handling with token tracking

Token tracking is consistently implemented across all error handlers, ensuring token usage is properly reported even in failure scenarios.

Also applies to: 146-148, 233-235, 254-256, 310-312


282-284: Show implementation of _append_tokens

The code uses _append_tokens method but its implementation is not visible in the provided code. Please ensure this method is properly implemented to handle token collection and pipeline assignment.

Let's verify if the method is implemented:

Also applies to: 299-301

✅ Verification successful

Let me try a different approach to search for the implementation of _append_tokens.


Implementation of _append_tokens is properly defined in the base pipeline class

The method _append_tokens is implemented in app/pipeline/pipeline.py as:

def _append_tokens(self, tokens: TokenUsageDTO, pipeline: PipelineEnum) -> None:
    tokens.pipeline = pipeline
    self.tokens.append(tokens)

The implementation is correct and properly handles:

  • Setting the pipeline type for the tokens
  • Appending the tokens to the pipeline's token collection

The usage in the exercise chat pipeline is consistent with this implementation and other pipeline classes.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for _append_tokens implementation
ast-grep --pattern 'def _append_tokens($_, $_) { $$$ }'

Length of output: 57


Script:

#!/bin/bash
# Search for _append_tokens using ripgrep for better coverage
rg "_append_tokens" -A 5

Length of output: 5052

app/retrieval/lecture_retrieval.py (1)

9-10: LGTM! Import statements and class attribute initialization look good.

The imports are correctly organized, the type annotation uses List from the typing module, and the tokens list is properly initialized in the constructor.

Also applies to: 86-87, 105-105

Comment on lines +244 to +246
token_usage = self.llm.tokens
token_usage.pipeline = PipelineEnum.IRIS_LECTURE_RETRIEVAL_PIPELINE
self.tokens.append(self.llm.tokens)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

Refactor token tracking to address thread safety and code duplication.

The current implementation has two issues:

  1. Token tracking code is duplicated across methods
  2. Concurrent access to self.tokens can lead to race conditions when methods run in parallel

Consider this comprehensive solution:

  1. First, extract the token tracking logic into a helper method:
def _track_token_usage(self) -> TokenUsageDTO:
    """Track token usage for the current operation."""
    token_usage = self.llm.tokens
    token_usage.pipeline = PipelineEnum.IRIS_LECTURE_RETRIEVAL_PIPELINE
    return token_usage
  1. Then, modify the methods to return both the response and token usage:
 def rewrite_student_query(self, ...):
     try:
         response = (prompt | self.pipeline).invoke({})
-        token_usage = self.llm.tokens
-        token_usage.pipeline = PipelineEnum.IRIS_LECTURE_RETRIEVAL_PIPELINE
-        self.tokens.append(self.llm.tokens)
+        token_usage = self._track_token_usage()
         logger.info(f"Response from exercise chat pipeline: {response}")
-        return response
+        return response, token_usage
  1. Finally, update run_parallel_rewrite_tasks to safely aggregate tokens:
 def run_parallel_rewrite_tasks(self, ...):
     with concurrent.futures.ThreadPoolExecutor() as executor:
         # ... existing code ...
-        rewritten_query = rewritten_query_future.result()
-        hypothetical_answer_query = hypothetical_answer_query_future.result()
+        rewritten_query, tokens1 = rewritten_query_future.result()
+        hypothetical_answer_query, tokens2 = hypothetical_answer_query_future.result()
+        # Safely aggregate tokens after all tasks complete
+        self.tokens.extend([tokens1, tokens2])

This solution:

  • Eliminates code duplication
  • Ensures thread safety by aggregating tokens after all tasks complete
  • Improves maintainability through centralized token tracking logic

Also applies to: 284-286, 322-324, 364-366

@bassner bassner merged commit 3bf8510 into main Oct 23, 2024
11 checks passed
@bassner bassner deleted the feature/track-usage-of-iris-requests branch October 23, 2024 18:57
isabellagessl pushed a commit that referenced this pull request Nov 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Iris: Track the token usage of requests
5 participants