legalmind-ai 1.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of legalmind-ai might be problematic. Click here for more details.

Files changed (58) hide show
  1. legalmind/__init__.py +1 -0
  2. legalmind/ai/__init__.py +7 -0
  3. legalmind/ai/legal_ai.py +232 -0
  4. legalmind/analyzers/__init__.py +0 -0
  5. legalmind/api/__init__.py +0 -0
  6. legalmind/api/server.py +288 -0
  7. legalmind/config.py +41 -0
  8. legalmind/core.py +92 -0
  9. legalmind/core_enhanced.py +206 -0
  10. legalmind/enhanced_search.py +148 -0
  11. legalmind/prompt_templates.py +284 -0
  12. legalmind/providers/__init__.py +0 -0
  13. legalmind/providers/fallback/__init__.py +11 -0
  14. legalmind/providers/fallback/config.py +66 -0
  15. legalmind/providers/fallback/data_loader.py +308 -0
  16. legalmind/providers/fallback/enhanced_system.py +151 -0
  17. legalmind/providers/fallback/system.py +456 -0
  18. legalmind/providers/fallback/versalaw2_core/__init__.py +11 -0
  19. legalmind/providers/fallback/versalaw2_core/config.py +66 -0
  20. legalmind/providers/fallback/versalaw2_core/data_loader.py +308 -0
  21. legalmind/providers/fallback/versalaw2_core/enhanced_system.py +151 -0
  22. legalmind/providers/fallback/versalaw2_core/system.py +456 -0
  23. legalmind/providers/qodo.py +139 -0
  24. legalmind/providers/qodo_ai.py +85 -0
  25. legalmind/study_cases/CROSS_PROJECT_INTEGRATION_ANALYSIS.md +411 -0
  26. legalmind/study_cases/DAFTAR_KASUS_PRIORITAS_ANALISIS.md +779 -0
  27. legalmind/study_cases/JAWABAN_ANALISIS_3_KASUS_MENANTANG.md +393 -0
  28. legalmind/study_cases/JAWABAN_TERBAIK_KONTRAK_REAL.md +854 -0
  29. legalmind/study_cases/LEGAL_PROJECTS_ANALYSIS_REPORT.md +442 -0
  30. legalmind/study_cases/PORTFOLIO_11_KASUS_LENGKAP.md +458 -0
  31. legalmind/study_cases/RINGKASAN_3_KASUS_TECH_INTERNASIONAL.md +565 -0
  32. legalmind/study_cases/RINGKASAN_HASIL_PENGUJIAN.md +112 -0
  33. legalmind/study_cases/RINGKASAN_IDE_MONETISASI.md +464 -0
  34. legalmind/study_cases/RINGKASAN_LENGKAP.md +419 -0
  35. legalmind/study_cases/RINGKASAN_VISUAL_HASIL_ANALISIS.md +331 -0
  36. legalmind/study_cases/Real_Studycase_Law_International_Edition.md +434 -0
  37. legalmind/study_cases/analyze_5_additional_cases.py +905 -0
  38. legalmind/study_cases/analyze_5_additional_cases_part2.py +461 -0
  39. legalmind/study_cases/analyze_challenging_cases.py +963 -0
  40. legalmind/study_cases/analyze_international_tech_cases.py +1706 -0
  41. legalmind/study_cases/analyze_real_problematic_contracts.py +603 -0
  42. legalmind/study_cases/kuhp_baru_2026/analisis_perbandingan/ANALISIS_PERUBAHAN_SISTEM_PEMIDANAAN.md +16 -0
  43. legalmind/study_cases/kuhp_baru_2026/analisis_perbandingan/PERBANDINGAN_KOMPREHENSIF_KUHP_LAMA_BARU.md +27 -0
  44. legalmind/study_cases/kuhp_baru_2026/analisis_perbandingan/STUDI_KASUS_TRANSISI_KUHP_BARU.md +16 -0
  45. legalmind/study_cases/kuhp_baru_2026/implementasi_praktis/ANALISIS_DAMPAK_BISNIS_KUHP_BARU.md +16 -0
  46. legalmind/study_cases/kuhp_baru_2026/implementasi_praktis/CHECKLIST_KOMPLIANCE_KUHP_BARU.md +16 -0
  47. legalmind/study_cases/kuhp_baru_2026/implementasi_praktis/PANDUAN_TRANSISI_KUHP_BARU_2026.md +28 -0
  48. legalmind/study_cases/kuhp_baru_2026/studi_kasus/KASUS_KEKERASAN_SEKSUAL_BARU.md +16 -0
  49. legalmind/study_cases/kuhp_baru_2026/studi_kasus/KASUS_KORUPSI_DAN_GRATIFIKASI.md +16 -0
  50. legalmind/study_cases/kuhp_baru_2026/studi_kasus/KASUS_TINDAK_PIDANA_SIBER_KUHP_BARU.md +16 -0
  51. legalmind/study_cases/kuhp_baru_2026/topik_khusus/HUKUM_YANG_HIDUP_DI_MASYARAKAT.md +16 -0
  52. legalmind/study_cases/kuhp_baru_2026/topik_khusus/PIDANA_TAMBAHAN_DAN_TINDAKAN.md +16 -0
  53. legalmind/study_cases/kuhp_baru_2026/topik_khusus/TINDAK_PIDANA_SIBER_KUHP_BARU.md +16 -0
  54. legalmind_ai-1.1.0.dist-info/METADATA +93 -0
  55. legalmind_ai-1.1.0.dist-info/RECORD +58 -0
  56. legalmind_ai-1.1.0.dist-info/WHEEL +5 -0
  57. legalmind_ai-1.1.0.dist-info/entry_points.txt +4 -0
  58. legalmind_ai-1.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,308 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Enhanced MayaLaw Data Loader
4
+ Supports multiple markdown formats
5
+ """
6
+
7
+ import re
8
+ from pathlib import Path
9
+ from typing import List, Dict, Optional
10
+ import logging
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+ class MayaLawDataLoader:
15
+ """Enhanced data loader with multiple parsers"""
16
+
17
+ def __init__(self, mayalaw_path="/root/dragon/global/mayalaw"):
18
+ self.mayalaw_path = Path(mayalaw_path)
19
+ self.cases = []
20
+ self.stats = {
21
+ 'files_loaded': 0,
22
+ 'cases_loaded': 0,
23
+ 'errors': []
24
+ }
25
+ self.load_all_cases()
26
+
27
+ def load_all_cases(self):
28
+ """Load all study cases from MayaLaw"""
29
+ files_to_load = [
30
+ ("JAWABAN_LENGKAP_20_PERTANYAAN_HUKUM.md", "pertanyaan_format"),
31
+ ("LAW_LIBRARY_BATCH_IV_ANSWERS.md", "qa_format"),
32
+ ("LAW_LIBRARY_BATCH_V_FINAL.md", "qa_format"),
33
+ ("LAW_LIBRARY_BATCH_IV_PART2.md", "qa_format"),
34
+ ("ADVANCED_LEGAL_QUESTIONS_20_PART2.md", "pertanyaan_simple"),
35
+ ]
36
+
37
+ for filename, parser_type in files_to_load:
38
+ filepath = self.mayalaw_path / filename
39
+ if filepath.exists():
40
+ try:
41
+ cases = self.parse_file(filepath, parser_type)
42
+ self.cases.extend(cases)
43
+ self.stats['files_loaded'] += 1
44
+ self.stats['cases_loaded'] += len(cases)
45
+ logger.info(f"✅ Loaded {len(cases)} cases from {filename}")
46
+ print(f"✅ Loaded {len(cases)} cases from {filename}")
47
+ except Exception as e:
48
+ error_msg = f"Error loading {filename}: {e}"
49
+ self.stats['errors'].append(error_msg)
50
+ logger.error(error_msg)
51
+ print(f"⚠️ {error_msg}")
52
+ else:
53
+ logger.warning(f"File not found: {filename}")
54
+
55
+ print(f"\n📚 Total: {len(self.cases)} study cases loaded from {self.stats['files_loaded']} files\n")
56
+ logger.info(f"Total cases loaded: {len(self.cases)}")
57
+
58
+ def parse_file(self, filepath: Path, parser_type: str) -> List[Dict]:
59
+ """Parse file based on type"""
60
+ with open(filepath, 'r', encoding='utf-8') as f:
61
+ content = f.read()
62
+
63
+ if parser_type == "pertanyaan_format":
64
+ return self.parse_pertanyaan_format(content, filepath.name)
65
+ elif parser_type == "qa_format":
66
+ return self.parse_qa_format(content, filepath.name)
67
+ elif parser_type == "pertanyaan_simple":
68
+ return self.parse_pertanyaan_simple(content, filepath.name)
69
+ else:
70
+ logger.warning(f"Unknown parser type: {parser_type}")
71
+ return []
72
+
73
+ def parse_pertanyaan_format(self, content: str, filename: str) -> List[Dict]:
74
+ """Parse '## 📋 PERTANYAAN #N' format"""
75
+ cases = []
76
+ pattern = r'##\s+📋\s+PERTANYAAN\s+#(\d+)'
77
+ parts = re.split(pattern, content)
78
+
79
+ for i in range(1, len(parts), 2):
80
+ if i+1 < len(parts):
81
+ case_num = parts[i]
82
+ case_content = parts[i+1]
83
+ case = self.parse_case_content(case_num, case_content, filename)
84
+ if case:
85
+ cases.append(case)
86
+
87
+ return cases
88
+
89
+ def parse_qa_format(self, content: str, filename: str) -> List[Dict]:
90
+ """Parse Q&A format like '**Q1:**'"""
91
+ cases = []
92
+
93
+ # Try multiple Q&A patterns
94
+ patterns = [
95
+ r'\*\*Q(\d+):\s*(.*?)\*\*',
96
+ r'##\s+\*\*Q(\d+):',
97
+ r'Q(\d+):\s+(.+?)(?=Q\d+:|$)',
98
+ ]
99
+
100
+ for pattern in patterns:
101
+ matches = re.finditer(pattern, content, re.DOTALL)
102
+ for match in matches:
103
+ case_num = match.group(1)
104
+ # Get content after this Q until next Q or end
105
+ start_pos = match.end()
106
+ next_q = re.search(r'\*\*Q\d+:', content[start_pos:])
107
+ end_pos = start_pos + next_q.start() if next_q else len(content)
108
+ case_content = content[start_pos:end_pos]
109
+
110
+ case = self.parse_qa_content(case_num, case_content, filename)
111
+ if case:
112
+ cases.append(case)
113
+
114
+ if cases: # If we found cases with this pattern, stop trying others
115
+ break
116
+
117
+ return cases
118
+
119
+ def parse_pertanyaan_simple(self, content: str, filename: str) -> List[Dict]:
120
+ """Parse simple '## PERTANYAAN N' format"""
121
+ cases = []
122
+ pattern = r'##\s+PERTANYAAN\s+(\d+)'
123
+ parts = re.split(pattern, content)
124
+
125
+ for i in range(1, len(parts), 2):
126
+ if i+1 < len(parts):
127
+ case_num = parts[i]
128
+ case_content = parts[i+1]
129
+ case = self.parse_case_content(case_num, case_content, filename)
130
+ if case:
131
+ cases.append(case)
132
+
133
+ return cases
134
+
135
+ def parse_case_content(self, num: str, content: str, filename: str) -> Optional[Dict]:
136
+ """Parse detailed case content with sections"""
137
+
138
+ # Extract KASUS
139
+ kasus_match = re.search(r'\*\*KASUS:\*\*\s*(.*?)(?=\*\*PERTANYAAN:|\*\*JAWABAN:|###|\Z)', content, re.DOTALL)
140
+ kasus = kasus_match.group(1).strip() if kasus_match else ""
141
+
142
+ # Extract PERTANYAAN
143
+ pertanyaan_match = re.search(r'\*\*PERTANYAAN:\*\*\s*(.*?)(?=---|###|\*\*JAWABAN:|\Z)', content, re.DOTALL)
144
+ pertanyaan = pertanyaan_match.group(1).strip() if pertanyaan_match else ""
145
+
146
+ # Extract JAWABAN
147
+ jawaban_match = re.search(r'###\s+⚖️\s+JAWABAN\s*(.*?)(?=###|\Z)', content, re.DOTALL)
148
+ if not jawaban_match:
149
+ jawaban_match = re.search(r'\*\*JAWABAN:\*\*\s*(.*?)(?=###|\Z)', content, re.DOTALL)
150
+ jawaban = jawaban_match.group(1).strip() if jawaban_match else ""
151
+
152
+ # Extract DASAR HUKUM
153
+ dasar_hukum_match = re.search(r'###\s+📖\s+DASAR HUKUM\s*(.*?)(?=###|\Z)', content, re.DOTALL)
154
+ dasar_hukum = dasar_hukum_match.group(1).strip() if dasar_hukum_match else ""
155
+
156
+ # Extract ANALISIS
157
+ analisis_match = re.search(r'###\s+🔍\s+ANALISIS\s*(.*?)(?=##|\Z)', content, re.DOTALL)
158
+ analisis = analisis_match.group(1).strip() if analisis_match else ""
159
+
160
+ # Extract references
161
+ pasal = self.extract_pasal(content)
162
+ uu = self.extract_uu(content)
163
+
164
+ # Build case
165
+ case = {
166
+ 'id': f'case_{num}',
167
+ 'number': num,
168
+ 'file': filename,
169
+ 'kasus': kasus[:500] if kasus else "",
170
+ 'pertanyaan': pertanyaan[:500] if pertanyaan else "",
171
+ 'jawaban': jawaban[:800] if jawaban else "",
172
+ 'dasar_hukum': dasar_hukum[:500] if dasar_hukum else "",
173
+ 'analisis': analisis[:1000] if analisis else "",
174
+ 'pasal': pasal,
175
+ 'uu': uu,
176
+ 'full_content': content[:2000]
177
+ }
178
+
179
+ # Only return if we have meaningful content
180
+ if kasus or pertanyaan or jawaban:
181
+ return case
182
+ return None
183
+
184
+ def parse_qa_content(self, num: str, content: str, filename: str) -> Optional[Dict]:
185
+ """Parse Q&A style content"""
186
+
187
+ # For Q&A format, the question is usually at the start
188
+ lines = content.strip().split('\n')
189
+ question = lines[0].strip() if lines else ""
190
+
191
+ # Answer is usually after "JAWABAN:" or "A:"
192
+ answer_match = re.search(r'(?:JAWABAN:|A:)\s*(.*?)(?=\*\*Q\d+:|\Z)', content, re.DOTALL)
193
+ answer = answer_match.group(1).strip() if answer_match else content[:500]
194
+
195
+ # Extract references
196
+ pasal = self.extract_pasal(content)
197
+ uu = self.extract_uu(content)
198
+
199
+ case = {
200
+ 'id': f'case_{num}',
201
+ 'number': num,
202
+ 'file': filename,
203
+ 'kasus': "",
204
+ 'pertanyaan': question[:500],
205
+ 'jawaban': answer[:800],
206
+ 'dasar_hukum': "",
207
+ 'analisis': "",
208
+ 'pasal': pasal,
209
+ 'uu': uu,
210
+ 'full_content': content[:2000]
211
+ }
212
+
213
+ if question or answer:
214
+ return case
215
+ return None
216
+
217
+ def extract_pasal(self, content: str) -> List[str]:
218
+ """Extract Pasal references"""
219
+ pasal_patterns = [
220
+ r'Pasal\s+(\d+(?:\s+ayat\s+\(\d+\))?)\s+([A-Z]+)',
221
+ r'Pasal\s+(\d+)',
222
+ ]
223
+
224
+ pasal_list = []
225
+ for pattern in pasal_patterns:
226
+ matches = re.findall(pattern, content)
227
+ for match in matches:
228
+ if isinstance(match, tuple):
229
+ if len(match) == 2:
230
+ pasal_list.append(f"Pasal {match[0]} {match[1]}")
231
+ else:
232
+ pasal_list.append(f"Pasal {match[0]}")
233
+ else:
234
+ pasal_list.append(f"Pasal {match}")
235
+
236
+ # Remove duplicates
237
+ seen = set()
238
+ unique = []
239
+ for p in pasal_list:
240
+ if p not in seen:
241
+ seen.add(p)
242
+ unique.append(p)
243
+
244
+ return unique[:10]
245
+
246
+ def extract_uu(self, content: str) -> List[str]:
247
+ """Extract UU references"""
248
+ uu_patterns = [
249
+ r'UU\s+No\.?\s*(\d+)\s+Tahun\s+(\d+)',
250
+ r'UU\s+No\.?\s*(\d+)/(\d+)',
251
+ ]
252
+
253
+ uu_list = []
254
+ for pattern in uu_patterns:
255
+ matches = re.findall(pattern, content)
256
+ for match in matches:
257
+ uu_list.append(f"UU No. {match[0]} Tahun {match[1]}")
258
+
259
+ return list(set(uu_list))[:5]
260
+
261
+ def search(self, query: str, top_k: int = 3) -> List[Dict]:
262
+ """Search for relevant cases"""
263
+ query_lower = query.lower()
264
+
265
+ scored_cases = []
266
+ for case in self.cases:
267
+ score = self.calculate_relevance(query_lower, case)
268
+ if score > 0:
269
+ scored_cases.append((score, case))
270
+
271
+ scored_cases.sort(reverse=True, key=lambda x: x[0])
272
+ return [case for score, case in scored_cases[:top_k]]
273
+
274
+ def calculate_relevance(self, query: str, case: Dict) -> float:
275
+ """Calculate relevance score"""
276
+ score = 0.0
277
+
278
+ # High weight for pertanyaan
279
+ if query in case.get('pertanyaan', '').lower():
280
+ score += 20
281
+
282
+ # Medium weight for kasus
283
+ if query in case.get('kasus', '').lower():
284
+ score += 10
285
+
286
+ # Lower weight for jawaban/analisis
287
+ if query in case.get('jawaban', '').lower():
288
+ score += 5
289
+ if query in case.get('analisis', '').lower():
290
+ score += 3
291
+
292
+ # Keyword matching
293
+ keywords = [k for k in query.split() if len(k) > 3]
294
+ for keyword in keywords:
295
+ full_content = case.get('full_content', '').lower()
296
+ count = full_content.count(keyword)
297
+ score += count * 2
298
+
299
+ return score
300
+
301
+ def get_stats(self) -> Dict:
302
+ """Get loading statistics"""
303
+ return {
304
+ 'total_cases': len(self.cases),
305
+ 'files_loaded': self.stats['files_loaded'],
306
+ 'cases_by_file': {},
307
+ 'errors': self.stats['errors']
308
+ }
@@ -0,0 +1,151 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Enhanced VersaLaw2 System with Maya Wisdom Integration
4
+ Combines MayaLaw cases + Maya Wisdom + AI
5
+ """
6
+
7
+ import sys
8
+ from pathlib import Path
9
+ import logging
10
+
11
+ # Add maya-legal-system to path
12
+ maya_system_path = Path("/root/dragon/global/mayalaw/maya-legal-system")
13
+ if maya_system_path.exists():
14
+ sys.path.insert(0, str(maya_system_path))
15
+
16
+ from .system import VersaLaw2System
17
+ from .config import Config
18
+
19
+ logger = logging.getLogger(__name__)
20
+
21
+ class EnhancedVersaLaw2System(VersaLaw2System):
22
+ """
23
+ Enhanced system with Maya Wisdom integration
24
+
25
+ Features:
26
+ - MayaLaw cases (126 cases)
27
+ - Maya Wisdom knowledge base
28
+ - AI processing
29
+ - Combined context
30
+ """
31
+
32
+ def __init__(self, config=None):
33
+ """Initialize enhanced system"""
34
+ super().__init__(config)
35
+
36
+ # Try to load Maya Wisdom
37
+ self.wisdom = None
38
+ self.wisdom_available = False
39
+
40
+ try:
41
+ from core.maya_wisdom_processor import MayaWisdomProcessor
42
+ self.wisdom = MayaWisdomProcessor()
43
+ self.wisdom_available = True
44
+ print("✅ Maya Wisdom Processor loaded")
45
+ logger.info("Maya Wisdom Processor loaded successfully")
46
+ except ImportError as e:
47
+ print("⚠️ Maya Wisdom not available (optional)")
48
+ logger.warning(f"Maya Wisdom not loaded: {e}")
49
+ except Exception as e:
50
+ print(f"⚠️ Error loading Maya Wisdom: {e}")
51
+ logger.error(f"Maya Wisdom error: {e}")
52
+
53
+ def ask(self, question, use_cache=True, include_wisdom=True):
54
+ """
55
+ Enhanced ask with Maya Wisdom
56
+
57
+ Args:
58
+ question: Legal question
59
+ use_cache: Use caching
60
+ include_wisdom: Include Maya Wisdom in context
61
+
62
+ Returns:
63
+ Enhanced result with wisdom
64
+ """
65
+
66
+ # Get wisdom if available and requested
67
+ wisdom_response = None
68
+ if include_wisdom and self.wisdom_available:
69
+ try:
70
+ wisdom_response = self.wisdom.process_legal_question(question)
71
+ logger.info("Maya Wisdom response generated")
72
+ except Exception as e:
73
+ logger.warning(f"Maya Wisdom processing error: {e}")
74
+
75
+ # Get standard result
76
+ result = super().ask(question, use_cache)
77
+
78
+ # Enhance result with wisdom
79
+ if wisdom_response:
80
+ result['wisdom'] = wisdom_response
81
+ result['enhanced'] = True
82
+
83
+ # Add wisdom to metadata
84
+ result['metadata']['wisdom_type'] = wisdom_response.get('type', 'unknown')
85
+ result['metadata']['wisdom_confidence'] = wisdom_response.get('confidence', 0.0)
86
+ else:
87
+ result['enhanced'] = False
88
+
89
+ return result
90
+
91
+ def print_answer(self, result):
92
+ """Enhanced print with wisdom"""
93
+
94
+ # Print wisdom if available
95
+ if result.get('enhanced') and result.get('wisdom'):
96
+ wisdom = result['wisdom']
97
+
98
+ print(f"{'='*60}")
99
+ print("🧠 MAYA WISDOM")
100
+ print(f"{'='*60}\n")
101
+
102
+ print(f"Type: {wisdom.get('type', 'N/A')}")
103
+ print(f"Confidence: {wisdom.get('confidence', 0):.0%}\n")
104
+
105
+ if 'answer' in wisdom:
106
+ print(f"Basic Knowledge:")
107
+ print(f"{wisdom['answer']}\n")
108
+
109
+ if 'details' in wisdom:
110
+ print(f"Details:")
111
+ for key, value in wisdom['details'].items():
112
+ print(f" • {key}: {value}")
113
+ print()
114
+
115
+ # Print standard answer
116
+ super().print_answer(result)
117
+
118
+ def get_stats(self):
119
+ """Enhanced stats with wisdom info"""
120
+ stats = super().get_stats()
121
+
122
+ stats['wisdom'] = {
123
+ 'available': self.wisdom_available,
124
+ 'loaded': self.wisdom is not None
125
+ }
126
+
127
+ return stats
128
+
129
+ def create_enhanced_system(ai_provider='mock', api_key=None):
130
+ """
131
+ Helper function to create enhanced system
132
+
133
+ Args:
134
+ ai_provider: 'openai', 'deepseek', 'qodo', or 'mock'
135
+ api_key: API key for the provider
136
+
137
+ Returns:
138
+ EnhancedVersaLaw2System instance
139
+ """
140
+ config = Config()
141
+ config['ai_provider'] = ai_provider
142
+
143
+ if api_key:
144
+ if ai_provider == 'openai':
145
+ config['openai_api_key'] = api_key
146
+ elif ai_provider == 'deepseek':
147
+ config['deepseek_api_key'] = api_key
148
+ elif ai_provider == 'qodo':
149
+ config['qodo_api_key'] = api_key
150
+
151
+ return EnhancedVersaLaw2System(config)