ngpt 3.3.0__tar.gz → 3.4.1__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.
Files changed (62) hide show
  1. {ngpt-3.3.0 → ngpt-3.4.1}/.github/workflows/aur-publish.yml +12 -1
  2. {ngpt-3.3.0 → ngpt-3.4.1}/PKG-INFO +1 -1
  3. ngpt-3.4.1/PKGBUILD +66 -0
  4. {ngpt-3.3.0 → ngpt-3.4.1}/ngpt/cli/args.py +35 -10
  5. {ngpt-3.3.0 → ngpt-3.4.1}/ngpt/utils/cli_config.py +1 -1
  6. {ngpt-3.3.0 → ngpt-3.4.1}/ngpt/utils/web_search.py +26 -5
  7. {ngpt-3.3.0 → ngpt-3.4.1}/pyproject.toml +1 -1
  8. {ngpt-3.3.0 → ngpt-3.4.1}/uv.lock +1 -1
  9. ngpt-3.3.0/PKGBUILD +0 -24
  10. {ngpt-3.3.0 → ngpt-3.4.1}/.github/workflows/python-publish.yml +0 -0
  11. {ngpt-3.3.0 → ngpt-3.4.1}/.gitignore +0 -0
  12. {ngpt-3.3.0 → ngpt-3.4.1}/.python-version +0 -0
  13. {ngpt-3.3.0 → ngpt-3.4.1}/COMMIT_GUIDELINES.md +0 -0
  14. {ngpt-3.3.0 → ngpt-3.4.1}/CONTRIBUTING.md +0 -0
  15. {ngpt-3.3.0 → ngpt-3.4.1}/LICENSE +0 -0
  16. {ngpt-3.3.0 → ngpt-3.4.1}/README.md +0 -0
  17. {ngpt-3.3.0 → ngpt-3.4.1}/docs/CONTRIBUTING.md +0 -0
  18. {ngpt-3.3.0 → ngpt-3.4.1}/docs/LICENSE.md +0 -0
  19. {ngpt-3.3.0 → ngpt-3.4.1}/docs/README.md +0 -0
  20. {ngpt-3.3.0 → ngpt-3.4.1}/docs/_config.yml +0 -0
  21. {ngpt-3.3.0 → ngpt-3.4.1}/docs/api/README.md +0 -0
  22. {ngpt-3.3.0 → ngpt-3.4.1}/docs/api/cli.md +0 -0
  23. {ngpt-3.3.0 → ngpt-3.4.1}/docs/api/cli_config.md +0 -0
  24. {ngpt-3.3.0 → ngpt-3.4.1}/docs/api/client.md +0 -0
  25. {ngpt-3.3.0 → ngpt-3.4.1}/docs/api/config.md +0 -0
  26. {ngpt-3.3.0 → ngpt-3.4.1}/docs/api/logging.md +0 -0
  27. {ngpt-3.3.0 → ngpt-3.4.1}/docs/assets/css/style.scss +0 -0
  28. {ngpt-3.3.0 → ngpt-3.4.1}/docs/configuration.md +0 -0
  29. {ngpt-3.3.0 → ngpt-3.4.1}/docs/examples/README.md +0 -0
  30. {ngpt-3.3.0 → ngpt-3.4.1}/docs/examples/advanced.md +0 -0
  31. {ngpt-3.3.0 → ngpt-3.4.1}/docs/examples/basic.md +0 -0
  32. {ngpt-3.3.0 → ngpt-3.4.1}/docs/examples/cli_components.md +0 -0
  33. {ngpt-3.3.0 → ngpt-3.4.1}/docs/examples/integrations.md +0 -0
  34. {ngpt-3.3.0 → ngpt-3.4.1}/docs/installation.md +0 -0
  35. {ngpt-3.3.0 → ngpt-3.4.1}/docs/overview.md +0 -0
  36. {ngpt-3.3.0 → ngpt-3.4.1}/docs/usage/README.md +0 -0
  37. {ngpt-3.3.0 → ngpt-3.4.1}/docs/usage/cli_config.md +0 -0
  38. {ngpt-3.3.0 → ngpt-3.4.1}/docs/usage/cli_framework.md +0 -0
  39. {ngpt-3.3.0 → ngpt-3.4.1}/docs/usage/cli_usage.md +0 -0
  40. {ngpt-3.3.0 → ngpt-3.4.1}/docs/usage/gitcommsg.md +0 -0
  41. {ngpt-3.3.0 → ngpt-3.4.1}/docs/usage/library_usage.md +0 -0
  42. {ngpt-3.3.0 → ngpt-3.4.1}/ngpt/__init__.py +0 -0
  43. {ngpt-3.3.0 → ngpt-3.4.1}/ngpt/__main__.py +0 -0
  44. {ngpt-3.3.0 → ngpt-3.4.1}/ngpt/cli/__init__.py +0 -0
  45. {ngpt-3.3.0 → ngpt-3.4.1}/ngpt/cli/config_manager.py +0 -0
  46. {ngpt-3.3.0 → ngpt-3.4.1}/ngpt/cli/formatters.py +0 -0
  47. {ngpt-3.3.0 → ngpt-3.4.1}/ngpt/cli/interactive.py +0 -0
  48. {ngpt-3.3.0 → ngpt-3.4.1}/ngpt/cli/main.py +0 -0
  49. {ngpt-3.3.0 → ngpt-3.4.1}/ngpt/cli/modes/__init__.py +0 -0
  50. {ngpt-3.3.0 → ngpt-3.4.1}/ngpt/cli/modes/chat.py +0 -0
  51. {ngpt-3.3.0 → ngpt-3.4.1}/ngpt/cli/modes/code.py +0 -0
  52. {ngpt-3.3.0 → ngpt-3.4.1}/ngpt/cli/modes/gitcommsg.py +0 -0
  53. {ngpt-3.3.0 → ngpt-3.4.1}/ngpt/cli/modes/rewrite.py +0 -0
  54. {ngpt-3.3.0 → ngpt-3.4.1}/ngpt/cli/modes/shell.py +0 -0
  55. {ngpt-3.3.0 → ngpt-3.4.1}/ngpt/cli/modes/text.py +0 -0
  56. {ngpt-3.3.0 → ngpt-3.4.1}/ngpt/cli/renderers.py +0 -0
  57. {ngpt-3.3.0 → ngpt-3.4.1}/ngpt/cli/ui.py +0 -0
  58. {ngpt-3.3.0 → ngpt-3.4.1}/ngpt/client.py +0 -0
  59. {ngpt-3.3.0 → ngpt-3.4.1}/ngpt/utils/__init__.py +0 -0
  60. {ngpt-3.3.0 → ngpt-3.4.1}/ngpt/utils/config.py +0 -0
  61. {ngpt-3.3.0 → ngpt-3.4.1}/ngpt/utils/log.py +0 -0
  62. {ngpt-3.3.0 → ngpt-3.4.1}/wiki.md +0 -0
@@ -10,6 +10,10 @@ on:
10
10
  description: 'Package version (leave empty to use current pyproject.toml version)'
11
11
  required: false
12
12
  default: ''
13
+ pkgrel:
14
+ description: 'Package release number (leave empty to keep current pkgrel)'
15
+ required: false
16
+ default: ''
13
17
 
14
18
  jobs:
15
19
  publish-aur:
@@ -40,6 +44,13 @@ jobs:
40
44
 
41
45
  # Update version in PKGBUILD
42
46
  sed -i "s/^pkgver=.*/pkgver=$VERSION/" PKGBUILD
47
+
48
+ # Update pkgrel if provided
49
+ if [[ "${{ github.event_name }}" == "workflow_dispatch" && -n "${{ github.event.inputs.pkgrel }}" ]]; then
50
+ PKGREL="${{ github.event.inputs.pkgrel }}"
51
+ echo "Updating package release to: $PKGREL"
52
+ sed -i "s/^pkgrel=.*/pkgrel=$PKGREL/" PKGBUILD
53
+ fi
43
54
 
44
55
  - name: Publish AUR package
45
56
  uses: KSXGitHub/github-actions-deploy-aur@v4.1.1
@@ -52,7 +63,7 @@ jobs:
52
63
  commit_username: ${{ secrets.AUR_USERNAME }}
53
64
  commit_email: ${{ secrets.AUR_EMAIL }}
54
65
  ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
55
- commit_message: "${{ github.event_name == 'workflow_dispatch' && 'Manual update to version' || 'Update to version' }} ${{ steps.extract_version.outputs.version }}"
66
+ commit_message: "${{ github.event_name == 'workflow_dispatch' && 'Manual update to version' || 'Update to version' }} ${{ steps.extract_version.outputs.version }}${{ github.event.inputs.pkgrel && format(' with pkgrel={0}', github.event.inputs.pkgrel) || '' }}"
56
67
  ssh_keyscan_types: rsa,ecdsa,ed25519
57
68
  updpkgsums: true # Let the action update checksums automatically
58
69
  test: false # Disable testing since the environment doesn't have necessary tools
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ngpt
3
- Version: 3.3.0
3
+ Version: 3.4.1
4
4
  Summary: Swiss army knife for LLMs: powerful CLI, interactive chatbot, and flexible Python library. Works with OpenAI, Ollama, Groq, Claude, Gemini, and any OpenAI-compatible API.
5
5
  Project-URL: Homepage, https://github.com/nazdridoy/ngpt
6
6
  Project-URL: Repository, https://github.com/nazdridoy/ngpt
ngpt-3.4.1/PKGBUILD ADDED
@@ -0,0 +1,66 @@
1
+ # Maintainer: nazdridoy <nazdridoy399@gmail.com>
2
+ pkgname=ngpt
3
+ pkgver=0.0.0 # Automatically updated by CI on release
4
+ pkgrel=1
5
+ pkgdesc="Swiss army knife for LLMs: powerful CLI, interactive chatbot, and flexible Python library. Works with OpenAI, Ollama, Groq, Claude, Gemini, and any OpenAI-compatible API."
6
+ arch=('any')
7
+ url="https://github.com/nazdridoy/ngpt"
8
+ license=('MIT')
9
+ depends=('python' 'python-requests>=2.31.0' 'python-rich>=10.0.0' 'python-prompt_toolkit>=3.0.0' 'python-pyperclip>=1.8.0')
10
+ makedepends=('python-build' 'python-installer' 'python-wheel' 'python-hatchling' 'python-pip')
11
+ options=(!debug)
12
+ source=("${pkgname}-${pkgver}.tar.gz::https://github.com/nazdridoy/${pkgname}/archive/v${pkgver}.tar.gz")
13
+ sha256sums=('SKIP') # Automatically updated by CI on release
14
+
15
+ prepare() {
16
+ cd "$pkgname-$pkgver"
17
+ # Install dependencies using pip since they're not in main Arch repos
18
+ mkdir -p vendor
19
+ pip install --target=vendor duckduckgo-search>=3.0.0 trafilatura>=1.6.0
20
+
21
+ # Add an __init__.py file to modify sys.path to include our bundled dependencies
22
+ cat > ngpt/bundled_deps.py << 'EOF'
23
+ import os
24
+ import sys
25
+
26
+ def setup_bundled_deps():
27
+ # Add the bundled dependencies to the path
28
+ bundled_path = os.path.join(os.path.dirname(__file__), 'vendor')
29
+ if os.path.exists(bundled_path) and bundled_path not in sys.path:
30
+ sys.path.insert(0, bundled_path)
31
+ EOF
32
+
33
+ # Modify __init__.py to include the bundled deps setup
34
+ # First check if it already imports bundled_deps
35
+ if ! grep -q "bundled_deps" ngpt/__init__.py; then
36
+ # Make a backup of the original file
37
+ cp ngpt/__init__.py ngpt/__init__.py.bak
38
+
39
+ # Add the import at the top of the file
40
+ echo 'from .bundled_deps import setup_bundled_deps' > ngpt/__init__.py.new
41
+ echo 'setup_bundled_deps()' >> ngpt/__init__.py.new
42
+ cat ngpt/__init__.py.bak >> ngpt/__init__.py.new
43
+ mv ngpt/__init__.py.new ngpt/__init__.py
44
+ fi
45
+ }
46
+
47
+ build() {
48
+ cd "$pkgname-$pkgver"
49
+ python -m build --wheel --no-isolation
50
+ }
51
+
52
+ package() {
53
+ cd "$pkgname-$pkgver"
54
+ python -m installer --destdir="$pkgdir" dist/*.whl
55
+
56
+ # Install the bundled dependencies in the ngpt package directory
57
+ if [ -d "vendor" ]; then
58
+ # Get the ngpt package directory
59
+ ngpt_pkg_dir=$(python -c "import site; print(site.getsitepackages()[0])")/ngpt
60
+ mkdir -p "$pkgdir$ngpt_pkg_dir/vendor"
61
+ cp -r vendor/* "$pkgdir$ngpt_pkg_dir/vendor/"
62
+ fi
63
+
64
+ install -Dm644 LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
65
+ install -Dm644 README.md "$pkgdir/usr/share/doc/$pkgname/README.md"
66
+ }
@@ -79,14 +79,19 @@ def setup_argument_parser():
79
79
  help='Set filepath to log conversation to, or create a temporary log file if no path provided')
80
80
  global_group.add_argument('--preprompt',
81
81
  help='Set custom system prompt to control AI behavior')
82
- global_group.add_argument('--no-stream', action='store_true',
83
- help='Return the whole response without streaming')
84
- global_group.add_argument('--prettify', action='store_const', const='auto',
85
- help='Render markdown responses and code with syntax highlighting and formatting')
86
- global_group.add_argument('--stream-prettify', action='store_true',
87
- help='Enable streaming with markdown rendering (automatically uses Rich renderer)')
82
+
83
+ # Output display options (mutually exclusive group)
84
+ output_group = parser.add_argument_group('Output Display Options (mutually exclusive)')
85
+ output_exclusive_group = output_group.add_mutually_exclusive_group()
86
+ output_exclusive_group.add_argument('--no-stream', action='store_true',
87
+ help='Return the whole response without streaming or formatting')
88
+ output_exclusive_group.add_argument('--prettify', action='store_const', const='auto',
89
+ help='Render complete response with markdown and code formatting (non-streaming)')
90
+ output_exclusive_group.add_argument('--stream-prettify', action='store_true', default=True,
91
+ help='Stream response with real-time markdown rendering (default)')
92
+
88
93
  global_group.add_argument('--renderer', choices=['auto', 'rich', 'glow'], default='auto',
89
- help='Select which markdown renderer to use with --prettify (auto, rich, or glow)')
94
+ help='Select which markdown renderer to use with --prettify or --stream-prettify (auto, rich, or glow)')
90
95
 
91
96
  # GitCommit message options
92
97
  gitcommsg_group = parser.add_argument_group('Git Commit Message Options')
@@ -134,9 +139,29 @@ def validate_args(args):
134
139
  if args.all and not args.show_config:
135
140
  raise ValueError("--all can only be used with --show-config")
136
141
 
137
- # Check if --prettify is used with --stream-prettify (conflict)
138
- if args.prettify and args.stream_prettify:
139
- raise ValueError("--prettify and --stream-prettify cannot be used together. Choose one option.")
142
+ # These three options are mutually exclusive rendering modes
143
+ provided_modes = []
144
+ if '--no-stream' in sys.argv:
145
+ provided_modes.append('--no-stream')
146
+ if '--prettify' in sys.argv:
147
+ provided_modes.append('--prettify')
148
+ if '--stream-prettify' in sys.argv:
149
+ provided_modes.append('--stream-prettify')
150
+
151
+ # If more than one rendering mode explicitly provided, raise error
152
+ if len(provided_modes) > 1:
153
+ raise ValueError(f"The options {', '.join(provided_modes)} cannot be used together. These options are mutually exclusive.")
154
+
155
+ # Handle the conflict between default stream-prettify and explicitly provided options
156
+ if args.no_stream:
157
+ args.stream_prettify = False
158
+ args.prettify = False
159
+ elif args.prettify:
160
+ args.stream_prettify = False
161
+ args.no_stream = False
162
+ elif args.stream_prettify:
163
+ args.no_stream = False
164
+ args.prettify = False
140
165
 
141
166
  # Check if --stream-prettify is used but Rich is not available
142
167
  if args.stream_prettify and not has_markdown_renderer('rich'):
@@ -15,7 +15,7 @@ CLI_CONFIG_OPTIONS = {
15
15
  "preprompt": {"type": "str", "default": None, "context": ["all"]},
16
16
  "no-stream": {"type": "bool", "default": False, "context": ["all"], "exclusive": ["prettify", "stream-prettify"]},
17
17
  "prettify": {"type": "bool", "default": False, "context": ["all"], "exclusive": ["no-stream", "stream-prettify"]},
18
- "stream-prettify": {"type": "bool", "default": False, "context": ["all"], "exclusive": ["no-stream", "prettify"]},
18
+ "stream-prettify": {"type": "bool", "default": True, "context": ["all"], "exclusive": ["no-stream", "prettify"]},
19
19
  "renderer": {"type": "str", "default": "auto", "context": ["all"]},
20
20
  "config-index": {"type": "int", "default": 0, "context": ["all"], "exclusive": ["provider"]},
21
21
  "web-search": {"type": "bool", "default": False, "context": ["all"]},
@@ -11,6 +11,7 @@ from duckduckgo_search import DDGS
11
11
  from urllib.parse import urlparse
12
12
  import requests
13
13
  import sys
14
+ import datetime
14
15
 
15
16
  # Get actual logger from global context instead of using standard logging
16
17
  from . import log
@@ -36,7 +37,7 @@ def get_logger():
36
37
  def debug(self, msg): pass
37
38
  return DefaultLogger()
38
39
 
39
- def perform_web_search(query: str, max_results: int = 3) -> List[Dict[str, Any]]:
40
+ def perform_web_search(query: str, max_results: int = 5) -> List[Dict[str, Any]]:
40
41
  """
41
42
  Search the web using DuckDuckGo and return relevant results.
42
43
 
@@ -211,10 +212,13 @@ def get_web_search_results(query: str, max_results: int = 3, max_chars_per_resul
211
212
  logger.info(f"Successfully retrieved content from all {success_count} sources")
212
213
  else:
213
214
  logger.error("No search results were found")
215
+
216
+ # Add current timestamp
217
+ current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
214
218
 
215
219
  return {
216
220
  'query': query,
217
- 'timestamp': 'current_time', # Could replace with actual timestamp
221
+ 'timestamp': current_time,
218
222
  'results': enhanced_results
219
223
  }
220
224
 
@@ -230,8 +234,9 @@ def format_web_search_results_for_prompt(search_results: Dict[str, Any]) -> str:
230
234
  """
231
235
  query = search_results['query']
232
236
  results = search_results['results']
237
+ timestamp = search_results['timestamp']
233
238
 
234
- formatted_text = f"[Web Search Results for: {query}]\n\n"
239
+ formatted_text = f"[Web Search Results for: {query} (searched at {timestamp})]\n\n"
235
240
 
236
241
  for i, result in enumerate(results, 1):
237
242
  formatted_text += f"RESULT {i}: {result['title']}\n"
@@ -239,11 +244,27 @@ def format_web_search_results_for_prompt(search_results: Dict[str, Any]) -> str:
239
244
  formatted_text += f"CONTENT:\n{result['content']}\n\n"
240
245
 
241
246
  formatted_text += f"[End of Web Search Results]\n\n"
242
- formatted_text += "Consider the above information when answering the following question:\n\n"
247
+ formatted_text += "Use the above web search information to help answer the user's question. When using this information:\n"
248
+ formatted_text += "1. Use numbered citations in square brackets [1], [2], etc. when presenting information from search results\n"
249
+ formatted_text += "2. Include a numbered reference list at the end of your response with the source URLs\n"
250
+ formatted_text += "3. Format citations like 'According to [1]...' or 'Research indicates [2]...' or add citations at the end of sentences or paragraphs\n"
251
+ formatted_text += "4. If search results contain conflicting information, acknowledge the differences and explain them with citations\n"
252
+ formatted_text += "5. If the search results don't provide sufficient information, acknowledge the limitations\n"
253
+ formatted_text += "6. Balance information from multiple sources when appropriate\n"
254
+ formatted_text += "7. YOU MUST include an empty blockquote line ('>') between each reference in the reference list\n"
255
+ formatted_text += "8. YOU MUST include ALL available references (between 2-7 sources) in your reference list\n\n"
256
+ formatted_text += "Example citation format in text:\n"
257
+ formatted_text += "Today is Thursday [1] and it's expected to rain tomorrow [2].\n\n"
258
+ formatted_text += "Example reference format (YOU MUST FOLLOW THIS EXACT FORMAT WITH EMPTY LINES BETWEEN REFERENCES):\n"
259
+ formatted_text += "> [0] https://example.com/date\n"
260
+ formatted_text += ">\n"
261
+ formatted_text += "> [1] https://weather.com/forecast\n"
262
+ formatted_text += ">\n"
263
+ formatted_text += "> [2] https://www.timeanddate.com\n\n"
243
264
 
244
265
  return formatted_text
245
266
 
246
- def enhance_prompt_with_web_search(prompt: str, max_results: int = 3, logger=None) -> str:
267
+ def enhance_prompt_with_web_search(prompt: str, max_results: int = 5, logger=None) -> str:
247
268
  """
248
269
  Enhance a prompt with web search results.
249
270
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ngpt"
3
- version = "3.3.0"
3
+ version = "3.4.1"
4
4
  description = "Swiss army knife for LLMs: powerful CLI, interactive chatbot, and flexible Python library. Works with OpenAI, Ollama, Groq, Claude, Gemini, and any OpenAI-compatible API."
5
5
  authors = [
6
6
  {name = "nazDridoy", email = "nazdridoy399@gmail.com"},
@@ -431,7 +431,7 @@ wheels = [
431
431
 
432
432
  [[package]]
433
433
  name = "ngpt"
434
- version = "3.3.0"
434
+ version = "3.4.1"
435
435
  source = { editable = "." }
436
436
  dependencies = [
437
437
  { name = "duckduckgo-search", version = "7.2.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" },
ngpt-3.3.0/PKGBUILD DELETED
@@ -1,24 +0,0 @@
1
- # Maintainer: nazdridoy <nazdridoy399@gmail.com>
2
- pkgname=ngpt
3
- pkgver=0.0.0 # Automatically updated by CI on release
4
- pkgrel=1
5
- pkgdesc="Swiss army knife for LLMs: powerful CLI, interactive chatbot, and flexible Python library. Works with OpenAI, Ollama, Groq, Claude, Gemini, and any OpenAI-compatible API."
6
- arch=('any')
7
- url="https://github.com/nazdridoy/ngpt"
8
- license=('MIT')
9
- depends=('python' 'python-requests>=2.31.0' 'python-rich>=10.0.0' 'python-prompt_toolkit>=3.0.0' 'python-pyperclip>=1.8.0')
10
- makedepends=('python-build' 'python-installer' 'python-wheel' 'python-hatchling')
11
- source=("${pkgname}-${pkgver}.tar.gz::https://github.com/nazdridoy/${pkgname}/archive/v${pkgver}.tar.gz")
12
- sha256sums=('SKIP') # Automatically updated by CI on release
13
-
14
- build() {
15
- cd "$pkgname-$pkgver"
16
- python -m build --wheel --no-isolation
17
- }
18
-
19
- package() {
20
- cd "$pkgname-$pkgver"
21
- python -m installer --destdir="$pkgdir" dist/*.whl
22
- install -Dm644 LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
23
- install -Dm644 README.md "$pkgdir/usr/share/doc/$pkgname/README.md"
24
- }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes