Skip to content

Commit

Permalink
Code interpreter (#46)
Browse files Browse the repository at this point in the history
  • Loading branch information
kgrofelnik authored Mar 28, 2024
1 parent 1d5f8ba commit 64672d2
Show file tree
Hide file tree
Showing 8 changed files with 118 additions and 3 deletions.
2 changes: 1 addition & 1 deletion contracts/contracts/OpenAiChatGpt.sol
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ contract OpenAiChatGpt {
stop : "", // null
temperature : 10, // Example temperature (scaled up, 10 means 1.0), > 20 means null
topP : 101, // Percentage 0-100, > 100 means null
tools : "[{\"type\":\"function\",\"function\":{\"name\":\"web_search\",\"description\":\"Search the internet\",\"parameters\":{\"type\":\"object\",\"properties\":{\"query\":{\"type\":\"string\",\"description\":\"Search query\"}},\"required\":[\"query\"]}}}]",
tools : "[{\"type\":\"function\",\"function\":{\"name\":\"web_search\",\"description\":\"Search the internet\",\"parameters\":{\"type\":\"object\",\"properties\":{\"query\":{\"type\":\"string\",\"description\":\"Search query\"}},\"required\":[\"query\"]}}},{\"type\":\"function\",\"function\":{\"name\":\"code_interpreter\",\"description\":\"Evaluates python code in a sandbox environment. The environment resets on every execution. You must send the whole script every time and print your outputs. Script should be pure python code that can be evaluated. It should be in python format NOT markdown. The code should NOT be wrapped in backticks. All python packages including requests, matplotlib, scipy, numpy, pandas, etc are available. Output can only be read from stdout, and stdin. Do not use things like plot.show() as it will not work. print() any output and results so you can capture the output.\",\"parameters\":{\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"string\",\"description\":\"The pure python script to be evaluated. The contents will be in main.py. It should not be in markdown format.\"}},\"required\":[\"code\"]}}}]",
toolChoice : "auto", // "none" or "auto"
user : "" // null
});
Expand Down
42 changes: 41 additions & 1 deletion contracts/test/OpenAiChatGpt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,47 @@ describe("OpenAiChatGpt", function () {
await chatGpt.startChat("Hello");
// promptId: 0, callbackId: 0
const openAiConf = await oracle.openAiConfigurations(0)
expect(openAiConf.toString()).to.equal("gpt-4-turbo-preview,21,,1000,21,{\"type\":\"text\"},0,,10,101,[{\"type\":\"function\",\"function\":{\"name\":\"web_search\",\"description\":\"Search the internet\",\"parameters\":{\"type\":\"object\",\"properties\":{\"query\":{\"type\":\"string\",\"description\":\"Search query\"}},\"required\":[\"query\"]}}}],auto,")
const tools = [
{
"type": "function",
"function": {
"name": "web_search",
"description": "Search the internet",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Search query"
}
},
"required": [
"query"
]
}
}
},
{
"type": "function",
"function": {
"name": "code_interpreter",
"description": "Evaluates python code in a sandbox environment. The environment resets on every execution. You must send the whole script every time and print your outputs. Script should be pure python code that can be evaluated. It should be in python format NOT markdown. The code should NOT be wrapped in backticks. All python packages including requests, matplotlib, scipy, numpy, pandas, etc are available. Output can only be read from stdout, and stdin. Do not use things like plot.show() as it will not work. print() any output and results so you can capture the output.",
"parameters": {
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "The pure python script to be evaluated. The contents will be in main.py. It should not be in markdown format."
}
},
"required": [
"code"
]
}
}
}
];
expect(openAiConf.toString()).to.equal(`gpt-4-turbo-preview,21,,1000,21,{\"type\":\"text\"},0,,10,101,${JSON.stringify(tools)},auto,`);
});
it("Oracle can add response", async () => {
const {chatGpt, oracle, allSigners} = await loadFixture(deploy);
Expand Down
7 changes: 7 additions & 0 deletions oracles/oracle.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from src.domain.tools.search import web_search_use_case
from src.domain.knowledge_base import index_knowledge_base_use_case
from src.domain.knowledge_base import query_knowledge_base_use_case
from src.domain.tools.code_interpreter import python_interpreter_use_case
from src.entities import Chat
from src.entities import FunctionCall
from src.entities import KnowledgeBaseIndexingRequest
Expand Down Expand Up @@ -98,6 +99,12 @@ async def _call_function(function_call: FunctionCall, semaphore: Semaphore):
)
response = web_search_result.result
error_message = web_search_result.error
elif function_call.function_type == "code_interpreter":
python_interpreter_result = await python_interpreter_use_case.execute(
formatted_input
)
response = python_interpreter_result.stdout
error_message = python_interpreter_result.stderr
else:
response = ""
error_message = f"Unknown function '{function_call.function_type}'"
Expand Down
2 changes: 2 additions & 0 deletions oracles/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@
GCS_BUCKET_NAME = os.getenv("GCS_BUCKET_NAME", "galadriel-assets")
SERVE_METRICS = os.getenv("SERVE_METRICS", "False").lower() == "true"
NFT_STORAGE_API_KEY = os.getenv("NFT_STORAGE_API_KEY")
BEARLY_API_KEY = os.getenv("BEARLY_API_KEY")

KNOWLEDGE_BASE_MAX_SIZE_BYTES = int(
os.getenv("KNOWLEDGE_BASE_MAX_SIZE_BYTES", 10485760)
)
KNOWLEDGE_BASE_CACHE_MAX_SIZE = int(os.getenv("KNOWLEDGE_BASE_CACHE_MAX_SIZE", 100))

8 changes: 8 additions & 0 deletions oracles/src/domain/tools/code_interpreter/entities.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from dataclasses import dataclass


@dataclass
class PythonInterpreterResult:
stdout: str
stderr: str
exit_code: int
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import re
import base64
import aiohttp
import settings
from typing import Optional
from src.domain.tools.code_interpreter.entities import PythonInterpreterResult


async def _interpret_code(code: str) -> Optional[PythonInterpreterResult]:
try:
async with aiohttp.ClientSession() as session:
async with session.post(
"https://exec.bearly.ai/v1/interpreter",
headers={
"Authorization": settings.BEARLY_API_KEY,
},
json={
"fileContents": code,
"inputFiles": [],
"outputDir": "output/",
"outputAsLinks": True,
},
) as response:
response.raise_for_status()
data = await response.json()
return PythonInterpreterResult(
stdout=(
base64.b64decode(data["stdoutBasesixtyfour"]).decode()
if data["stdoutBasesixtyfour"]
else ""
),
stderr=(
base64.b64decode(data["stderrBasesixtyfour"]).decode()
if data["stderrBasesixtyfour"]
else ""
),
exit_code=data["exitCode"],
)
except Exception as e:
return PythonInterpreterResult(stdout="", stderr=str(e), exit_code=1)


async def _strip_markdown_code(md_string: str) -> str:
stripped_string = re.sub(r"^`{1,3}.*?\n", "", md_string, flags=re.DOTALL)
stripped_string = re.sub(r"`{1,3}$", "", stripped_string)
return stripped_string


async def execute(code: str) -> Optional[PythonInterpreterResult]:
clean_code = await _strip_markdown_code(code)
return await _interpret_code(clean_code)


if __name__ == "__main__":
import asyncio

print(asyncio.run(execute("print(2 + 2)")))
2 changes: 1 addition & 1 deletion oracles/src/entities.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from openai.types.chat import ChatCompletion
from openai.types.chat import ChatCompletionToolParam

ALLOWED_FUNCTION_NAMES = ["image_generation", "web_search"]
ALLOWED_FUNCTION_NAMES = ["image_generation", "web_search", "code_interpreter"]

OpenAiModelType = Literal["gpt-4-turbo-preview", "gpt-3.5-turbo-1106"]

Expand Down
1 change: 1 addition & 0 deletions oracles/template.env
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ ORACLE_ADDRESS="0x"
ORACLE_ABI_PATH="../arbitrum-contracts/artifacts/contracts/Oracle.sol/Oracle.json"

GCS_BUCKET_NAME="galadriel-assets"
BEARLY_API_KEY=""
SERVE_METRICS="False"
NFT_STORAGE_API_KEY=""

Expand Down

0 comments on commit 64672d2

Please sign in to comment.