PraisonAI 0.0.52__py3-none-any.whl → 0.0.53__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 PraisonAI might be problematic. Click here for more details.
- praisonai/deploy.py +1 -1
- praisonai/ui/context.py +93 -108
- {praisonai-0.0.52.dist-info → praisonai-0.0.53.dist-info}/METADATA +9 -1
- {praisonai-0.0.52.dist-info → praisonai-0.0.53.dist-info}/RECORD +7 -7
- {praisonai-0.0.52.dist-info → praisonai-0.0.53.dist-info}/LICENSE +0 -0
- {praisonai-0.0.52.dist-info → praisonai-0.0.53.dist-info}/WHEEL +0 -0
- {praisonai-0.0.52.dist-info → praisonai-0.0.53.dist-info}/entry_points.txt +0 -0
praisonai/deploy.py
CHANGED
|
@@ -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.
|
|
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
|
|
praisonai/ui/context.py
CHANGED
|
@@ -2,7 +2,9 @@ import os
|
|
|
2
2
|
import fnmatch
|
|
3
3
|
import re
|
|
4
4
|
import yaml
|
|
5
|
+
from pathlib import Path
|
|
5
6
|
import logging
|
|
7
|
+
|
|
6
8
|
# Set up logging
|
|
7
9
|
logger = logging.getLogger(__name__)
|
|
8
10
|
log_level = os.getenv("LOGLEVEL", "INFO").upper()
|
|
@@ -24,111 +26,103 @@ class ContextGatherer:
|
|
|
24
26
|
self.directory = directory
|
|
25
27
|
self.output_file = output_file
|
|
26
28
|
self.relevant_extensions = relevant_extensions or [
|
|
27
|
-
'.py',
|
|
28
|
-
'.
|
|
29
|
-
'.
|
|
30
|
-
'.
|
|
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
|
|
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'
|
|
63
33
|
]
|
|
64
34
|
self.max_file_size = max_file_size
|
|
65
35
|
self.max_tokens = int(os.getenv("PRAISONAI_MAX_TOKENS", max_tokens))
|
|
66
36
|
self.ignore_patterns = self.get_ignore_patterns()
|
|
67
37
|
|
|
68
38
|
def get_ignore_patterns(self):
|
|
69
|
-
"""
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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
|
|
80
62
|
settings_path = os.path.join(self.directory, 'settings.yaml')
|
|
81
63
|
if os.path.exists(settings_path):
|
|
82
64
|
with open(settings_path, 'r') as f:
|
|
83
65
|
settings = yaml.safe_load(f)
|
|
84
66
|
if 'code' in settings and 'ignore_files' in settings['code']:
|
|
85
|
-
|
|
86
|
-
return settings['code']['ignore_files']
|
|
67
|
+
ignore_patterns.extend(settings['code']['ignore_files'])
|
|
87
68
|
|
|
88
|
-
# 3.
|
|
69
|
+
# 3. Load from environment variable
|
|
89
70
|
ignore_files_env = os.getenv("PRAISONAI_IGNORE_FILES")
|
|
90
71
|
if ignore_files_env:
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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
|
|
108
97
|
|
|
109
98
|
def should_ignore(self, file_path):
|
|
110
|
-
"""
|
|
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
|
+
"""
|
|
111
103
|
relative_path = os.path.relpath(file_path, self.directory)
|
|
112
104
|
if relative_path.startswith('.'):
|
|
113
105
|
return True
|
|
114
106
|
for pattern in self.ignore_patterns:
|
|
115
|
-
if fnmatch.fnmatch(relative_path, pattern)
|
|
107
|
+
if fnmatch.fnmatch(relative_path, pattern) or \
|
|
108
|
+
fnmatch.fnmatch(os.path.basename(file_path), pattern):
|
|
116
109
|
return True
|
|
117
110
|
return False
|
|
118
111
|
|
|
119
112
|
def is_relevant_file(self, file_path):
|
|
120
113
|
"""Determine if a file is relevant for the context."""
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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)
|
|
124
117
|
|
|
125
118
|
def gather_context(self):
|
|
126
|
-
"""Gather context from relevant files
|
|
119
|
+
"""Gather context from relevant files, respecting ignore patterns."""
|
|
127
120
|
context = []
|
|
128
|
-
total_files =
|
|
121
|
+
total_files = 0
|
|
129
122
|
processed_files = 0
|
|
130
123
|
|
|
131
124
|
for root, dirs, files in os.walk(self.directory):
|
|
125
|
+
total_files += len(files)
|
|
132
126
|
dirs[:] = [d for d in dirs if not self.should_ignore(os.path.join(root, d))]
|
|
133
127
|
for file in files:
|
|
134
128
|
file_path = os.path.join(root, file)
|
|
@@ -138,57 +132,54 @@ class ContextGatherer:
|
|
|
138
132
|
content = f.read()
|
|
139
133
|
context.append(f"File: {file_path}\n\n{content}\n\n{'='*50}\n")
|
|
140
134
|
except Exception as e:
|
|
141
|
-
|
|
135
|
+
logger.error(f"Error reading {file_path}: {e}")
|
|
142
136
|
processed_files += 1
|
|
143
137
|
print(f"\rProcessed {processed_files}/{total_files} files", end="", flush=True)
|
|
144
138
|
print() # New line after progress indicator
|
|
145
139
|
return '\n'.join(context)
|
|
146
140
|
|
|
147
141
|
def count_tokens(self, text):
|
|
148
|
-
"""Count
|
|
149
|
-
|
|
150
|
-
tokens = re.findall(r'\b\w+\b|[^\w\s]', text)
|
|
151
|
-
return len(tokens)
|
|
142
|
+
"""Count tokens using a simple whitespace-based tokenizer."""
|
|
143
|
+
return len(text.split())
|
|
152
144
|
|
|
153
145
|
def truncate_context(self, context):
|
|
154
|
-
"""Truncate context to
|
|
155
|
-
tokens =
|
|
146
|
+
"""Truncate context to stay within the token limit."""
|
|
147
|
+
tokens = context.split()
|
|
156
148
|
if len(tokens) > self.max_tokens:
|
|
157
|
-
|
|
158
|
-
|
|
149
|
+
truncated_context = ' '.join(tokens[:self.max_tokens])
|
|
150
|
+
logger.warning("Context truncated due to token limit.")
|
|
151
|
+
return truncated_context
|
|
159
152
|
return context
|
|
160
153
|
|
|
161
154
|
def save_context(self, context):
|
|
162
155
|
"""Save the gathered context to a file."""
|
|
163
156
|
with open(self.output_file, 'w', encoding='utf-8') as f:
|
|
164
157
|
f.write(context)
|
|
165
|
-
|
|
158
|
+
|
|
166
159
|
def get_context_tree(self):
|
|
167
|
-
"""Generate a formatted tree structure of
|
|
160
|
+
"""Generate a formatted tree structure of included files and folders."""
|
|
168
161
|
tree = []
|
|
169
|
-
start_dir =
|
|
170
|
-
|
|
162
|
+
start_dir = Path(self.directory)
|
|
163
|
+
|
|
171
164
|
def add_to_tree(path, prefix=''):
|
|
172
|
-
contents = sorted(
|
|
165
|
+
contents = sorted(path.iterdir())
|
|
173
166
|
pointers = [('└── ' if i == len(contents) - 1 else '├── ') for i in range(len(contents))]
|
|
174
|
-
for pointer,
|
|
175
|
-
|
|
176
|
-
if self.should_ignore(
|
|
167
|
+
for pointer, item in zip(pointers, contents):
|
|
168
|
+
# Use should_ignore for consistency
|
|
169
|
+
if self.should_ignore(item):
|
|
177
170
|
continue
|
|
178
|
-
|
|
179
|
-
rel_path =
|
|
180
|
-
tree.append(f"{prefix}{pointer}{
|
|
181
|
-
|
|
182
|
-
if
|
|
183
|
-
add_to_tree(
|
|
184
|
-
elif self.is_relevant_file(full_path):
|
|
185
|
-
continue # We've already added the file to the tree
|
|
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 '│ '))
|
|
186
177
|
|
|
187
178
|
add_to_tree(start_dir)
|
|
188
179
|
return '\n'.join(tree)
|
|
189
180
|
|
|
190
181
|
def run(self):
|
|
191
|
-
"""
|
|
182
|
+
"""Execute the context gathering, truncation, and reporting."""
|
|
192
183
|
context = self.gather_context()
|
|
193
184
|
context = self.truncate_context(context)
|
|
194
185
|
token_count = self.count_tokens(context)
|
|
@@ -200,17 +191,11 @@ class ContextGatherer:
|
|
|
200
191
|
return context, token_count, context_tree
|
|
201
192
|
|
|
202
193
|
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
|
-
)
|
|
194
|
+
gatherer = ContextGatherer()
|
|
210
195
|
context, token_count, context_tree = gatherer.run()
|
|
211
196
|
print(f"\nThe context contains approximately {token_count} tokens.")
|
|
212
197
|
print("First 500 characters of context:")
|
|
213
198
|
print(context[:500] + "...")
|
|
214
199
|
|
|
215
200
|
if __name__ == "__main__":
|
|
216
|
-
main()
|
|
201
|
+
main()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: PraisonAI
|
|
3
|
-
Version: 0.0.
|
|
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)
|
|
@@ -4,7 +4,7 @@ praisonai/agents_generator.py,sha256=8d1WRbubvEkBrW1HZ7_xnGyqgJi0yxmXa3MgTIqef1c
|
|
|
4
4
|
praisonai/auto.py,sha256=9spTXqj47Hmmqv5QHRYE_RzSVHH_KoPbaZjskUj2UcE,7895
|
|
5
5
|
praisonai/chainlit_ui.py,sha256=bNR7s509lp0I9JlJNvwCZRUZosC64qdvlFCt8NmFamQ,12216
|
|
6
6
|
praisonai/cli.py,sha256=VaVEJlc8c_aE2SBY6xN7WIbHrqNcXGR2xrDzFAsD2B8,14504
|
|
7
|
-
praisonai/deploy.py,sha256=
|
|
7
|
+
praisonai/deploy.py,sha256=K27eI4Qhptov8NKD_El414VZtxxuVYmUXX-jvLck1kg,6028
|
|
8
8
|
praisonai/inbuilt_tools/__init__.py,sha256=mUKnbL6Gram9c9f2m8wJwEzURBLmPEOcHzwySBH89YA,74
|
|
9
9
|
praisonai/inbuilt_tools/autogen_tools.py,sha256=svYkM2N7DVFvbiwgoAS7U_MqTOD8rHf8VD3BaFUV5_Y,14907
|
|
10
10
|
praisonai/inc/__init__.py,sha256=sPDlYBBwdk0VlWzaaM_lG0_LD07lS2HRGvPdxXJFiYg,62
|
|
@@ -24,7 +24,7 @@ praisonai/public/thriller.svg,sha256=2dYY72EcgbEyTxS4QzjAm37Y4srtPWEW4vCMFki98ZI
|
|
|
24
24
|
praisonai/test.py,sha256=RZKq3UEFb6AnFFiHER3zBXfNmlteSLBlrTmOvnpnZLo,4092
|
|
25
25
|
praisonai/ui/chat.py,sha256=S3a5u0mI7RO5QFbKckz4z8b32gRTiX8kauSHvQBTMco,9238
|
|
26
26
|
praisonai/ui/code.py,sha256=KLJir8sfzNnZRm2mlAVprGBsZ6wId6yDLsSfN3A2Qdk,10012
|
|
27
|
-
praisonai/ui/context.py,sha256
|
|
27
|
+
praisonai/ui/context.py,sha256=4Rn0BZg9IKMtkKk3s784dStvbMMogW8fMU4xb1gQ9dY,8484
|
|
28
28
|
praisonai/ui/public/fantasy.svg,sha256=4Gs3kIOux-pjGtw6ogI_rv5_viVJxnE5gRwGilsSg0o,1553
|
|
29
29
|
praisonai/ui/public/game.svg,sha256=y2QMaA01m8XzuDjTOBWzupOC3-TpnUl9ah89mIhviUw,2406
|
|
30
30
|
praisonai/ui/public/logo_dark.png,sha256=frHz1zkrnivGssJgk9iy1cabojkVgm8B4MllFwL_CnI,17050
|
|
@@ -33,8 +33,8 @@ praisonai/ui/public/movie.svg,sha256=aJ2EQ8vXZusVsF2SeuAVxP4RFJzQ14T26ejrGYdBgzk
|
|
|
33
33
|
praisonai/ui/public/thriller.svg,sha256=2dYY72EcgbEyTxS4QzjAm37Y4srtPWEW4vCMFki98ZI,3163
|
|
34
34
|
praisonai/ui/sql_alchemy.py,sha256=HsyeRq-G9qbQobHWpTJHHKQiT4FvYw_7iuv-2PNh0IU,27419
|
|
35
35
|
praisonai/version.py,sha256=ugyuFliEqtAwQmH4sTlc16YXKYbFWDmfyk87fErB8-8,21
|
|
36
|
-
praisonai-0.0.
|
|
37
|
-
praisonai-0.0.
|
|
38
|
-
praisonai-0.0.
|
|
39
|
-
praisonai-0.0.
|
|
40
|
-
praisonai-0.0.
|
|
36
|
+
praisonai-0.0.53.dist-info/LICENSE,sha256=kqvFysVlnFxYOu0HxCe2HlmZmJtdmNGOxWRRkT9TsWc,1035
|
|
37
|
+
praisonai-0.0.53.dist-info/METADATA,sha256=h20mwjB5fkGUjRvHQB_r66zt_tpKH-1uPLntxj7qFCk,11707
|
|
38
|
+
praisonai-0.0.53.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
39
|
+
praisonai-0.0.53.dist-info/entry_points.txt,sha256=Qg41eW3A1-dvdV5tF7LqChfYof8Rihk2rN1fiEE3vnk,53
|
|
40
|
+
praisonai-0.0.53.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|