Skip to content

Commit

Permalink
add explain
Browse files Browse the repository at this point in the history
  • Loading branch information
odashi committed Mar 6, 2023
1 parent 51f20dc commit 603270d
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 5 deletions.
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,27 @@ Synthesizes a Python function described in the prompt.
(3, 2)
```

### `davinci_functions.explain`

Describes the behavior of given functions.

```python
>>> def f(x):
... return x * 3
...
>>> davinci_functions.explain(f)
'This function takes a variable x and multiplies it by 3, then returns the result.'
>>> def f(a, b, c):
... return (-b + math.sqrt(b**2 - 4.0 * a * c)) / (2.0 * a)
...
>>> davinci_functions.explain(f)
'This function implements the Quadratic Formula to calculate the solution of a ...
quadratic equation. The equation is of the form ax^2 + bx + c = 0. The function ...
takes three parameters a, b, and c, which are the coefficients of the equation. It ...
then calculates the solution using the formula (-b + sqrt(b^2 - 4ac)) / (2a) and ...
returns the result.'
```


## Caveats

Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ classifiers = [
"Programming Language :: Python :: 3.11",
]
dependencies = [
"dill>=0.3.6",
"openai>=0.27.0",
]
dynamic = [
Expand Down
2 changes: 2 additions & 0 deletions src/davinci_functions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@
except Exception:
__version__ = ""

from davinci_functions._explain import explain
from davinci_functions._function import function
from davinci_functions._judge import judge
from davinci_functions._list import list

__all__ = [
"explain",
"function",
"judge",
"list",
Expand Down
68 changes: 68 additions & 0 deletions src/davinci_functions/_explain.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
"""implementation of `explain` function."""

from __future__ import annotations

import textwrap
from collections.abc import Callable
from typing import Any

import dill # type: ignore[import]
import openai


def explain(fn: Callable[..., Any]) -> str:
"""Describes the behavior of the given function.
Args:
fn: A callable. The corresponding source code must be associated to this object.
i.e., inspect.getsource(fn) should work.
Returns:
The description of `fn` written by GPT.
Example:
>>> def my_function(x):
... if x == 0:
... return 1.0
... else:
... return math.sin(x) / x
...
>>> f = davinci_functions.explain(my_function)
'This function takes a single argument x and returns a float value. If x is ...
0, it returns 1.0, otherwise it returns the result of the sine of x divided ...
by x. This is known as the sinc function.'
"""
src = dill.source.getsource(fn)
base_prompt = textwrap.dedent(
"""\
Describe the detailed behavior of the following Python function.
The question may have multiple lines.
It is written between "BEGIN_QUESTION" and "END_QUESTION".
The answer is written after "ANSWER".
The result may have multiple lines.
It is recommended to write as detailed explanation as possible.
If the algorithm written in the function has some contexts, describe it as well.
For example, if the algorithm has a name, it should be written in the answer.
BEGIN_QUESTION
def sum(a, b):
return a + b
END_QUESTION
ANSWER
This function adds two variables a and b and returns its result.
BEGIN_QUESTION
{}
END_QUESTION
ANSWER
"""
)

return openai.Completion.create( # type: ignore[no-any-return, no-untyped-call]
model="text-davinci-003",
prompt=base_prompt.format(src),
max_tokens=2048,
temperature=0,
)["choices"][0]["text"]
19 changes: 19 additions & 0 deletions src/davinci_functions/_explain_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"""Tests for davinci_functions._explain."""

from __future__ import annotations

import pytest_mock

from davinci_functions._explain import explain


def test_explain(mocker: pytest_mock.MockerFixture) -> None:
mocker.patch(
"openai.Completion.create",
return_value={"choices": [{"text": "This is a test."}]},
)

def dummy() -> int:
return 42

assert explain(dummy) == "This is a test."
5 changes: 3 additions & 2 deletions src/davinci_functions/_function.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""implementation of `list` function."""
"""implementation of `function` function."""

from __future__ import annotations

Expand All @@ -24,7 +24,8 @@ def function(prompt: str) -> Callable[..., Any]:
A callable object that may represent the behavior of the prompt.
Raises:
SyntaxError: GPT didn't return a Python literal.
SyntaxError: GPT didn't return a meaningful Python program.
TypeError: GPT didn't return a Python callable.
Example:
>>> f = davinci_functions.list("Multiply the argument x by 2.")
Expand Down
6 changes: 3 additions & 3 deletions src/davinci_functions/_function_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from davinci_functions._function import function


def test_judge_true(mocker: pytest_mock.MockerFixture) -> None:
def test_function(mocker: pytest_mock.MockerFixture) -> None:
mocker.patch(
"openai.Completion.create",
return_value={"choices": [{"text": "def func(x):\n return x * 2"}]},
Expand All @@ -19,7 +19,7 @@ def test_judge_true(mocker: pytest_mock.MockerFixture) -> None:
assert f(3) == 6


def test_judge_non_python(mocker: pytest_mock.MockerFixture) -> None:
def test_function_non_python(mocker: pytest_mock.MockerFixture) -> None:
mocker.patch(
"openai.Completion.create",
return_value={"choices": [{"text": "Error."}]},
Expand All @@ -29,7 +29,7 @@ def test_judge_non_python(mocker: pytest_mock.MockerFixture) -> None:
function("This is a test.")


def test_judge_non_function(mocker: pytest_mock.MockerFixture) -> None:
def test_function_non_function(mocker: pytest_mock.MockerFixture) -> None:
mocker.patch(
"openai.Completion.create",
return_value={"choices": [{"text": "func = 42"}]},
Expand Down

0 comments on commit 603270d

Please sign in to comment.