PraisonAI 0.0.52__py3-none-any.whl → 0.0.54__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 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.52 gunicorn markdown\n")
59
+ file.write("RUN pip install flask praisonai==0.0.54 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', # 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
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
- """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
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
- logger.debug(f"Using ignore patterns from settings.yaml: {settings['code']['ignore_files']}")
86
- return settings['code']['ignore_files']
67
+ ignore_patterns.extend(settings['code']['ignore_files'])
87
68
 
88
- # 3. Fallback to PRAISONAI_IGNORE_FILES env variable
69
+ # 3. Load from environment variable
89
70
  ignore_files_env = os.getenv("PRAISONAI_IGNORE_FILES")
90
71
  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
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
- """Check if a file should be ignored based on patterns."""
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
- 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)
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 in the directory."""
119
+ """Gather context from relevant files, respecting ignore patterns."""
127
120
  context = []
128
- total_files = sum(len(files) for _, _, files in os.walk(self.directory))
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
- print(f"Error reading {file_path}: {e}")
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 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)
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 fit within the specified token limit."""
155
- tokens = re.findall(r'\b\w+\b|[^\w\s]', context)
146
+ """Truncate context to stay within the token limit."""
147
+ tokens = context.split()
156
148
  if len(tokens) > self.max_tokens:
157
- truncated_tokens = tokens[:self.max_tokens]
158
- return ' '.join(truncated_tokens)
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 the folder, including only relevant files."""
160
+ """Generate a formatted tree structure of included files and folders."""
168
161
  tree = []
169
- start_dir = os.path.abspath(self.directory)
170
-
162
+ start_dir = Path(self.directory)
163
+
171
164
  def add_to_tree(path, prefix=''):
172
- contents = sorted(os.listdir(path))
165
+ contents = sorted(path.iterdir())
173
166
  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):
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 = 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
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
- """Run the context gathering process and return the context and token count."""
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.52
3
+ Version: 0.0.54
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
@@ -19,12 +19,12 @@ Provides-Extra: gradio
19
19
  Provides-Extra: openai
20
20
  Provides-Extra: ui
21
21
  Requires-Dist: agentops (>=0.2.6) ; extra == "agentops"
22
- Requires-Dist: aiosqlite (>=0.20.0) ; extra == "code"
22
+ Requires-Dist: aiosqlite (>=0.20.0) ; extra == "chat" or extra == "code"
23
23
  Requires-Dist: chainlit (>=1.1.301,<2.0.0) ; extra == "ui" or extra == "chat" or extra == "code"
24
24
  Requires-Dist: crewai (>=0.32.0)
25
25
  Requires-Dist: flask (>=3.0.0) ; extra == "api"
26
26
  Requires-Dist: gradio (>=4.26.0) ; extra == "gradio"
27
- Requires-Dist: greenlet (>=3.0.3) ; extra == "code"
27
+ Requires-Dist: greenlet (>=3.0.3) ; extra == "chat" or extra == "code"
28
28
  Requires-Dist: langchain-anthropic (>=0.1.13) ; extra == "anthropic"
29
29
  Requires-Dist: langchain-cohere (>=0.1.4) ; extra == "cohere"
30
30
  Requires-Dist: langchain-google-genai (>=1.0.4) ; extra == "google"
@@ -61,6 +61,16 @@ Description-Content-Type: text/markdown
61
61
 
62
62
  Praison AI, leveraging both AutoGen and CrewAI or any other agent framework, represents a low-code, centralised framework designed to simplify the creation and orchestration of multi-agent systems for various LLM applications, emphasizing ease of use, customization, and human-agent interaction.
63
63
 
64
+ <div align="center">
65
+ <picture>
66
+ <source media="(prefers-color-scheme: dark)" srcset="docs/images/architecture-dark.png">
67
+ <source media="(prefers-color-scheme: light)" srcset="docs/images/architecture-light.png">
68
+ <img alt="PraisonAI Architecture" src="docs/images/architecture-light.png">
69
+ </picture>
70
+ </div>
71
+
72
+ ## Google Colab
73
+
64
74
  | | Cookbook | Open in Colab |
65
75
  | ------------- | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
66
76
  | Basic | PraisonAI | <a target="_blank" href="https://colab.research.google.com/github/MervinPraison/PraisonAI/blob/main/cookbooks/praisonai-googlecolab.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/></a> |
@@ -75,6 +85,14 @@ praisonai --init create a movie script about dog in moon
75
85
  praisonai
76
86
  ```
77
87
 
88
+ ## Different User Interfaces:
89
+
90
+ | Interface | Description | URL |
91
+ |---|---|---|
92
+ | **UI** | Multi Agents such as CrewAI or AutoGen | [https://docs.praison.ai/ui/ui](https://docs.praison.ai/ui/ui) |
93
+ | **Chat** | Chat with 100+ LLMs, single AI Agent | [https://docs.praison.ai/ui/chat](https://docs.praison.ai/ui/chat) |
94
+ | **Code** | Chat with entire Codebase, single AI Agent | [https://docs.praison.ai/ui/code](https://docs.praison.ai/ui/code) |
95
+
78
96
  ## Table of Contents
79
97
 
80
98
  - [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=TZUQmMCRG9qZY34GBdd8BJ8Aaaiac2AcNOr3N4y4OdM,6028
7
+ praisonai/deploy.py,sha256=H7UzS6kqr9MBhow4-Ah5rqOukKs2pBuBR8SkaCpcwDw,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=-iAYzhQ4zOdhYdM5VgKEFQmHIQSCiTazReJs_51mHfE,9445
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.52.dist-info/LICENSE,sha256=kqvFysVlnFxYOu0HxCe2HlmZmJtdmNGOxWRRkT9TsWc,1035
37
- praisonai-0.0.52.dist-info/METADATA,sha256=p5keIFdjB4LMPWOy47FzYdxsXAfpd9mOGWvceM3syqc,11262
38
- praisonai-0.0.52.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
39
- praisonai-0.0.52.dist-info/entry_points.txt,sha256=Qg41eW3A1-dvdV5tF7LqChfYof8Rihk2rN1fiEE3vnk,53
40
- praisonai-0.0.52.dist-info/RECORD,,
36
+ praisonai-0.0.54.dist-info/LICENSE,sha256=kqvFysVlnFxYOu0HxCe2HlmZmJtdmNGOxWRRkT9TsWc,1035
37
+ praisonai-0.0.54.dist-info/METADATA,sha256=gN0h13dvW6KvZD2wpuGZkoaO8TRcBpytB3_8t79Tg7U,12084
38
+ praisonai-0.0.54.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
39
+ praisonai-0.0.54.dist-info/entry_points.txt,sha256=Qg41eW3A1-dvdV5tF7LqChfYof8Rihk2rN1fiEE3vnk,53
40
+ praisonai-0.0.54.dist-info/RECORD,,