from
typing
import
Callable
,
Dict
,
List
, Union,
Any
import
math
import
dataclasses
from
functools
import
wraps
from
google
import
genai
from
google.genai
import
types
API_KEY
=
'xxxxxxxxxx'
client
=
genai.Client(api_key
=
API_KEY)
MAX_COUNT
=
4
@dataclasses
.dataclass
class
Count_f_call:
count:
int
=
0
need_terminate:
bool
=
False
func_count
=
Count_f_call()
def
add_count(func):
@wraps
(func)
def
wrapper(
*
args,
*
*
kwargs):
func_count.count
+
=
1
if
func_count.count > MAX_COUNT: func_count.need_terminate
=
True
return
func(
*
args,
*
*
kwargs)
return
wrapper
def
zero_count(func):
def
wrapper(
*
args,
*
*
kwargs):
func_count.count
=
0
func_count.need_terminate
=
False
func(
*
args,
*
*
kwargs)
return
wrapper
def
tokenize(s:
str
)
-
>
list
[
str
]:
return
s.replace(
'('
,
' ( '
).replace(
')'
,
' ) '
).split()
def
parse(expression:
str
)
-
>
list
[
str
]:
"Read a expression from a string."
return
tokenize(expression)
@add_count
def
calculator(expression:
str
)
-
> Union[
str
,
int
,
float
]:
if
func_count.need_terminate:
return
"Warning: exceed the max function call times in a single LLM call"
available_operations:
List
[
str
]
=
[
"+"
,
"-"
,
"*"
,
"/"
,
"^"
,
"sqrt"
,
"abs"
,
"sin"
,
"cos"
,
"tan"
,
"log"
,
"exp"
,
"round"
]
print
(f
"\r函数调用:{func_count.count} 算式: {expression}"
,end
=
'',flush
=
True
)
try
:
tokens
=
parse(expression)
return
_evaluate_expression(tokens, available_operations)
except
Exception as e:
return
f
"Error: An unexpected error occurred: {str(e)}"
def
_evaluate_expression(tokens:
list
[
str
], available_operations:
List
[
str
])
-
> Union[
str
,
int
,
float
]:
if
not
tokens:
return
"Error: Empty expression."
if
tokens[
0
]
=
=
'('
:
tokens.pop(
0
)
if
not
tokens:
return
"Error: Unbalanced parenthesis."
operation
=
tokens.pop(
0
)
if
operation
not
in
available_operations:
return
f
"Error: Unsupported operation: {operation}. Available operations are: {', '.join(available_operations)}"
arguments
=
[]
while
tokens
and
tokens[
0
] !
=
')'
:
arg
=
_evaluate_expression(tokens, available_operations)
if
isinstance
(arg,
str
)
and
arg.startswith(
"Error:"
):
return
arg
arguments.append(arg)
if
not
tokens:
return
"Error: Unbalanced parenthesis."
tokens.pop(
0
)
return
_apply_operation(operation, arguments)
try
:
return
float
(tokens.pop(
0
))
except
(ValueError, IndexError):
return
"Error: Invalid number or unexpected token."
def
_apply_operation(operation:
str
, arguments:
List
[Union[
int
,
float
]])
-
> Union[
str
,
int
,
float
]:
match operation:
case
"+"
:
return
sum
(arguments)
case
"-"
:
if
len
(arguments) !
=
2
:
return
"Error: Subtraction requires exactly 2 arguments."
return
arguments[
0
]
-
arguments[
1
]
case
"*"
:
result
=
1
for
arg
in
arguments:
result
*
=
arg
return
result
case
"/"
:
if
len
(arguments) !
=
2
:
return
"Error: Division requires exactly 2 arguments."
if
arguments[
1
]
=
=
0
:
return
"Error: Division by zero."
return
arguments[
0
]
/
arguments[
1
]
case
"^"
:
if
len
(arguments) !
=
2
:
return
"Error: Power operation requires exactly 2 arguments."
return
arguments[
0
]
*
*
arguments[
1
]
case
"sqrt"
:
if
len
(arguments) !
=
1
:
return
"Error: Square root requires exactly 1 argument."
if
arguments[
0
] <
0
:
return
"Error: Cannot take square root of negative number."
return
math.sqrt(arguments[
0
])
case
"abs"
:
if
len
(arguments) !
=
1
:
return
"Error: Absolute value requires exactly 1 argument."
return
abs
(arguments[
0
])
case
"sin"
|
"cos"
|
"tan"
:
if
len
(arguments) !
=
1
:
return
f
"Error: {operation} requires exactly 1 argument."
if
operation
=
=
"sin"
:
return
math.sin(arguments[
0
])
elif
operation
=
=
"cos"
:
return
math.cos(arguments[
0
])
else
:
return
math.tan(arguments[
0
])
case
"log"
:
if
len
(arguments) !
=
1
:
return
"Error: Logarithm requires exactly 1 argument."
if
arguments[
0
] <
=
0
:
return
"Error: Cannot take logarithm of non-positive number."
return
math.log(arguments[
0
])
case
"exp"
:
if
len
(arguments) !
=
1
:
return
"Error: Exponential requires exactly 1 argument."
return
math.exp(arguments[
0
])
case
"round"
:
if
len
(arguments)
=
=
1
:
return
round
(arguments[
0
])
elif
len
(arguments)
=
=
2
:
return
round
(arguments[
0
], arguments[
1
])
else
:
return
"Error: Rounding requires 1 or 2 arguments."
case _:
return
"Error: Invalid operation."
@zero_count
def
llm_call(content_text):
response
=
client.models.generate_content(
model
=
'gemini-2.0-flash-exp'
,
contents
=
content_text,
config
=
types.GenerateContentConfig(
system_instruction
=
'you are helpful assistant, when encounter function call task,in addition to completing task,also keep the final raw json sent to funcition '
,
temperature
=
0.7
,
tools
=
[calculator],
),
)
print
(
'-'
*
40
)
print
(response.text)
if
__name__
=
=
"__main__"
:
import
os
os.environ[
'http_proxy'
]
=
'http://127.0.0.1:8000'
os.environ[
'https_proxy'
]
=
'http://127.0.0.1:8000'
while
True
:
content_text
=
input
(
"请输入问题:"
).strip()
llm_call(content_text)
input
("")