PraisonAI 0.0.52__tar.gz → 0.0.53__tar.gz

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 PraisonAI might be problematic. Click here for more details.

Files changed (40) hide show
  1. {praisonai-0.0.52 → praisonai-0.0.53}/PKG-INFO +9 -1
  2. {praisonai-0.0.52 → praisonai-0.0.53}/README.md +8 -0
  3. {praisonai-0.0.52 → praisonai-0.0.53}/praisonai/deploy.py +1 -1
  4. praisonai-0.0.53/praisonai/ui/context.py +201 -0
  5. {praisonai-0.0.52 → praisonai-0.0.53}/pyproject.toml +1 -1
  6. praisonai-0.0.52/praisonai/ui/context.py +0 -216
  7. {praisonai-0.0.52 → praisonai-0.0.53}/LICENSE +0 -0
  8. {praisonai-0.0.52 → praisonai-0.0.53}/praisonai/__init__.py +0 -0
  9. {praisonai-0.0.52 → praisonai-0.0.53}/praisonai/__main__.py +0 -0
  10. {praisonai-0.0.52 → praisonai-0.0.53}/praisonai/agents_generator.py +0 -0
  11. {praisonai-0.0.52 → praisonai-0.0.53}/praisonai/auto.py +0 -0
  12. {praisonai-0.0.52 → praisonai-0.0.53}/praisonai/chainlit_ui.py +0 -0
  13. {praisonai-0.0.52 → praisonai-0.0.53}/praisonai/cli.py +0 -0
  14. {praisonai-0.0.52 → praisonai-0.0.53}/praisonai/inbuilt_tools/__init__.py +0 -0
  15. {praisonai-0.0.52 → praisonai-0.0.53}/praisonai/inbuilt_tools/autogen_tools.py +0 -0
  16. {praisonai-0.0.52 → praisonai-0.0.53}/praisonai/inc/__init__.py +0 -0
  17. {praisonai-0.0.52 → praisonai-0.0.53}/praisonai/inc/models.py +0 -0
  18. {praisonai-0.0.52 → praisonai-0.0.53}/praisonai/public/android-chrome-192x192.png +0 -0
  19. {praisonai-0.0.52 → praisonai-0.0.53}/praisonai/public/android-chrome-512x512.png +0 -0
  20. {praisonai-0.0.52 → praisonai-0.0.53}/praisonai/public/apple-touch-icon.png +0 -0
  21. {praisonai-0.0.52 → praisonai-0.0.53}/praisonai/public/fantasy.svg +0 -0
  22. {praisonai-0.0.52 → praisonai-0.0.53}/praisonai/public/favicon-16x16.png +0 -0
  23. {praisonai-0.0.52 → praisonai-0.0.53}/praisonai/public/favicon-32x32.png +0 -0
  24. {praisonai-0.0.52 → praisonai-0.0.53}/praisonai/public/favicon.ico +0 -0
  25. {praisonai-0.0.52 → praisonai-0.0.53}/praisonai/public/game.svg +0 -0
  26. {praisonai-0.0.52 → praisonai-0.0.53}/praisonai/public/logo_dark.png +0 -0
  27. {praisonai-0.0.52 → praisonai-0.0.53}/praisonai/public/logo_light.png +0 -0
  28. {praisonai-0.0.52 → praisonai-0.0.53}/praisonai/public/movie.svg +0 -0
  29. {praisonai-0.0.52 → praisonai-0.0.53}/praisonai/public/thriller.svg +0 -0
  30. {praisonai-0.0.52 → praisonai-0.0.53}/praisonai/test.py +0 -0
  31. {praisonai-0.0.52 → praisonai-0.0.53}/praisonai/ui/chat.py +0 -0
  32. {praisonai-0.0.52 → praisonai-0.0.53}/praisonai/ui/code.py +0 -0
  33. {praisonai-0.0.52 → praisonai-0.0.53}/praisonai/ui/public/fantasy.svg +0 -0
  34. {praisonai-0.0.52 → praisonai-0.0.53}/praisonai/ui/public/game.svg +0 -0
  35. {praisonai-0.0.52 → praisonai-0.0.53}/praisonai/ui/public/logo_dark.png +0 -0
  36. {praisonai-0.0.52 → praisonai-0.0.53}/praisonai/ui/public/logo_light.png +0 -0
  37. {praisonai-0.0.52 → praisonai-0.0.53}/praisonai/ui/public/movie.svg +0 -0
  38. {praisonai-0.0.52 → praisonai-0.0.53}/praisonai/ui/public/thriller.svg +0 -0
  39. {praisonai-0.0.52 → praisonai-0.0.53}/praisonai/ui/sql_alchemy.py +0 -0
  40. {praisonai-0.0.52 → praisonai-0.0.53}/praisonai/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PraisonAI
3
- Version: 0.0.52
3
+ Version: 0.0.53
4
4
  Summary: PraisonAI application combines AutoGen and CrewAI or similar frameworks into a low-code solution for building and managing multi-agent LLM systems, focusing on simplicity, customization, and efficient human-agent collaboration.
5
5
  Author: Mervin Praison
6
6
  Requires-Python: >=3.10,<3.13
@@ -75,6 +75,14 @@ praisonai --init create a movie script about dog in moon
75
75
  praisonai
76
76
  ```
77
77
 
78
+ ## Different User Interfaces:
79
+
80
+ | Interface | Description | URL |
81
+ |---|---|---|
82
+ | **UI** | Multi Agents such as CrewAI or AutoGen | [https://docs.praison.ai/ui/ui](https://docs.praison.ai/ui/ui) |
83
+ | **Chat** | Chat with 100+ LLMs, single AI Agent | [https://docs.praison.ai/ui/chat](https://docs.praison.ai/ui/chat) |
84
+ | **Code** | Chat with entire Codebase, single AI Agent | [https://docs.praison.ai/ui/code](https://docs.praison.ai/ui/code) |
85
+
78
86
  ## Table of Contents
79
87
 
80
88
  - [Installation](#installation)
@@ -34,6 +34,14 @@ praisonai --init create a movie script about dog in moon
34
34
  praisonai
35
35
  ```
36
36
 
37
+ ## Different User Interfaces:
38
+
39
+ | Interface | Description | URL |
40
+ |---|---|---|
41
+ | **UI** | Multi Agents such as CrewAI or AutoGen | [https://docs.praison.ai/ui/ui](https://docs.praison.ai/ui/ui) |
42
+ | **Chat** | Chat with 100+ LLMs, single AI Agent | [https://docs.praison.ai/ui/chat](https://docs.praison.ai/ui/chat) |
43
+ | **Code** | Chat with entire Codebase, single AI Agent | [https://docs.praison.ai/ui/code](https://docs.praison.ai/ui/code) |
44
+
37
45
  ## Table of Contents
38
46
 
39
47
  - [Installation](#installation)
@@ -56,7 +56,7 @@ class CloudDeployer:
56
56
  file.write("FROM python:3.11-slim\n")
57
57
  file.write("WORKDIR /app\n")
58
58
  file.write("COPY . .\n")
59
- file.write("RUN pip install flask praisonai==0.0.52 gunicorn markdown\n")
59
+ file.write("RUN pip install flask praisonai==0.0.53 gunicorn markdown\n")
60
60
  file.write("EXPOSE 8080\n")
61
61
  file.write('CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]\n')
62
62
 
@@ -0,0 +1,201 @@
1
+ import os
2
+ import fnmatch
3
+ import re
4
+ import yaml
5
+ from pathlib import Path
6
+ import logging
7
+
8
+ # Set up logging
9
+ logger = logging.getLogger(__name__)
10
+ log_level = os.getenv("LOGLEVEL", "INFO").upper()
11
+ logger.handlers = []
12
+
13
+ # Set up logging to console
14
+ console_handler = logging.StreamHandler()
15
+ console_handler.setLevel(log_level)
16
+ console_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
17
+ console_handler.setFormatter(console_formatter)
18
+ logger.addHandler(console_handler)
19
+
20
+ # Set the logging level for the logger
21
+ logger.setLevel(log_level)
22
+
23
+ class ContextGatherer:
24
+ def __init__(self, directory='.', output_file='context.txt',
25
+ relevant_extensions=None, max_file_size=1_000_000, max_tokens=900000):
26
+ self.directory = directory
27
+ self.output_file = output_file
28
+ self.relevant_extensions = relevant_extensions or [
29
+ '.py', '.js', '.ts', '.java', '.rb', '.php', '.pl', '.pm', '.c', '.h',
30
+ '.cpp', '.hpp', '.cs', '.vb', '.swift', '.kt', '.m', '.mm', '.go', '.rs',
31
+ '.hs', '.r', '.lua', '.sh', '.bat', '.clj', '.scala', '.erl', '.ex',
32
+ '.ml', '.fs', '.groovy', '.jsm', '.jsx', '.tsx', '.yaml'
33
+ ]
34
+ self.max_file_size = max_file_size
35
+ self.max_tokens = int(os.getenv("PRAISONAI_MAX_TOKENS", max_tokens))
36
+ self.ignore_patterns = self.get_ignore_patterns()
37
+
38
+ def get_ignore_patterns(self):
39
+ """
40
+ Loads ignore patterns from various sources, prioritizing them in
41
+ the following order:
42
+ 1. .praisonignore
43
+ 2. settings.yaml (under code.ignore_files)
44
+ 3. PRAISONAI_IGNORE_FILES environment variable
45
+ 4. .gitignore
46
+ 5. Default patterns
47
+ """
48
+ ignore_patterns = []
49
+
50
+ def load_from_file(filepath):
51
+ if os.path.exists(filepath):
52
+ with open(filepath, 'r') as f:
53
+ ignore_patterns.extend(
54
+ line.strip() for line in f
55
+ if line.strip() and not line.startswith('#')
56
+ )
57
+
58
+ # 1. Load from .praisonignore
59
+ load_from_file(os.path.join(self.directory, '.praisonignore'))
60
+
61
+ # 2. Load from settings.yaml
62
+ settings_path = os.path.join(self.directory, 'settings.yaml')
63
+ if os.path.exists(settings_path):
64
+ with open(settings_path, 'r') as f:
65
+ settings = yaml.safe_load(f)
66
+ if 'code' in settings and 'ignore_files' in settings['code']:
67
+ ignore_patterns.extend(settings['code']['ignore_files'])
68
+
69
+ # 3. Load from environment variable
70
+ ignore_files_env = os.getenv("PRAISONAI_IGNORE_FILES")
71
+ if ignore_files_env:
72
+ ignore_patterns.extend(ignore_files_env.split(","))
73
+
74
+ # 4. Load from .gitignore
75
+ load_from_file(os.path.join(self.directory, '.gitignore'))
76
+
77
+ # 5. Default patterns (only if no patterns loaded from above sources)
78
+ if not ignore_patterns:
79
+ ignore_patterns = [
80
+ ".*", "*.pyc", "__pycache__", ".git", ".gitignore", ".vscode",
81
+ ".idea", ".DS_Store", "*.lock", "*.pyc", ".env", "docs", "tests",
82
+ "test", "tmp", "temp", "*.txt", "*.md", "*.json", "*.csv", "*.tsv",
83
+ "public", "*.sql", "*.sqlite", "*.db", "*.db3", "*.sqlite3",
84
+ "*.log", "*.zip", "*.gz", "*.tar", "*.rar", "*.7z", "*.pdf",
85
+ "*.jpg", "*.jpeg", "*.png", "*.gif", "*.svg", "cookbooks",
86
+ "assets", "__pycache__", "dist", "build", "node_modules", "venv"
87
+ ]
88
+ logger.debug(f"Using default ignore patterns: {ignore_patterns}")
89
+
90
+ # Modify patterns to match directories and add leading '*' if necessary
91
+ modified_ignore_patterns = [
92
+ '*' + pattern if not pattern.startswith('.') and not pattern.startswith('*') else pattern
93
+ for pattern in ignore_patterns
94
+ ]
95
+ logger.debug(f"Final ignore patterns: {modified_ignore_patterns}")
96
+ return modified_ignore_patterns
97
+
98
+ def should_ignore(self, file_path):
99
+ """
100
+ Check if a file or directory should be ignored based on patterns.
101
+ Handles both file names and directory names for more comprehensive filtering.
102
+ """
103
+ relative_path = os.path.relpath(file_path, self.directory)
104
+ if relative_path.startswith('.'):
105
+ return True
106
+ for pattern in self.ignore_patterns:
107
+ if fnmatch.fnmatch(relative_path, pattern) or \
108
+ fnmatch.fnmatch(os.path.basename(file_path), pattern):
109
+ return True
110
+ return False
111
+
112
+ def is_relevant_file(self, file_path):
113
+ """Determine if a file is relevant for the context."""
114
+ return os.path.isfile(file_path) and \
115
+ os.path.getsize(file_path) <= self.max_file_size and \
116
+ any(file_path.endswith(ext) for ext in self.relevant_extensions)
117
+
118
+ def gather_context(self):
119
+ """Gather context from relevant files, respecting ignore patterns."""
120
+ context = []
121
+ total_files = 0
122
+ processed_files = 0
123
+
124
+ for root, dirs, files in os.walk(self.directory):
125
+ total_files += len(files)
126
+ dirs[:] = [d for d in dirs if not self.should_ignore(os.path.join(root, d))]
127
+ for file in files:
128
+ file_path = os.path.join(root, file)
129
+ if not self.should_ignore(file_path) and self.is_relevant_file(file_path):
130
+ try:
131
+ with open(file_path, 'r', encoding='utf-8') as f:
132
+ content = f.read()
133
+ context.append(f"File: {file_path}\n\n{content}\n\n{'='*50}\n")
134
+ except Exception as e:
135
+ logger.error(f"Error reading {file_path}: {e}")
136
+ processed_files += 1
137
+ print(f"\rProcessed {processed_files}/{total_files} files", end="", flush=True)
138
+ print() # New line after progress indicator
139
+ return '\n'.join(context)
140
+
141
+ def count_tokens(self, text):
142
+ """Count tokens using a simple whitespace-based tokenizer."""
143
+ return len(text.split())
144
+
145
+ def truncate_context(self, context):
146
+ """Truncate context to stay within the token limit."""
147
+ tokens = context.split()
148
+ if len(tokens) > self.max_tokens:
149
+ truncated_context = ' '.join(tokens[:self.max_tokens])
150
+ logger.warning("Context truncated due to token limit.")
151
+ return truncated_context
152
+ return context
153
+
154
+ def save_context(self, context):
155
+ """Save the gathered context to a file."""
156
+ with open(self.output_file, 'w', encoding='utf-8') as f:
157
+ f.write(context)
158
+
159
+ def get_context_tree(self):
160
+ """Generate a formatted tree structure of included files and folders."""
161
+ tree = []
162
+ start_dir = Path(self.directory)
163
+
164
+ def add_to_tree(path, prefix=''):
165
+ contents = sorted(path.iterdir())
166
+ pointers = [('└── ' if i == len(contents) - 1 else '├── ') for i in range(len(contents))]
167
+ for pointer, item in zip(pointers, contents):
168
+ # Use should_ignore for consistency
169
+ if self.should_ignore(item):
170
+ continue
171
+
172
+ rel_path = item.relative_to(start_dir)
173
+ tree.append(f"{prefix}{pointer}{rel_path}")
174
+
175
+ if item.is_dir():
176
+ add_to_tree(item, prefix + (' ' if pointer == '└── ' else '│ '))
177
+
178
+ add_to_tree(start_dir)
179
+ return '\n'.join(tree)
180
+
181
+ def run(self):
182
+ """Execute the context gathering, truncation, and reporting."""
183
+ context = self.gather_context()
184
+ context = self.truncate_context(context)
185
+ token_count = self.count_tokens(context)
186
+ print(f"Context gathered successfully.")
187
+ print(f"Total number of tokens (estimated): {token_count}")
188
+ # self.save_context(context)
189
+ context_tree = self.get_context_tree()
190
+ logger.debug(f"Context tree:\n{context_tree}")
191
+ return context, token_count, context_tree
192
+
193
+ def main():
194
+ gatherer = ContextGatherer()
195
+ context, token_count, context_tree = gatherer.run()
196
+ print(f"\nThe context contains approximately {token_count} tokens.")
197
+ print("First 500 characters of context:")
198
+ print(context[:500] + "...")
199
+
200
+ if __name__ == "__main__":
201
+ main()
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "PraisonAI"
3
- version = "0.0.52"
3
+ version = "0.0.53"
4
4
  description = "PraisonAI application combines AutoGen and CrewAI or similar frameworks into a low-code solution for building and managing multi-agent LLM systems, focusing on simplicity, customization, and efficient human-agent collaboration."
5
5
  authors = ["Mervin Praison"]
6
6
  license = ""
@@ -1,216 +0,0 @@
1
- import os
2
- import fnmatch
3
- import re
4
- import yaml
5
- import logging
6
- # Set up logging
7
- logger = logging.getLogger(__name__)
8
- log_level = os.getenv("LOGLEVEL", "INFO").upper()
9
- logger.handlers = []
10
-
11
- # Set up logging to console
12
- console_handler = logging.StreamHandler()
13
- console_handler.setLevel(log_level)
14
- console_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
15
- console_handler.setFormatter(console_formatter)
16
- logger.addHandler(console_handler)
17
-
18
- # Set the logging level for the logger
19
- logger.setLevel(log_level)
20
-
21
- class ContextGatherer:
22
- def __init__(self, directory='.', output_file='context.txt',
23
- relevant_extensions=None, max_file_size=1_000_000, max_tokens=900000):
24
- self.directory = directory
25
- self.output_file = output_file
26
- self.relevant_extensions = relevant_extensions or [
27
- '.py', # Python
28
- '.js', # JavaScript
29
- '.ts', # TypeScript
30
- '.java', # Java
31
- '.rb', # Ruby
32
- '.php', # PHP
33
- '.pl', # Perl
34
- '.pm', # Perl Module
35
- '.c', # C
36
- '.h', # C Header
37
- '.cpp', # C++
38
- '.hpp', # C++ Header
39
- '.cs', # C#
40
- '.vb', # Visual Basic
41
- '.swift', # Swift
42
- '.kt', # Kotlin
43
- '.m', # Objective-C
44
- '.mm', # Objective-C++
45
- '.go', # Go
46
- '.rs', # Rust
47
- '.hs', # Haskell
48
- '.r', # R
49
- '.lua', # Lua
50
- '.sh', # Shell Script
51
- '.bat', # Batch File
52
- '.clj', # Clojure
53
- '.scala', # Scala
54
- '.erl', # Erlang
55
- '.ex', # Elixir
56
- '.ml', # OCaml
57
- '.fs', # F#
58
- '.groovy', # Groovy
59
- '.jsm', # JavaScript Module
60
- '.jsx', # JavaScript XML
61
- '.tsx', # TypeScript XML
62
- '.yaml', # YAML
63
- ]
64
- self.max_file_size = max_file_size
65
- self.max_tokens = int(os.getenv("PRAISONAI_MAX_TOKENS", max_tokens))
66
- self.ignore_patterns = self.get_ignore_patterns()
67
-
68
- def get_ignore_patterns(self):
69
- """Read .gitignore file and return ignore patterns."""
70
-
71
- # 1. Check for .praisonignore
72
- praisonignore_path = os.path.join(self.directory, '.praisonignore')
73
- if os.path.exists(praisonignore_path):
74
- with open(praisonignore_path, 'r') as f:
75
- praisonignore_patterns = [line.strip() for line in f if line.strip() and not line.startswith('#')]
76
- logger.debug(f"Using ignore patterns from .praisonignore: {praisonignore_patterns}")
77
- return praisonignore_patterns
78
-
79
- # 2. Fallback to settings.yaml
80
- settings_path = os.path.join(self.directory, 'settings.yaml')
81
- if os.path.exists(settings_path):
82
- with open(settings_path, 'r') as f:
83
- settings = yaml.safe_load(f)
84
- if 'code' in settings and 'ignore_files' in settings['code']:
85
- logger.debug(f"Using ignore patterns from settings.yaml: {settings['code']['ignore_files']}")
86
- return settings['code']['ignore_files']
87
-
88
- # 3. Fallback to PRAISONAI_IGNORE_FILES env variable
89
- ignore_files_env = os.getenv("PRAISONAI_IGNORE_FILES")
90
- if ignore_files_env:
91
- logger.debug(f"Using ignore patterns from PRAISONAI_IGNORE_FILES: {ignore_files_env}")
92
- return ignore_files_env.split(",")
93
-
94
- default_patterns = [".*", "*.pyc", "__pycache__", ".git", ".gitignore", ".vscode",
95
- ".idea", ".DS_Store", "*.lock", "*.pyc", ".env",
96
- "docs", "tests", "test", "tmp", "temp",
97
- "*.txt", "*.md", "*.json", "*.csv", "*.tsv","public",
98
- "*.sql", "*.sqlite", "*.db", "*.db3", "*.sqlite3", "*.log", "*.zip", "*.gz",
99
- "*.tar", "*.rar", "*.7z", "*.pdf", "*.jpg", "*.jpeg", "*.png", "*.gif", "*.svg",
100
- "cookbooks", "assets", "__pycache__", "dist", "build", "node_modules", "venv",]
101
- gitignore_path = os.path.join(self.directory, '.gitignore')
102
- if os.path.exists(gitignore_path):
103
- with open(gitignore_path, 'r') as f:
104
- gitignore_patterns = [line.strip() for line in f if line.strip() and not line.startswith('#')]
105
- logger.debug(f"Ignored gitignore and default files: {ignore_files_env}")
106
- return list(set(default_patterns + gitignore_patterns))
107
- return default_patterns
108
-
109
- def should_ignore(self, file_path):
110
- """Check if a file should be ignored based on patterns."""
111
- relative_path = os.path.relpath(file_path, self.directory)
112
- if relative_path.startswith('.'):
113
- return True
114
- for pattern in self.ignore_patterns:
115
- if fnmatch.fnmatch(relative_path, pattern):
116
- return True
117
- return False
118
-
119
- def is_relevant_file(self, file_path):
120
- """Determine if a file is relevant for the context."""
121
- if os.path.getsize(file_path) > self.max_file_size:
122
- return False
123
- return any(file_path.endswith(ext) for ext in self.relevant_extensions)
124
-
125
- def gather_context(self):
126
- """Gather context from relevant files in the directory."""
127
- context = []
128
- total_files = sum(len(files) for _, _, files in os.walk(self.directory))
129
- processed_files = 0
130
-
131
- for root, dirs, files in os.walk(self.directory):
132
- dirs[:] = [d for d in dirs if not self.should_ignore(os.path.join(root, d))]
133
- for file in files:
134
- file_path = os.path.join(root, file)
135
- if not self.should_ignore(file_path) and self.is_relevant_file(file_path):
136
- try:
137
- with open(file_path, 'r', encoding='utf-8') as f:
138
- content = f.read()
139
- context.append(f"File: {file_path}\n\n{content}\n\n{'='*50}\n")
140
- except Exception as e:
141
- print(f"Error reading {file_path}: {e}")
142
- processed_files += 1
143
- print(f"\rProcessed {processed_files}/{total_files} files", end="", flush=True)
144
- print() # New line after progress indicator
145
- return '\n'.join(context)
146
-
147
- def count_tokens(self, text):
148
- """Count the number of tokens in the given text using a simple tokenizer."""
149
- # Split on whitespace and punctuation
150
- tokens = re.findall(r'\b\w+\b|[^\w\s]', text)
151
- return len(tokens)
152
-
153
- def truncate_context(self, context):
154
- """Truncate context to fit within the specified token limit."""
155
- tokens = re.findall(r'\b\w+\b|[^\w\s]', context)
156
- if len(tokens) > self.max_tokens:
157
- truncated_tokens = tokens[:self.max_tokens]
158
- return ' '.join(truncated_tokens)
159
- return context
160
-
161
- def save_context(self, context):
162
- """Save the gathered context to a file."""
163
- with open(self.output_file, 'w', encoding='utf-8') as f:
164
- f.write(context)
165
-
166
- def get_context_tree(self):
167
- """Generate a formatted tree structure of the folder, including only relevant files."""
168
- tree = []
169
- start_dir = os.path.abspath(self.directory)
170
-
171
- def add_to_tree(path, prefix=''):
172
- contents = sorted(os.listdir(path))
173
- pointers = [('└── ' if i == len(contents) - 1 else '├── ') for i in range(len(contents))]
174
- for pointer, name in zip(pointers, contents):
175
- full_path = os.path.join(path, name)
176
- if self.should_ignore(full_path):
177
- continue
178
-
179
- rel_path = os.path.relpath(full_path, start_dir)
180
- tree.append(f"{prefix}{pointer}{name}")
181
-
182
- if os.path.isdir(full_path):
183
- add_to_tree(full_path, prefix + (' ' if pointer == '└── ' else '│ '))
184
- elif self.is_relevant_file(full_path):
185
- continue # We've already added the file to the tree
186
-
187
- add_to_tree(start_dir)
188
- return '\n'.join(tree)
189
-
190
- def run(self):
191
- """Run the context gathering process and return the context and token count."""
192
- context = self.gather_context()
193
- context = self.truncate_context(context)
194
- token_count = self.count_tokens(context)
195
- print(f"Context gathered successfully.")
196
- print(f"Total number of tokens (estimated): {token_count}")
197
- # self.save_context(context)
198
- context_tree = self.get_context_tree()
199
- logger.debug(f"Context tree:\n{context_tree}")
200
- return context, token_count, context_tree
201
-
202
- def main():
203
- gatherer = ContextGatherer(
204
- directory='.',
205
- output_file='context.txt',
206
- relevant_extensions=['.py'],
207
- max_file_size=500_000, # 500KB
208
- max_tokens=60000
209
- )
210
- context, token_count, context_tree = gatherer.run()
211
- print(f"\nThe context contains approximately {token_count} tokens.")
212
- print("First 500 characters of context:")
213
- print(context[:500] + "...")
214
-
215
- if __name__ == "__main__":
216
- main()
File without changes
File without changes
File without changes
File without changes