Skip to content

Commit

Permalink
Merge branch 'main' into add_docker
Browse files Browse the repository at this point in the history
  • Loading branch information
ducanhdt authored Aug 6, 2023
2 parents 724817f + 0478187 commit 86c866d
Show file tree
Hide file tree
Showing 36 changed files with 1,133 additions and 682 deletions.
14 changes: 9 additions & 5 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
OPENAI_API_KEY= # your openai api key (required)
CODEBOX_API_KEY= # your codebox api key (optional, required for production)
VERBOSE=False # set to True to enable verbose logging
# (required)
OPENAI_API_KEY=
# (optional, required for production)
# CODEBOX_API_KEY=
# (set True to enable logging)
VERBOSE=False

STORAGE_TYPE="redis" # "file" or "redis"

STORAGE_TYPE="file" # "file" or "redis"

RD_HOST=
RD_PORT=

SESSION_STORAGE_FOLDER="session_storage"
SESSION_STORAGE_FOLDER="session_storage"
2 changes: 1 addition & 1 deletion .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# These are supported funding model platforms

github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
github: shroominic
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: shroominic
Expand Down
16 changes: 16 additions & 0 deletions .github/workflows/code-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: code-check

on: [push]

jobs:
pre-commit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: 3.9
- name: Install pre-commit
run: pip install pre-commit
- name: Run pre-commit
run: pre-commit run --all-files
31 changes: 31 additions & 0 deletions .github/workflows/python-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Upload Python Package

on:
release:
types: [published]

permissions:
contents: read

jobs:
deploy:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v3
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install build
- name: Build package
run: python -m build
- name: Publish package
uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}
27 changes: 27 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v2.3.0
hooks:
- id: check-yaml
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/psf/black
rev: 23.7.0
hooks:
- id: black
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.4.1
hooks:
- id: mypy
args: [--ignore-missing-imports, --follow-imports=skip]
additional_dependencies: [types-requests]
- repo: https://github.com/pre-commit/mirrors-isort
rev: v5.9.3
hooks:
- id: isort
args: [--profile=black]
- repo: https://github.com/PYCQA/flake8
rev: 6.1.0
hooks:
- id: flake8
args: [--max-line-length=88]
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@ You can run everything local except the LLM using your own OpenAI API Key.
Get your OpenAI API Key [here](https://platform.openai.com/account/api-keys) and install the package.

```bash
pip install codeinterpreterapi
pip install "codeinterpreterapi[all]"
```

Everything for local experiments are installed with the `all` extra.
For deployments, you can use `pip install codeinterpreterapi` instead which does not install the additional dependencies.

## Usage

Make sure to set the `OPENAI_API_KEY` environment variable (or use a `.env` file)
Expand Down Expand Up @@ -56,7 +59,7 @@ if __name__ == "__main__":

```

![Bitcoin YTD](https://github.com/shroominic/codeinterpreter-api/blob/main/examples/assets/bitcoin_chart.png?raw=true)
![Bitcoin YTD](https://github.com/shroominic/codeinterpreter-api/blob/main/examples/assets/bitcoin_chart.png?raw=true)
Bitcoin YTD Chart Output

## Dataset Analysis
Expand Down Expand Up @@ -91,7 +94,7 @@ if __name__ == "__main__":
asyncio.run(main())
```

![Iris Dataset Analysis](https://github.com/shroominic/codeinterpreter-api/blob/main/examples/assets/iris_analysis.png?raw=true)
![Iris Dataset Analysis](https://github.com/shroominic/codeinterpreter-api/blob/main/examples/assets/iris_analysis.png?raw=true)
Iris Dataset Analysis Output

## Production
Expand Down Expand Up @@ -127,7 +130,7 @@ streamlit run frontend/app.py
## Contact

You can contact me at [contact@shroominic.com](mailto:contact@shroominic.com).
But I prefer to use [Twitter](https://twitter.com/shroominic) or [Discord](https://gptassistant.app/community) DMs.
But I prefer to use [Twitter](https://twitter.com/shroominic) or [Discord](https://discord.gg/QYzBtq37) DMs.

## Support this project

Expand Down
4 changes: 3 additions & 1 deletion codeinterpreterapi/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
from codeinterpreterapi.schema import File
from codeinterpreterapi.session import CodeInterpreterSession
from codeinterpreterapi.schema import File

__all__ = ["CodeInterpreterSession", "File"]
3 changes: 3 additions & 0 deletions codeinterpreterapi/agents/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from .functions_agent import OpenAIFunctionsAgent

__all__ = ["OpenAIFunctionsAgent"]
2 changes: 2 additions & 0 deletions codeinterpreterapi/agents/custom_agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# TODO: override some methods of the ConversationalAgent class
# to improve the agent's performance
Original file line number Diff line number Diff line change
@@ -1,25 +1,21 @@
"""
Module implements an agent that uses OpenAI's APIs function enabled API.
This file is a modified version of the original file
This file is a modified version of the original file
from langchain/agents/openai_functions_agent/base.py.
Credits go to the original authors :)
"""


import json
from dataclasses import dataclass
from json import JSONDecodeError
from typing import Any, List, Optional, Sequence, Tuple, Union

from pydantic import root_validator

from langchain.agents import BaseSingleActionAgent
from langchain.base_language import BaseLanguageModel
from langchain.callbacks.base import BaseCallbackManager
from langchain.callbacks.manager import Callbacks
from langchain.chat_models.openai import ChatOpenAI
from langchain.schema import BasePromptTemplate
from langchain.prompts.chat import (
BaseMessagePromptTemplate,
ChatPromptTemplate,
Expand All @@ -31,13 +27,14 @@
AgentFinish,
AIMessage,
BaseMessage,
BasePromptTemplate,
FunctionMessage,
OutputParserException,
HumanMessage,
SystemMessage,
)
from langchain.tools import BaseTool
from langchain.tools.convert_to_openai import format_tool_to_openai_function
from pydantic import root_validator


@dataclass
Expand Down
9 changes: 9 additions & 0 deletions codeinterpreterapi/chains/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from .extract_code import extract_python_code
from .modifications_check import get_file_modifications
from .rm_dl_link import remove_download_link

__all__ = [
"extract_python_code",
"get_file_modifications",
"remove_download_link",
]
41 changes: 41 additions & 0 deletions codeinterpreterapi/chains/extract_code.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from langchain.base_language import BaseLanguageModel
from langchain.chat_models.anthropic import ChatAnthropic


# TODO: make async
def extract_python_code(
text: str,
llm: BaseLanguageModel,
retry: int = 2,
):
pass


async def test():
llm = ChatAnthropic(model="claude-1.3") # type: ignore

code = """
import matplotlib.pyplot as plt
x = list(range(1, 11))
y = [29, 39, 23, 32, 4, 43, 43, 23, 43, 77]
plt.plot(x, y, marker='o')
plt.xlabel('Index')
plt.ylabel('Value')
plt.title('Data Plot')
plt.show()
"""

print(extract_python_code(code, llm))


if __name__ == "__main__":
import asyncio

import dotenv

dotenv.load_dotenv()

asyncio.run(test())
48 changes: 24 additions & 24 deletions codeinterpreterapi/chains/modifications_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@
from typing import List, Optional

from langchain.base_language import BaseLanguageModel
from langchain.chat_models.openai import ChatOpenAI
from langchain.schema import AIMessage, OutputParserException
from langchain.chat_models.anthropic import ChatAnthropic

from codeinterpreterapi.prompts import determine_modifications_function, determine_modifications_prompt
from codeinterpreterapi.prompts import determine_modifications_prompt


async def get_file_modifications(
Expand All @@ -15,44 +14,45 @@ async def get_file_modifications(
) -> Optional[List[str]]:
if retry < 1:
return None
messages = determine_modifications_prompt.format_prompt(code=code).to_messages()
message = await llm.apredict_messages(messages, functions=[determine_modifications_function])

if not isinstance(message, AIMessage):
raise OutputParserException("Expected an AIMessage")
prompt = determine_modifications_prompt.format(code=code)

function_call = message.additional_kwargs.get("function_call", None)
result = await llm.apredict(prompt, stop="```")

if function_call is None:
try:
result = json.loads(result)
except json.JSONDecodeError:
result = ""
if not result or not isinstance(result, dict) or "modifications" not in result:
return await get_file_modifications(code, llm, retry=retry - 1)
else:
function_call = json.loads(function_call["arguments"])
return function_call["modifications"]
return result["modifications"]


async def test():
llm = ChatOpenAI(model="gpt-3.5") # type: ignore
llm = ChatAnthropic(model="claude-1.3") # type: ignore

code = """
import matplotlib.pyplot as plt
import matplotlib.pyplot as plt
x = list(range(1, 11))
y = [29, 39, 23, 32, 4, 43, 43, 23, 43, 77]
x = list(range(1, 11))
y = [29, 39, 23, 32, 4, 43, 43, 23, 43, 77]
plt.plot(x, y, marker='o')
plt.xlabel('Index')
plt.ylabel('Value')
plt.title('Data Plot')
plt.plot(x, y, marker='o')
plt.xlabel('Index')
plt.ylabel('Value')
plt.title('Data Plot')
plt.show()
"""
plt.show()
"""

print(await get_file_modifications(code, llm))


if __name__ == "__main__":
import asyncio
from dotenv import load_dotenv
load_dotenv()

import dotenv

dotenv.load_dotenv()

asyncio.run(test())
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ async def remove_download_link(
input_response: str,
llm: BaseLanguageModel,
) -> str:
messages = remove_dl_link_prompt.format_prompt(input_response=input_response).to_messages()
messages = remove_dl_link_prompt.format_prompt(
input_response=input_response
).to_messages()
message = await llm.apredict_messages(messages)

if not isinstance(message, AIMessage):
Expand All @@ -21,14 +23,18 @@ async def remove_download_link(
async def test():
llm = ChatOpenAI(model="gpt-3.5-turbo-0613") # type: ignore

example = "I have created the plot to your dataset.\n\nLink to the file [here](sandbox:/plot.png)."

example = (
"I have created the plot to your dataset.\n\n"
"Link to the file [here](sandbox:/plot.png)."
)
print(await remove_download_link(example, llm))


if __name__ == "__main__":
import asyncio

from dotenv import load_dotenv

load_dotenv()

asyncio.run(test())
5 changes: 3 additions & 2 deletions codeinterpreterapi/config.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from pydantic import BaseSettings
from dotenv import load_dotenv
from typing import Optional

from dotenv import load_dotenv
from pydantic import BaseSettings

# .env file
load_dotenv(dotenv_path="./.env")

Expand Down
10 changes: 8 additions & 2 deletions codeinterpreterapi/prompts/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
from .modifications_check import determine_modifications_prompt
from .remove_dl_link import remove_dl_link_prompt
from .system_message import system_message as code_interpreter_system_message
from .modifications_check import determine_modifications_function, determine_modifications_prompt
from .remove_dl_link import remove_dl_link_prompt

__all__ = [
"determine_modifications_prompt",
"remove_dl_link_prompt",
"code_interpreter_system_message",
]
Loading

0 comments on commit 86c866d

Please sign in to comment.