Skip to main content

odoo-knowledge-agent

Scrape Odoo forum solved threads to build error prevention guardrails and auto-fix scripts. Extract patterns from 1000+ solved issues to prevent common mistakes before deployment and auto-heal production problems. Combines web scraping, AI pattern extraction, preventive guardrails generation, and auto-patch scripts for Odoo custom development lifecycle.

소스 정보

저장소
jgtolentino/insightpulse-odoo
최근 소스 활동
2025년 11월 3일 17:52
감지된 SKILL.md 언어
영어
스타
22
포크
10

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

파일 탐색기
2 개 파일

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
odoo-knowledge-agent
description
Scrape Odoo forum solved threads to build error prevention guardrails and auto-fix scripts. Extract patterns from 1000+ solved issues to prevent common mistakes before deployment and auto-heal production problems. Combines web scraping, AI pattern extraction, preventive guardrails generation, and auto-patch scripts for Odoo custom development lifecycle.
# Odoo Knowledge Agent - Error Prevention & Auto-Fix System ## When to Use This Skill Use this skill when you need to: - **Prevent Odoo errors before deployment** with guardrails - **Auto-heal production issues** using community-validated fixes - **Build intelligence from Odoo forum** solved threads (1000+ cases) - **Generate error code reference** and troubleshooting guides - **Create preventive checks** for module development - **Implement auto-patch systems** for known failure patterns - **Reduce debugging time** by learning from community solutions - **Build SOP library** for common Odoo development errors ## Core Capabilities ### 1. Forum Scraping Intelligence **Scrape Odoo Forum for Solved Threads** - Extract 1000+ solved issues across all categories - Parse accepted answers and code fixes - Identify error patterns and root causes - Build searchable knowledge base ### 2. Guardrails Generation **Preventive Error Checks** - Block common mistakes before deployment - Validate manifest files automatically - Check field synchronization issues - Enforce best practices (OCA standards) ### 3. Auto-Patch Scripts **Automated Error Fixes** - Apply community-validated solutions - Fix known issues automatically - Handle common migration problems - Self-healing production systems ### 4. Vision-Based UI Automation **askui-Compatible Automation** - UI actions without brittle selectors - Cross-browser compatibility - Screenshot-based validation - Self-healing test scripts ## Prerequisites ### Required Software - Python 3.11+ - Beautiful Soup 4 / Firecrawl - Odoo 19 instance for testing - Supabase for knowledge storage ### Optional Integrations - OpenAI API for pattern extraction - GitHub Actions for CI/CD integration - Perplexity for research enhancement ### Python Dependencies ```python beautifulsoup4 requests firecrawl-py supabase-py openai pyyaml gitpython ``` ## Implementation Patterns ### Forum Scraper ```python # scrape_solved_threads.py import requests from bs4 import BeautifulSoup from supabase import create_client import time from datetime import datetime class OdooForumScraper: def __init__(self, supabase_url, supabase_key): self.base_url = "https://www.odoo.com/forum" self.supabase = create_client(supabase_url, supabase_key) self.session = requests.Session() self.session.headers.update({ 'User-Agent': 'OdooKnowledgeBot/1.0' }) def scrape_solved_threads(self, pages=100): """ Scrape Odoo forum for solved threads """ threads = [] for page in range(1, pages + 1): print(f"Scraping page {page}/{pages}...") url = f"{self.base_url}/questions?filters=solved&page={page}" response = self.session.get(url) soup = BeautifulSoup(response.content, 'html.parser') # Extract thread links thread_elements = soup.select('.o_wforum_question') for thread in thread_elements: thread_url = thread.find('a')['href'] if not thread_url.startswith('http'): thread_url = f"https://www.odoo.com{thread_url}" # Get thread details thread_data = self.scrape_thread_details(thread_url) if thread_data: threads.append(thread_data) self.store_thread(thread_data) time.sleep(2) # Rate limiting time.sleep(5) # Pause between pages return threads def scrape_thread_details(self, url): """ Extract question, accepted answer, and code snippets """ try: response = self.session.get(url) soup = BeautifulSoup(response.content, 'html.parser') # Extract question question_elem = soup.select_one('.o_wforum_question_text') question = question_elem.text.strip() if question_elem else "" # Extract title title_elem = soup.select_one('h1.o_wforum_title') title = title_elem.text.strip() if title_elem else "" # Extract accepted answer accepted_answer = soup.select_one('.o_wforum_answer.o_wforum_answer_correct') if not accepted_answer: return None # Skip if no accepted answer answer_text = accepted_answer.select_one('.o_wforum_answer_text').text.strip() # Extract code snippets code_blocks = accepted_answer.select('pre code') code_snippets = [block.text.strip() for block in code_blocks] # Extract tags/category tags = [tag.text.strip() for tag in soup.select('.o_wforum_tag')] # Extract metadata views_elem = soup.select_one('.o_wforum_views') views = int(views_elem.text.strip()) if views_elem else 0 return { 'url': url, 'title': title, 'question': question, 'answer': answer_text, 'code_snippets': code_snippets, 'tags': tags, 'views': views, 'scraped_at': datetime.now().isoformat() } except Exception as e: print(f"Error scraping {url}: {e}") return None def store_thread(self, thread_data): """ Store thread in Supabase knowledge base """ self.supabase.table('odoo_solved_threads').upsert({ 'thread_url': thread_data['url'], 'title': thread_data['title'], 'question': thread_data['question'], 'answer': thread_data['answer'], 'code_snippets': thread_data['code_snippets'], 'tags': thread_data['tags'], 'views': thread_data['views'], 'scraped_at': thread_data['scraped_at'] }).execute() def extract_error_patterns(self): """ Use AI to extract common error patterns """ # Fetch all threads threads = self.supabase.table('odoo_solved_threads').select('*').execute() # Group by error type using AI from openai import OpenAI client = OpenAI() patterns = {} for thread in threads.data: # Ask GPT to categorize the error response = client.chat.completions.create( model="gpt-4", messages=[ {"role": "system", "content": "You are an Odoo expert. Categorize this error and extract the fix pattern."}, {"role": "user", "content": f"Title: {thread['title']}\n\nQuestion: {thread['question']}\n\nAnswer: {thread['answer']}"} ] ) pattern = response.choices[0].message.content # Extract category category = self.extract_category(pattern) if category not in patterns: patterns[category] = [] patterns[category].append({ 'thread': thread, 'pattern': pattern }) return patterns def extract_category(self, pattern_text): """ Extract error category from AI analysis """ # Common Odoo error categories categories = { 'manifest': ['__manifest__', 'module', 'dependency'], 'field': ['field', 'column', 'attribute'], 'view': ['view', 'xml', 'template'], 'security': ['access', 'rights', 'permission'], 'orm': ['orm', 'recordset', 'browse'], 'workflow': ['workflow', 'state', 'transition'], 'accounting': ['invoice', 'payment', 'journal'], 'inventory': ['stock', 'picking', 'quant'] } pattern_lower = pattern_text.lower() for category, keywords in categories.items(): if any(keyword in pattern_lower for keyword in keywords): return category return 'general' # Usage scraper = OdooForumScraper( supabase_url=os.getenv('SUPABASE_URL'), supabase_key=os.getenv('SUPABASE_KEY') ) # Scrape 100 pages (~1,100 solved threads) threads = scraper.scrape_solved_threads(pages=100) # Extract patterns patterns = scraper.extract_error_patterns() print(f"Scraped {len(threads)} solved threads") print(f"Identified {len(patterns)} error patterns") ``` ### Guardrail Generator ```python # generate_guardrails.py import yaml from pathlib import Path class GuardrailGenerator: def __init__(self, patterns): self.patterns = patterns self.guardrails_dir = Path('guardrails') self.guardrails_dir.mkdir(exist_ok=True) def generate_manifest_guardrail(self): """ GR-INSTALL-004: Manifest validation """ guardrail = { 'id': 'GR-INSTALL-004', 'name': 'Manifest Validation', 'description': 'Prevent module installation failures due to invalid __manifest__.py', 'category': 'manifest', 'severity': 'HIGH', 'checks': [ { 'name': 'Required Keys Present', 'pattern': r"'name':|\"name\":", 'error_message': "Missing required 'name' key in __manifest__.py", 'fix': 'Add name = "Module Name" to __manifest__.py' }, { 'name': 'Valid Dependencies', 'pattern': r"'depends':\s*\[.*?\]", 'error_message': "Invalid or missing 'depends' list", 'fix': 'Ensure depends list contains only installed modules' }, { 'name': 'Version Format', 'pattern': r"'version':\s*'\\d+\\.\\d+'", 'error_message': "Invalid version format (should be X.Y)", 'fix': 'Use semantic versioning: version = "1.0"' } ], 'prevention_script': ''' def validate_manifest(manifest_path): with open(manifest_path) as f: manifest = eval(f.read()) required_keys = ['name', 'version', 'depends', 'data'] missing = [k for k in required_keys if k not in manifest] if missing: raise ValueError(f"Missing required keys: {missing}") # Validate version format version = manifest['version'] if not re.match(r'^\\d+\\.\\d+$', version): raise ValueError(f"Invalid version format: {version}") return True ''', 'auto_fix_script': ''' def fix_manifest(manifest_path): with open(manifest_path) as f: content = f.read() # Add missing keys with defaults if "'name'" not in content and '"name"' not in content: content = "{'name': 'My Module',\n" + content if "'version'" not in content: content += "\\n'version': '1.0'," if "'depends'" not in content: content += "\\n'depends': ['base']," with open(manifest_path, 'w') as f: f.write(content) ''' } output_path = self.guardrails_dir / 'GR-INSTALL-004.yaml' with open(output_path, 'w') as f: yaml.dump(guardrail, f, default_flow_style=False) return guardrail def generate_field_sync_guardrail(self): """ GR-POS-001: POS field synchronization """ guardrail = { 'id': 'GR-POS-001', 'name': 'POS Field Sync Prevention', 'description': 'Prevent POS order/line desync when adding custom fields', 'category': 'field', 'severity': 'CRITICAL', 'background': ''' Common Issue: Adding fields to pos.order.line but forgetting to add export/import in pos.order causes data loss on session closure. Affected Models: - pos.order (parent) - pos.order.line (child) Root Cause: POS uses JSON export/import for order data persistence. Custom fields not included in _export_for_ui() are silently dropped. ''', 'checks': [ { 'name': 'Check POS Line Fields', 'pattern': r'class PosOrderLine.*?:', 'error_message': 'Added field to pos.order.line without updating pos.order export', 'fix': 'Add field to _export_for_ui() in pos.order' } ], 'prevention_script': ''' def check_pos_field_sync(module_path): """Validate POS field synchronization""" pos_order_line_file = module_path / 'models' / 'pos_order_line.py'
GitHub에서 보기
이 SKILL.md는 매우 커서 SkillsMP가 여기에는 첫 섹션만 미리 보여줍니다. GitHub에서 보기