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.
- ultragpt-0.1.0/LICENSE.rst +22 -0
- ultragpt-0.1.0/MANIFEST.in +1 -0
- ultragpt-0.1.0/PKG-INFO +166 -0
- ultragpt-0.1.0/README.md +154 -0
- ultragpt-0.1.0/setup.cfg +4 -0
- ultragpt-0.1.0/setup.py +28 -0
- ultragpt-0.1.0/src/ultragpt/__init__.py +1 -0
- ultragpt-0.1.0/src/ultragpt/core.py +534 -0
- ultragpt-0.1.0/src/ultragpt/prompts.py +136 -0
- ultragpt-0.1.0/src/ultragpt/schemas.py +11 -0
- ultragpt-0.1.0/src/ultragpt.egg-info/PKG-INFO +166 -0
- ultragpt-0.1.0/src/ultragpt.egg-info/SOURCES.txt +13 -0
- ultragpt-0.1.0/src/ultragpt.egg-info/dependency_links.txt +1 -0
- ultragpt-0.1.0/src/ultragpt.egg-info/requires.txt +5 -0
- ultragpt-0.1.0/src/ultragpt.egg-info/top_level.txt +1 -0
|
@@ -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
|
ultragpt-0.1.0/PKG-INFO
ADDED
|
@@ -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>
|
ultragpt-0.1.0/README.md
ADDED
|
@@ -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>
|
ultragpt-0.1.0/setup.cfg
ADDED
ultragpt-0.1.0/setup.py
ADDED
|
@@ -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,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 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ultragpt
|