Skip to content

Commit

Permalink
make it compatible with openai library update
Browse files Browse the repository at this point in the history
  • Loading branch information
Fakamoto committed Oct 16, 2024
1 parent 59beaf0 commit 339f6d1
Show file tree
Hide file tree
Showing 6 changed files with 945 additions and 279 deletions.
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@

## Prerequisites

- Python 3.6+ and an active internet connection.
- `OPENAI_API_KEY` environment variable set up.
- Access to the `gpt-4-1106-preview` model.
- Python 3.10+
- `OPENAI_API_KEY` environment variable set up


## Installation
Expand Down Expand Up @@ -61,7 +60,7 @@ For queries or contributions, contact via email at [email protected] or on
## FAQs

**Q: How accurate are the commands generated by claix?**
A: claix uses a GPT-4 powered assistant specialized in CLIs for high accuracy.
A: claix uses a gpt-4o-mini powered assistant specialized in CLIs for high accuracy.

**Q: Can it handle complex instructions?**
A: Currently optimized for single-step commands, with plans to handle multi-step instructions in the future.
Expand Down
47 changes: 19 additions & 28 deletions claix/ai.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import time
from typing import Optional
import instructor
from pydantic import BaseModel
from pydantic import BaseModel, Field
from openai import OpenAI
import json
import instructor


class ClaixCommand(BaseModel):
Expand All @@ -15,16 +16,17 @@ class ClaixCommand(BaseModel):
command (Optional[str]): The string command to execute.
explanation (Optional[str]): The explanation of the command.
"""
is_command: bool
command: Optional[str]
explanation: Optional[str]
is_command: bool = Field(description="True if the response is a command, False otherwise")
command: Optional[str] = Field(description="The string command to execute")
explanation: Optional[str] = Field(description="The explanation of the command")


class Claix:
def __init__(self, assistant_id: str, thread_id: str = None):
self.assistant_id = assistant_id
self.thread_id = thread_id
self.client = OpenAI()
self.client: OpenAI = instructor.patch(OpenAI())
self.model = "gpt-4o-mini"

def __call__(self, prompt, thread_id=None):
if not thread_id:
Expand All @@ -38,10 +40,13 @@ def __call__(self, prompt, thread_id=None):

text_response: str = self.get_last_message(thread_id)

claix_command: ClaixCommand = self.populate_model_from_text(ClaixCommand, text_response)

if not claix_command.command:
claix_command.is_command = False
claix_command: ClaixCommand = self.client.chat.completions.create(
model=self.model, # Use self.model instead of hardcoding
response_model=ClaixCommand,
messages=[
{"role": "user", "content": text_response},
],
)

return claix_command

Expand All @@ -65,24 +70,24 @@ def get_revised_command(
revision_instructions: str,
original_instructions: str,
proposed_command: str,
) -> str:
) -> ClaixCommand:
revision_prompt = (
f"I want to: {original_instructions}\n"
f"The proposed solution was: {proposed_command}\n\n"
f"but I want to modify this solution considering this: {revision_instructions}\n\n"
f"please give me a new solution considering that"
)

revised_solution: str = self(revision_prompt)
revised_solution: ClaixCommand = self(revision_prompt)

return revised_solution

@staticmethod
def create_assistant(
name: str,
instructions: str,
model: str = "gpt-4-1106-preview",
tools: list[dict] = [{"type": "code_interpreter"}, {"type": "retrieval"}],
model: str = "gpt-4o-mini",
tools: list[dict] = [{"type": "code_interpreter"}, {"type": "file_search"}],
):
client = OpenAI()
assistant = client.beta.assistants.create(
Expand All @@ -99,20 +104,6 @@ def create_thread():
thread = client.beta.threads.create()
return thread

@staticmethod
def populate_model_from_text(model: BaseModel, text: str) -> BaseModel:
client = instructor.patch(OpenAI())
"""Populates a pydantic model from a text."""
response: model = client.chat.completions.create(
model="gpt-3.5-turbo",
response_model=model,
messages=[
{"role": "user", "content": text},
],
max_retries=3,
)
return response

def create_thread_message(self, prompt: str, thread_id: str):
message = self.client.beta.threads.messages.create(
thread_id=thread_id,
Expand Down
2 changes: 1 addition & 1 deletion claix/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def main(
thread_id = get_or_create_default_thread_id()

console = Console()
claix = Claix(assistant_id, thread_id)
claix: Claix = Claix(assistant_id, thread_id)
state = State.PROCESS_INSTRUCTIONS

start = True
Expand Down
41 changes: 26 additions & 15 deletions claix/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
from enum import Enum, auto
import rich
import inquirer
from claix.ai import Claix

from claix.ai import Claix, ClaixCommand
import dbm

USER_OS = "Windows" if os.name == "nt" else "Posix"

Expand Down Expand Up @@ -61,22 +61,31 @@ def run_shell_command(command):


def get_assistant_id(assistant: str = "default"):
with shelve.open(str(db_path)) as db:
try:
return db["assistants"][assistant]["id"]
except KeyError:
return None
try:
with shelve.open(str(db_path)) as db:
try:
return db["assistants"][assistant]["id"]
except KeyError:
return None
except dbm.error:
# If the database can't be opened, we'll create a new one
return None


def set_assistant_id(assistant_id, assistant="default"):
with shelve.open(str(db_path)) as db:
assistants = db.get("assistants", {})
default = assistants.get(assistant)
if default:
db["assistants"][assistant]["id"] = assistant_id
else:
db["assistants"] = {assistant: {"id": assistant_id}}
return assistant_id
try:
with shelve.open(str(db_path)) as db:
assistants = db.get("assistants", {})
default = assistants.get(assistant)
if default:
db["assistants"][assistant]["id"] = assistant_id
else:
db["assistants"] = {assistant: {"id": assistant_id}}
return assistant_id
except dbm.error:
# If we can't open or create the database, we'll just return the assistant_id
# This means we'll create a new assistant each time, but it's better than crashing
return assistant_id


def get_or_create_default_assistant_id():
Expand All @@ -85,6 +94,8 @@ def get_or_create_default_assistant_id():
assistant = Claix.create_assistant(
name="default",
instructions=DEFAULT_INSTRUCTIONS,
model="gpt-4o-mini",
tools=[{"type": "code_interpreter"}, {"type": "file_search"}]
)
assistant_id = set_assistant_id(assistant.id, assistant="default")
return assistant_id
Expand Down
Loading

0 comments on commit 339f6d1

Please sign in to comment.