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,456 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ VersaLaw2 Integrated System
4
+ Complete production-ready implementation
5
+ """
6
+
7
+ import logging
8
+ from typing import Dict, List, Optional
9
+ from pathlib import Path
10
+ import json
11
+ import hashlib
12
+ from datetime import datetime
13
+
14
+ from .data_loader import MayaLawDataLoader
15
+ from .config import Config
16
+
17
+ # Setup logging
18
+ logging.basicConfig(
19
+ level=logging.INFO,
20
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
21
+ )
22
+ logger = logging.getLogger(__name__)
23
+
24
+ class VersaLaw2Classifier:
25
+ """Enhanced classifier"""
26
+
27
+ def __init__(self):
28
+ self.categories = {
29
+ 'hukum_pidana': {
30
+ 'keywords': ['pidana', 'pencurian', 'pembunuhan', 'korupsi', 'narkotika',
31
+ 'hakim', 'terdakwa', 'minimum', 'maksimum', 'penjara', 'hukuman'],
32
+ 'weight': 1.0
33
+ },
34
+ 'hukum_perdata': {
35
+ 'keywords': ['perdata', 'gugatan', 'wanprestasi', 'kontrak', 'perjanjian',
36
+ 'ganti rugi', 'sengketa'],
37
+ 'weight': 1.0
38
+ },
39
+ 'hukum_keluarga': {
40
+ 'keywords': ['perceraian', 'cerai', 'nafkah', 'waris', 'anak', 'nikah',
41
+ 'perkawinan'],
42
+ 'weight': 1.0
43
+ },
44
+ 'hukum_bisnis': {
45
+ 'keywords': ['perusahaan', 'pt', 'cv', 'saham', 'ipo', 'merger', 'akuisisi'],
46
+ 'weight': 1.0
47
+ },
48
+ 'hukum_properti': {
49
+ 'keywords': ['tanah', 'sertifikat', 'properti', 'bangunan', 'hak tanggungan'],
50
+ 'weight': 1.0
51
+ },
52
+ 'hukum_tata_negara': {
53
+ 'keywords': ['konstitusi', 'uud', 'mahkamah konstitusi', 'pemilu', 'dpr'],
54
+ 'weight': 1.0
55
+ },
56
+ }
57
+
58
+ def classify(self, question: str) -> Dict:
59
+ """Classify legal question"""
60
+ question_lower = question.lower()
61
+
62
+ scores = {}
63
+ for category, data in self.categories.items():
64
+ score = sum(1 for kw in data['keywords'] if kw in question_lower)
65
+ if score > 0:
66
+ scores[category] = score * data['weight']
67
+
68
+ if scores:
69
+ best_category = max(scores, key=scores.get)
70
+ total_words = len(question.split())
71
+ confidence = min(scores[best_category] / max(total_words, 1), 0.95)
72
+
73
+ return {
74
+ 'category': best_category,
75
+ 'confidence': confidence,
76
+ 'all_scores': scores
77
+ }
78
+
79
+ return {
80
+ 'category': 'umum',
81
+ 'confidence': 0.3,
82
+ 'all_scores': {}
83
+ }
84
+
85
+ class AIProcessor:
86
+ """AI processor with support for multiple providers"""
87
+
88
+ def __init__(self, provider: str = "mock", api_key: Optional[str] = None, config: Optional[Config] = None):
89
+ self.provider = provider
90
+ self.api_key = api_key
91
+ self.config = config or Config()
92
+
93
+ if provider == "openai" and api_key:
94
+ try:
95
+ from openai import OpenAI
96
+ self.client = OpenAI(api_key=api_key)
97
+ self.model = "gpt-4-turbo-preview"
98
+ logger.info("OpenAI client initialized")
99
+ except ImportError:
100
+ logger.warning("OpenAI package not installed, falling back to mock")
101
+ self.provider = "mock"
102
+
103
+ elif provider == "deepseek" and api_key:
104
+ try:
105
+ from openai import OpenAI
106
+ self.client = OpenAI(
107
+ api_key=api_key,
108
+ base_url="https://api.deepseek.com/v1"
109
+ )
110
+ self.model = "deepseek-chat"
111
+ logger.info("DeepSeek client initialized")
112
+ except ImportError:
113
+ logger.warning("OpenAI package not installed, falling back to mock")
114
+ self.provider = "mock"
115
+
116
+ elif provider == "qodo" and api_key:
117
+ try:
118
+ from openai import OpenAI
119
+ base_url = self.config.get('qodo_base_url', 'https://api.qodo.ai/v1')
120
+ self.client = OpenAI(
121
+ api_key=api_key,
122
+ base_url=base_url
123
+ )
124
+ self.model = "qodo-chat" # Adjust based on Qodo.ai's actual model name
125
+ logger.info(f"Qodo.ai client initialized (250 free calls available!)")
126
+ print("āœ… Qodo.ai initialized - 250 free calls available!")
127
+ except ImportError:
128
+ logger.warning("OpenAI package not installed, falling back to mock")
129
+ self.provider = "mock"
130
+ except Exception as e:
131
+ logger.warning(f"Qodo.ai initialization failed: {e}, falling back to mock")
132
+ self.provider = "mock"
133
+
134
+ else:
135
+ self.provider = "mock"
136
+ logger.info("Using mock AI processor")
137
+
138
+ def generate_answer(self, question: str, context: Dict) -> Dict:
139
+ """Generate answer using AI"""
140
+
141
+ if self.provider == "mock":
142
+ return self._mock_answer(question, context)
143
+ else:
144
+ return self._real_ai_answer(question, context)
145
+
146
+ def _real_ai_answer(self, question: str, context: Dict) -> Dict:
147
+ """Generate answer using real AI"""
148
+ try:
149
+ prompt = self._build_prompt(question, context)
150
+
151
+ response = self.client.chat.completions.create(
152
+ model=self.model,
153
+ messages=[
154
+ {
155
+ "role": "system",
156
+ "content": "Anda adalah ahli hukum Indonesia yang sangat berpengalaman. "
157
+ "Jawab pertanyaan berdasarkan konteks yang diberikan dengan akurat."
158
+ },
159
+ {
160
+ "role": "user",
161
+ "content": prompt
162
+ }
163
+ ],
164
+ temperature=self.config.get('ai_temperature', 0.3),
165
+ max_tokens=self.config.get('ai_max_tokens', 2000)
166
+ )
167
+
168
+ return {
169
+ 'answer': response.choices[0].message.content,
170
+ 'model': self.model,
171
+ 'usage': response.usage._asdict()
172
+ }
173
+
174
+ except Exception as e:
175
+ logger.error(f"AI generation error: {e}")
176
+ return self._mock_answer(question, context)
177
+
178
+ def _build_prompt(self, question: str, context: Dict) -> str:
179
+ """Build prompt for AI"""
180
+ cases = context.get('cases', [])
181
+
182
+ context_text = ""
183
+ for case in cases[:2]: # Use top 2 cases
184
+ context_text += f"""
185
+ KASUS #{case['number']}:
186
+ {case.get('kasus', '')}
187
+
188
+ PERTANYAAN:
189
+ {case.get('pertanyaan', '')}
190
+
191
+ JAWABAN:
192
+ {case.get('jawaban', '')[:400]}
193
+
194
+ DASAR HUKUM:
195
+ {', '.join(case.get('pasal', [])[:3])}
196
+ {', '.join(case.get('uu', [])[:2])}
197
+
198
+ ---
199
+ """
200
+
201
+ prompt = f"""
202
+ Berdasarkan konteks kasus hukum berikut dari database MayaLaw,
203
+ jawab pertanyaan dengan akurat dan detail.
204
+
205
+ KONTEKS DARI MAYALAW:
206
+ {context_text}
207
+
208
+ PERTANYAAN USER:
209
+ {question}
210
+
211
+ Berikan jawaban yang:
212
+ 1. āœ… Akurat berdasarkan hukum Indonesia
213
+ 2. āœ… Merujuk pada Pasal dan UU yang spesifik dari konteks
214
+ 3. āœ… Menjelaskan dengan bahasa yang mudah dipahami
215
+ 4. āœ… Menyertakan analisis hukum yang mendalam
216
+ 5. āœ… Memberikan tingkat keyakinan (confidence level)
217
+
218
+ Format jawaban:
219
+ ## āš–ļø JAWABAN:
220
+ [Jawaban singkat dan jelas]
221
+
222
+ ## šŸ“– DASAR HUKUM:
223
+ [Pasal dan UU yang relevan]
224
+
225
+ ## šŸ” ANALISIS:
226
+ [Penjelasan detail]
227
+
228
+ ## šŸ’Æ TINGKAT KEYAKINAN:
229
+ [Persentase dan alasan]
230
+ """
231
+ return prompt
232
+
233
+ def _mock_answer(self, question: str, context: Dict) -> Dict:
234
+ """Mock answer for testing"""
235
+ cases = context.get('cases', [])
236
+
237
+ if not cases:
238
+ answer = f"""## āš ļø INFORMASI
239
+
240
+ Pertanyaan: "{question}"
241
+
242
+ Saat ini tidak ditemukan kasus yang relevan di database MayaLaw untuk pertanyaan ini.
243
+
244
+ ## šŸ’” SARAN
245
+
246
+ 1. Coba rumuskan pertanyaan dengan kata kunci yang lebih spesifik
247
+ 2. Konsultasikan dengan ahli hukum untuk analisis mendalam
248
+ 3. Database sedang dikembangkan untuk mencakup lebih banyak kasus
249
+ """
250
+ return {
251
+ 'answer': answer,
252
+ 'model': 'mock',
253
+ 'usage': {'total_tokens': 50}
254
+ }
255
+
256
+ case = cases[0]
257
+
258
+ answer = f"""## āš–ļø JAWABAN
259
+
260
+ {case.get('jawaban', 'Berdasarkan analisis hukum...')[:400]}
261
+
262
+ ## šŸ“– DASAR HUKUM
263
+
264
+ """
265
+
266
+ if case.get('pasal'):
267
+ answer += "**Pasal yang Relevan:**\n"
268
+ for pasal in case['pasal'][:5]:
269
+ answer += f"- {pasal}\n"
270
+ answer += "\n"
271
+
272
+ if case.get('uu'):
273
+ answer += "**Undang-Undang:**\n"
274
+ for uu in case['uu'][:3]:
275
+ answer += f"- {uu}\n"
276
+ answer += "\n"
277
+
278
+ if case.get('dasar_hukum'):
279
+ answer += f"{case['dasar_hukum'][:300]}\n\n"
280
+
281
+ answer += f"""## šŸ” ANALISIS
282
+
283
+ {case.get('analisis', '')[:600]}
284
+
285
+ ## šŸ“š REFERENSI
286
+
287
+ Berdasarkan Kasus #{case['number']} dari database MayaLaw ({case['file']})
288
+
289
+ ## šŸ’Æ TINGKAT KEYAKINAN
290
+
291
+ 95% - Jawaban berdasarkan studi kasus yang relevan dan terverifikasi
292
+ """
293
+
294
+ return {
295
+ 'answer': answer,
296
+ 'model': 'mock',
297
+ 'usage': {'total_tokens': len(answer.split())}
298
+ }
299
+
300
+ class CacheManager:
301
+ """Simple cache manager"""
302
+
303
+ def __init__(self, cache_dir: str = "/root/dragon/global/lab/.cache"):
304
+ self.cache_dir = Path(cache_dir)
305
+ self.cache_dir.mkdir(parents=True, exist_ok=True)
306
+ self.enabled = True
307
+
308
+ def get_cache_key(self, question: str) -> str:
309
+ """Generate cache key"""
310
+ return hashlib.md5(question.encode()).hexdigest()
311
+
312
+ def get(self, question: str) -> Optional[Dict]:
313
+ """Get cached result"""
314
+ if not self.enabled:
315
+ return None
316
+
317
+ cache_key = self.get_cache_key(question)
318
+ cache_file = self.cache_dir / f"{cache_key}.json"
319
+
320
+ if cache_file.exists():
321
+ try:
322
+ with open(cache_file, 'r', encoding='utf-8') as f:
323
+ return json.load(f)
324
+ except:
325
+ return None
326
+ return None
327
+
328
+ def set(self, question: str, result: Dict):
329
+ """Cache result"""
330
+ if not self.enabled:
331
+ return
332
+
333
+ cache_key = self.get_cache_key(question)
334
+ cache_file = self.cache_dir / f"{cache_key}.json"
335
+
336
+ try:
337
+ with open(cache_file, 'w', encoding='utf-8') as f:
338
+ json.dump(result, f, ensure_ascii=False, indent=2)
339
+ except Exception as e:
340
+ logger.warning(f"Cache write error: {e}")
341
+
342
+ class VersaLaw2System:
343
+ """Complete VersaLaw2 integrated system"""
344
+
345
+ def __init__(self, config: Optional[Config] = None):
346
+ self.config = config or Config()
347
+
348
+ print("šŸš€ Initializing VersaLaw2 System...")
349
+ print("="*60)
350
+
351
+ # Initialize components
352
+ self.data_loader = MayaLawDataLoader(self.config['mayalaw_path'])
353
+ self.classifier = VersaLaw2Classifier()
354
+ print("āœ… Classifier ready")
355
+
356
+ self.ai_processor = AIProcessor(
357
+ provider=self.config['ai_provider'],
358
+ api_key=self.config.get('ai_api_key') or self.config.get('qodo_api_key') or self.config.get('deepseek_api_key') or self.config.get('openai_api_key'),
359
+ config=self.config
360
+ )
361
+ print(f"āœ… AI processor ready (mode: {self.ai_processor.provider})")
362
+
363
+ self.cache = CacheManager(self.config['cache_dir'])
364
+ print(f"āœ… Cache {'enabled' if self.cache.enabled else 'disabled'}")
365
+
366
+ print("="*60)
367
+ print("šŸŽ‰ System ready!\n")
368
+
369
+ logger.info("VersaLaw2 System initialized successfully")
370
+
371
+ def ask(self, question: str, use_cache: bool = True) -> Dict:
372
+ """Answer legal question"""
373
+
374
+ # Check cache
375
+ if use_cache:
376
+ cached = self.cache.get(question)
377
+ if cached:
378
+ logger.info(f"Cache hit for question: {question[:50]}")
379
+ print("šŸ’¾ Using cached result")
380
+ return cached
381
+
382
+ print(f"\n{'='*60}")
383
+ print(f"šŸ“ PERTANYAAN: {question}")
384
+ print(f"{'='*60}\n")
385
+
386
+ # Step 1: Classify
387
+ print("1ļøāƒ£ Mengklasifikasi...")
388
+ classification = self.classifier.classify(question)
389
+ print(f" āœ… Kategori: {classification['category']}")
390
+ print(f" āœ… Confidence: {classification['confidence']:.0%}\n")
391
+
392
+ # Step 2: Search
393
+ print("2ļøāƒ£ Mencari di MayaLaw...")
394
+ relevant_cases = self.data_loader.search(
395
+ question,
396
+ top_k=self.config['max_search_results']
397
+ )
398
+ print(f" āœ… Ditemukan: {len(relevant_cases)} kasus\n")
399
+
400
+ if relevant_cases:
401
+ for i, case in enumerate(relevant_cases, 1):
402
+ print(f" {i}. Kasus #{case['number']}: {case['pertanyaan'][:60]}...")
403
+ print()
404
+
405
+ # Step 3: Generate answer
406
+ print("3ļøāƒ£ Memproses dengan AI...")
407
+ context = {'cases': relevant_cases}
408
+ ai_response = self.ai_processor.generate_answer(question, context)
409
+ print(f" āœ… Generated\n")
410
+
411
+ # Build result
412
+ result = {
413
+ 'question': question,
414
+ 'classification': classification,
415
+ 'cases_found': len(relevant_cases),
416
+ 'cases': relevant_cases,
417
+ 'answer': ai_response['answer'],
418
+ 'metadata': {
419
+ 'ai_model': ai_response['model'],
420
+ 'tokens': ai_response['usage']['total_tokens'],
421
+ 'confidence': 0.95 if relevant_cases else 0.5,
422
+ 'timestamp': datetime.now().isoformat()
423
+ }
424
+ }
425
+
426
+ # Cache result
427
+ if use_cache:
428
+ self.cache.set(question, result)
429
+
430
+ logger.info(f"Question answered: {question[:50]}")
431
+
432
+ return result
433
+
434
+ def print_answer(self, result: Dict):
435
+ """Pretty print answer"""
436
+ print(f"{'='*60}")
437
+ print("šŸ“Š HASIL ANALISIS")
438
+ print(f"{'='*60}\n")
439
+
440
+ print(f"šŸŽÆ Kategori: {result['classification']['category']}")
441
+ print(f"šŸ“š Kasus: {result['cases_found']}")
442
+ print(f"šŸ’Æ Confidence: {result['metadata']['confidence']:.0%}\n")
443
+
444
+ print(f"{'='*60}")
445
+ print(result['answer'])
446
+ print(f"{'='*60}\n")
447
+
448
+ def get_stats(self) -> Dict:
449
+ """Get system statistics"""
450
+ return {
451
+ 'system': {
452
+ 'ai_provider': self.ai_processor.provider,
453
+ 'cache_enabled': self.cache.enabled,
454
+ },
455
+ 'data': self.data_loader.get_stats()
456
+ }
@@ -0,0 +1,139 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Demo VersaLaw2 with Qodo.ai
4
+ 250 Free Calls Available!
5
+ """
6
+
7
+ import sys
8
+ import os
9
+ from pathlib import Path
10
+
11
+ sys.path.insert(0, str(Path(__file__).parent))
12
+
13
+ from versalaw2_core.enhanced_system import create_enhanced_system
14
+
15
+ def main():
16
+ """Run Qodo.ai demo"""
17
+
18
+ print("\n" + "="*60)
19
+ print("āš–ļø VERSALAW2 WITH QODO.AI")
20
+ print("="*60)
21
+ print("šŸŽ 250 FREE CALLS AVAILABLE!")
22
+ print("="*60)
23
+ print("\nPowered by:")
24
+ print(" • VersaLaw2 Framework (21 analyzers)")
25
+ print(" • MayaLaw Database (126 study cases)")
26
+ print(" • Maya Wisdom Processor (legal knowledge)")
27
+ print(" • Qodo.ai API (250 free calls!)")
28
+ print("="*60 + "\n")
29
+
30
+ # Get API key
31
+ api_key = os.getenv('QODO_API_KEY')
32
+
33
+ if not api_key:
34
+ print("āš ļø QODO_API_KEY not found in environment variables")
35
+ print("\nšŸ“ To use Qodo.ai:")
36
+ print(" 1. Get free API key from: https://qodo.ai")
37
+ print(" 2. Set environment variable:")
38
+ print(" export QODO_API_KEY='your-api-key-here'")
39
+ print(" 3. Run this script again")
40
+ print("\nšŸ’” Or run with mock AI for testing:")
41
+ print(" python demo_versalaw2.py")
42
+ print()
43
+ return
44
+
45
+ # Initialize with Qodo.ai
46
+ print("šŸš€ Initializing with Qodo.ai...")
47
+ try:
48
+ system = create_enhanced_system(
49
+ ai_provider='qodo',
50
+ api_key=api_key
51
+ )
52
+ except Exception as e:
53
+ print(f"āŒ Error initializing Qodo.ai: {e}")
54
+ print("\nšŸ’” Falling back to mock AI...")
55
+ system = create_enhanced_system(
56
+ ai_provider='mock',
57
+ api_key=None
58
+ )
59
+
60
+ # Demo questions
61
+ demo_questions = [
62
+ "Apa syarat sah perjanjian?",
63
+ "Apakah hakim boleh menjatuhkan pidana di bawah minimum?",
64
+ "Bagaimana prosedur mengajukan gugatan perceraian?",
65
+ ]
66
+
67
+ print("\nšŸ“‹ Demo Questions:\n")
68
+ for i, q in enumerate(demo_questions, 1):
69
+ print(f"{i}. {q}")
70
+
71
+ print("\n" + "="*60)
72
+ print("Starting analysis with Qodo.ai...")
73
+ print("="*60 + "\n")
74
+
75
+ for i, question in enumerate(demo_questions, 1):
76
+ print(f"\n{'#'*60}")
77
+ print(f"QODO.AI DEMO {i}/{len(demo_questions)}")
78
+ print(f"{'#'*60}\n")
79
+
80
+ # Ask question
81
+ result = system.ask(question, include_wisdom=True)
82
+
83
+ # Print answer
84
+ system.print_answer(result)
85
+
86
+ # Show API info
87
+ print(f"\nšŸ’” API Info:")
88
+ print(f" Provider: {result['metadata']['ai_model']}")
89
+ print(f" Tokens used: {result['metadata']['tokens']}")
90
+
91
+ if system.ai_processor.provider == 'qodo':
92
+ remaining = 250 - i # Approximate
93
+ print(f" šŸŽ Estimated free calls remaining: ~{remaining}")
94
+
95
+ print()
96
+
97
+ # Show statistics
98
+ print("\n" + "="*60)
99
+ print("šŸ“Š SESSION STATISTICS")
100
+ print("="*60)
101
+
102
+ stats = system.get_stats()
103
+ print(f"\nšŸ¤– AI Provider: {stats['system']['ai_provider']}")
104
+ print(f"šŸ’¾ Cache: {'Enabled' if stats['system']['cache_enabled'] else 'Disabled'}")
105
+ print(f"šŸ“š MayaLaw Cases: {stats['data']['total_cases']}")
106
+ print(f"šŸ“ Files Loaded: {stats['data']['files_loaded']}")
107
+ print(f"🧠 Maya Wisdom: {'Available' if stats['wisdom']['available'] else 'Not Available'}")
108
+
109
+ if system.ai_processor.provider == 'qodo':
110
+ print(f"\nšŸŽ Qodo.ai Free Calls:")
111
+ print(f" Total available: 250")
112
+ print(f" Used in this demo: {len(demo_questions)}")
113
+ print(f" Estimated remaining: ~{250 - len(demo_questions)}")
114
+
115
+ print("\n" + "="*60)
116
+ print("āœ… QODO.AI DEMO COMPLETED!")
117
+ print("="*60)
118
+
119
+ print("\nšŸ’” Benefits of Qodo.ai:")
120
+ print(" āœ… 250 free calls for testing")
121
+ print(" āœ… Real AI responses (not mock)")
122
+ print(" āœ… No credit card required")
123
+ print(" āœ… Perfect for evaluation")
124
+
125
+ print("\nšŸš€ Next Steps:")
126
+ print(" 1. Continue testing with remaining free calls")
127
+ print(" 2. Evaluate quality vs DeepSeek/OpenAI")
128
+ print(" 3. Choose best provider for production")
129
+
130
+ print("\nšŸ“Š Cost Comparison:")
131
+ print(" • Qodo.ai: 250 free calls, then check pricing")
132
+ print(" • DeepSeek: $0.28 per 1,000 calls (CHEAPEST!)")
133
+ print(" • OpenAI: $20 per 1,000 calls")
134
+ print(" • Mock: Free (testing only)")
135
+
136
+ print()
137
+
138
+ if __name__ == "__main__":
139
+ main()
@@ -0,0 +1,85 @@
1
+ """
2
+ Qodo AI Provider for LegalMind
3
+ """
4
+ import os
5
+ import requests
6
+ from typing import Dict, Any, Optional
7
+
8
+ class QodoAIAnalyzer:
9
+ """Qodo AI integration for legal analysis"""
10
+
11
+ def __init__(self, api_key: str):
12
+ self.api_key = api_key
13
+ self.base_url = "https://api.qodo.ai/v1/completions"
14
+ self.headers = {
15
+ "Authorization": f"Bearer {api_key}",
16
+ "Content-Type": "application/json"
17
+ }
18
+
19
+ def analyze(self, question: str, context: Optional[Dict] = None) -> Dict[str, Any]:
20
+ """Analyze legal question using Qodo AI"""
21
+
22
+ # Build prompt with legal context
23
+ prompt = self._build_legal_prompt(question, context)
24
+
25
+ payload = {
26
+ "prompt": prompt,
27
+ "max_tokens": 800,
28
+ "temperature": 0.3
29
+ }
30
+
31
+ try:
32
+ response = requests.post(
33
+ self.base_url,
34
+ headers=self.headers,
35
+ json=payload,
36
+ timeout=30
37
+ )
38
+
39
+ if response.status_code == 200:
40
+ result = response.json()
41
+ return self._parse_response(result, question)
42
+ else:
43
+ return {
44
+ "success": False,
45
+ "error": f"Qodo AI API error: {response.status_code}",
46
+ "provider": "qodo_ai"
47
+ }
48
+
49
+ except Exception as e:
50
+ return {
51
+ "success": False,
52
+ "error": str(e),
53
+ "provider": "qodo_ai"
54
+ }
55
+
56
+ def _build_legal_prompt(self, question: str, context: Optional[Dict] = None) -> str:
57
+ """Build legal analysis prompt"""
58
+ base_prompt = f"""Anda adalah asisten hukum profesional Indonesia. Berikan analisis hukum yang akurat berdasarkan UU yang berlaku.
59
+
60
+ PERTANYAAN: {question}
61
+
62
+ JAWABAN HUKUM:"""
63
+
64
+ if context:
65
+ context_str = "\n".join([f"{k}: {v}" for k, v in context.items()])
66
+ base_prompt = f"KONTEKS:\n{context_str}\n\n{base_prompt}"
67
+
68
+ return base_prompt
69
+
70
+ def _parse_response(self, result: Dict, question: str) -> Dict[str, Any]:
71
+ """Parse Qodo AI response"""
72
+ if 'choices' in result and len(result['choices']) > 0:
73
+ answer = result['choices'][0].get('text', '').strip()
74
+ elif 'text' in result:
75
+ answer = result['text'].strip()
76
+ else:
77
+ answer = "Tidak dapat memproses jawaban."
78
+
79
+ return {
80
+ "success": True,
81
+ "question": question,
82
+ "answer": answer,
83
+ "provider": "qodo_ai",
84
+ "raw_response": result
85
+ }