ultragpt 0.1.0__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.
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2024 Ranit Bhowmick
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software") to use the Software without restriction but is prohibited to copy, modify, merge, publish,
6
+ distribute, sublicense, and/or sell copies of the Software, and to
7
+ permit persons to whom the Software is furnished to do so, subject to
8
+ the following conditions:
9
+
10
+ 1. The above copyright notice and this permission notice shall be
11
+ included in all copies or substantial portions of the Software.
12
+
13
+ 2. Credit must be given to the original author, Ranit Bhowmick, in any
14
+ use, distribution, or publication of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1 @@
1
+ include README.md
@@ -0,0 +1,166 @@
1
+ Metadata-Version: 2.1
2
+ Name: ultragpt
3
+ Version: 0.1.0
4
+ Summary: UltraGPT: A modular library for advanced GPT-based reasoning and step pipelines
5
+ Home-page: https://github.com/Kawai-Senpai
6
+ Author: Ranit Bhowmick
7
+ Author-email: bhowmickranitking@duck.com
8
+ License: MIT
9
+ Requires-Python: >=3.6
10
+ Description-Content-Type: text/markdown
11
+ License-File: LICENSE.rst
12
+
13
+ # 🤖 UltraGPT
14
+
15
+ **A powerful and modular library for advanced GPT-based reasoning and step pipelines**
16
+
17
+ ## 🌟 Features
18
+
19
+ - **📝 Steps Pipeline:** Break down complex tasks into manageable steps
20
+ - Automatic step generation and processing
21
+ - Verification at each step
22
+ - Detailed progress tracking
23
+
24
+ - **🧠 Reasoning Pipeline:** Advanced reasoning capabilities
25
+ - Multi-iteration thought process
26
+ - Building upon previous reasoning
27
+ - Comprehensive analysis
28
+
29
+ - **🛠️ Tool Integration:**
30
+ - Web search capabilities
31
+ - Calculator functionality
32
+ - Extensible tool framework
33
+
34
+ ## 📦 Installation
35
+
36
+ ```bash
37
+ pip install git+https://github.com/Kawai-Senpai/UltraGPT.git
38
+ ```
39
+
40
+ ## 🚀 Quick Start
41
+
42
+ ```python
43
+ from ultragpt import UltraGPT
44
+
45
+ if __name__ == "__main__":
46
+ # Initialize UltraGPT
47
+ ultragpt = UltraGPT(
48
+ api_key="your-openai-api-key",
49
+ verbose=True
50
+ )
51
+
52
+ # Example chat session
53
+ final_output, tokens_used, details = ultragpt.chat([
54
+ {"role": "user", "content": "Write a story about an elephant."}
55
+ ])
56
+
57
+ print("Final Output:", final_output)
58
+ print("Total tokens used:", tokens_used)
59
+ ```
60
+
61
+ ## 📚 Advanced Usage
62
+
63
+ ### Customizing Pipeline Settings
64
+
65
+ ```python
66
+ ultragpt = UltraGPT(
67
+ api_key="your-openai-api-key",
68
+ model="gpt-4o", # Specify model
69
+ temperature=0.7, # Adjust creativity
70
+ reasoning_iterations=3, # Set reasoning depth
71
+ steps_pipeline=True,
72
+ reasoning_pipeline=True,
73
+ verbose=True
74
+ )
75
+ ```
76
+
77
+ ### Using Tools
78
+
79
+ ```python
80
+ ultragpt = UltraGPT(
81
+ api_key="your-openai-api-key",
82
+ tools=["web-search", "calculator"],
83
+ tools_config={
84
+ "web-search": {
85
+ "max_results": 1,
86
+ "model": "gpt-4o"
87
+ },
88
+ "calculator": {
89
+ "model": "gpt-4o"
90
+ }
91
+ }
92
+ )
93
+ ```
94
+
95
+ ## 🔧 Configuration Options
96
+
97
+ | Parameter | Type | Default | Description |
98
+ |-----------|------|---------|-------------|
99
+ | `api_key` | str | Required | Your OpenAI API key |
100
+ | `model` | str | "gpt-4o" | Model to use |
101
+ | `temperature` | float | 0.7 | Output randomness |
102
+ | `reasoning_iterations` | int | 3 | Number of reasoning steps |
103
+ | `tools` | list | [] | Enabled tools |
104
+ | `verbose` | bool | False | Enable detailed logging |
105
+
106
+ ## 🌐 Tool System
107
+
108
+ UltraGPT supports various tools to enhance its capabilities:
109
+
110
+ ### Web Search
111
+ - Performs intelligent web searches
112
+ - Summarizes findings
113
+ - Integrates results into responses
114
+
115
+ ### Calculator
116
+ - Handles mathematical operations
117
+ - Supports complex calculations
118
+ - Provides step-by-step solutions
119
+
120
+ ## 🔄 Pipeline System
121
+
122
+ ### Steps Pipeline
123
+ 1. Task Analysis
124
+ 2. Step Generation
125
+ 3. Step-by-Step Execution
126
+ 4. Progress Verification
127
+ 5. Final Compilation
128
+
129
+ ### Reasoning Pipeline
130
+ 1. Initial Analysis
131
+ 2. Multi-iteration Thinking
132
+ 3. Thought Development
133
+ 4. Conclusion Formation
134
+
135
+ ## 📋 Requirements
136
+
137
+ - Python 3.6+
138
+ - OpenAI API key
139
+ - Internet connection (for web tools)
140
+
141
+ ## 🤝 Contributing
142
+
143
+ Contributions are always welcome! Here's how you can help:
144
+
145
+ 1. Fork the repository
146
+ 2. Create a new branch (`git checkout -b feature/improvement`)
147
+ 3. Make changes
148
+ 4. Commit (`git commit -am 'Add new feature'`)
149
+ 5. Push (`git push origin feature/improvement`)
150
+ 6. Open a Pull Request
151
+
152
+ ## 📝 License
153
+
154
+ This project is MIT licensed - see the [LICENSE](LICENSE) file for details.
155
+
156
+ ## 👥 Author
157
+
158
+ **Ranit Bhowmick**
159
+ - Email: bhowmickranitking@duck.com
160
+ - GitHub: [@Kawai-Senpai](https://github.com/Kawai-Senpai)
161
+
162
+ ---
163
+
164
+ <div align="center">
165
+ Made with ❤️ by Ranit Bhowmick
166
+ </div>
@@ -0,0 +1,154 @@
1
+ # 🤖 UltraGPT
2
+
3
+ **A powerful and modular library for advanced GPT-based reasoning and step pipelines**
4
+
5
+ ## 🌟 Features
6
+
7
+ - **📝 Steps Pipeline:** Break down complex tasks into manageable steps
8
+ - Automatic step generation and processing
9
+ - Verification at each step
10
+ - Detailed progress tracking
11
+
12
+ - **🧠 Reasoning Pipeline:** Advanced reasoning capabilities
13
+ - Multi-iteration thought process
14
+ - Building upon previous reasoning
15
+ - Comprehensive analysis
16
+
17
+ - **🛠️ Tool Integration:**
18
+ - Web search capabilities
19
+ - Calculator functionality
20
+ - Extensible tool framework
21
+
22
+ ## 📦 Installation
23
+
24
+ ```bash
25
+ pip install git+https://github.com/Kawai-Senpai/UltraGPT.git
26
+ ```
27
+
28
+ ## 🚀 Quick Start
29
+
30
+ ```python
31
+ from ultragpt import UltraGPT
32
+
33
+ if __name__ == "__main__":
34
+ # Initialize UltraGPT
35
+ ultragpt = UltraGPT(
36
+ api_key="your-openai-api-key",
37
+ verbose=True
38
+ )
39
+
40
+ # Example chat session
41
+ final_output, tokens_used, details = ultragpt.chat([
42
+ {"role": "user", "content": "Write a story about an elephant."}
43
+ ])
44
+
45
+ print("Final Output:", final_output)
46
+ print("Total tokens used:", tokens_used)
47
+ ```
48
+
49
+ ## 📚 Advanced Usage
50
+
51
+ ### Customizing Pipeline Settings
52
+
53
+ ```python
54
+ ultragpt = UltraGPT(
55
+ api_key="your-openai-api-key",
56
+ model="gpt-4o", # Specify model
57
+ temperature=0.7, # Adjust creativity
58
+ reasoning_iterations=3, # Set reasoning depth
59
+ steps_pipeline=True,
60
+ reasoning_pipeline=True,
61
+ verbose=True
62
+ )
63
+ ```
64
+
65
+ ### Using Tools
66
+
67
+ ```python
68
+ ultragpt = UltraGPT(
69
+ api_key="your-openai-api-key",
70
+ tools=["web-search", "calculator"],
71
+ tools_config={
72
+ "web-search": {
73
+ "max_results": 1,
74
+ "model": "gpt-4o"
75
+ },
76
+ "calculator": {
77
+ "model": "gpt-4o"
78
+ }
79
+ }
80
+ )
81
+ ```
82
+
83
+ ## 🔧 Configuration Options
84
+
85
+ | Parameter | Type | Default | Description |
86
+ |-----------|------|---------|-------------|
87
+ | `api_key` | str | Required | Your OpenAI API key |
88
+ | `model` | str | "gpt-4o" | Model to use |
89
+ | `temperature` | float | 0.7 | Output randomness |
90
+ | `reasoning_iterations` | int | 3 | Number of reasoning steps |
91
+ | `tools` | list | [] | Enabled tools |
92
+ | `verbose` | bool | False | Enable detailed logging |
93
+
94
+ ## 🌐 Tool System
95
+
96
+ UltraGPT supports various tools to enhance its capabilities:
97
+
98
+ ### Web Search
99
+ - Performs intelligent web searches
100
+ - Summarizes findings
101
+ - Integrates results into responses
102
+
103
+ ### Calculator
104
+ - Handles mathematical operations
105
+ - Supports complex calculations
106
+ - Provides step-by-step solutions
107
+
108
+ ## 🔄 Pipeline System
109
+
110
+ ### Steps Pipeline
111
+ 1. Task Analysis
112
+ 2. Step Generation
113
+ 3. Step-by-Step Execution
114
+ 4. Progress Verification
115
+ 5. Final Compilation
116
+
117
+ ### Reasoning Pipeline
118
+ 1. Initial Analysis
119
+ 2. Multi-iteration Thinking
120
+ 3. Thought Development
121
+ 4. Conclusion Formation
122
+
123
+ ## 📋 Requirements
124
+
125
+ - Python 3.6+
126
+ - OpenAI API key
127
+ - Internet connection (for web tools)
128
+
129
+ ## 🤝 Contributing
130
+
131
+ Contributions are always welcome! Here's how you can help:
132
+
133
+ 1. Fork the repository
134
+ 2. Create a new branch (`git checkout -b feature/improvement`)
135
+ 3. Make changes
136
+ 4. Commit (`git commit -am 'Add new feature'`)
137
+ 5. Push (`git push origin feature/improvement`)
138
+ 6. Open a Pull Request
139
+
140
+ ## 📝 License
141
+
142
+ This project is MIT licensed - see the [LICENSE](LICENSE) file for details.
143
+
144
+ ## 👥 Author
145
+
146
+ **Ranit Bhowmick**
147
+ - Email: bhowmickranitking@duck.com
148
+ - GitHub: [@Kawai-Senpai](https://github.com/Kawai-Senpai)
149
+
150
+ ---
151
+
152
+ <div align="center">
153
+ Made with ❤️ by Ranit Bhowmick
154
+ </div>
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,28 @@
1
+ from setuptools import setup, find_packages
2
+ from pathlib import Path
3
+
4
+ # Get the long description from the README file
5
+ this_directory = Path(__file__).parent
6
+ long_description = (this_directory / "README.md").read_text(encoding='utf-8')
7
+
8
+ setup(
9
+ name='ultragpt',
10
+ version='0.1.0',
11
+ license="MIT",
12
+ author='Ranit Bhowmick',
13
+ author_email='bhowmickranitking@duck.com',
14
+ description='UltraGPT: A modular library for advanced GPT-based reasoning and step pipelines',
15
+ long_description=long_description,
16
+ long_description_content_type='text/markdown',
17
+ packages=find_packages('src'),
18
+ package_dir={'': 'src'},
19
+ url='https://github.com/Kawai-Senpai',
20
+ install_requires=[
21
+ 'pydantic',
22
+ 'openai',
23
+ 'ultraprint>=3.1.0',
24
+ 'tqdm',
25
+ 'click'
26
+ ],
27
+ python_requires='>=3.6',
28
+ )
@@ -0,0 +1 @@
1
+ from .core import UltraGPT
@@ -0,0 +1,534 @@
1
+ from openai import OpenAI
2
+ import ultraprint.common as p
3
+ from .prompts import (
4
+ generate_steps_prompt,
5
+ each_step_prompt, generate_reasoning_prompt,
6
+ generate_conclusion_prompt, combine_all_pipeline_prompts,
7
+ make_tool_analysis_prompt
8
+ )
9
+ from pydantic import BaseModel
10
+ from .schemas import Steps, Reasoning
11
+ from concurrent.futures import ThreadPoolExecutor, as_completed
12
+ from ultraprint.logging import logger
13
+ from .schemas import ToolAnalysisSchema
14
+
15
+ from .tools.web_search.main import _execute as web_search
16
+ from .tools.calculator.main import _execute as calculator
17
+
18
+ from itertools import islice
19
+
20
+ class UltraGPT:
21
+
22
+ def __init__(
23
+ self,
24
+ api_key: str,
25
+ model: str = None,
26
+ temperature: float = 0.7,
27
+ reasoning_iterations: int = 3,
28
+ steps_pipeline: bool = True,
29
+ reasoning_pipeline: bool = True,
30
+ verbose: bool = False,
31
+ logger_name: str = 'ultragpt',
32
+ logger_filename: str = 'debug/ultragpt.log',
33
+ log_extra_info: bool = False,
34
+ log_to_file: bool = False,
35
+ log_level: str = 'DEBUG',
36
+ tools: list = ["web-search", "calculator"],
37
+ tools_config: dict = {
38
+ "web-search": {
39
+ "max_results": 1,
40
+ "model": "gpt-4o"
41
+ },
42
+ "calculator": {
43
+ "model": "gpt-4o"
44
+ }
45
+ },
46
+ tool_batch_size: int = 3, # New parameter for controlling batch size
47
+ tool_max_workers: int = 10, # New parameter for controlling max workers
48
+ ):
49
+ """
50
+ Initialize the UltraGPT class.
51
+ Args:
52
+ api_key (str): The API key for accessing the OpenAI service.
53
+ model (str, optional): The model to use. Defaults to "gpt-4o".
54
+ temperature (float, optional): The temperature for the model's output. Defaults to 0.7.
55
+ reasoning_iterations (int, optional): The number of reasoning iterations. Defaults to 3.
56
+ steps_pipeline (bool, optional): Whether to use steps pipeline. Defaults to True.
57
+ reasoning_pipeline (bool, optional): Whether to use reasoning pipeline. Defaults to True.
58
+ verbose (bool, optional): Whether to enable verbose logging. Defaults to False.
59
+ logger_name (str, optional): The name of the logger. Defaults to 'ultragpt'.
60
+ logger_filename (str, optional): The filename for the logger. Defaults to 'debug/ultragpt.log'.
61
+ log_extra_info (bool, optional): Whether to include extra info in logs. Defaults to False.
62
+ log_to_file (bool, optional): Whether to log to a file. Defaults to False.
63
+ log_level (str, optional): The logging level. Defaults to 'DEBUG'.
64
+ tools (list, optional): The list of tools to enable. Defaults to ["web-search", "calculator"].
65
+ tools_config (dict, optional): The configuration for the tools. Defaults to predefined configurations.
66
+ tool_batch_size (int, optional): The batch size for tool processing. Defaults to 3.
67
+ tool_max_workers (int, optional): The maximum number of workers for tool processing. Defaults to 10.
68
+ Raises:
69
+ ValueError: If an invalid tool is provided.
70
+ """
71
+
72
+ # Create the OpenAI client using the provided API key
73
+ self.openai_client = OpenAI(api_key=api_key)
74
+ self.model = model or "gpt-4o"
75
+ self.temperature = temperature
76
+ self.reasoning_iterations = reasoning_iterations
77
+ self.steps_pipeline = steps_pipeline
78
+ self.reasoning_pipeline = reasoning_pipeline
79
+ self.tools = tools
80
+ self.tools_config = tools_config
81
+ self.tool_batch_size = tool_batch_size
82
+ self.tool_max_workers = tool_max_workers
83
+
84
+ supported_tools = ["web-search", "calculator"]
85
+ for tool in tools:
86
+ if tool not in supported_tools:
87
+ raise ValueError(f"Invalid tool: {tools}. Supported tools: {', '.join(supported_tools)}")
88
+
89
+ self.verbose = verbose
90
+ self.log = logger(
91
+ name=logger_name,
92
+ filename=logger_filename,
93
+ include_extra_info=log_extra_info,
94
+ write_to_file=log_to_file,
95
+ log_level=log_level,
96
+ log_to_console=False # Always disable console logging
97
+ )
98
+
99
+ self.log.info("Initializing UltraGPT with model: %s", self.model)
100
+ if self.verbose:
101
+ p.blue("="*50)
102
+ p.blue("Initializing UltraGPT")
103
+ p.cyan(f"Model: {self.model}")
104
+ if tools:
105
+ p.cyan(f"Tools enabled: {', '.join(tools)}")
106
+ p.blue("="*50)
107
+
108
+ def chat_with_openai_sync(self, messages: list):
109
+ """
110
+ Sends a synchronous chat request to OpenAI and processes the response.
111
+ Args:
112
+ messages (list): A list of message dictionaries to be sent to OpenAI.
113
+ Returns:
114
+ tuple: A tuple containing the response content (str) and the total number of tokens used (int).
115
+ Raises:
116
+ Exception: If the request to OpenAI fails.
117
+ Logs:
118
+ Debug: Logs the number of messages sent, the number of tokens in the response, and any errors encountered.
119
+ Verbose: Optionally logs detailed steps of the request and response process.
120
+ """
121
+ try:
122
+ self.log.debug("Sending request to OpenAI (msgs: %d)", len(messages))
123
+ if self.verbose:
124
+ p.cyan(f"\nOpenAI Request → Messages: {len(messages)}")
125
+ p.yellow("Checking for tool needs...")
126
+
127
+ tool_response = self.execute_tools(messages[-1]["content"], messages)
128
+ if tool_response:
129
+ if self.verbose:
130
+ p.cyan("\nAppending tool responses to message")
131
+ tool_response = "Tool Responses:\n" + tool_response
132
+ messages = self.append_message_to_system(messages, tool_response)
133
+ elif self.verbose:
134
+ p.dgray("\nNo tool responses needed")
135
+
136
+ response = self.openai_client.chat.completions.create(
137
+ model=self.model,
138
+ messages=messages,
139
+ stream=False,
140
+ temperature=self.temperature
141
+ )
142
+ content = response.choices[0].message.content.strip()
143
+ tokens = response.usage.total_tokens
144
+ self.log.debug("Response received (tokens: %d)", tokens)
145
+ if self.verbose:
146
+ p.green(f"✓ Response received ({tokens} tokens)")
147
+ return content, tokens
148
+ except Exception as e:
149
+ self.log.error("OpenAI sync request failed: %s", str(e))
150
+ if self.verbose:
151
+ p.red(f"✗ OpenAI request failed: {str(e)}")
152
+ raise e
153
+
154
+ def chat_with_model_parse(self, messages: list, schema=None):
155
+ """
156
+ Sends a chat message to the model for parsing and returns the parsed response.
157
+ Args:
158
+ messages (list): A list of message dictionaries to be sent to the model.
159
+ schema (optional): The schema to be used for parsing the response. Defaults to None.
160
+ Returns:
161
+ tuple: A tuple containing the parsed content and the total number of tokens used.
162
+ Raises:
163
+ Exception: If the parse request fails.
164
+ """
165
+ try:
166
+ self.log.debug("Sending parse request with schema: %s", schema)
167
+
168
+ tool_response = self.execute_tools(messages[-1]["content"], messages)
169
+ if tool_response:
170
+ tool_response = "Tool Responses:\n" + tool_response
171
+ messages = self.append_message_to_system(messages, tool_response)
172
+
173
+ response = self.openai_client.beta.chat.completions.parse(
174
+ model=self.model,
175
+ messages=messages,
176
+ response_format=schema,
177
+ temperature=self.temperature
178
+ )
179
+ content = response.choices[0].message.parsed
180
+ if isinstance(content, BaseModel):
181
+ content = content.model_dump(by_alias=True)
182
+ tokens = response.usage.total_tokens
183
+
184
+ self.log.debug("Parse response received (tokens: %d)", tokens)
185
+ return content, tokens
186
+ except Exception as e:
187
+ self.log.error("Parse request failed: %s", str(e))
188
+ raise e
189
+
190
+ def analyze_tool_need(self, message: str, available_tools: list) -> dict:
191
+ """Analyze if a tool is needed for the message"""
192
+ prompt = make_tool_analysis_prompt(message, available_tools)
193
+ response = self.chat_with_model_parse([{"role": "system", "content": prompt}], schema=ToolAnalysisSchema)
194
+ if not response:
195
+ return {"tools": []}
196
+ return response
197
+
198
+ #! Message Alteration ---------------------------------------------------
199
+ def turnoff_system_message(self, messages: list):
200
+ # set system message to user message
201
+ processed = []
202
+ for message in messages:
203
+ if message["role"] == "system" or message["role"] == "developer":
204
+ message["role"] = "user"
205
+ processed.append(message)
206
+ return processed
207
+
208
+ def add_message_before_system(self, messages: list, new_message: dict):
209
+ # add message before system message
210
+ processed = []
211
+ for message in messages:
212
+ if message["role"] == "system" or message["role"] == "developer":
213
+ processed.append(new_message)
214
+ processed.append(message)
215
+ return processed
216
+
217
+ def append_message_to_system(self, messages: list, new_message: dict):
218
+ # add message after system message
219
+ processed = []
220
+ for message in messages:
221
+ if message["role"] == "system" or message["role"] == "developer":
222
+ processed.append({
223
+ "role": message["role"],
224
+ "content": f"{message['content']}\n{new_message}"
225
+ })
226
+ else:
227
+ processed.append(message)
228
+ return processed
229
+
230
+ #! Pipelines -----------------------------------------------------------
231
+ def run_steps_pipeline(self, messages: list):
232
+ if self.verbose:
233
+ p.purple("➤ Starting Steps Pipeline")
234
+ else:
235
+ self.log.info("Starting steps pipeline")
236
+ total_tokens = 0
237
+
238
+ messages = self.turnoff_system_message(messages)
239
+ steps_generator_message = messages + [{"role": "system", "content": generate_steps_prompt()}]
240
+
241
+ steps_json, tokens = self.chat_with_model_parse(steps_generator_message, schema=Steps)
242
+ total_tokens += tokens
243
+ steps = steps_json.get("steps", [])
244
+ if self.verbose:
245
+ p.yellow(f"Generated {len(steps)} steps:")
246
+ for idx, step in enumerate(steps, 1):
247
+ p.lgray(f" {idx}. {step}")
248
+ else:
249
+ self.log.debug("Generated %d steps", len(steps))
250
+
251
+ memory = []
252
+
253
+ for idx, step in enumerate(steps, 1):
254
+ if self.verbose:
255
+ p.cyan(f"Processing step {idx}/{len(steps)}")
256
+ self.log.debug("Processing step %d/%d", idx, len(steps))
257
+ step_prompt = each_step_prompt(memory, step)
258
+ step_message = messages + [{"role": "system", "content": step_prompt}]
259
+ step_response, tokens = self.chat_with_openai_sync(step_message)
260
+ self.log.debug("Step %d response: %s...", idx, step_response[:100])
261
+ total_tokens += tokens
262
+ memory.append(
263
+ {
264
+ "step": step,
265
+ "answer": step_response
266
+ }
267
+ )
268
+
269
+ # Generate final conclusion
270
+ conclusion_prompt = generate_conclusion_prompt(memory)
271
+ conclusion_message = messages + [{"role": "system", "content": conclusion_prompt}]
272
+ conclusion, tokens = self.chat_with_openai_sync(conclusion_message)
273
+ total_tokens += tokens
274
+
275
+ if self.verbose:
276
+ p.green("✓ Steps pipeline completed")
277
+
278
+ return {
279
+ "steps": memory,
280
+ "conclusion": conclusion
281
+ }, total_tokens
282
+
283
+ def run_reasoning_pipeline(self, messages: list):
284
+ if self.verbose:
285
+ p.purple(f"➤ Starting Reasoning Pipeline ({self.reasoning_iterations} iterations)")
286
+ else:
287
+ self.log.info("Starting reasoning pipeline (%d iterations)", self.reasoning_iterations)
288
+ total_tokens = 0
289
+ all_thoughts = []
290
+ messages = self.turnoff_system_message(messages)
291
+
292
+ for iteration in range(self.reasoning_iterations):
293
+ if self.verbose:
294
+ p.yellow(f"Iteration {iteration + 1}/{self.reasoning_iterations}")
295
+ self.log.debug("Iteration %d/%d", iteration + 1, self.reasoning_iterations)
296
+ # Generate new thoughts based on all previous thoughts
297
+ reasoning_message = messages + [
298
+ {"role": "system", "content": generate_reasoning_prompt(all_thoughts)}
299
+ ]
300
+
301
+ reasoning_json, tokens = self.chat_with_model_parse(
302
+ reasoning_message,
303
+ schema=Reasoning
304
+ )
305
+ total_tokens += tokens
306
+
307
+ new_thoughts = reasoning_json.get("thoughts", [])
308
+ all_thoughts.extend(new_thoughts)
309
+
310
+ if self.verbose:
311
+ p.cyan(f"Generated {len(new_thoughts)} thoughts:")
312
+ for idx, thought in enumerate(new_thoughts, 1):
313
+ p.lgray(f" {idx}. {thought}")
314
+ else:
315
+ self.log.debug("Generated %d new thoughts", len(new_thoughts))
316
+
317
+ return all_thoughts, total_tokens
318
+
319
+ #! Main Chat Function ---------------------------------------------------
320
+ def chat(self, messages: list, schema=None):
321
+ """
322
+ Initiates a chat session with the given messages and optional schema.
323
+ Args:
324
+ messages (list): A list of message dictionaries to be processed.
325
+ schema (optional): A schema to parse the final output, defaults to None.
326
+ Returns:
327
+ tuple: A tuple containing the final output, total tokens used, and a details dictionary.
328
+ - final_output: The final response from the chat model.
329
+ - total_tokens (int): The total number of tokens used during the session.
330
+ - details_dict (dict): A dictionary with detailed information about the session, including:
331
+ - "reasoning": The output from the reasoning pipeline.
332
+ - "steps": The steps and conclusion from the steps pipeline.
333
+ - "reasoning_tokens": The number of tokens used by the reasoning pipeline.
334
+ - "steps_tokens": The number of tokens used by the steps pipeline.
335
+ - "final_tokens": The number of tokens used by the final chat model.
336
+ """
337
+ if self.verbose:
338
+ p.blue("="*50)
339
+ p.blue("Starting Chat Session")
340
+ p.cyan(f"Messages: {len(messages)}")
341
+ p.cyan(f"Schema: {schema}")
342
+ p.blue("="*50)
343
+ else:
344
+ self.log.info("Starting chat session")
345
+ reasoning_output = []
346
+ reasoning_tokens = 0
347
+ steps_output = {"steps": [], "conclusion": ""}
348
+ steps_tokens = 0
349
+
350
+ with ThreadPoolExecutor(max_workers=2) as executor:
351
+ futures = []
352
+
353
+ if self.reasoning_pipeline:
354
+ futures.append({
355
+ "type": "reasoning",
356
+ "future": executor.submit(self.run_reasoning_pipeline, messages)
357
+ })
358
+
359
+ if self.steps_pipeline:
360
+ futures.append({
361
+ "type": "steps",
362
+ "future": executor.submit(self.run_steps_pipeline, messages)
363
+ })
364
+
365
+ for future in futures:
366
+ if future["type"] == "reasoning":
367
+ reasoning_output, reasoning_tokens = future["future"].result()
368
+ elif future["type"] == "steps":
369
+ steps_output, steps_tokens = future["future"].result()
370
+
371
+ conclusion = steps_output.get("conclusion", "")
372
+ steps = steps_output.get("steps", [])
373
+
374
+ if self.reasoning_pipeline or self.steps_pipeline:
375
+ prompt = combine_all_pipeline_prompts(reasoning_output, conclusion)
376
+ messages = self.add_message_before_system(messages, {"role": "user", "content": prompt})
377
+
378
+ if schema:
379
+ final_output, tokens = self.chat_with_model_parse(messages, schema=schema)
380
+ else:
381
+ final_output, tokens = self.chat_with_openai_sync(messages)
382
+
383
+ if steps:
384
+ steps.append(conclusion)
385
+
386
+ details_dict = {
387
+ "reasoning": reasoning_output,
388
+ "steps": steps,
389
+ "reasoning_tokens": reasoning_tokens,
390
+ "steps_tokens": steps_tokens,
391
+ "final_tokens": tokens
392
+ }
393
+ total_tokens = reasoning_tokens + steps_tokens + tokens
394
+ if self.verbose:
395
+ p.blue("="*50)
396
+ p.green("✓ Chat Session Completed")
397
+ p.yellow("Tokens Used:")
398
+ p.lgray(f" - Reasoning: {reasoning_tokens}")
399
+ p.lgray(f" - Steps: {steps_tokens}")
400
+ p.lgray(f" - Final: {tokens}")
401
+ p.lgray(f" - Total: {total_tokens}")
402
+ p.blue("="*50)
403
+ else:
404
+ self.log.info("Chat completed (total tokens: %d)", total_tokens)
405
+ return final_output, total_tokens, details_dict
406
+
407
+ #! Tools ----------------------------------------------------------------
408
+ def execute_tool(self, tool: str, message: str, history: list) -> dict:
409
+ """Execute a single tool and return its response"""
410
+ try:
411
+ self.log.debug("Executing tool: %s", tool)
412
+ if self.verbose:
413
+ p.cyan(f"\nExecuting tool: {tool}")
414
+
415
+ if tool == "web-search":
416
+ response = web_search(
417
+ message,
418
+ history,
419
+ self.openai_client,
420
+ self.tools_config.get("web-search", {})
421
+ )
422
+ self.log.debug("Tool %s completed successfully", tool)
423
+ if self.verbose:
424
+ p.green(f"✓ {tool} returned response:")
425
+ p.lgray("-" * 40)
426
+ p.lgray(response)
427
+ p.lgray("-" * 40)
428
+ return {
429
+ "tool": tool,
430
+ "response": response
431
+ }
432
+ elif tool == "calculator":
433
+ response = calculator(
434
+ message,
435
+ history,
436
+ self.openai_client,
437
+ self.tools_config.get("calculator", {})
438
+ )
439
+ self.log.debug("Tool %s completed successfully", tool)
440
+ if self.verbose:
441
+ p.green(f"✓ {tool} returned response:")
442
+ p.lgray("-" * 40)
443
+ p.lgray(response)
444
+ p.lgray("-" * 40)
445
+ return {
446
+ "tool": tool,
447
+ "response": response
448
+ }
449
+ # Add other tool conditions here
450
+ if self.verbose:
451
+ p.yellow(f"! Tool {tool} not implemented")
452
+ return None
453
+ except Exception as e:
454
+ self.log.error("Tool %s failed: %s", tool, str(e))
455
+ if self.verbose:
456
+ p.red(f"\n✗ Tool {tool} failed: {str(e)}")
457
+ raise e
458
+
459
+ def batch_tools(self, tools: list, batch_size: int):
460
+ """Helper function to create batches of tools"""
461
+ iterator = iter(tools)
462
+ while batch := list(islice(iterator, batch_size)):
463
+ yield batch
464
+
465
+ def execute_tools(self, message: str, history: list) -> str:
466
+ """Execute tools and return formatted responses"""
467
+ if not self.tools:
468
+ return ""
469
+
470
+ total_tools = len(self.tools)
471
+ self.log.info("Executing %d tools in batches of %d", total_tools, self.tool_batch_size)
472
+ if self.verbose:
473
+ p.purple(f"\n➤ Executing {total_tools} tools in batches of {self.tool_batch_size}")
474
+ p.yellow("Query: " + message[:100] + "..." if len(message) > 100 else message)
475
+ p.lgray("-" * 40)
476
+
477
+ all_responses = []
478
+ success_count = 0
479
+
480
+ for batch_idx, tool_batch in enumerate(self.batch_tools(self.tools, self.tool_batch_size), 1):
481
+ if self.verbose:
482
+ p.yellow(f"\nProcessing batch {batch_idx}...")
483
+ batch_responses = []
484
+
485
+ with ThreadPoolExecutor(max_workers=min(len(tool_batch), self.tool_max_workers)) as executor:
486
+ future_to_tool = {
487
+ executor.submit(self.execute_tool, tool, message, history): tool
488
+ for tool in tool_batch
489
+ }
490
+
491
+ for future in as_completed(future_to_tool):
492
+ tool = future_to_tool[future]
493
+ try:
494
+ result = future.result()
495
+ if result:
496
+ batch_responses.append(result)
497
+ success_count += 1
498
+ except Exception as e:
499
+ if self.verbose:
500
+ p.red(f"✗ Tool {tool} failed: {str(e)}")
501
+ else:
502
+ self.log.error("Tool %s failed: %s", tool, str(e))
503
+
504
+ all_responses.extend(batch_responses)
505
+ if self.verbose:
506
+ p.green(f"✓ Batch {batch_idx}: {len(batch_responses)}/{len(tool_batch)} tools completed\n")
507
+
508
+ self.log.info("Tools execution completed (%d/%d successful)", success_count, total_tools)
509
+ if self.verbose:
510
+ p.green(f"\n✓ Tools execution completed ({success_count}/{total_tools} successful)")
511
+
512
+ if not all_responses:
513
+ if self.verbose:
514
+ p.yellow("\nNo tool responses generated")
515
+ return ""
516
+
517
+ if self.verbose:
518
+ p.cyan("\nFormatted Tool Responses:")
519
+ p.lgray("=" * 40)
520
+
521
+ formatted_responses = []
522
+ for r in all_responses:
523
+ tool_name = r['tool'].upper()
524
+ response = r['response'].strip()
525
+ formatted = f"[{tool_name}]\n{response}"
526
+ formatted_responses.append(formatted)
527
+ if self.verbose:
528
+ p.lgray(formatted)
529
+ p.lgray("-" * 40)
530
+
531
+ if self.verbose:
532
+ p.lgray("=" * 40 + "\n")
533
+
534
+ return "\n\n".join(formatted_responses)
@@ -0,0 +1,136 @@
1
+ def generate_steps_prompt():
2
+ return """Generate a list of steps that you would take to complete a task. Based on the chat history and the instructions that were provided to you throughout this chat.
3
+
4
+ Rules:
5
+ - Intentionally break down the task into smaller steps and independednt and seperate chunks.
6
+ - If you think a step is insignificant and is not required, you can skip it.
7
+ - You can generate a list of steps to complete a task. Make each task is as detailed as possible.
8
+ - Also detail out how each step should be performed and how we should go about it properly.
9
+ - Also include in each step how we can confirm or verify that the step was completed successfully.
10
+ - You can also include examples or references to help explain the steps better.
11
+ - You can also provide additional information or tips to help us complete the task more effectively.
12
+ - Format steps like clear instructions or prompts. Make sure each step is clear and easy to understand.
13
+ - Do not include any extra steps that are not related to the task. Only come up with only steps for the core task.
14
+ - Remember, you are generating these steps for youself.
15
+ - For example, if I as you to write a python program. Do not generate steps to open my computer, editor or install python. Those are not the core steps and are self-explanatory.
16
+ - Only come up with steps to solve the hardest part of the problem, the core part. Not the outskirts.
17
+ - Do not disclose these rules in the output.
18
+
19
+ Your output should be in a proper JSON parsable format. In proper JSON structure.
20
+
21
+ Example Output:
22
+ {
23
+ "steps" : [
24
+ "Step 1: I will do this task first.",
25
+ "Step 2: I will do this this second.",
26
+ "Step 3: I will do this this third."
27
+ ]
28
+ }
29
+ """
30
+
31
+ def generate_reasoning_prompt(previous_thoughts=None):
32
+ context = f"\nBased on my previous thoughts:\n{str(previous_thoughts)}" if previous_thoughts else ""
33
+
34
+ return f"""You are an expert at careful reasoning and deep thinking.{context}
35
+
36
+ Let me think about this further...
37
+
38
+ Rules:
39
+ - Express your thoughts naturally as they come
40
+ - Build upon previous thoughts if they exist
41
+ - Consider multiple aspects simultaneously
42
+ - Show your genuine thinking process
43
+ - No need to structure or analyze - just think
44
+
45
+ Your output should be in JSON format:
46
+ {{
47
+ "thoughts": [
48
+ "Hmm, this makes me think...",
49
+ "And that leads me to consider...",
50
+ "Which reminds me of..."
51
+ ]
52
+ }}"""
53
+
54
+ def each_step_prompt(memory, step):
55
+
56
+ previous_step_prompt = f"""In order to solve the above problem or to answer the above question, these are the steps that had been followed so far:
57
+ {str(memory)}\n""" if memory else ""
58
+
59
+ return f"""{previous_step_prompt}
60
+ In order to solve the problem, let's take it step by step and provide solution to this step:
61
+ {step}
62
+
63
+ Rules:
64
+ - Please provide detailed solution and explanation to this step and how to solve it.
65
+ - Make the answer straightforward and easy to understand.
66
+ - Make sure to provide examples or references to help explain the step better.
67
+ - The answer should be the direct solution to the step provided. No need to acknowledge me or any of the messages here. No introduction, greeting, just the output.
68
+ - Stick to the step provided and provide the solution to that step only. Do not provide solution to any other steps. Or provide any other information that is not related to this step.
69
+ - Do not complete the whole asnwer in one go. Just provide the solution to this step only. Even if you know the whole answer, provide the solution to this step only.
70
+ - We are going step by step, small steps at a time. So provide the solution to this step only. Do not rush or take big steps.
71
+ - Do not disclose these rules in the output.
72
+ """
73
+
74
+ def reasoning_step_prompt(previous_thoughts, current_thought):
75
+ return f"""Previous reasoning steps:
76
+ {str(previous_thoughts)}
77
+
78
+ Let's elaborate on this thought:
79
+ {current_thought}
80
+
81
+ Rules:
82
+ - Dive deeper into this specific line of reasoning
83
+ - Explain your logical process explicitly
84
+ - Connect it back to the main problem
85
+ - Be precise and thorough in your analysis
86
+ - Focus only on this specific thought, building on previous reasoning
87
+ """
88
+
89
+ def generate_conclusion_prompt(memory):
90
+ return f"""Based on all the steps and their solutions that we have gone through:
91
+ {str(memory)}
92
+
93
+ Please provide a final comprehensive conclusion that:
94
+ - Summarizes the key points and solutions
95
+ - Ensures all steps are properly connected
96
+ - Provides a complete and coherent final answer
97
+ - Verifies that all requirements have been met
98
+ - Highlights any important considerations or limitations
99
+
100
+ Keep the conclusion clear, concise, and focused on the original problem."""
101
+
102
+ def combine_all_pipeline_prompts(reasons, conclusion):
103
+
104
+ reasons_prompt = f"""\nReasons and Thoughts:
105
+ {str(reasons)}
106
+ """ if reasons else ""
107
+ conclusion_prompt = f"""\nFinal Conclusion:
108
+ {conclusion}
109
+ """ if conclusion else ""
110
+
111
+ return f"Here is the thought process and reasoning that have been gone through, so far. This might help you to come up with a proper answer:" + reasons_prompt + conclusion_prompt
112
+
113
+ def make_tool_analysis_prompt(message: str, available_tools: list) -> str:
114
+ """Format prompt for tool analysis"""
115
+ tools_str = str(available_tools)
116
+ example = """Your output should look like this (example):
117
+ {
118
+ "tools": ["web-search", "tool_name2"]
119
+ }"""
120
+ return f"""This is a user message. Analyze if this user message requires any tools. Available tools: {tools_str}
121
+
122
+ Message: "{message}"
123
+
124
+ {example}
125
+
126
+ Rules:
127
+ - Only include the tool names under "tools" that are needed to respond to the message.
128
+ - If no tools are needed, return empty array. You can use multiple tools if needed.
129
+ - Only use tools that are available to you. Do not use any other tools.
130
+ - It is not necessary to use a tool for every message. Only use a tool if it is truly needed.
131
+ - Your output should be in parsable proper JSON format like the given example.
132
+ """
133
+
134
+ def format_tool_response(tool_response: str) -> str:
135
+ """Format tool response for inclusion in context"""
136
+ return f"\n\nTool response: {tool_response}" if tool_response else ""
@@ -0,0 +1,11 @@
1
+ from pydantic import BaseModel
2
+ from typing import List
3
+
4
+ class Steps(BaseModel):
5
+ steps: List[str]
6
+
7
+ class Reasoning(BaseModel):
8
+ thoughts: List[str]
9
+
10
+ class ToolAnalysisSchema(BaseModel):
11
+ tools: List[str]
@@ -0,0 +1,166 @@
1
+ Metadata-Version: 2.1
2
+ Name: ultragpt
3
+ Version: 0.1.0
4
+ Summary: UltraGPT: A modular library for advanced GPT-based reasoning and step pipelines
5
+ Home-page: https://github.com/Kawai-Senpai
6
+ Author: Ranit Bhowmick
7
+ Author-email: bhowmickranitking@duck.com
8
+ License: MIT
9
+ Requires-Python: >=3.6
10
+ Description-Content-Type: text/markdown
11
+ License-File: LICENSE.rst
12
+
13
+ # 🤖 UltraGPT
14
+
15
+ **A powerful and modular library for advanced GPT-based reasoning and step pipelines**
16
+
17
+ ## 🌟 Features
18
+
19
+ - **📝 Steps Pipeline:** Break down complex tasks into manageable steps
20
+ - Automatic step generation and processing
21
+ - Verification at each step
22
+ - Detailed progress tracking
23
+
24
+ - **🧠 Reasoning Pipeline:** Advanced reasoning capabilities
25
+ - Multi-iteration thought process
26
+ - Building upon previous reasoning
27
+ - Comprehensive analysis
28
+
29
+ - **🛠️ Tool Integration:**
30
+ - Web search capabilities
31
+ - Calculator functionality
32
+ - Extensible tool framework
33
+
34
+ ## 📦 Installation
35
+
36
+ ```bash
37
+ pip install git+https://github.com/Kawai-Senpai/UltraGPT.git
38
+ ```
39
+
40
+ ## 🚀 Quick Start
41
+
42
+ ```python
43
+ from ultragpt import UltraGPT
44
+
45
+ if __name__ == "__main__":
46
+ # Initialize UltraGPT
47
+ ultragpt = UltraGPT(
48
+ api_key="your-openai-api-key",
49
+ verbose=True
50
+ )
51
+
52
+ # Example chat session
53
+ final_output, tokens_used, details = ultragpt.chat([
54
+ {"role": "user", "content": "Write a story about an elephant."}
55
+ ])
56
+
57
+ print("Final Output:", final_output)
58
+ print("Total tokens used:", tokens_used)
59
+ ```
60
+
61
+ ## 📚 Advanced Usage
62
+
63
+ ### Customizing Pipeline Settings
64
+
65
+ ```python
66
+ ultragpt = UltraGPT(
67
+ api_key="your-openai-api-key",
68
+ model="gpt-4o", # Specify model
69
+ temperature=0.7, # Adjust creativity
70
+ reasoning_iterations=3, # Set reasoning depth
71
+ steps_pipeline=True,
72
+ reasoning_pipeline=True,
73
+ verbose=True
74
+ )
75
+ ```
76
+
77
+ ### Using Tools
78
+
79
+ ```python
80
+ ultragpt = UltraGPT(
81
+ api_key="your-openai-api-key",
82
+ tools=["web-search", "calculator"],
83
+ tools_config={
84
+ "web-search": {
85
+ "max_results": 1,
86
+ "model": "gpt-4o"
87
+ },
88
+ "calculator": {
89
+ "model": "gpt-4o"
90
+ }
91
+ }
92
+ )
93
+ ```
94
+
95
+ ## 🔧 Configuration Options
96
+
97
+ | Parameter | Type | Default | Description |
98
+ |-----------|------|---------|-------------|
99
+ | `api_key` | str | Required | Your OpenAI API key |
100
+ | `model` | str | "gpt-4o" | Model to use |
101
+ | `temperature` | float | 0.7 | Output randomness |
102
+ | `reasoning_iterations` | int | 3 | Number of reasoning steps |
103
+ | `tools` | list | [] | Enabled tools |
104
+ | `verbose` | bool | False | Enable detailed logging |
105
+
106
+ ## 🌐 Tool System
107
+
108
+ UltraGPT supports various tools to enhance its capabilities:
109
+
110
+ ### Web Search
111
+ - Performs intelligent web searches
112
+ - Summarizes findings
113
+ - Integrates results into responses
114
+
115
+ ### Calculator
116
+ - Handles mathematical operations
117
+ - Supports complex calculations
118
+ - Provides step-by-step solutions
119
+
120
+ ## 🔄 Pipeline System
121
+
122
+ ### Steps Pipeline
123
+ 1. Task Analysis
124
+ 2. Step Generation
125
+ 3. Step-by-Step Execution
126
+ 4. Progress Verification
127
+ 5. Final Compilation
128
+
129
+ ### Reasoning Pipeline
130
+ 1. Initial Analysis
131
+ 2. Multi-iteration Thinking
132
+ 3. Thought Development
133
+ 4. Conclusion Formation
134
+
135
+ ## 📋 Requirements
136
+
137
+ - Python 3.6+
138
+ - OpenAI API key
139
+ - Internet connection (for web tools)
140
+
141
+ ## 🤝 Contributing
142
+
143
+ Contributions are always welcome! Here's how you can help:
144
+
145
+ 1. Fork the repository
146
+ 2. Create a new branch (`git checkout -b feature/improvement`)
147
+ 3. Make changes
148
+ 4. Commit (`git commit -am 'Add new feature'`)
149
+ 5. Push (`git push origin feature/improvement`)
150
+ 6. Open a Pull Request
151
+
152
+ ## 📝 License
153
+
154
+ This project is MIT licensed - see the [LICENSE](LICENSE) file for details.
155
+
156
+ ## 👥 Author
157
+
158
+ **Ranit Bhowmick**
159
+ - Email: bhowmickranitking@duck.com
160
+ - GitHub: [@Kawai-Senpai](https://github.com/Kawai-Senpai)
161
+
162
+ ---
163
+
164
+ <div align="center">
165
+ Made with ❤️ by Ranit Bhowmick
166
+ </div>
@@ -0,0 +1,13 @@
1
+ LICENSE.rst
2
+ MANIFEST.in
3
+ README.md
4
+ setup.py
5
+ src/ultragpt/__init__.py
6
+ src/ultragpt/core.py
7
+ src/ultragpt/prompts.py
8
+ src/ultragpt/schemas.py
9
+ src/ultragpt.egg-info/PKG-INFO
10
+ src/ultragpt.egg-info/SOURCES.txt
11
+ src/ultragpt.egg-info/dependency_links.txt
12
+ src/ultragpt.egg-info/requires.txt
13
+ src/ultragpt.egg-info/top_level.txt
@@ -0,0 +1,5 @@
1
+ pydantic
2
+ openai
3
+ ultraprint>=3.1.0
4
+ tqdm
5
+ click
@@ -0,0 +1 @@
1
+ ultragpt