-
Notifications
You must be signed in to change notification settings - Fork 203
mito-ai: add v1 google doc rule import #1997
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
aarondr77
wants to merge
8
commits into
dev
Choose a base branch
from
feat/dynamic-rule-creation
base: dev
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
9502dee
mito-ai: add v1 google doc rule import
aarondr77 310acbd
mito-ai: form polish
aarondr77 d769352
mito-ai: add rule metadata
aarondr77 5aae709
mito-ai: refresh google drive rules on load
aarondr77 23be43c
mito-ai: reopen rule configuration
aarondr77 a899fd4
mito-ai: cleanup
aarondr77 4e04f81
mito-ai: fix form reset bug
aarondr77 b816676
mito-ai: add jest tests
aarondr77 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| # Copyright (c) Saga Inc. | ||
| # Distributed under the terms of the GNU Affero General Public License v3.0 License. | ||
|
|
||
| import re | ||
| import requests | ||
| from typing import Optional, Dict, Any | ||
| from urllib.parse import urlparse, parse_qs | ||
| import logging | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
| class GoogleDriveService: | ||
| """Service for fetching content from Google Drive URLs""" | ||
|
|
||
| @staticmethod | ||
| def extract_file_id(url: str) -> Optional[str]: | ||
| """Extract file ID from Google Drive URL""" | ||
| patterns = [ | ||
| r'/d/([a-zA-Z0-9-_]+)', # Standard Google Drive URL | ||
| r'id=([a-zA-Z0-9-_]+)', # URL with id parameter | ||
| ] | ||
|
|
||
| for pattern in patterns: | ||
| match = re.search(pattern, url) | ||
| if match: | ||
| return match.group(1) | ||
|
|
||
| return None | ||
|
|
||
| @staticmethod | ||
| def get_file_type(url: str) -> Optional[str]: | ||
| """Determine if URL is a Google Docs URL""" | ||
| if '/document/' in url: | ||
| return 'document' | ||
| return None | ||
|
|
||
| @staticmethod | ||
| def get_export_url(file_id: str) -> str: | ||
| """Generate export URL for Google Docs file""" | ||
| return f"https://docs.google.com/document/d/{file_id}/export?format=txt" | ||
|
|
||
| @staticmethod | ||
| def fetch_content(url: str) -> Dict[str, Any]: | ||
| """ | ||
| Fetch content from Google Docs URL | ||
|
|
||
| Args: | ||
| url: Google Docs URL | ||
|
|
||
| Returns: | ||
| Dict containing content, file_type, and metadata | ||
| """ | ||
| try: | ||
| # Extract file ID and type | ||
| file_id = GoogleDriveService.extract_file_id(url) | ||
| if not file_id: | ||
| raise ValueError("Invalid Google Docs URL: Could not extract file ID") | ||
|
|
||
| file_type = GoogleDriveService.get_file_type(url) | ||
| if not file_type: | ||
| raise ValueError("Unsupported file type. Only Google Docs are supported") | ||
|
|
||
| # Generate export URL | ||
| export_url = GoogleDriveService.get_export_url(file_id) | ||
|
|
||
| # Fetch content | ||
| response = requests.get(export_url, timeout=30) | ||
| response.raise_for_status() | ||
|
|
||
| content = response.text | ||
|
|
||
| return { | ||
| 'content': content, | ||
| 'file_type': file_type, | ||
| 'file_id': file_id, | ||
| 'success': True, | ||
| 'error': None | ||
| } | ||
|
|
||
| except requests.exceptions.RequestException as e: | ||
| logger.error(f"Failed to fetch Google Docs content: {e}") | ||
| return { | ||
| 'content': None, | ||
| 'file_type': None, | ||
| 'file_id': None, | ||
| 'success': False, | ||
| 'error': f"Failed to fetch content: {str(e)}" | ||
| } | ||
| except Exception as e: | ||
| logger.error(f"Error processing Google Docs URL: {e}") | ||
| return { | ||
| 'content': None, | ||
| 'file_type': None, | ||
| 'file_id': None, | ||
| 'success': False, | ||
| 'error': f"Error processing URL: {str(e)}" | ||
| } | ||
|
|
||
| @staticmethod | ||
| def is_valid_google_docs_url(url: str) -> bool: | ||
| """Check if URL is a valid Google Docs URL""" | ||
| if not url: | ||
| return False | ||
|
|
||
| # Check if it's a Google Docs URL | ||
| if not url.startswith('https://docs.google.com/document/'): | ||
| return False | ||
|
|
||
| # Check if it contains a file ID | ||
| file_id = GoogleDriveService.extract_file_id(url) | ||
| return file_id is not None |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,11 +1,14 @@ | ||
| # Copyright (c) Saga Inc. | ||
| # Distributed under the terms of the GNU Affero General Public License v3.0 License. | ||
|
|
||
| from typing import Any, Final, List, Optional | ||
| from typing import Any, Final, List, Optional, Dict | ||
| import os | ||
| import json | ||
| from datetime import datetime | ||
| from mito_ai.utils.schema import MITO_FOLDER | ||
|
|
||
| RULES_DIR_PATH: Final[str] = os.path.join(MITO_FOLDER, 'rules') | ||
| RULES_METADATA_FILE: str = os.path.join(RULES_DIR_PATH, 'metadata.json') | ||
|
|
||
| def set_rules_file(rule_name: str, value: Any) -> None: | ||
| """ | ||
|
|
@@ -54,3 +57,78 @@ def get_all_rules() -> List[str]: | |
| # Log the error if needed and return empty list | ||
| print(f"Error reading rules directory: {e}") | ||
| return [] | ||
|
|
||
|
|
||
| def load_rules_metadata() -> Dict[str, Any]: | ||
| """Load rules metadata from file""" | ||
| if not os.path.exists(RULES_METADATA_FILE): | ||
| return {} | ||
|
|
||
| try: | ||
| with open(RULES_METADATA_FILE, 'r') as f: | ||
| return json.load(f) | ||
| except (json.JSONDecodeError, IOError): | ||
| return {} | ||
|
|
||
|
|
||
| def save_rules_metadata(metadata: Dict[str, Any]) -> None: | ||
| """Save rules metadata to file""" | ||
| # Ensure the directory exists | ||
| if not os.path.exists(RULES_DIR_PATH): | ||
| os.makedirs(RULES_DIR_PATH) | ||
|
|
||
| with open(RULES_METADATA_FILE, 'w') as f: | ||
| json.dump(metadata, f, indent=2) | ||
|
|
||
|
|
||
| def set_rule_with_metadata(rule_name: str, content: str, rule_type: str = "manual", google_drive_url: Optional[str] = None) -> None: | ||
| """Set a rule with metadata including rule type and optional Google Drive URL""" | ||
| # Save the content to the .md file | ||
| set_rules_file(rule_name, content) | ||
|
|
||
| # Update metadata | ||
| metadata = load_rules_metadata() | ||
| metadata[rule_name] = { | ||
| 'rule_type': rule_type, | ||
| 'google_drive_url': google_drive_url, | ||
| 'last_updated': datetime.now().isoformat() | ||
| } | ||
| save_rules_metadata(metadata) | ||
|
|
||
|
|
||
| def get_rule_metadata(rule_name: str) -> Optional[Dict[str, Any]]: | ||
| """Get rule metadata""" | ||
| metadata = load_rules_metadata() | ||
| return metadata.get(rule_name) | ||
|
|
||
|
|
||
| def refresh_google_drive_rules() -> Dict[str, Any]: | ||
| """Refresh all Google Drive rules""" | ||
| from mito_ai.rules.google_drive_service import GoogleDriveService | ||
|
|
||
| metadata = load_rules_metadata() | ||
| results = {'success': [], 'errors': []} | ||
|
|
||
| for rule_name, rule_metadata in metadata.items(): | ||
| if rule_metadata.get('rule_type') == 'google_doc' and rule_metadata.get('google_drive_url'): | ||
| try: | ||
| # Fetch fresh content from Google Drive | ||
| result = GoogleDriveService.fetch_content(rule_metadata['google_drive_url']) | ||
|
|
||
| if result['success']: | ||
| # Update the rule content | ||
| set_rule_with_metadata(rule_name, result['content'], 'google_doc', rule_metadata['google_drive_url']) | ||
| results['success'].append(rule_name) | ||
| else: | ||
| results['errors'].append({ | ||
| 'rule': rule_name, | ||
| 'error': result['error'] | ||
| }) | ||
|
|
||
| except Exception as e: | ||
| results['errors'].append({ | ||
| 'rule': rule_name, | ||
| 'error': str(e) | ||
| }) | ||
|
|
||
| return results | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: Circular Dependency in Google Drive Refresh FunctionThe |
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Mutable Constant Path Causes File Operation Errors
The
RULES_METADATA_FILEis declared as a mutablestrinstead ofFinal[str]. This makes the constant path susceptible to accidental reassignment, which could cause file operations to fail or write to incorrect locations.