jarvis-ai-assistant 0.1.108__py3-none-any.whl → 0.1.110__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 jarvis-ai-assistant might be problematic. Click here for more details.

jarvis/utils.py CHANGED
@@ -4,7 +4,7 @@ import time
4
4
  import os
5
5
  from enum import Enum
6
6
  from datetime import datetime
7
- from typing import Any, Dict, Optional
7
+ from typing import Any, Dict, List, Optional
8
8
  import colorama
9
9
  from colorama import Fore, Style as ColoramaStyle
10
10
  import numpy as np
@@ -12,13 +12,14 @@ from prompt_toolkit import PromptSession
12
12
  from prompt_toolkit.styles import Style as PromptStyle
13
13
  from prompt_toolkit.formatted_text import FormattedText
14
14
  from sentence_transformers import SentenceTransformer
15
+ from tqdm import tqdm
15
16
  from transformers import AutoModelForSequenceClassification, AutoTokenizer
16
17
  import torch
17
18
  import yaml
18
19
  import faiss
19
20
  from pygments.lexers import guess_lexer
20
21
  from pygments.util import ClassNotFound
21
-
22
+ import psutil
22
23
  from rich.console import Console
23
24
  from rich.theme import Theme
24
25
  from rich.panel import Panel
@@ -163,7 +164,7 @@ class PrettyOutput:
163
164
  return formatted
164
165
 
165
166
  @staticmethod
166
- def print(text: str, output_type: OutputType, timestamp: bool = True, lang: Optional[str] = None):
167
+ def print(text: str, output_type: OutputType, timestamp: bool = True, lang: Optional[str] = None, traceback: bool = False):
167
168
  """Print formatted output using rich console"""
168
169
  # Get formatted header
169
170
  lang = lang if lang is not None else PrettyOutput._detect_language(text, default_lang='markdown')
@@ -176,7 +177,7 @@ class PrettyOutput:
176
177
  console.print(Panel(content, border_style=border_style, title=header, title_align="left", highlight=True))
177
178
 
178
179
  # Print stack trace for errors
179
- if output_type == OutputType.ERROR:
180
+ if traceback or output_type == OutputType.ERROR:
180
181
  console.print_exception()
181
182
 
182
183
  @staticmethod
@@ -370,6 +371,7 @@ def find_git_root(dir="."):
370
371
  return ret
371
372
 
372
373
  def has_uncommitted_changes():
374
+ os.system("git add .")
373
375
  # Check working directory changes
374
376
  working_changes = os.popen("git diff --exit-code").read().strip() != ""
375
377
  # Check staged changes
@@ -398,6 +400,26 @@ def load_embedding_model():
398
400
 
399
401
  return embedding_model
400
402
 
403
+ def load_tokenizer():
404
+ """Load tokenizer"""
405
+ model_name = "gpt2"
406
+ cache_dir = os.path.expanduser("~/.cache/huggingface/hub")
407
+
408
+ try:
409
+ tokenizer = AutoTokenizer.from_pretrained(
410
+ model_name,
411
+ cache_dir=cache_dir,
412
+ local_files_only=True
413
+ )
414
+ except Exception as e:
415
+ tokenizer = AutoTokenizer.from_pretrained(
416
+ model_name,
417
+ cache_dir=cache_dir,
418
+ local_files_only=False
419
+ )
420
+
421
+ return tokenizer
422
+
401
423
  def load_rerank_model():
402
424
  """Load reranking model"""
403
425
  model_name = "BAAI/bge-reranker-v2-m3"
@@ -441,23 +463,23 @@ def load_rerank_model():
441
463
 
442
464
  def is_long_context(files: list) -> bool:
443
465
  """Check if the file list belongs to a long context (total characters exceed 80% of the maximum context length)"""
444
- max_length = get_max_context_length()
445
- threshold = max_length * 0.8
446
- total_chars = 0
466
+ max_token_count = get_max_token_count()
467
+ threshold = max_token_count * 0.8
468
+ total_tokens = 0
447
469
 
448
470
  for file_path in files:
449
471
  try:
450
472
  with open(file_path, 'r', encoding='utf-8') as f:
451
473
  content = f.read()
452
- total_chars += len(content)
474
+ total_tokens += get_context_token_count(content)
453
475
 
454
- if total_chars > threshold:
476
+ if total_tokens > threshold:
455
477
  return True
456
478
  except Exception as e:
457
479
  PrettyOutput.print(f"Failed to read file {file_path}: {e}", OutputType.WARNING)
458
480
  continue
459
481
 
460
- return total_chars > threshold
482
+ return total_tokens > threshold
461
483
 
462
484
 
463
485
 
@@ -586,8 +608,74 @@ def get_file_line_count(filename: str) -> int:
586
608
  except Exception as e:
587
609
  return 0
588
610
 
589
- def get_max_context_length():
590
- return int(os.getenv('JARVIS_MAX_CONTEXT_LENGTH', '131072')) # 默认128k
611
+
612
+ def init_gpu_config() -> Dict:
613
+ """Initialize GPU configuration based on available hardware
614
+
615
+ Returns:
616
+ Dict: GPU configuration including memory sizes and availability
617
+ """
618
+ config = {
619
+ "has_gpu": False,
620
+ "shared_memory": 0,
621
+ "device_memory": 0,
622
+ "memory_fraction": 0.8 # 默认使用80%的可用内存
623
+ }
624
+
625
+ try:
626
+ import torch
627
+ if torch.cuda.is_available():
628
+ # 获取GPU信息
629
+ gpu_mem = torch.cuda.get_device_properties(0).total_memory
630
+ config["has_gpu"] = True
631
+ config["device_memory"] = gpu_mem
632
+
633
+ # 估算共享内存 (通常是系统内存的一部分)
634
+
635
+ system_memory = psutil.virtual_memory().total
636
+ config["shared_memory"] = min(system_memory * 0.5, gpu_mem * 2) # 取系统内存的50%或GPU内存的2倍中的较小值
637
+
638
+ # 设置CUDA内存分配
639
+ torch.cuda.set_per_process_memory_fraction(config["memory_fraction"])
640
+ torch.cuda.empty_cache()
641
+
642
+ PrettyOutput.print(
643
+ f"GPU initialized: {torch.cuda.get_device_name(0)}\n"
644
+ f"Device Memory: {gpu_mem / 1024**3:.1f}GB\n"
645
+ f"Shared Memory: {config['shared_memory'] / 1024**3:.1f}GB",
646
+ output_type=OutputType.SUCCESS
647
+ )
648
+ else:
649
+ PrettyOutput.print("No GPU available, using CPU mode", output_type=OutputType.WARNING)
650
+ except Exception as e:
651
+ PrettyOutput.print(f"GPU initialization failed: {str(e)}", output_type=OutputType.WARNING)
652
+
653
+ return config
654
+
655
+
656
+ def get_embedding(embedding_model: Any, text: str) -> np.ndarray:
657
+ """Get the vector representation of the text"""
658
+ embedding = embedding_model.encode(text,
659
+ normalize_embeddings=True,
660
+ show_progress_bar=False)
661
+ return np.array(embedding, dtype=np.float32)
662
+
663
+ def get_embedding_batch(embedding_model: Any, texts: List[str]) -> np.ndarray:
664
+ """Get embeddings for a batch of texts efficiently"""
665
+ try:
666
+ all_vectors = []
667
+ for text in texts:
668
+ vectors = get_embedding_with_chunks(embedding_model, text)
669
+ all_vectors.extend(vectors)
670
+ return np.vstack(all_vectors)
671
+ except Exception as e:
672
+ PrettyOutput.print(f"Batch embedding failed: {str(e)}", OutputType.ERROR)
673
+ return np.zeros((0, embedding_model.get_sentence_embedding_dimension()), dtype=np.float32)
674
+
675
+
676
+
677
+ def get_max_token_count():
678
+ return int(os.getenv('JARVIS_MAX_TOKEN_COUNT', '131072')) # 默认128k
591
679
 
592
680
  def get_thread_count():
593
681
  return int(os.getenv('JARVIS_THREAD_COUNT', '1'))
@@ -614,10 +702,7 @@ def get_min_paragraph_length() -> int:
614
702
  return int(os.getenv('JARVIS_MIN_PARAGRAPH_LENGTH', '50'))
615
703
 
616
704
  def get_max_paragraph_length() -> int:
617
- return int(os.getenv('JARVIS_MAX_PARAGRAPH_LENGTH', '1000'))
618
-
619
- def get_context_window() -> int:
620
- return int(os.getenv('JARVIS_CONTEXT_WINDOW', '5'))
705
+ return int(os.getenv('JARVIS_MAX_PARAGRAPH_LENGTH', '12800'))
621
706
 
622
707
  def get_shell_name() -> str:
623
708
  return os.getenv('SHELL', 'bash')
@@ -645,3 +730,57 @@ def get_cheap_platform_name() -> str:
645
730
 
646
731
  def get_cheap_model_name() -> str:
647
732
  return os.getenv('JARVIS_CHEAP_MODEL', os.getenv('JARVIS_MODEL', 'kimi'))
733
+
734
+ def split_text_into_chunks(text: str, max_length: int = 512) -> List[str]:
735
+ """Split text into chunks with overlapping windows"""
736
+ chunks = []
737
+ start = 0
738
+ while start < len(text):
739
+ end = start + max_length
740
+ # Find the nearest sentence boundary
741
+ if end < len(text):
742
+ while end > start and text[end] not in {'.', '!', '?', '\n'}:
743
+ end -= 1
744
+ if end == start: # No punctuation found, hard cut
745
+ end = start + max_length
746
+ chunk = text[start:end]
747
+ chunks.append(chunk)
748
+ # Overlap 20% of the window
749
+ start = end - int(max_length * 0.2)
750
+ return chunks
751
+
752
+ def get_embedding_with_chunks(embedding_model: Any, text: str) -> List[np.ndarray]:
753
+ """Get embeddings for text chunks"""
754
+ chunks = split_text_into_chunks(text, 512)
755
+ if not chunks:
756
+ return []
757
+
758
+ vectors = []
759
+ for chunk in chunks:
760
+ vector = get_embedding(embedding_model, chunk)
761
+ vectors.append(vector)
762
+ return vectors
763
+
764
+
765
+ def get_context_token_count(text: str) -> int:
766
+ """Get the token count of the text using the tokenizer
767
+
768
+ Args:
769
+ text: The input text to count tokens for
770
+
771
+ Returns:
772
+ int: The number of tokens in the text
773
+ """
774
+ try:
775
+ # Use a fast tokenizer that's good at general text
776
+ tokenizer = load_tokenizer()
777
+ chunks = split_text_into_chunks(text, 512)
778
+ return sum([len(tokenizer.encode(chunk)) for chunk in chunks])
779
+
780
+ except Exception as e:
781
+ PrettyOutput.print(f"Error counting tokens: {str(e)}", OutputType.WARNING)
782
+ # Fallback to rough character-based estimate
783
+ return len(text) // 4 # Rough estimate of 4 chars per token
784
+
785
+
786
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: jarvis-ai-assistant
3
- Version: 0.1.108
3
+ Version: 0.1.110
4
4
  Summary: Jarvis: An AI assistant that uses tools to interact with the system
5
5
  Home-page: https://github.com/skyfireitdiy/Jarvis
6
6
  Author: skyfire
@@ -58,8 +58,9 @@ Requires-Dist: yaspin>=2.5.0
58
58
  Requires-Dist: rich>=13.3.1
59
59
  Requires-Dist: pygments>=2.15.0
60
60
  Requires-Dist: fuzzywuzzy>=0.18.0
61
- Requires-Dist: python-Levenshtein>=0.26.1
62
- Requires-Dist: jedi>=0.19.0
61
+ Requires-Dist: python-Levenshtein>=0.25.0
62
+ Requires-Dist: jedi>=0.17.2
63
+ Requires-Dist: psutil>=7.0.0
63
64
  Provides-Extra: dev
64
65
  Requires-Dist: pytest; extra == "dev"
65
66
  Requires-Dist: black; extra == "dev"
@@ -161,6 +162,14 @@ Jarvis supports configuration through environment variables that can be set in t
161
162
  | OYI_API_KEY | API key for OYI platform | - | Required for OYI |
162
163
  | OLLAMA_API_BASE | Base URL for Ollama API | http://localhost:11434 | No |
163
164
 
165
+ ## Minimal Configuration (Example with OpenAI-compatible Interface)
166
+
167
+ ```bash
168
+ JARVIS_PLATFORM=openai
169
+ JARVIS_MODEL=deepseek-chat
170
+ OPENAI_API_KEY=your_openai_api_key
171
+ OPENAI_API_BASE=https://api.deepseek.com/v1
172
+ ```
164
173
 
165
174
  ## 🎯 Usage
166
175
 
@@ -1,13 +1,13 @@
1
- jarvis/__init__.py,sha256=hCWwxdx-HHSIwE8vf6Yfn-___pFPgINrCmQcUL8j_XI,51
2
- jarvis/agent.py,sha256=7FDrJc2_JlY9u7TRfeHKZRQ0PrY04r-0w4H64eGcbUM,22626
3
- jarvis/utils.py,sha256=0w1rYsSovS7vgbHNdfdzpo3zSb3y-KWM7RvYMqBhDnM,22086
1
+ jarvis/__init__.py,sha256=0rw1RD8VrgfjPxXtqbnGEx3Aj9K4mgrYWuVSzACO3Ic,51
2
+ jarvis/agent.py,sha256=eV2Bgm5Q6gnQb2QeEo9bHCDaLY0v3RSV8Ylm_gS2_Yc,22678
3
+ jarvis/utils.py,sha256=7v9hs9Tlyi9XMLYkPUzbzzMXGuAlJAx5999O2d7kP9A,26945
4
4
  jarvis/jarvis_code_agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
- jarvis/jarvis_code_agent/code_agent.py,sha256=DDKqM4m235Ryd8aMHbHKeC0ULdNLF6JPW__FKbI-Gk0,10748
6
- jarvis/jarvis_code_agent/file_select.py,sha256=KNxalhepCM2e-V__ca8ErmbXSXHP_1xmd0UEVWUXic8,8083
7
- jarvis/jarvis_code_agent/patch.py,sha256=bbNB8k8mebjPVsNdI8aT3oOyjLyAhUQbKmX54tyziDk,4034
8
- jarvis/jarvis_code_agent/relevant_files.py,sha256=PxSKQyHfCe6878bDqP6XyQd_jwcvNK4a9YKTfpLImRI,6160
5
+ jarvis/jarvis_code_agent/code_agent.py,sha256=nigsmCK6D2z0dFU_1HFNYEvXr3lWdl0rm6p4VgiOk6o,5980
6
+ jarvis/jarvis_code_agent/file_select.py,sha256=1kOVRLPS1GZcDyGpCW9hOPbfCEwF8f0-qVPaRZPHzoM,8154
7
+ jarvis/jarvis_code_agent/patch.py,sha256=bOhegGKs4JEmJJOZfUlmwzGI6kakMyi2Q62HADJ7Npk,4594
8
+ jarvis/jarvis_code_agent/relevant_files.py,sha256=Q4nI45zuyWt5aKuc4OR7-a6UbOXOym3oEzQJvqxkF8Q,946
9
9
  jarvis/jarvis_codebase/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- jarvis/jarvis_codebase/main.py,sha256=UfFLwOZQoOKSKnpk_Ive1azEYO4-Cm8fICxULGAvqUU,39889
10
+ jarvis/jarvis_codebase/main.py,sha256=40ySTIrQld5uW60vW9pawZopjDNVvtmlW27oNVaJXH0,39683
11
11
  jarvis/jarvis_lsp/base.py,sha256=_7pdbMKjdtYBW0DsRbjIodDHM3J7df-YgXHejN_WIrU,4490
12
12
  jarvis/jarvis_lsp/cpp.py,sha256=F7Zo3BErkvtWS1_H9zQO83pX_FUmnijux-2SjhWzKCE,4985
13
13
  jarvis/jarvis_lsp/go.py,sha256=p8LULiFdq4qjDYQzXFlzH0-FQZ3IyfiwN_sbO9i0L_A,5310
@@ -20,12 +20,12 @@ jarvis/jarvis_platform/base.py,sha256=nQ-rsJL1Z-gMev3TPoY7tYdwxhCJY8LG6_gtJ-maiW
20
20
  jarvis/jarvis_platform/kimi.py,sha256=3yiOL2PsEcKEL0Yj0Hm3lTg9M0Ahy0Ou1AUnJ0AS0Ss,15768
21
21
  jarvis/jarvis_platform/ollama.py,sha256=9Ptu-UzRMnNxqFlx9uDpHO0_Imrzf0Wfw9sZqnv2wRI,5681
22
22
  jarvis/jarvis_platform/openai.py,sha256=NYAIaQbFH9Usg5ZxkBSek1F0imu-pDB9Qf6Am0AtU0s,4130
23
- jarvis/jarvis_platform/oyi.py,sha256=mV8tsQty2Htz--DNemBAnCiauih3JQ4jSyuZi5L4WQo,15089
23
+ jarvis/jarvis_platform/oyi.py,sha256=11WcpJu0rsQfcHP1SVVwpbOjBoJzvQ6LELHWQMCvyzw,15065
24
24
  jarvis/jarvis_platform/registry.py,sha256=9QLoihcnkYckrCzgNnlTqaLn_z_HMhaxMSyUNb8IEys,8538
25
25
  jarvis/jarvis_platform_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
26
  jarvis/jarvis_platform_manager/main.py,sha256=17607aNAStqJ1sOQLTGi6Tnv-cIQme_r5YvbB_S3enc,4985
27
27
  jarvis/jarvis_rag/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
- jarvis/jarvis_rag/main.py,sha256=3BpRz4XrdSLUmH1IENXoKAFqjMxckwtWrGrhdUxOsNw,34626
28
+ jarvis/jarvis_rag/main.py,sha256=Lr3b2eTB9TXZGZGdG4Sl9bdtE5NFRbv_bRysxeWNCEo,31354
29
29
  jarvis/jarvis_smart_shell/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
30
  jarvis/jarvis_smart_shell/main.py,sha256=VdUR-x932OccEwU0pcQM_pb_I4yfrAutE3hfm6jf5es,3955
31
31
  jarvis/jarvis_tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -51,12 +51,12 @@ jarvis/jarvis_tools/methodology.py,sha256=RFqcVjKuj8ESGmNYcQz_HyphsitDvF3XtqgGaq
51
51
  jarvis/jarvis_tools/rag.py,sha256=2fQHqc4bw8JM-OxGTsHobLIOTo8Mip3rdtJCmAoY8XU,4952
52
52
  jarvis/jarvis_tools/read_code.py,sha256=5DGmeXTgumAiG0RP1xB4sF4NdmBm5BEGjRRlIBzjGnQ,4002
53
53
  jarvis/jarvis_tools/read_webpage.py,sha256=JCReSXhkDHDkQ606sZYIKG1Itlprjpmu1sSbF-Ed-jI,2478
54
- jarvis/jarvis_tools/registry.py,sha256=mkAQ1NDPwDy1ESAaAFnzSxAJRrhce3NO3E7cWkb-quA,11732
54
+ jarvis/jarvis_tools/registry.py,sha256=OR-BxSVfI3ER_1rAPMZfLf45E2YpheeS01j8MJ8RGso,11841
55
55
  jarvis/jarvis_tools/search.py,sha256=PLSSNETyajpqDoStCTfkoy-D41IMNudTuVzonMlT6Aw,9225
56
56
  jarvis/jarvis_tools/select_code_files.py,sha256=bjJGwCNw0Ue_8jW60K1gcy1rUgKqoHihicu5SS58WNk,1890
57
- jarvis_ai_assistant-0.1.108.dist-info/LICENSE,sha256=AGgVgQmTqFvaztRtCAXsAMryUymB18gZif7_l2e1XOg,1063
58
- jarvis_ai_assistant-0.1.108.dist-info/METADATA,sha256=OWN4NKRNvFiqIc7mL9XN4-a488mjwbV_TCUX5bhyFkQ,14153
59
- jarvis_ai_assistant-0.1.108.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
60
- jarvis_ai_assistant-0.1.108.dist-info/entry_points.txt,sha256=UYj4FYvOH8jJ0GgCJTA_TAmJ3wvikos-hUVbCwt_KOc,480
61
- jarvis_ai_assistant-0.1.108.dist-info/top_level.txt,sha256=1BOxyWfzOP_ZXj8rVTDnNCJ92bBGB0rwq8N1PCpoMIs,7
62
- jarvis_ai_assistant-0.1.108.dist-info/RECORD,,
57
+ jarvis_ai_assistant-0.1.110.dist-info/LICENSE,sha256=AGgVgQmTqFvaztRtCAXsAMryUymB18gZif7_l2e1XOg,1063
58
+ jarvis_ai_assistant-0.1.110.dist-info/METADATA,sha256=0Ogu7gge_EAhRT6p7HXEqeGNb4uAFMa6MedSJQsp0yY,14392
59
+ jarvis_ai_assistant-0.1.110.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
60
+ jarvis_ai_assistant-0.1.110.dist-info/entry_points.txt,sha256=UYj4FYvOH8jJ0GgCJTA_TAmJ3wvikos-hUVbCwt_KOc,480
61
+ jarvis_ai_assistant-0.1.110.dist-info/top_level.txt,sha256=1BOxyWfzOP_ZXj8rVTDnNCJ92bBGB0rwq8N1PCpoMIs,7
62
+ jarvis_ai_assistant-0.1.110.dist-info/RECORD,,