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

Spotlight api #110

Open
wants to merge 25 commits into
base: master
Choose a base branch
from
Open

Spotlight api #110

wants to merge 25 commits into from

Conversation

ruuushhh
Copy link
Contributor

@ruuushhh ruuushhh commented Sep 11, 2024

Summary by CodeRabbit

  • New Features

    • Integrated Django's admin interface for easier model management.
    • Added functionality for user queries with AI response generation using OpenAI and AWS Bedrock.
    • Introduced API views for managing recent queries and user support requests.
    • Established a structured prompt system for the AI assistant to enhance user interactions.
    • Implemented new Query and CopyExportSettings models to store user queries and export settings.
    • Enhanced routing capabilities by adding a spotlight API endpoint.
    • Expanded the ActionService with methods for field mapping and triggering exports.
    • Introduced services for citation extraction, response formatting, and suggestions generation.
    • Defined comprehensive prompts for the AI assistant to improve user query handling.
  • Bug Fixes

    • Enhanced error handling for AI response generation.
  • Documentation

    • Updated configuration files to include new environment variables for AWS and OpenAI integration.
  • Chores

    • Added new dependencies for AWS and OpenAI services in the requirements file.
    • Added the spotlight app to the installed applications in the settings.

Copy link

coderabbitai bot commented Sep 11, 2024

Walkthrough

The changes introduce a new Django application named "spotlight," enhancing functionalities such as model registration, API interactions with OpenAI and AWS Bedrock, and user query handling. Key components include models for storing user queries, serializers for data conversion, views for API endpoints, and services for processing queries. The application structure is further improved with new environment variables, dependencies, and URL routing configurations, establishing a foundation for advanced AI-driven features.

Changes

Files Change Summary
apps/spotlight/admin.py, apps/spotlight/apps.py Introduced admin interface integration and application configuration class for 'spotlight'.
apps/spotlight/llm.py Implemented functions for interacting with OpenAI and AWS Bedrock APIs, including error handling.
apps/spotlight/migrations/0001_initial.py, apps/spotlight/models.py Added Query model with fields for storing user queries, metadata, and timestamps, along with foreign key relationships.
apps/spotlight/migrations/0002_copyexportsettings.py, apps/spotlight/models.py Introduced CopyExportSettings model for managing export settings related to workspaces.
apps/spotlight/prompts/spotlight_prompt.py, apps/spotlight/prompts/suggestion_context_page_prompt.py Defined prompts for AI interactions, outlining structured responses for user queries.
apps/spotlight/serializers.py Created QuerySerializer class for serializing and deserializing Query model instances.
apps/spotlight/service.py Defined HelpService, QueryService, and ActionService classes for handling user queries and executing actions.
apps/spotlight/tests.py Introduced a test suite placeholder for future test cases.
apps/spotlight/urls.py, quickbooks_desktop_api/urls.py Established URL routing for spotlight API endpoints.
apps/spotlight/views.py Implemented API views for managing user queries and responses.
quickbooks_desktop_api/settings.py Updated settings to include the spotlight app and modified REST framework configurations.
requirements.txt Added new dependencies for boto3 and openai libraries.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant QueryView
    participant QueryService
    participant HelpService
    participant LLM

    User->>QueryView: Submit query
    QueryView->>QueryService: Get suggestions
    QueryService->>LLM: Format and send query
    LLM-->>QueryService: Return suggestions
    QueryService-->>QueryView: Return suggestions
    QueryView-->>User: Display suggestions

    User->>HelpQueryView: Request help
    HelpQueryView->>HelpService: Get support response
    HelpService->>LLM: Send user query
    LLM-->>HelpService: Return support response
    HelpService-->>HelpQueryView: Return formatted response
    HelpQueryView-->>User: Display support response
Loading

🐰 In the spotlight, new features bloom,
With queries and prompts, they chase away gloom.
From OpenAI's wisdom to AWS's might,
Our rabbit friends hop with delight!
With every new change, we leap and we cheer,
For a brighter tomorrow, the future is near! 🌟

Assessment against linked issues

Objective Addressed Explanation
Integrate AI functionalities for user queries
Implement models for user query storage
Establish API endpoints for query management
Enhance application settings and configurations
Add tests for new functionalities Test cases are currently not implemented.

Possibly related issues

  • None identified as related to the objectives of this PR.

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>.
    • 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 generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @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

Tests Skipped Failures Errors Time
60 0 💤 16 ❌ 0 🔥 9.708s ⏱️

Copy link

@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: 9

Outside diff range and nitpick comments (3)
apps/spotlight/models.py (1)

13-13: Consider removing the underscore prefix from the _llm_response field name.

In Django models, the underscore prefix convention for indicating private attributes is not enforced at the database level. It's more of a guideline for developers to treat these fields as internal to the model.

Consider removing the underscore prefix to follow Django's conventional naming style, unless there's a strong reason to treat this field as private.

-_llm_response = models.JSONField(default={})
+llm_response = models.JSONField(default={})
apps/spotlight/urls.py (1)

1-14: Consider removing the comments.

The comments are helpful for understanding how to define URL patterns but can be removed to keep the file concise.

Apply this diff to remove the comments:

-"""quickbooks_desktop_api URL Configuration
-The `urlpatterns` list routes URLs to views. For more information please see:
-    https://docs.djangoproject.com/en/3.0/topics/http/urls/
-Examples:
-Function views
-    1. Add an import:  from my_app import views
-    2. Add a URL to urlpatterns:  path('', views.home, name='home')
-Class-based views
-    1. Add an import:  from other_app.views import Home
-    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
-Including another URLconf
-    1. Import the include() function: from django.urls import include, path
-    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
-"""
apps/spotlight/migrations/0001_initial.py (1)

1-32: LGTM! Consider the naming convention for the _llm_response field.

The migration follows the standard Django migration structure and creates the Query model with appropriate fields and relationships.

However, please consider the naming convention for the _llm_response field. The leading underscore suggests that it is a "private" or "internal" field. If this field should not be accessed directly, consider using a property or method to encapsulate the access to this field.

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 96fee28 and 6df4b54.

Files selected for processing (16)
  • apps/spotlight/admin.py (1 hunks)
  • apps/spotlight/apps.py (1 hunks)
  • apps/spotlight/llm.py (1 hunks)
  • apps/spotlight/migrations/0001_initial.py (1 hunks)
  • apps/spotlight/models.py (1 hunks)
  • apps/spotlight/prompts/spotlight_prompt.py (1 hunks)
  • apps/spotlight/prompts/support_genie.py (1 hunks)
  • apps/spotlight/serializers.py (1 hunks)
  • apps/spotlight/service.py (1 hunks)
  • apps/spotlight/tests.py (1 hunks)
  • apps/spotlight/urls.py (1 hunks)
  • apps/spotlight/views.py (1 hunks)
  • docker-compose.yml.template (1 hunks)
  • quickbooks_desktop_api/settings.py (2 hunks)
  • quickbooks_desktop_api/urls.py (1 hunks)
  • requirements.txt (1 hunks)
Files skipped from review due to trivial changes (1)
  • apps/spotlight/apps.py
Additional context used
Ruff
apps/spotlight/tests.py

1-1: django.test.TestCase imported but unused

Remove unused import: django.test.TestCase

(F401)

apps/spotlight/admin.py

1-1: django.contrib.admin imported but unused

Remove unused import: django.contrib.admin

(F401)

apps/spotlight/llm.py

51-51: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)

Additional comments not posted (18)
apps/spotlight/serializers.py (1)

6-9: LGTM!

The QuerySerializer is correctly defined and follows Django REST framework conventions. It is also exposing only the required query field, which is a good practice to limit the API surface.

apps/spotlight/models.py (1)

14-14: Verify the desired on delete behavior for the user field.

The user field specifies on_delete=models.CASCADE, which means when a User is deleted, all their associated Query objects will also be deleted.

This is a reasonable default, but consider if this is the desired behavior or if you want to handle user deletions differently (e.g., anonymizing queries instead of deleting them).

quickbooks_desktop_api/urls.py (1)

22-22: LGTM!

The code change is approved.

The new URL pattern is correctly added to the urlpatterns list, following the existing pattern. This change is necessary to enable the spotlight functionality and does not introduce any issues.

apps/spotlight/prompts/support_genie.py (1)

1-12: LGTM!

The prompt provides clear and comprehensive instructions for the question-answering agent. It emphasizes the importance of relying solely on the provided search results, avoiding assumptions, and providing factual responses. The placeholders allow for dynamic insertion of search results and output format instructions.

The prompt is well-structured and should effectively guide the agent in answering user questions based on the available information.

requirements.txt (1)

1-4: LGTM!

The addition of the boto3 and openai dependencies is approved.

Pinning the specific versions of the dependencies is a good practice to ensure reproducibility and avoid potential issues with future versions. The "LLM Clients" comment provides clarity on the purpose of these dependencies.

apps/spotlight/urls.py (1)

21-25: LGTM!

The URL patterns are correctly defined using the path function and the imported views.

apps/spotlight/service.py (4)

9-14: LGTM!

The code changes are approved.


17-26: LGTM!

The code changes are approved.


29-35: LGTM!

The code changes are approved.


40-44: LGTM!

The code changes are approved.

docker-compose.yml.template (1)

28-32: New environment variables added for AWS and OpenAI integration.

The changes introduce new environment variables related to AWS (AWS_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY) and OpenAI (OPENAI_API_KEY). Additionally, there's a KNOWLEDGE_BASE_ID variable.

It's good to see that the sensitive information (access keys and API keys) is not committed and the template file contains empty strings as placeholders.

Could you please provide more context on how these variables will be used and the planned integration with AWS and OpenAI? Also, what is the purpose of the KNOWLEDGE_BASE_ID variable?

apps/spotlight/views.py (1)

74-79: LGTM!

The code changes are approved.

apps/spotlight/llm.py (2)

29-52: LGTM!

The code changes are approved.

Tools
Ruff

51-51: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


55-96: LGTM!

The code changes are approved.

quickbooks_desktop_api/settings.py (3)

62-63: LGTM!

Adding 'apps.spotlight' to INSTALLED_APPS is necessary for integrating the new spotlight app into the project.


109-112: Verify the reason for commenting out DEFAULT_PERMISSION_CLASSES.

Commenting out DEFAULT_PERMISSION_CLASSES disables the default permission classes for the Django REST Framework. This might be okay for development or testing purposes, but it's crucial to ensure that proper authentication and permissions are in place before deploying to production.

Please provide the reason for commenting out DEFAULT_PERMISSION_CLASSES and confirm that it will be re-enabled before production deployment.


113-115: Verify the reason for commenting out DEFAULT_AUTHENTICATION_CLASSES.

Commenting out DEFAULT_AUTHENTICATION_CLASSES disables the default authentication classes for the Django REST Framework. This might be okay for development or testing purposes, but it's crucial to ensure that proper authentication is in place before deploying to production.

Please provide the reason for commenting out DEFAULT_AUTHENTICATION_CLASSES and confirm that it will be re-enabled before production deployment.

apps/spotlight/prompts/spotlight_prompt.py (1)

1-408: Comprehensive and well-structured prompt string.

The prompt string for the AI assistant is well-designed and covers all the necessary aspects for generating relevant suggestions based on user queries. Here are some key strengths:

  1. Clear and detailed guidelines: The guidelines provide a step-by-step approach for the AI assistant to analyze queries, generate suggestions, and format the response. The guidelines also address edge cases, such as handling ambiguous or unmatched queries.

  2. Consistent JSON response structure: The JSON response structure is well-defined and consistent across the examples. It includes the user's search query and separate arrays for actions, navigations, and help suggestions, each containing a unique code, title, and description.

  3. Relevant and diverse examples: The examples cover a range of user queries related to expense management and IIF file handling, demonstrating the AI assistant's ability to provide specific and relevant suggestions based on the predefined suggestion map.

Overall, the prompt string serves as a solid foundation for the AI assistant to generate helpful and accurate suggestions for users.

@@ -0,0 +1,3 @@
from django.test import TestCase
Copy link

Choose a reason for hiding this comment

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

Remove unused import.

The import statement from django.test import TestCase is unused in the file.

Apply this diff to remove the unused import:

-from django.test import TestCase
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
from django.test import TestCase
Tools
Ruff

1-1: django.test.TestCase imported but unused

Remove unused import: django.test.TestCase

(F401)

@@ -0,0 +1,3 @@
from django.contrib import admin
Copy link

Choose a reason for hiding this comment

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

Remove the unused import.

The django.contrib.admin module is imported but not used in this file.

Apply this diff to remove the unused import:

-from django.contrib import admin
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
from django.contrib import admin
Tools
Ruff

1-1: django.contrib.admin imported but unused

Remove unused import: django.contrib.admin

(F401)

class Query(models.Model):
id = models.AutoField(primary_key=True)
query = models.TextField()
workspace_id = models.IntegerField(help_text="Workspace id of the organization")
Copy link

Choose a reason for hiding this comment

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

Use a foreign key for the workspace_id field if it references a Workspace model.

The workspace_id field is an integer field, which implies it's a reference to a Workspace model (not shown in this file).

Consider using a foreign key field instead of a raw integer field if indeed this is meant to be a reference to another model. This would enforce referential integrity at the database level.

-workspace_id = models.IntegerField(help_text="Workspace id of the organization")
+workspace = models.ForeignKey(
+    'Workspace',  
+    on_delete=models.CASCADE,
+    help_text="Reference to the associated Workspace"
+)

Note: Replace 'Workspace' with the actual Workspace model class if it's defined in the same file, or with the full app label and model name (e.g., 'myapp.Workspace') if it's in a different app.

Committable suggestion was skipped due to low confidence.

Comment on lines +13 to +28
# class RecentQueryView(generics.ListAPIView):
# serializer_class = QuerySerializer
# # lookup_field = 'workspace_id'
# # lookup_url_kwarg = 'workspace_id'

# def get_queryset(self):
# filters = {
# # 'workspace_id': self.kwargs.get('workspace_id'),
# # 'user': self.request.user,
# 'workspace_id': 1,
# 'user_id': 1,
# }

# return Query.objects.filter(
# **filters
# ).all().order_by("-created_at")[:5]
Copy link

Choose a reason for hiding this comment

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

Remove the commented out code.

This class is not being used and can be safely removed to improve code readability and maintainability.

Comment on lines +48 to +53
# recent_queries = []
# for query in _recent_queries:
# recent_queries.append({
# "query": query.query,
# "suggestions": query._llm_response["suggestions"]
# })
Copy link

Choose a reason for hiding this comment

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

Remove the commented out code.

This code is not being used and can be safely removed to improve code readability and maintainability.

Comment on lines 37 to 42
filters = {
# 'workspace_id': self.kwargs.get('workspace_id'),
# 'user': self.request.user,
'workspace_id': 1,
'user_id': 1,
}
Copy link

Choose a reason for hiding this comment

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

Use dynamic values for workspace_id and user_id.

The filters dictionary should not use hardcoded values. Instead, retrieve the values from the request or URL parameters.

Apply this diff to fix the issue:

-filters = {
-    # 'workspace_id': self.kwargs.get('workspace_id'),
-    # 'user': self.request.user,
-    'workspace_id': 1,
-    'user_id': 1,
-}
+filters = {
+    'workspace_id': self.kwargs.get('workspace_id'),
+    'user_id': request.user.id,
+}
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
filters = {
# 'workspace_id': self.kwargs.get('workspace_id'),
# 'user': self.request.user,
'workspace_id': 1,
'user_id': 1,
}
filters = {
'workspace_id': self.kwargs.get('workspace_id'),
'user_id': request.user.id,
}

Comment on lines 65 to 70
Query.objects.create(
query=user_query,
workspace_id=1,
_llm_response=suggestions,
user_id=1
)
Copy link

Choose a reason for hiding this comment

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

Use dynamic values for workspace_id and user_id.

The workspace_id and user_id values should not be hardcoded when creating a new Query object. Instead, retrieve the values from the request or URL parameters.

Apply this diff to fix the issue:

-Query.objects.create(
-    query=user_query,
-    workspace_id=1,
-    _llm_response=suggestions,
-    user_id=1
-)
+Query.objects.create(
+    query=user_query,
+    workspace_id=kwargs.get('workspace_id'),
+    _llm_response=suggestions,
+    user_id=request.user.id
+)
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
Query.objects.create(
query=user_query,
workspace_id=1,
_llm_response=suggestions,
user_id=1
)
Query.objects.create(
query=user_query,
workspace_id=kwargs.get('workspace_id'),
_llm_response=suggestions,
user_id=request.user.id
)

Comment on lines +95 to +96
except json.JSONDecodeError as e:
print(e)
Copy link

Choose a reason for hiding this comment

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

Raise an exception instead of printing the error message.

The function prints the error message instead of raising an exception. This can be improved by raising an exception with the error message.

Apply this diff to fix the issue:

-    except json.JSONDecodeError as e:
-        print(e)
+    except json.JSONDecodeError as e:
+        raise Exception(message=str(e)) from e
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
except json.JSONDecodeError as e:
print(e)
except json.JSONDecodeError as e:
raise Exception(message=str(e)) from e

Comment on lines +50 to +51
except (openai.OpenAIError, json.JSONDecodeError) as e:
raise Exception(message=str(e))
Copy link

Choose a reason for hiding this comment

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

Distinguish exceptions raised within the except clause.

The static analysis tool suggests using raise ... from err or raise ... from None to distinguish exceptions raised within the except clause from errors in exception handling.

Apply this diff to fix the issue:

-    except (openai.OpenAIError, json.JSONDecodeError) as e:
-        raise Exception(message=str(e))
+    except (openai.OpenAIError, json.JSONDecodeError) as e:
+        raise Exception(message=str(e)) from e
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
except (openai.OpenAIError, json.JSONDecodeError) as e:
raise Exception(message=str(e))
except (openai.OpenAIError, json.JSONDecodeError) as e:
raise Exception(message=str(e)) from e
Tools
Ruff

51-51: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)

Copy link

Tests Skipped Failures Errors Time
60 0 💤 16 ❌ 0 🔥 9.607s ⏱️

@ruuushhh ruuushhh added the deploy Triggers deployment of active branch to Staging label Sep 12, 2024
Copy link

Tests Skipped Failures Errors Time
60 0 💤 16 ❌ 0 🔥 9.438s ⏱️

Copy link

@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

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 4d528cb and 7ff8109.

Files selected for processing (4)
  • apps/spotlight/urls.py (1 hunks)
  • apps/spotlight/views.py (1 hunks)
  • apps/workspaces/tasks.py (1 hunks)
  • apps/workspaces/views.py (2 hunks)
Files skipped from review as they are similar to previous changes (1)
  • apps/spotlight/urls.py
Additional context used
Ruff
apps/spotlight/views.py

6-6: django_q.tasks.async_task imported but unused

Remove unused import: django_q.tasks.async_task

(F401)

Additional comments not posted (6)
apps/workspaces/views.py (2)

19-19: LGTM!

The import statement is consistent with the renamed function trigger_export in apps/workspaces/tasks.py.


101-101: Verify the return value of trigger_export.

The code changes are consistent with the AI-generated summary and reflect a significant alteration in the control flow and logic of the post method. However, it's important to verify that the trigger_export function returns the correct value for new_expenses_imported.

Run the following script to verify the return value of trigger_export:

Verification successful

Verification successful: trigger_export returns a boolean value.

The trigger_export function correctly returns a boolean value indicating the presence of new, unexported expenses. This aligns with the intended use of the new_expenses_imported variable in the post method.

  • apps/workspaces/tasks.py, line 110: return new_expenses_imported confirms the return of a boolean value.
Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the return value of `trigger_export`.

# Test: Search for the function implementation. Expect: The function should return a boolean value.
ast-grep --lang python --pattern $'def trigger_export($$$):
  $$$
  return $$$'

Length of output: 487

apps/workspaces/tasks.py (1)

105-110: LGTM!

The trigger_export function is well-implemented and follows the existing code structure and style. It effectively triggers the export process by calling the run_import_export function and checks for any new expenses that have not been exported. The function is properly documented, and the naming is clear and descriptive.

The function efficiently queries the Expense model to determine if there are any pending exports and returns a boolean value to indicate the presence of new expenses. This approach is straightforward and provides a clear way to check the export status.

Overall, the code changes are well-structured, reuse existing functionality, and enhance the export process functionality in a clean and maintainable way.

apps/spotlight/views.py (3)

38-60: LGTM!

The RecentQueryView class correctly retrieves the 5 most recent queries for a workspace and user using dynamic values from the request and URL parameters.


81-87: LGTM!

The HelpQueryView class correctly retrieves a support response for a user query using the help service.


89-109: LGTM!

The ActionQueryView class correctly triggers an action based on the provided code using the code_action_map.

from django.db import transaction
from rest_framework import generics
import requests
from django_q.tasks import async_task
Copy link

Choose a reason for hiding this comment

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

Remove the unused import.

The import of django_q.tasks.async_task is not being used in the file and can be safely removed to improve code readability and maintainability.

Apply this diff to remove the unused import:

-from django_q.tasks import async_task
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
from django_q.tasks import async_task
Tools
Ruff

6-6: django_q.tasks.async_task imported but unused

Remove unused import: django_q.tasks.async_task

(F401)

Copy link

Tests Skipped Failures Errors Time
60 0 💤 16 ❌ 0 🔥 9.876s ⏱️

Copy link

Tests Skipped Failures Errors Time
60 0 💤 16 ❌ 0 🔥 9.638s ⏱️

Copy link

Tests Skipped Failures Errors Time
60 0 💤 16 ❌ 0 🔥 9.935s ⏱️

Copy link

Tests Skipped Failures Errors Time
60 0 💤 16 ❌ 0 🔥 9.476s ⏱️

Copy link

Tests Skipped Failures Errors Time
60 0 💤 16 ❌ 0 🔥 9.858s ⏱️

Copy link

Tests Skipped Failures Errors Time
60 0 💤 16 ❌ 0 🔥 9.815s ⏱️

Copy link

Tests Skipped Failures Errors Time
60 0 💤 16 ❌ 0 🔥 9.928s ⏱️

Copy link

@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)
apps/spotlight/prompts/suggestion_context_page_prompt.py (1)

1-175: The prompt template is well-structured and comprehensive. Great job!

The SUGGESTION_PROMPT string provides clear objectives, detailed instructions, and a wide range of examples for the AI agent to generate appropriate suggestions based on user input. The important considerations section also addresses potential edge cases and ensures accurate and consistent responses.

To further improve the prompt, consider adding a brief explanation of the JSON output format to ensure that the AI agent generates suggestions in the expected structure. For example:

 Output should be in JSON format. 
+The JSON output should have a "suggestions" object containing an "actions" array. Each action should be an object with "code", "title", and "description" properties.

This additional clarification can help maintain consistency in the AI agent's responses.

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 023c335 and 88b97e4.

Files selected for processing (4)
  • apps/spotlight/prompts/suggestion_context_page_prompt.py (1 hunks)
  • apps/spotlight/service.py (1 hunks)
  • apps/spotlight/urls.py (1 hunks)
  • apps/spotlight/views.py (1 hunks)
Files skipped from review as they are similar to previous changes (1)
  • apps/spotlight/urls.py
Additional context used
Ruff
apps/spotlight/views.py

5-5: requests imported but unused

Remove unused import: requests

(F401)


6-6: django_q.tasks.async_task imported but unused

Remove unused import: django_q.tasks.async_task

(F401)


12-12: apps.workspaces.models.FyleCredential imported but unused

Remove unused import: apps.workspaces.models.FyleCredential

(F401)


13-13: apps.fyle.helpers.get_access_token imported but unused

Remove unused import: apps.fyle.helpers.get_access_token

(F401)


14-14: rest_framework.response.Response imported but unused

Remove unused import: rest_framework.response.Response

(F401)

apps/spotlight/service.py

269-269: Local variable post_response is assigned to but never used

Remove assignment to unused variable post_response

(F841)


287-287: Local variable post_response is assigned to but never used

Remove assignment to unused variable post_response

(F841)


305-305: Local variable post_response is assigned to but never used

Remove assignment to unused variable post_response

(F841)


323-323: Local variable post_response is assigned to but never used

Remove assignment to unused variable post_response

(F841)

Additional comments not posted (22)
apps/spotlight/views.py (4)

83-89: LGTM!

The class implementation looks good and there are no issues to report.


91-106: LGTM!

The class implementation looks good and there are no issues to report.


107-113: LGTM!

The class implementation looks good and there are no issues to report.


55-60: Remove the commented out code.

This code is not being used and can be safely removed to improve code readability and maintainability.

apps/spotlight/service.py (18)

17-20: LGTM!

The ActionResponse dataclass is well-structured and correctly defines the fields for an action response.


23-52: LGTM!

The HelpService class methods are well-structured and correctly implement the logic for extracting citations and formatting responses.


54-60: LGTM!

The QueryService class method is well-structured and correctly implements the logic for getting suggestions based on a user query.


62-69: LGTM!

The SuggestionService class method is well-structured and correctly implements the logic for getting suggestions based on a user query.


74-92: LGTM!

The _get_action_function_from_code method is well-structured and correctly maps action codes to their corresponding functions.


95-99: LGTM!

The get_headers method is well-structured and correctly returns the headers for making API requests.


102-104: LGTM!

The get_access_token method is well-structured and correctly retrieves the access token for a given workspace.


107-117: LGTM!

The set_reimbursable_expenses_export_module_bill method is well-structured and correctly sets the reimbursable expense export type to 'BILL'.


120-130: LGTM!

The set_reimbursable_expenses_export_module_journal_entry method is well-structured and correctly sets the reimbursable expense export type to 'JOURNAL_ENTRY'.


133-143: LGTM!

The set_reimbursable_expenses_export_grouping_expense method is well-structured and correctly sets the reimbursable expense export grouping to 'EXPENSE'.


146-156: LGTM!

The set_reimbursable_expenses_export_grouping_report method is well-structured and correctly sets the reimbursable expense export grouping to 'REPORT'.


159-169: LGTM!

The set_reimbursable_expenses_export_state_processing method is well-structured and correctly sets the reimbursable expense export state to 'PAYMENT_PROCESSING'.


172-182: LGTM!

The set_reimbursable_expenses_export_state_paid method is well-structured and correctly sets the reimbursable expense export state to 'PAID'.


200-208: LGTM!

The set_cc_export_to_corporate_card_purchase method is well-structured and correctly sets the credit card expense export type to 'CREDIT_CARD_PURCHASE'.


212-220: LGTM!

The set_cc_export_to_journal_entry method is well-structured and correctly sets the credit card expense export type to 'JOURNAL_ENTRY'.


223-234: LGTM!

The set_cc_grouping_to_report method is well-structured and correctly sets the credit card expense grouping to 'REPORT'.


238-249: LGTM!

The set_cc_grouping_to_expense method is well-structured and correctly sets the credit card expense grouping to 'EXPENSE'.


269-269: Remove the unused variable assignment.

The set_customer_field_mapping_to_project method is well-structured and implemented correctly. However, there is an unused variable assignment that should be removed.

Please remove the assignment to the unused variable post_response:

-post_response = requests.post(url, headers=headers, data=json.dumps(action_response))

<details>
<summary>Tools</summary>

<details>
<summary>Ruff</summary><blockquote>

269-269: Local variable `post_response` is assigned to but never used

Remove assignment to unused variable `post_response`

(F841)

</blockquote></details>

</details>

</blockquote></details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Comment on lines +5 to +14
import requests
from django_q.tasks import async_task

from apps.spotlight.models import Query
from apps.spotlight.serializers import QuerySerializer

from .service import ActionService, HelpService, QueryService, SuggestionService
from apps.workspaces.models import FyleCredential
from apps.fyle.helpers import get_access_token
from rest_framework.response import Response
Copy link

Choose a reason for hiding this comment

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

Remove the unused imports.

The following imports are not being used in the file and can be safely removed to improve code readability and maintainability:

  • requests at line 5
  • django_q.tasks.async_task at line 6
  • apps.workspaces.models.FyleCredential at line 12
  • apps.fyle.helpers.get_access_token at line 13
  • rest_framework.response.Response at line 14

Apply this diff to remove the unused imports:

-import requests
-from django_q.tasks import async_task
-from apps.workspaces.models import FyleCredential
-from apps.fyle.helpers import get_access_token
-from rest_framework.response import Response
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
import requests
from django_q.tasks import async_task
from apps.spotlight.models import Query
from apps.spotlight.serializers import QuerySerializer
from .service import ActionService, HelpService, QueryService, SuggestionService
from apps.workspaces.models import FyleCredential
from apps.fyle.helpers import get_access_token
from rest_framework.response import Response
from apps.spotlight.models import Query
from apps.spotlight.serializers import QuerySerializer
from .service import ActionService, HelpService, QueryService, SuggestionService
Tools
Ruff

5-5: requests imported but unused

Remove unused import: requests

(F401)


6-6: django_q.tasks.async_task imported but unused

Remove unused import: django_q.tasks.async_task

(F401)


12-12: apps.workspaces.models.FyleCredential imported but unused

Remove unused import: apps.workspaces.models.FyleCredential

(F401)


13-13: apps.fyle.helpers.get_access_token imported but unused

Remove unused import: apps.fyle.helpers.get_access_token

(F401)


14-14: rest_framework.response.Response imported but unused

Remove unused import: rest_framework.response.Response

(F401)

"Content-Type": "application/json"
}
url = f'http://localhost:8000/api/workspaces/{workspace_id}/trigger_export/'
action_response = requests.post(url, json={}, headers=headers)
Copy link

Choose a reason for hiding this comment

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

Remove the unused variable assignment.

The trigger_export method is well-structured and implemented correctly. However, there is an unused variable assignment that should be removed.

Please remove the assignment to the unused variable action_response:

-action_response = requests.post(url, json={}, headers=headers)
+requests.post(url, json={}, headers=headers)
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
action_response = requests.post(url, json={}, headers=headers)
requests.post(url, json={}, headers=headers)

Copy link

Tests Skipped Failures Errors Time
60 0 💤 16 ❌ 0 🔥 9.625s ⏱️

Copy link

@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: 5

Outside diff range and nitpick comments (1)
apps/spotlight/models.py (1)

13-13: Consider removing the underscore prefix from _llm_response if this field needs to be accessed directly.

In Python, a single underscore prefix is used as a convention to indicate that a field is meant for internal use or is "private" to the class.

If _llm_response needs to be accessed directly from outside the Query class, remove the underscore prefix:

-_llm_response = models.JSONField(default={})
+llm_response = models.JSONField(default={})

However, if the underscore is intentional and this field should not be accessed directly, you can ignore this comment.

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 88b97e4 and 2dce048.

Files selected for processing (3)
  • apps/spotlight/migrations/0002_copyexportsettings.py (1 hunks)
  • apps/spotlight/models.py (1 hunks)
  • apps/spotlight/service.py (1 hunks)
Additional context used
Ruff
apps/spotlight/service.py

274-274: Local variable post_response is assigned to but never used

Remove assignment to unused variable post_response

(F841)


292-292: Local variable post_response is assigned to but never used

Remove assignment to unused variable post_response

(F841)


310-310: Local variable post_response is assigned to but never used

Remove assignment to unused variable post_response

(F841)


328-328: Local variable post_response is assigned to but never used

Remove assignment to unused variable post_response

(F841)

Additional comments not posted (8)
apps/spotlight/migrations/0002_copyexportsettings.py (1)

1-25: LGTM!

The migration file follows the standard structure and the model fields are well-defined with appropriate data types and constraints. The use of nullable JSON fields for storing export settings is a good choice for handling unstructured data. The model is correctly registered in the database using the db_table option.

apps/spotlight/models.py (2)

12-12: ** Use a foreign key for the workspace_id field if it references a Workspace model.**

As mentioned in the previous review, consider using a foreign key field instead of a raw integer field if workspace_id is meant to be a reference to a Workspace model. This would enforce referential integrity at the database level.

-workspace_id = models.IntegerField(help_text="Workspace id of the organization")
+workspace = models.ForeignKey(
+    'Workspace',  
+    on_delete=models.CASCADE,
+    help_text="Reference to the associated Workspace"
+)

Note: Replace 'Workspace' with the actual Workspace model class if it's defined in the same file, or with the full app label and model name (e.g., 'myapp.Workspace') if it's in a different app.


25-32: The model fields and table name follow the project's naming conventions.

The CopyExportSettings model class follows the project's naming conventions for fields and the database table name.

apps/spotlight/service.py (5)

18-21: LGTM!

The ActionResponse dataclass is correctly defined with appropriate fields and default values.


24-53: LGTM!

The HelpService class and its methods are well-structured and implemented correctly. The extract_citations method efficiently extracts unique URLs from the citations, and the format_response method properly formats the response by appending the extracted citations. The get_support_response method appropriately calls the llm.get_support_response_from_bedrock function and formats the response.


55-62: LGTM!

The QueryService class and its get_suggestions method are correctly implemented. The method properly formats the prompt and calls the llm.get_openai_response function to get the suggestions.


63-71: LGTM!

The SuggestionService class and its get_suggestions method are correctly implemented. The method properly formats the prompt and calls the llm.get_openai_response function to get the suggestions.


72-433: Great implementation of the ActionService class!

The ActionService class is well-structured and contains several methods for performing various actions related to export settings and field mappings. The methods are properly implemented and handle different scenarios effectively. The action method serves as a convenient entry point to call the appropriate action function based on the provided code.

Tools
Ruff

274-274: Local variable post_response is assigned to but never used

Remove assignment to unused variable post_response

(F841)


292-292: Local variable post_response is assigned to but never used

Remove assignment to unused variable post_response

(F841)


310-310: Local variable post_response is assigned to but never used

Remove assignment to unused variable post_response

(F841)


328-328: Local variable post_response is assigned to but never used

Remove assignment to unused variable post_response

(F841)


class CopyExportSettings(models.Model):

workspace_id = models.IntegerField(help_text="Workspace id of the organization")
Copy link

Choose a reason for hiding this comment

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

Use a foreign key for the workspace_id field if it references a Workspace model.

Similar to the Query model, consider using a foreign key field instead of a raw integer field if workspace_id is meant to be a reference to a Workspace model. This would enforce referential integrity at the database level.

-workspace_id = models.IntegerField(help_text="Workspace id of the organization")
+workspace = models.ForeignKey(
+    'Workspace',  
+    on_delete=models.CASCADE,
+    help_text="Reference to the associated Workspace"
+)

Note: Replace 'Workspace' with the actual Workspace model class if it's defined in the same file, or with the full app label and model name (e.g., 'myapp.Workspace') if it's in a different app.

Committable suggestion was skipped due to low confidence.

action_response= action_response.json()
if action_response.get('project_type') != 'PROJECT' and action_response.get('class_type') != 'COST_CENTER':
action_response['project_type'] = 'PROJECT'
post_response = requests.post(url, headers=headers, data=json.dumps(action_response))
Copy link

Choose a reason for hiding this comment

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

Remove the unused variable assignment.

The post_response variable is assigned but never used in the set_customer_field_mapping_to_project method. Please remove the assignment:

-post_response = requests.post(url, headers=headers, data=json.dumps(action_response))
+requests.post(url, headers=headers, data=json.dumps(action_response))
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
post_response = requests.post(url, headers=headers, data=json.dumps(action_response))
requests.post(url, headers=headers, data=json.dumps(action_response))
Tools
Ruff

274-274: Local variable post_response is assigned to but never used

Remove assignment to unused variable post_response

(F841)

action_response= action_response.json()
if action_response.get('project_type') != 'PROJECT' and action_response.get('class_type') != 'COST_CENTER':
action_response['class_type'] = 'PROJECT'
post_response = requests.post(url, headers=headers, data=json.dumps(action_response))
Copy link

Choose a reason for hiding this comment

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

Remove the unused variable assignment.

The post_response variable is assigned but never used in the set_class_field_mapping_to_project method. Please remove the assignment:

-post_response = requests.post(url, headers=headers, data=json.dumps(action_response))
+requests.post(url, headers=headers, data=json.dumps(action_response))
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
post_response = requests.post(url, headers=headers, data=json.dumps(action_response))
requests.post(url, headers=headers, data=json.dumps(action_response))
Tools
Ruff

310-310: Local variable post_response is assigned to but never used

Remove assignment to unused variable post_response

(F841)

action_response= action_response.json()
if action_response.get('project_type') != 'COST_CENTER' and action_response.get('class_type') != 'PROJECT':
action_response['project_type'] = 'COST_CENTER'
post_response = requests.post(url, headers=headers, data=json.dumps(action_response))
Copy link

Choose a reason for hiding this comment

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

Remove the unused variable assignment.

The post_response variable is assigned but never used in the set_customer_field_mapping_to_cost_center method. Please remove the assignment:

-post_response = requests.post(url, headers=headers, data=json.dumps(action_response))
+requests.post(url, headers=headers, data=json.dumps(action_response))
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
post_response = requests.post(url, headers=headers, data=json.dumps(action_response))
requests.post(url, headers=headers, data=json.dumps(action_response))
Tools
Ruff

292-292: Local variable post_response is assigned to but never used

Remove assignment to unused variable post_response

(F841)

action_response= action_response.json()
if action_response.get('project_type') != 'COST_CENTER' and action_response.get('class_type') != 'PROJECT':
action_response['class_type'] = 'COST_CENTER'
post_response = requests.post(url, headers=headers, data=json.dumps(action_response))
Copy link

Choose a reason for hiding this comment

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

Remove the unused variable assignment.

The post_response variable is assigned but never used in the set_class_field_mapping_to_cost_center method. Please remove the assignment:

-post_response = requests.post(url, headers=headers, data=json.dumps(action_response))
+requests.post(url, headers=headers, data=json.dumps(action_response))
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
post_response = requests.post(url, headers=headers, data=json.dumps(action_response))
requests.post(url, headers=headers, data=json.dumps(action_response))
Tools
Ruff

328-328: Local variable post_response is assigned to but never used

Remove assignment to unused variable post_response

(F841)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
deploy Triggers deployment of active branch to Staging
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants