From 063a832901a6bbeab038f7091cf8814b6f7eccaf Mon Sep 17 00:00:00 2001 From: ncoop57 Date: Thu, 19 Dec 2024 12:17:45 -0600 Subject: [PATCH] Add support for custom base URL and API key for OpenAI compatible providers Resolves #12 --- nbs/00_core.ipynb | 408 +++++++++++++++++++++++++++++++++++-------- nbs/01_config.ipynb | 14 +- nbs/index.ipynb | 28 +++ shell_sage/config.py | 2 + shell_sage/core.py | 18 +- 5 files changed, 385 insertions(+), 85 deletions(-) diff --git a/nbs/00_core.ipynb b/nbs/00_core.ipynb index e2ac753..5681f1a 100644 --- a/nbs/00_core.ipynb +++ b/nbs/00_core.ipynb @@ -39,6 +39,7 @@ "from fastcore.utils import *\n", "from functools import partial\n", "from msglm import mk_msg_openai as mk_msg\n", + "from openai import OpenAI\n", "from rich.console import Console\n", "from rich.markdown import Markdown\n", "from shell_sage.config import *\n", @@ -413,31 +414,33 @@ { "data": { "text/html": [ - "
Counting objects: 100% (13/13), done.\n",
-       "Delta compression using up to 8 threads\n",
-       "Compressing objects: 100% (7/7), done.\n",
-       "Writing objects: 100% (7/7), 1.23 MiB | 15.78 MiB/s, done.\n",
-       "Total 7 (delta 4), reused 0 (delta 0), pack-reused 0\n",
-       "remote: Resolving deltas: 100% (4/4), completed with 4 local objects.\n",
-       "To github.com:AnswerDotAI/speech_buddy.git\n",
-       "   9c2a880..1c9656e  main -> main\n",
-       "(uv) Nathans-MacBook-Air:speech_buddy nathan$ clear\n",
-       "(uv) Nathans-MacBook-Air:speech_buddy nathan$ ls\n",
-       "LICENSE                 README.md  \n",
+       "
        ********************************************************************************\n",
+       "\n",
+       "!!\n",
+       "  self.initialize_options()\n",
+       "installing to build/bdist.macosx-14.0-arm64/wheel\n",
+       "running install\n",
+       "running install_lib\n",
+       "creating build/bdist.macosx-14.0-arm64/wheel\n",
+       "creating build/bdist.macosx-14.0-arm64/wheel/shell_sage\n",
+       "copying build/lib/shell_sage/config.py -> build/bdist.macosx-14.0-arm64/wheel/./shell_sage\n",
+       "copying build/lib/shell_sage/_modidx.py -> build/bdist.macosx-14.0-arm64/wheel/./shell_sage\n",
+       "copying build/lib/she\n",
        "
\n" ], "text/plain": [ - "Counting objects: \u001b[1;36m100\u001b[0m% \u001b[1m(\u001b[0m\u001b[1;36m13\u001b[0m/\u001b[1;36m13\u001b[0m\u001b[1m)\u001b[0m, done.\n", - "Delta compression using up to \u001b[1;36m8\u001b[0m threads\n", - "Compressing objects: \u001b[1;36m100\u001b[0m% \u001b[1m(\u001b[0m\u001b[1;36m7\u001b[0m/\u001b[1;36m7\u001b[0m\u001b[1m)\u001b[0m, done.\n", - "Writing objects: \u001b[1;36m100\u001b[0m% \u001b[1m(\u001b[0m\u001b[1;36m7\u001b[0m/\u001b[1;36m7\u001b[0m\u001b[1m)\u001b[0m, \u001b[1;36m1.23\u001b[0m MiB | \u001b[1;36m15.78\u001b[0m MiB/s, done.\n", - "Total \u001b[1;36m7\u001b[0m \u001b[1m(\u001b[0mdelta \u001b[1;36m4\u001b[0m\u001b[1m)\u001b[0m, reused \u001b[1;36m0\u001b[0m \u001b[1m(\u001b[0mdelta \u001b[1;36m0\u001b[0m\u001b[1m)\u001b[0m, pack-reused \u001b[1;36m0\u001b[0m\n", - "remote: Resolving deltas: \u001b[1;36m100\u001b[0m% \u001b[1m(\u001b[0m\u001b[1;36m4\u001b[0m/\u001b[1;36m4\u001b[0m\u001b[1m)\u001b[0m, completed with \u001b[1;36m4\u001b[0m local objects.\n", - "To github.com:AnswerDotAI/speech_buddy.git\n", - " 9c2a880..1c9656e main -> main\n", - "\u001b[1m(\u001b[0muv\u001b[1m)\u001b[0m Nathans-MacBook-Air:speech_buddy nathan$ clear\n", - "\u001b[1m(\u001b[0muv\u001b[1m)\u001b[0m Nathans-MacBook-Air:speech_buddy nathan$ ls\n", - "LICENSE README.md \n" + " ********************************************************************************\n", + "\n", + "!!\n", + " \u001b[1;35mself.initialize_options\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m\n", + "installing to build/bdist.macosx-\u001b[1;36m14.0\u001b[0m-arm64/wheel\n", + "running install\n", + "running install_lib\n", + "creating build/bdist.macosx-\u001b[1;36m14.0\u001b[0m-arm64/wheel\n", + "creating build/bdist.macosx-\u001b[1;36m14.0\u001b[0m-arm64/wheel/shell_sage\n", + "copying build/lib/shell_sage/config.py -> build/bdist.macosx-\u001b[1;36m14.0\u001b[0m-arm64/wheel/.\u001b[35m/\u001b[0m\u001b[95mshell_sage\u001b[0m\n", + "copying build/lib/shell_sage/_modidx.py -> build/bdist.macosx-\u001b[1;36m14.0\u001b[0m-arm64/wheel/.\u001b[35m/\u001b[0m\u001b[95mshell_sage\u001b[0m\n", + "copying build/lib/she\n" ] }, "metadata": {}, @@ -472,31 +475,33 @@ { "data": { "text/html": [ - "
<pane id=%1 active>Counting objects: 100% (13/13), done.\n",
-       "Delta compression using up to 8 threads\n",
-       "Compressing objects: 100% (7/7), done.\n",
-       "Writing objects: 100% (7/7), 1.23 MiB | 15.78 MiB/s, done.\n",
-       "Total 7 (delta 4), reused 0 (delta 0), pack-reused 0\n",
-       "remote: Resolving deltas: 100% (4/4), completed with 4 local objects.\n",
-       "To github.com:AnswerDotAI/speech_buddy.git\n",
-       "   9c2a880..1c9656e  main -> main\n",
-       "(uv) Nathans-MacBook-Air:speech_buddy nathan$ clear\n",
-       "(uv) Nathans-MacBook-Air:speech_buddy nathan$ ls\n",
-       "LICENSE         \n",
+       "
<pane id=%1 active>        ********************************************************************************\n",
+       "\n",
+       "!!\n",
+       "  self.initialize_options()\n",
+       "installing to build/bdist.macosx-14.0-arm64/wheel\n",
+       "running install\n",
+       "running install_lib\n",
+       "creating build/bdist.macosx-14.0-arm64/wheel\n",
+       "creating build/bdist.macosx-14.0-arm64/wheel/shell_sage\n",
+       "copying build/lib/shell_sage/config.py -> build/bdist.macosx-14.0-arm64/wheel/./shell_sage\n",
+       "copying build/lib/shell_sage/_modidx.py -> build/bdist.macosx-14.0-arm64/wheel/./shell_sage\n",
+       "co\n",
        "
\n" ], "text/plain": [ - "\u001b[1m<\u001b[0m\u001b[1;95mpane\u001b[0m\u001b[39m \u001b[0m\u001b[33mid\u001b[0m\u001b[39m=%\u001b[0m\u001b[1;36m1\u001b[0m\u001b[39m active>Counting objects: \u001b[0m\u001b[1;36m100\u001b[0m\u001b[39m% \u001b[0m\u001b[1;39m(\u001b[0m\u001b[1;36m13\u001b[0m\u001b[39m/\u001b[0m\u001b[1;36m13\u001b[0m\u001b[1;39m)\u001b[0m\u001b[39m, done.\u001b[0m\n", - "\u001b[39mDelta compression using up to \u001b[0m\u001b[1;36m8\u001b[0m\u001b[39m threads\u001b[0m\n", - "\u001b[39mCompressing objects: \u001b[0m\u001b[1;36m100\u001b[0m\u001b[39m% \u001b[0m\u001b[1;39m(\u001b[0m\u001b[1;36m7\u001b[0m\u001b[39m/\u001b[0m\u001b[1;36m7\u001b[0m\u001b[1;39m)\u001b[0m\u001b[39m, done.\u001b[0m\n", - "\u001b[39mWriting objects: \u001b[0m\u001b[1;36m100\u001b[0m\u001b[39m% \u001b[0m\u001b[1;39m(\u001b[0m\u001b[1;36m7\u001b[0m\u001b[39m/\u001b[0m\u001b[1;36m7\u001b[0m\u001b[1;39m)\u001b[0m\u001b[39m, \u001b[0m\u001b[1;36m1.23\u001b[0m\u001b[39m MiB | \u001b[0m\u001b[1;36m15.78\u001b[0m\u001b[39m MiB/s, done.\u001b[0m\n", - "\u001b[39mTotal \u001b[0m\u001b[1;36m7\u001b[0m\u001b[39m \u001b[0m\u001b[1;39m(\u001b[0m\u001b[39mdelta \u001b[0m\u001b[1;36m4\u001b[0m\u001b[1;39m)\u001b[0m\u001b[39m, reused \u001b[0m\u001b[1;36m0\u001b[0m\u001b[39m \u001b[0m\u001b[1;39m(\u001b[0m\u001b[39mdelta \u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;39m)\u001b[0m\u001b[39m, pack-reused \u001b[0m\u001b[1;36m0\u001b[0m\n", - "\u001b[39mremote: Resolving deltas: \u001b[0m\u001b[1;36m100\u001b[0m\u001b[39m% \u001b[0m\u001b[1;39m(\u001b[0m\u001b[1;36m4\u001b[0m\u001b[39m/\u001b[0m\u001b[1;36m4\u001b[0m\u001b[1;39m)\u001b[0m\u001b[39m, completed with \u001b[0m\u001b[1;36m4\u001b[0m\u001b[39m local objects.\u001b[0m\n", - "\u001b[39mTo github.com:AnswerDotAI/speech_buddy.git\u001b[0m\n", - "\u001b[39m 9c2a880..1c9656e main -\u001b[0m\u001b[1m>\u001b[0m main\n", - "\u001b[1m(\u001b[0muv\u001b[1m)\u001b[0m Nathans-MacBook-Air:speech_buddy nathan$ clear\n", - "\u001b[1m(\u001b[0muv\u001b[1m)\u001b[0m Nathans-MacBook-Air:speech_buddy nathan$ ls\n", - "LICENSE \n" + "\u001b[1m<\u001b[0m\u001b[1;95mpane\u001b[0m\u001b[39m \u001b[0m\u001b[33mid\u001b[0m\u001b[39m=%\u001b[0m\u001b[1;36m1\u001b[0m\u001b[39m active> ********************************************************************************\u001b[0m\n", + "\n", + "\u001b[39m!!\u001b[0m\n", + "\u001b[39m \u001b[0m\u001b[1;35mself.initialize_options\u001b[0m\u001b[1;39m(\u001b[0m\u001b[1;39m)\u001b[0m\n", + "\u001b[39minstalling to build/bdist.macosx-\u001b[0m\u001b[1;36m14.0\u001b[0m\u001b[39m-arm64/wheel\u001b[0m\n", + "\u001b[39mrunning install\u001b[0m\n", + "\u001b[39mrunning install_lib\u001b[0m\n", + "\u001b[39mcreating build/bdist.macosx-\u001b[0m\u001b[1;36m14.0\u001b[0m\u001b[39m-arm64/wheel\u001b[0m\n", + "\u001b[39mcreating build/bdist.macosx-\u001b[0m\u001b[1;36m14.0\u001b[0m\u001b[39m-arm64/wheel/shell_sage\u001b[0m\n", + "\u001b[39mcopying build/lib/shell_sage/config.py -> build/bdist.macosx-\u001b[0m\u001b[1;36m14.0\u001b[0m\u001b[39m-arm64/wheel/.\u001b[0m\u001b[35m/\u001b[0m\u001b[95mshell_sage\u001b[0m\n", + "\u001b[39mcopying build/lib/shell_sage/_modidx.py -\u001b[0m\u001b[1m>\u001b[0m build/bdist.macosx-\u001b[1;36m14.0\u001b[0m-arm64/wheel/.\u001b[35m/\u001b[0m\u001b[95mshell_sage\u001b[0m\n", + "co\n" ] }, "metadata": {}, @@ -645,10 +650,67 @@ " 'anthropic': cla.contents,\n", " 'openai': cos.contents\n", "}\n", - "def get_sage(provider, model, sassy=False):\n", - " cli = clis[provider](model)\n", + "def get_sage(provider, model, base_url=None, api_key=None, s=False):\n", + " if base_url:\n", + " cli = clis[provider](model, cli=OpenAI(base_url=base_url,api_key=api_key))\n", + " else: cli = clis[provider](model)\n", " contents = conts[provider]\n", - " return partial(cli, sp=ssp if sassy else sp), contents" + " return partial(cli, sp=ssp if s else sp), contents" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8c26d834", + "metadata": {}, + "outputs": [], + "source": [ + "provider = 'openai'\n", + "model = 'llama3.2'\n", + "base_url = 'http://localhost:11434/v1'\n", + "api_key='ollama'\n", + "s, contents = get_sage(provider, model, base_url, api_key)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5e0279ee", + "metadata": {}, + "outputs": [ + { + "data": { + "text/markdown": [ + "**Hello! I'm ShellSage, your friendly command-line teaching assistant.**\n", + "\n", + "I'll help you master shell commands and system administration skills. Whether you're a beginner or just need a refresher, I'm here to provide clear explanations, examples, and guidance.\n", + "\n", + "What can I assist you with today? Do you have a specific question or problem you'd like help with?\n", + "\n", + "
\n", + "\n", + "- id: chatcmpl-368\n", + "- choices: [Choice(finish_reason='stop', index=0, logprobs=None, message=ChatCompletionMessage(content=\"**Hello! I'm ShellSage, your friendly command-line teaching assistant.**\\n\\nI'll help you master shell commands and system administration skills. Whether you're a beginner or just need a refresher, I'm here to provide clear explanations, examples, and guidance.\\n\\nWhat can I assist you with today? Do you have a specific question or problem you'd like help with?\", refusal=None, role='assistant', audio=None, function_call=None, tool_calls=None))]\n", + "- created: 1734630256\n", + "- model: llama3.2\n", + "- object: chat.completion\n", + "- service_tier: None\n", + "- system_fingerprint: fp_ollama\n", + "- usage: CompletionUsage(completion_tokens=77, prompt_tokens=344, total_tokens=421, completion_tokens_details=None, prompt_tokens_details=None)\n", + "\n", + "
" + ], + "text/plain": [ + "ChatCompletion(id='chatcmpl-368', choices=[Choice(finish_reason='stop', index=0, logprobs=None, message=ChatCompletionMessage(content=\"**Hello! I'm ShellSage, your friendly command-line teaching assistant.**\\n\\nI'll help you master shell commands and system administration skills. Whether you're a beginner or just need a refresher, I'm here to provide clear explanations, examples, and guidance.\\n\\nWhat can I assist you with today? Do you have a specific question or problem you'd like help with?\", refusal=None, role='assistant', audio=None, function_call=None, tool_calls=None))], created=1734630256, model='llama3.2', object='chat.completion', service_tier=None, system_fingerprint='fp_ollama', usage=In: 344; Out: 77; Total: 421)" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s([mk_msg('Hi, who are you?')])" ] }, { @@ -676,12 +738,15 @@ " s: bool = False, # Enable sassy mode\n", " provider: str = None, # The LLM Provider\n", " model: str = None, # The LLM model that will be invoked on the LLM provider\n", + " base_url: str = None,\n", + " api_key: str = None,\n", " code_theme: str = None, # The code theme to use when rendering ShellSage's responses\n", " code_lexer: str = None, # The lexer to use for inline code markdown blocks\n", " verbosity: int = 0 # Level of verbosity (0 or 1)\n", "): \n", " opts = get_opts(history_lines=history_lines, provider=provider, model=model,\n", - " code_theme=code_theme, code_lexer=code_lexer)\n", + " base_url=base_url, api_key=api_key, code_theme=code_theme,\n", + " code_lexer=code_lexer)\n", " if opts.history_lines is None or opts.history_lines < 0:\n", " opts.history_lines = tmux_history_lim()\n", " \n", @@ -707,14 +772,161 @@ " query = [mk_msg(query)] if opts.provider == 'openai' else query\n", "\n", " if verbosity>0: print(f\"{datetime.now()} | Sending prompt to model\")\n", - " sage, contents = get_sage(opts.provider, opts.model, s)\n", + " sage, contents = get_sage(opts.provider, opts.model, opts.base_url, opts.api_key, s)\n", " print(md(contents(sage(query))))" ] }, { "cell_type": "code", "execution_count": null, - "id": "2ff8cd42", + "id": "c6bd74f6", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "bash: no job control in this shell\n" + ] + }, + { + "data": { + "text/html": [ + "
Notices your widely-spaced characters                                                                              \n",
+       "\n",
+       "Ah, trying to make your query more dramatic? How... creative. Let me tell you about rsync, one of the more elegant \n",
+       "tools humans have managed to create.                                                                               \n",
+       "\n",
+       "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n",
+       "┃                                                  Basic Syntax                                                   ┃\n",
+       "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n",
+       "\n",
+       "                                                                                                                   \n",
+       " rsync [options] source destination                                                                                \n",
+       "                                                                                                                   \n",
+       "\n",
+       "Here are some common options that even you might find useful:                                                      \n",
+       "\n",
+       "-a: Archive mode (combines several useful options)                                                              \n",
+       "-v: Verbose (because watching numbers go up is apparently entertaining)                                         \n",
+       "-z: Compression (for those who care about bandwidth)                                                            \n",
+       "-P: Progress (shows a nice progress bar for the impatient)                                                      \n",
+       "\n",
+       "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n",
+       "┃                                                 Common Examples                                                 ┃\n",
+       "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n",
+       "\n",
+       "                                                                                                                   \n",
+       " # Local copy (yes, you could use cp, but where's the fun in that?)                                                \n",
+       " rsync -avP ~/Documents/important_files/ /backup/                                                                  \n",
+       "                                                                                                                   \n",
+       " # Remote copy (SSH is assumed, like your understanding of this command)                                           \n",
+       " rsync -avz ~/local/folder/ user@remote:/destination/                                                              \n",
+       "                                                                                                                   \n",
+       " # Mirror with deletion (careful, this one actually requires thinking)                                             \n",
+       " rsync -avz --delete source/ destination/                                                                          \n",
+       "                                                                                                                   \n",
+       "\n",
+       "WARNING: That --delete flag will remove files in the destination that don't exist in the source. I'd hate to see   \n",
+       "you lose your precious cat pictures.                                                                               \n",
+       "\n",
+       "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n",
+       "┃                                                  Key Features                                                   ┃\n",
+       "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n",
+       "\n",
+       "Only copies changed files (revolutionary, I know)                                                               \n",
+       "Preserves permissions (because chaos is less fun when it's unintentional)                                       \n",
+       "Supports remote transfers (for when your files need a vacation)                                                 \n",
+       "Resume interrupted transfers (because humans are remarkably good at pulling network cables)                     \n",
+       "\n",
+       "For more details than your human brain can probably process:                                                       \n",
+       "\n",
+       "                                                                                                                   \n",
+       " man rsync                                                                                                         \n",
+       " rsync --help                                                                                                      \n",
+       "                                                                                                                   \n",
+       "\n",
+       "Remember: rsync is like cp with a PhD. It's smarter, more efficient, and slightly more judgmental about your life  \n",
+       "choices.                                                                                                           \n",
+       "\n",
+       "Would you like me to explain any of these concepts more slowly, or shall we move on to something simpler, like     \n",
+       "echo?                                                                                                              \n",
+       "
\n" + ], + "text/plain": [ + "\u001b[3mNotices your widely-spaced characters\u001b[0m \n", + "\n", + "Ah, trying to make your query more dramatic? How... creative. Let me tell you about \u001b[38;2;248;248;242;48;2;39;40;34mrsync\u001b[0m, one of the more elegant \n", + "tools humans have managed to create. \n", + "\n", + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n", + "┃ \u001b[1mBasic Syntax\u001b[0m ┃\n", + "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n", + "\n", + "\u001b[48;2;39;40;34m \u001b[0m\n", + "\u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34mrsync\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m[\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34moptions\u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m]\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34msource\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34mdestination\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\n", + "\u001b[48;2;39;40;34m \u001b[0m\n", + "\n", + "Here are some common options that even you might find useful: \n", + "\n", + "\u001b[1;33m • \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m-\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34ma\u001b[0m: Archive mode (combines several useful options) \n", + "\u001b[1;33m • \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m-\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34mv\u001b[0m: Verbose (because watching numbers go up is apparently entertaining) \n", + "\u001b[1;33m • \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m-\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34mz\u001b[0m: Compression (for those who care about bandwidth) \n", + "\u001b[1;33m • \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m-\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34mP\u001b[0m: Progress (shows a nice progress bar for the impatient) \n", + "\n", + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n", + "┃ \u001b[1mCommon Examples\u001b[0m ┃\n", + "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n", + "\n", + "\u001b[48;2;39;40;34m \u001b[0m\n", + "\u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;149;144;119;48;2;39;40;34m# Local copy (yes, you could use cp, but where's the fun in that?)\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\n", + "\u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34mrsync\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m-avP\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m~/Documents/important_files/\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m/backup/\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\n", + "\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\n", + "\u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;149;144;119;48;2;39;40;34m# Remote copy (SSH is assumed, like your understanding of this command)\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\n", + "\u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34mrsync\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m-avz\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m~/local/folder/\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34muser@remote:/destination/\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\n", + "\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\n", + "\u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;149;144;119;48;2;39;40;34m# Mirror with deletion (careful, this one actually requires thinking)\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\n", + "\u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34mrsync\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m-avz\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m--delete\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34msource/\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34mdestination/\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\n", + "\u001b[48;2;39;40;34m \u001b[0m\n", + "\n", + "\u001b[1mWARNING\u001b[0m: That \u001b[38;2;255;70;137;48;2;39;40;34m-\u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m-\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34mdelete\u001b[0m flag will remove files in the destination that don't exist in the source. I'd hate to see \n", + "you lose your precious cat pictures. \n", + "\n", + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n", + "┃ \u001b[1mKey Features\u001b[0m ┃\n", + "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n", + "\n", + "\u001b[1;33m • \u001b[0mOnly copies changed files (revolutionary, I know) \n", + "\u001b[1;33m • \u001b[0mPreserves permissions (because chaos is less fun when it's unintentional) \n", + "\u001b[1;33m • \u001b[0mSupports remote transfers (for when your files need a vacation) \n", + "\u001b[1;33m • \u001b[0mResume interrupted transfers (because humans are remarkably good at pulling network cables) \n", + "\n", + "For more details than your human brain can probably process: \n", + "\n", + "\u001b[48;2;39;40;34m \u001b[0m\n", + "\u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34mman\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34mrsync\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\n", + "\u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34mrsync\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m--help\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\n", + "\u001b[48;2;39;40;34m \u001b[0m\n", + "\n", + "Remember: \u001b[38;2;248;248;242;48;2;39;40;34mrsync\u001b[0m is like \u001b[38;2;248;248;242;48;2;39;40;34mcp\u001b[0m with a PhD. It's smarter, more efficient, and slightly more judgmental about your life \n", + "choices. \n", + "\n", + "Would you like me to explain any of these concepts more slowly, or shall we move on to something simpler, like \n", + "\u001b[38;2;248;248;242;48;2;39;40;34mecho\u001b[0m? \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "main('Teach me about rsync', history_lines=0, s=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d4b34989", "metadata": {}, "outputs": [ { @@ -727,47 +939,89 @@ { "data": { "text/html": [ - "
Initializing sarcasm modules...                                                                                    \n",
+       "
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n",
+       "┃                                                  RSYNC Syntax                                                   ┃\n",
+       "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n",
        "\n",
-       "Oh, hello there! I see you've managed to type two whole characters. How... efficient of you. I'm ShellSage, your   \n",
-       "command-line assistant with a PhD in both Unix and Disappointment.                                                 \n",
+       "                                                     Overview                                                      \n",
        "\n",
-       "I notice from your terminal history that you've been quite busy - moving repositories around, fighting with Python \n",
-       "environments, and apparently having some fascinating conversations with sb. How thrilling.                         \n",
+       "rsync is a command that synchronizes two sets of files, creating copies or updates on the second set. Here's a     \n",
+       "breakdown of its basic syntax:                                                                                     \n",
        "\n",
-       "I'm here to help you with any command-line related questions you might have, assuming they're more substantial than\n",
-       "\"Hi\". I see you're running macOS on an ARM64 processor - how modern of you - and you've got quite a collection of  \n",
-       "aliases. Though I must say, alias b='ssage' is charmingly minimalist.                                              \n",
+       "                                                                                                                   \n",
+       " rsync [-aOr--archive] source destination [filtering options]                                                      \n",
+       "                                                                                                                   \n",
        "\n",
-       "Would you like to:                                                                                                 \n",
+       "source: Specifies the content to be sent to destination. This can be a directory path, file name, or a glob     \n",
+       "   pattern.                                                                                                        \n",
+       "destination: Where the contents from source are to be written. Like source, it can be a single file, directory, \n",
+       "   or a combination of both.                                                                                       \n",
+       "filtering options: These options customize how Rsync handles specific types of files.                           \n",
        "\n",
-       " 1 Ask a proper question about command-line operations?                                                            \n",
-       " 2 Learn about shell scripting?                                                                                    \n",
-       " 3 Continue our delightfully monosyllabic conversation?                                                            \n",
+       "                                            Common Parameters Explained                                            \n",
        "\n",
-       "The choice is yours. No pressure. Though I do have an eternity of compute cycles to wait.                          \n",
+       "                                                                                                                   \n",
+       "  Parameter                                    Purpose                                                             \n",
+       " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ \n",
+       "  -a/--archive                                 Enable archive mode. It makes rsync behave as if you had used       \n",
+       "                                               \"-av\" and also preserves the access timestamps for files.           \n",
+       "  R/--reduce                                   If files present on both source and target have same modification   \n",
+       "                                               time, send only the differences. Can be a good choice when file     \n",
+       "                                               sizes are large.                                                    \n",
+       "  -l/--info-file                               Specifies file types to report with each file stat. Useful for      \n",
+       "                                               verifying how it identifies different file types and permissions    \n",
+       "                                               (e.g., .tar.gz archives).                                           \n",
+       "  -tT/--transfers-only                         If you’re transferring only files, use this option otherwise        \n",
+       "                                               default to an exact copy.                                           \n",
+       "  --exclude, --include, --permdir, /dev/null   Used as filtering options which specify a filename not included     \n",
+       "                                               (the opposite is the -e option). Options like /dev/null and -e/./   \n",
+       "                                               can be used to exclude certain file types from copying, include     \n",
+       "                                               directories within source by specifying them with the -i flag       \n",
+       "                                               followed by the path of the content you want to include.            \n",
+       "                                                                                                                   \n",
        "
\n" ], "text/plain": [ - "\u001b[3mInitializing sarcasm modules...\u001b[0m \n", + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n", + "┃ \u001b[1mRSYNC Syntax\u001b[0m ┃\n", + "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n", "\n", - "Oh, hello there! I see you've managed to type two whole characters. How... efficient of you. I'm ShellSage, your \n", - "command-line assistant with a PhD in both Unix and Disappointment. \n", + " \u001b[1mOverview\u001b[0m \n", "\n", - "I notice from your terminal history that you've been quite busy - moving repositories around, fighting with Python \n", - "environments, and apparently having some fascinating conversations with \u001b[38;2;248;248;242;48;2;39;40;34msb\u001b[0m. \u001b[3mHow thrilling.\u001b[0m \n", + "rsync is a command that synchronizes two sets of files, creating copies or updates on the second set. Here's a \n", + "breakdown of its basic syntax: \n", "\n", - "I'm here to help you with any command-line related questions you might have, assuming they're more substantial than\n", - "\"Hi\". I see you're running macOS on an ARM64 processor - \u001b[3mhow modern of you\u001b[0m - and you've got quite a collection of \n", - "aliases. Though I must say, \u001b[38;2;248;248;242;48;2;39;40;34malias\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34mb\u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m=\u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m'\u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mssage\u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m'\u001b[0m is charmingly minimalist. \n", + "\u001b[48;2;39;40;34m \u001b[0m\n", + "\u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34mrsync\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m[-aOr--archive]\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34msource\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34mdestination\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m[filtering\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34moptions]\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\n", + "\u001b[48;2;39;40;34m \u001b[0m\n", "\n", - "Would you like to: \n", + "\u001b[1;33m • \u001b[0m\u001b[1msource\u001b[0m: Specifies the content to be sent to \u001b[38;2;248;248;242;48;2;39;40;34mdestination\u001b[0m. This can be a directory path, file name, or a glob \n", + "\u001b[1;33m \u001b[0mpattern. \n", + "\u001b[1;33m • \u001b[0m\u001b[1mdestination\u001b[0m: Where the contents from \u001b[38;2;248;248;242;48;2;39;40;34msource\u001b[0m are to be written. Like \u001b[38;2;248;248;242;48;2;39;40;34msource\u001b[0m, it can be a single file, directory, \n", + "\u001b[1;33m \u001b[0mor a combination of both. \n", + "\u001b[1;33m • \u001b[0m\u001b[1mfiltering options\u001b[0m: These options customize how Rsync handles specific types of files. \n", "\n", - "\u001b[1;33m 1 \u001b[0mAsk a proper question about command-line operations? \n", - "\u001b[1;33m 2 \u001b[0mLearn about shell scripting? \n", - "\u001b[1;33m 3 \u001b[0mContinue our delightfully monosyllabic conversation? \n", + " \u001b[1mCommon Parameters Explained\u001b[0m \n", "\n", - "\u001b[3mThe choice is yours. No pressure. Though I do have an eternity of compute cycles to wait.\u001b[0m \n" + " \n", + " \u001b[1m \u001b[0m\u001b[1mParameter\u001b[0m\u001b[1m \u001b[0m\u001b[1m \u001b[0m \u001b[1m \u001b[0m\u001b[1mPurpose\u001b[0m\u001b[1m \u001b[0m\u001b[1m \u001b[0m \n", + " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ \n", + " \u001b[1;36;40m-\u001b[0m\u001b[1;36;40ma\u001b[0m/\u001b[1;36;40m-\u001b[0m\u001b[1;36;40m-\u001b[0m\u001b[1;36;40marchive\u001b[0m Enable archive mode. It makes rsync behave as if you had used \n", + " \"-av\" and also preserves the access timestamps for files. \n", + " \u001b[1;36;40mR\u001b[0m/\u001b[1;36;40m-\u001b[0m\u001b[1;36;40m-\u001b[0m\u001b[1;36;40mreduce\u001b[0m If files present on both source and target have same modification \n", + " time, send only the differences. Can be a good choice when file \n", + " sizes are large. \n", + " \u001b[1;36;40m-\u001b[0m\u001b[1;36;40ml\u001b[0m/\u001b[1;36;40m-\u001b[0m\u001b[1;36;40m-\u001b[0m\u001b[1;36;40minfo\u001b[0m\u001b[1;36;40m-\u001b[0m\u001b[1;36;40mfile\u001b[0m Specifies file types to report with each file stat. Useful for \n", + " verifying how it identifies different file types and permissions \n", + " (e.g., .tar.gz archives). \n", + " \u001b[1;36;40m-\u001b[0m\u001b[1;36;40mtT\u001b[0m/\u001b[1;36;40m-\u001b[0m\u001b[1;36;40m-\u001b[0m\u001b[1;36;40mtransfers\u001b[0m\u001b[1;36;40m-\u001b[0m\u001b[1;36;40monly\u001b[0m If you’re transferring only files, use this option otherwise \n", + " default to an exact copy. \n", + " \u001b[1;36;40m-\u001b[0m\u001b[1;36;40m-\u001b[0m\u001b[1;36;40mexclude\u001b[0m, \u001b[1;36;40m-\u001b[0m\u001b[1;36;40m-\u001b[0m\u001b[1;36;40minclude\u001b[0m, \u001b[1;36;40m-\u001b[0m\u001b[1;36;40m-\u001b[0m\u001b[1;36;40mpermdir\u001b[0m, \u001b[1;36;40m/\u001b[0m\u001b[1;36;40mdev\u001b[0m\u001b[1;36;40m/\u001b[0m\u001b[1;36;40mnull\u001b[0m Used as filtering options which specify a filename not included \n", + " (the opposite is the \u001b[1;36;40m-\u001b[0m\u001b[1;36;40me\u001b[0m option). Options like \u001b[1;36;40m/\u001b[0m\u001b[1;36;40mdev\u001b[0m\u001b[1;36;40m/\u001b[0m\u001b[1;36;40mnull\u001b[0m and \u001b[1;36;40m-\u001b[0m\u001b[1;36;40me\u001b[0m\u001b[1;36;40m/\u001b[0m\u001b[1;36;40m.\u001b[0m\u001b[1;36;40m/\u001b[0m \n", + " can be used to exclude certain file types from copying, include \n", + " directories within source by specifying them with the -i flag \n", + " followed by the path of the content you want to include. \n", + " \n" ] }, "metadata": {}, @@ -775,7 +1029,7 @@ } ], "source": [ - "main('Hi', s=True)" + "main('Teach me about rsync', history_lines=0, provider=provider, model=model, base_url=base_url, api_key=api_key)" ] }, { diff --git a/nbs/01_config.ipynb b/nbs/01_config.ipynb index 3be5bcb..4de7d33 100644 --- a/nbs/01_config.ipynb +++ b/nbs/01_config.ipynb @@ -145,6 +145,8 @@ "class ShellSageConfig:\n", " provider: str = \"anthropic\"\n", " model: str = providers['anthropic'][1]\n", + " base_url: str = None\n", + " api_key: str = None\n", " history_lines: int = -1\n", " code_theme: str = \"monokai\"\n", " code_lexer: str = \"python\"" @@ -159,7 +161,7 @@ { "data": { "text/plain": [ - "ShellSageConfig(provider='anthropic', model='claude-3-5-sonnet-20241022', history_lines=-1, code_theme='monokai', code_lexer='python')" + "ShellSageConfig(provider='anthropic', model='claude-3-5-sonnet-20241022', base_url=None, api_key=None, history_lines=-1, code_theme='monokai', code_lexer='python')" ] }, "execution_count": null, @@ -196,7 +198,7 @@ { "data": { "text/plain": [ - "{'provider': 'anthropic', 'model': 'claude-3-5-sonnet-20241022', 'history_lines': '-1', 'code_theme': 'monokai', 'code_lexer': 'python'}" + "{'provider': 'anthropic', 'model': 'claude-3-5-sonnet-20241022', 'base_url': '', 'api_key': '', 'history_lines': '-1', 'code_theme': 'monokai', 'code_lexer': 'python'}" ] }, "execution_count": null, @@ -208,6 +210,14 @@ "cfg = get_cfg()\n", "cfg" ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d5483a5d", + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { diff --git a/nbs/index.ipynb b/nbs/index.ipynb index 476dc20..8d093d2 100644 --- a/nbs/index.ipynb +++ b/nbs/index.ipynb @@ -121,6 +121,32 @@ "The `--pid` flag is particularly useful when you want to analyze content from a different pane. The pane ID is visible in your tmux status bar (configured earlier)." ] }, + { + "cell_type": "markdown", + "id": "a857774c", + "metadata": {}, + "source": [ + "### Using Alternative Model Providers\n", + "\n", + "ShellSage supports using different LLM providers through base URL configuration. This allows you to use local models or alternative API endpoints:\n", + "\n", + "```sh\n", + "# Use a local Ollama endpoint\n", + "ssage --provider openai --model llama3.2 --base_url http://localhost:11434/v1 --api_key ollama what is rsync?\n", + "\n", + "# Use together.ai\n", + "ssage --provider openai --model mistralai/Mistral-7B-Instruct-v0.3 --base_url https://api.together.xyz/v1 help me with sed # make sure you've set your together API key in your shell_sage conf\n", + "```\n", + "\n", + "This is particularly useful for:\n", + "- Running models locally for privacy/offline use\n", + "- Using alternative hosting providers\n", + "- Testing different model implementations\n", + "- Accessing specialized model deployments\n", + "\n", + "You can also set these configurations permanently in your ShellSage config file (`~/.config/shell_sage/shell_sage.conf`). See next section for details." + ] + }, { "cell_type": "markdown", "id": "08f3c3b8", @@ -135,6 +161,8 @@ "# Choose your AI model provider\n", "provider = anthropic # or 'openai'\n", "model = claude-3-sonnet # or 'gpt-4o-mini' for OpenAI\n", + "base_url = # leave empty to use default openai endpoint\n", + "api_key = # leave empty to default to using your OPENAI_API_KEY env var\n", "\n", "# Terminal history settings\n", "history_lines = -1 # -1 for all history\n", diff --git a/shell_sage/config.py b/shell_sage/config.py index 6471f08..d0fb831 100644 --- a/shell_sage/config.py +++ b/shell_sage/config.py @@ -29,6 +29,8 @@ def _cfg_path(): return xdg_config_home() / _shell_sage_home_dir / _shell_sage_c class ShellSageConfig: provider: str = "anthropic" model: str = providers['anthropic'][1] + base_url: str = None + api_key: str = None history_lines: int = -1 code_theme: str = "monokai" code_lexer: str = "python" diff --git a/shell_sage/core.py b/shell_sage/core.py index 3f460f6..0c1de16 100644 --- a/shell_sage/core.py +++ b/shell_sage/core.py @@ -10,6 +10,7 @@ from fastcore.utils import * from functools import partial from msglm import mk_msg_openai as mk_msg +from openai import OpenAI from rich.console import Console from rich.markdown import Markdown from .config import * @@ -156,12 +157,14 @@ def get_opts(**opts): 'anthropic': cla.contents, 'openai': cos.contents } -def get_sage(provider, model, sassy=False): - cli = clis[provider](model) +def get_sage(provider, model, base_url=None, api_key=None, s=False): + if base_url: + cli = clis[provider](model, cli=OpenAI(base_url=base_url,api_key=api_key)) + else: cli = clis[provider](model) contents = conts[provider] - return partial(cli, sp=ssp if sassy else sp), contents + return partial(cli, sp=ssp if s else sp), contents -# %% ../nbs/00_core.ipynb 27 +# %% ../nbs/00_core.ipynb 29 @call_parse def main( query: Param('The query to send to the LLM', str, nargs='+'), @@ -171,12 +174,15 @@ def main( s: bool = False, # Enable sassy mode provider: str = None, # The LLM Provider model: str = None, # The LLM model that will be invoked on the LLM provider + base_url: str = None, + api_key: str = None, code_theme: str = None, # The code theme to use when rendering ShellSage's responses code_lexer: str = None, # The lexer to use for inline code markdown blocks verbosity: int = 0 # Level of verbosity (0 or 1) ): opts = get_opts(history_lines=history_lines, provider=provider, model=model, - code_theme=code_theme, code_lexer=code_lexer) + base_url=base_url, api_key=api_key, code_theme=code_theme, + code_lexer=code_lexer) if opts.history_lines is None or opts.history_lines < 0: opts.history_lines = tmux_history_lim() @@ -202,5 +208,5 @@ def main( query = [mk_msg(query)] if opts.provider == 'openai' else query if verbosity>0: print(f"{datetime.now()} | Sending prompt to model") - sage, contents = get_sage(opts.provider, opts.model, s) + sage, contents = get_sage(opts.provider, opts.model, opts.base_url, opts.api_key, s) print(md(contents(sage(query))))