Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Code interpreter #46

Merged
merged 8 commits into from
Mar 28, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
2 changes: 1 addition & 1 deletion contracts/test/OpenAiChatGpt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ 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,")
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\"]}}},{\"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\"]}}}],auto,")
kgrofelnik marked this conversation as resolved.
Show resolved Hide resolved
});
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
Loading