chatterer 0.1.10__py3-none-any.whl → 0.1.11__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- chatterer/language_model.py +46 -45
- chatterer/tools/youtube.py +15 -1
- chatterer/utils/image.py +1 -1
- {chatterer-0.1.10.dist-info → chatterer-0.1.11.dist-info}/METADATA +1 -1
- {chatterer-0.1.10.dist-info → chatterer-0.1.11.dist-info}/RECORD +7 -7
- {chatterer-0.1.10.dist-info → chatterer-0.1.11.dist-info}/WHEEL +1 -1
- {chatterer-0.1.10.dist-info → chatterer-0.1.11.dist-info}/top_level.txt +0 -0
chatterer/language_model.py
CHANGED
@@ -35,13 +35,11 @@ DEFAULT_IMAGE_DESCRIPTION_INSTRUCTION = "Provide a detailed description of all v
|
|
35
35
|
DEFAULT_CODE_GENERATION_PROMPT = (
|
36
36
|
"You are utilizing a Python code execution tool now.\n"
|
37
37
|
"Your goal is to generate Python code that solves the task efficiently and appends both the code and its output to your context memory.\n"
|
38
|
-
"Since your context window is highly limited, type `pass` if no code execution is needed.\n"
|
39
38
|
"\n"
|
40
39
|
"To optimize tool efficiency, follow these guidelines:\n"
|
41
40
|
"- Write concise, efficient code that directly serves the intended purpose.\n"
|
42
41
|
"- Avoid unnecessary operations (e.g., excessive loops, recursion, or heavy computations).\n"
|
43
42
|
"- Handle potential errors gracefully (e.g., using try-except blocks).\n"
|
44
|
-
"- Prevent excessive output by limiting print statements to essential information only (e.g., avoid printing large datasets).\n"
|
45
43
|
"\n"
|
46
44
|
"Return your response strictly in the following JSON format:\n"
|
47
45
|
'{\n "code": "<your_python_code_here>"\n}\n\n'
|
@@ -393,30 +391,30 @@ def _with_structured_output(
|
|
393
391
|
return client.with_structured_output(schema=response_model, **structured_output_kwargs) # pyright: ignore[reportUnknownVariableType, reportUnknownMemberType]
|
394
392
|
|
395
393
|
|
396
|
-
def _add_message_last(messages: LanguageModelInput, prompt_to_add: str) -> LanguageModelInput:
|
397
|
-
if isinstance(messages, str):
|
398
|
-
messages += f"\n{prompt_to_add}"
|
399
|
-
elif isinstance(messages, Sequence):
|
400
|
-
messages = list(messages)
|
401
|
-
messages.append(SystemMessage(content=prompt_to_add))
|
402
|
-
else:
|
403
|
-
messages = messages.to_messages()
|
404
|
-
messages.append(SystemMessage(content=prompt_to_add))
|
405
|
-
return messages
|
406
|
-
|
407
|
-
|
408
|
-
# def _add_message_first(messages: LanguageModelInput, prompt_to_add: str) -> LanguageModelInput:
|
394
|
+
# def _add_message_last(messages: LanguageModelInput, prompt_to_add: str) -> LanguageModelInput:
|
409
395
|
# if isinstance(messages, str):
|
410
|
-
# messages
|
396
|
+
# messages += f"\n{prompt_to_add}"
|
411
397
|
# elif isinstance(messages, Sequence):
|
412
398
|
# messages = list(messages)
|
413
|
-
# messages.
|
399
|
+
# messages.append(SystemMessage(content=prompt_to_add))
|
414
400
|
# else:
|
415
401
|
# messages = messages.to_messages()
|
416
|
-
# messages.
|
402
|
+
# messages.append(SystemMessage(content=prompt_to_add))
|
417
403
|
# return messages
|
418
404
|
|
419
405
|
|
406
|
+
def _add_message_first(messages: LanguageModelInput, prompt_to_add: str) -> LanguageModelInput:
|
407
|
+
if isinstance(messages, str):
|
408
|
+
messages = f"{prompt_to_add}\n{messages}"
|
409
|
+
elif isinstance(messages, Sequence):
|
410
|
+
messages = list(messages)
|
411
|
+
messages.insert(0, SystemMessage(content=prompt_to_add))
|
412
|
+
else:
|
413
|
+
messages = messages.to_messages()
|
414
|
+
messages.insert(0, SystemMessage(content=prompt_to_add))
|
415
|
+
return messages
|
416
|
+
|
417
|
+
|
420
418
|
def augment_prompt_for_toolcall(
|
421
419
|
function_signatures: Iterable[FunctionSignature],
|
422
420
|
messages: LanguageModelInput,
|
@@ -425,14 +423,14 @@ def augment_prompt_for_toolcall(
|
|
425
423
|
function_reference_seperator: str = DEFAULT_FUNCTION_REFERENCE_SEPARATOR,
|
426
424
|
) -> LanguageModelInput:
|
427
425
|
if function_signatures:
|
428
|
-
messages =
|
426
|
+
messages = _add_message_first(
|
429
427
|
messages=messages,
|
430
428
|
prompt_to_add=FunctionSignature.as_prompt(
|
431
429
|
function_signatures, function_reference_prefix, function_reference_seperator
|
432
430
|
),
|
433
431
|
)
|
434
432
|
if prompt_for_code_invoke:
|
435
|
-
messages =
|
433
|
+
messages = _add_message_first(messages=messages, prompt_to_add=prompt_for_code_invoke)
|
436
434
|
return messages
|
437
435
|
|
438
436
|
|
@@ -450,16 +448,16 @@ def interactive_shell(
|
|
450
448
|
stop: Optional[list[str]] = None,
|
451
449
|
**kwargs: Any,
|
452
450
|
) -> None:
|
453
|
-
# Define the CodeExecutionDecision class using Pydantic
|
454
|
-
|
455
451
|
from rich.console import Console
|
456
452
|
from rich.prompt import Prompt
|
457
453
|
|
454
|
+
# 코드 실행 필요 여부를 판단하는 모델
|
458
455
|
class IsCodeExecutionNeeded(BaseModel):
|
459
456
|
is_code_execution_needed: bool = Field(
|
460
457
|
description="Whether Python tool calling is needed to answer user query."
|
461
458
|
)
|
462
459
|
|
460
|
+
# 추가 코드 실행 필요 여부를 판단하는 모델
|
463
461
|
class IsFurtherCodeExecutionNeeded(BaseModel):
|
464
462
|
review_on_code_execution: str = Field(description="Review on the code execution.")
|
465
463
|
next_action: str = Field(description="Next action to take.")
|
@@ -467,17 +465,12 @@ def interactive_shell(
|
|
467
465
|
description="Whether further Python tool calling is needed to answer user query."
|
468
466
|
)
|
469
467
|
|
470
|
-
#
|
471
|
-
# This tool namespace is persistent across multiple code executions.
|
468
|
+
# REPL 도구 초기화
|
472
469
|
if repl_tool is None:
|
473
470
|
repl_tool = get_default_repl_tool()
|
474
471
|
|
475
472
|
function_signatures: list[FunctionSignature] = FunctionSignature.from_callable(additional_callables)
|
476
|
-
|
477
|
-
# Initialize Rich console
|
478
473
|
console = Console()
|
479
|
-
|
480
|
-
# Initialize conversation context
|
481
474
|
context: list[BaseMessage] = []
|
482
475
|
if system_instruction:
|
483
476
|
if isinstance(system_instruction, BaseMessage):
|
@@ -485,23 +478,22 @@ def interactive_shell(
|
|
485
478
|
else:
|
486
479
|
context.extend(system_instruction)
|
487
480
|
|
488
|
-
#
|
481
|
+
# 환영 메시지
|
489
482
|
console.print("[bold blue]Welcome to the Interactive Chatterer Shell![/bold blue]")
|
490
483
|
console.print("Type 'quit' or 'exit' to end the conversation.")
|
491
484
|
|
492
485
|
while True:
|
493
|
-
#
|
486
|
+
# 사용자 입력 받기
|
494
487
|
user_input = Prompt.ask("[bold green]You[/bold green]")
|
495
488
|
if user_input.lower() in ["quit", "exit"]:
|
496
489
|
console.print("[bold blue]Goodbye![/bold blue]")
|
497
490
|
break
|
498
491
|
|
499
|
-
# Add user message to context
|
500
492
|
context.append(HumanMessage(content=user_input))
|
501
493
|
|
502
|
-
#
|
494
|
+
# 코드 실행 필요 여부 판단
|
503
495
|
decision = chatterer.generate_pydantic(
|
504
|
-
response_model=IsCodeExecutionNeeded,
|
496
|
+
response_model=IsCodeExecutionNeeded,
|
505
497
|
messages=augment_prompt_for_toolcall(
|
506
498
|
function_signatures=function_signatures,
|
507
499
|
messages=context,
|
@@ -511,8 +503,8 @@ def interactive_shell(
|
|
511
503
|
),
|
512
504
|
)
|
513
505
|
|
506
|
+
# 코드 실행 처리
|
514
507
|
if decision.is_code_execution_needed:
|
515
|
-
# Execute code if needed
|
516
508
|
code_result = chatterer.invoke_code_execution(
|
517
509
|
messages=context,
|
518
510
|
repl_tool=repl_tool,
|
@@ -530,8 +522,8 @@ def interactive_shell(
|
|
530
522
|
else:
|
531
523
|
code_session_messages: list[BaseMessage] = []
|
532
524
|
while True:
|
533
|
-
code_execution_message =
|
534
|
-
content=f"Executed code:\n```python\n{code_result.code}\n```\nOutput:\n{code_result.output}"
|
525
|
+
code_execution_message = AIMessage(
|
526
|
+
content=f"Executed code:\n```python\n{code_result.code}\n```\nOutput:\n{code_result.output}".strip()
|
535
527
|
)
|
536
528
|
code_session_messages.append(code_execution_message)
|
537
529
|
console.print("[bold yellow]Executed code:[/bold yellow]")
|
@@ -540,7 +532,7 @@ def interactive_shell(
|
|
540
532
|
console.print(code_result.output)
|
541
533
|
|
542
534
|
decision = chatterer.generate_pydantic(
|
543
|
-
response_model=IsFurtherCodeExecutionNeeded,
|
535
|
+
response_model=IsFurtherCodeExecutionNeeded,
|
544
536
|
messages=augment_prompt_for_toolcall(
|
545
537
|
function_signatures=function_signatures,
|
546
538
|
messages=context + code_session_messages,
|
@@ -549,31 +541,40 @@ def interactive_shell(
|
|
549
541
|
function_reference_seperator=function_reference_seperator,
|
550
542
|
),
|
551
543
|
)
|
552
|
-
review_on_code_execution = decision.review_on_code_execution
|
553
|
-
next_action = decision.next_action
|
544
|
+
review_on_code_execution = decision.review_on_code_execution.strip()
|
545
|
+
next_action = decision.next_action.strip()
|
554
546
|
console.print("[bold blue]AI:[/bold blue]")
|
555
547
|
console.print(f"-[bold yellow]Review on code execution:[/bold yellow] {review_on_code_execution}")
|
556
548
|
console.print(f"-[bold yellow]Next Action:[/bold yellow] {next_action}")
|
557
549
|
code_session_messages.append(
|
558
550
|
AIMessage(
|
559
|
-
content=f"- Review upon code execution: {
|
551
|
+
content=f"- Review upon code execution: {review_on_code_execution}\n- Next Action: {next_action}".strip()
|
560
552
|
)
|
561
553
|
)
|
562
554
|
if not decision.is_further_code_execution_needed:
|
563
555
|
tool_use_message = code_execution_message
|
564
556
|
break
|
565
557
|
else:
|
566
|
-
# No code execution required
|
567
558
|
tool_use_message = None
|
568
559
|
|
569
|
-
#
|
560
|
+
# 코드 실행 결과 컨텍스트에 추가
|
570
561
|
if tool_use_message:
|
571
562
|
context.append(tool_use_message)
|
572
563
|
|
573
|
-
#
|
574
|
-
|
564
|
+
# AI 응답 스트리밍 출력
|
565
|
+
console.print("[bold blue]AI:[/bold blue] ", end="")
|
566
|
+
response = ""
|
567
|
+
for chunk in chatterer.generate_stream(messages=context):
|
568
|
+
response += chunk
|
569
|
+
console.print(chunk, end="")
|
570
|
+
|
571
|
+
# 전체 응답 처리 후 컨텍스트에 추가
|
572
|
+
lines = response.split("\n")
|
573
|
+
if lines:
|
574
|
+
lines[-1] = lines[-1].rstrip() # 마지막 줄의 오른쪽 공백 제거
|
575
|
+
response = "\n".join(lines).strip()
|
575
576
|
context.append(AIMessage(content=response))
|
576
|
-
console.print(
|
577
|
+
console.print() # 응답 후 줄바꿈 추가
|
577
578
|
|
578
579
|
|
579
580
|
if __name__ == "__main__":
|
chatterer/tools/youtube.py
CHANGED
@@ -57,7 +57,21 @@ def get_youtube_video_subtitle(video_id: str) -> str:
|
|
57
57
|
|
58
58
|
|
59
59
|
def _get_video_id(suffix: str) -> str:
|
60
|
-
|
60
|
+
urllib_parse_result = urllib.parse.urlparse(suffix)
|
61
|
+
if urllib_parse_result.path.startswith("/shorts/"):
|
62
|
+
# Fore shorts (/shorts/...) the video ID is in the path
|
63
|
+
parts = urllib_parse_result.path.split("/")
|
64
|
+
if len(parts) < 3:
|
65
|
+
print(f"Failed to get video ID from {suffix}")
|
66
|
+
return ""
|
67
|
+
return parts[2]
|
68
|
+
|
69
|
+
query: str = urllib.parse.urlparse(suffix).query
|
70
|
+
query_strings = urllib.parse.parse_qs(query)
|
71
|
+
if "v" not in query_strings:
|
72
|
+
print(f"Failed to get video ID from {suffix}")
|
73
|
+
return ""
|
74
|
+
return next(iter(query_strings["v"]), "")
|
61
75
|
|
62
76
|
|
63
77
|
def _is_special_char(text: str) -> bool:
|
chatterer/utils/image.py
CHANGED
@@ -64,7 +64,7 @@ class Base64Image(BaseModel):
|
|
64
64
|
|
65
65
|
IMAGE_TYPES: ClassVar[tuple[str, ...]] = tuple(map(str, get_args(ImageType)))
|
66
66
|
IMAGE_PATTERN: ClassVar[re.Pattern[str]] = re.compile(
|
67
|
-
|
67
|
+
r"data:image/(" + "|".join(IMAGE_TYPES) + r");base64,([A-Za-z0-9+/]+={0,2})"
|
68
68
|
)
|
69
69
|
|
70
70
|
def __hash__(self) -> int:
|
@@ -1,5 +1,5 @@
|
|
1
1
|
chatterer/__init__.py,sha256=BPgCQ6VWGBXSh8xJr_0bpM0hcOOUz0KoxcKxOd9GYyI,1388
|
2
|
-
chatterer/language_model.py,sha256=
|
2
|
+
chatterer/language_model.py,sha256=DX_mU855JHHqE0gdnieWZNOwX1BjIO4VK4EightRL3w,24353
|
3
3
|
chatterer/messages.py,sha256=OtbZ3two0LUQ4PXES97FDIBUSO3IcMHdFV1VFkDL2mI,229
|
4
4
|
chatterer/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
5
|
chatterer/strategies/__init__.py,sha256=SdOggbmHpw4f7Njwy-T8q64e91OLOUp1k0a0ozZd4qI,221
|
@@ -7,7 +7,7 @@ chatterer/strategies/atom_of_thoughts.py,sha256=CygOCLu5vLk-fzY9O-iE3qLShfjD7iY4
|
|
7
7
|
chatterer/strategies/base.py,sha256=b2gMPqodp97OP1dkHfj0UqixjdjVhmTw_V5qJ7i2S6g,427
|
8
8
|
chatterer/tools/__init__.py,sha256=hmWIuLJWotGQodL__i4LLbHdXe7Nl5uKHqNke9tHMro,705
|
9
9
|
chatterer/tools/convert_to_text.py,sha256=kBqxCJ0IoiAw2eiPYqep_SPZm-TtYKF7mdACLsWQUuI,15915
|
10
|
-
chatterer/tools/youtube.py,sha256=
|
10
|
+
chatterer/tools/youtube.py,sha256=GhyE05JBF_eos01A_N-X5tZv4wQJ--IjErBbEBeNBpQ,6037
|
11
11
|
chatterer/tools/citation_chunking/__init__.py,sha256=gG7Fnkkp28UpcWMbfMY_4gqzZSZ8QzlhalHBoeoq7K0,82
|
12
12
|
chatterer/tools/citation_chunking/chunks.py,sha256=50Dpa43RaYftlNox8tM1qI8htZ3_AJ9Uyyn02WsmxYk,2173
|
13
13
|
chatterer/tools/citation_chunking/citation_chunker.py,sha256=yx5O9pUkowlNcFyyNf7f3sbq7-CV8AXOzFnviDldPR8,4894
|
@@ -20,8 +20,8 @@ chatterer/tools/webpage_to_markdown/playwright_bot.py,sha256=yP0KixYZNQ4Kn_ZCFDI
|
|
20
20
|
chatterer/tools/webpage_to_markdown/utils.py,sha256=ZLUU94imYciEdynD2K7Dmcsbt8BVQTaOP56Ba6DAFvk,12593
|
21
21
|
chatterer/utils/__init__.py,sha256=8nzpFJKU_wSRPH6LBP6HRBotPMrSl_VO9UlmFprTrK0,334
|
22
22
|
chatterer/utils/code_agent.py,sha256=UaWdeGzJMPzRSFy9yrxuveBJsvOPSa0te6OuE18bees,5143
|
23
|
-
chatterer/utils/image.py,sha256=
|
24
|
-
chatterer-0.1.
|
25
|
-
chatterer-0.1.
|
26
|
-
chatterer-0.1.
|
27
|
-
chatterer-0.1.
|
23
|
+
chatterer/utils/image.py,sha256=1imiyq6TB9NIIGx3zAA2OwMWuXlifYIAjwfWRWa4WIM,10858
|
24
|
+
chatterer-0.1.11.dist-info/METADATA,sha256=S3hRkxG1DlFc_NGrra1xhniiCDDVoVrow2N96OJy8i0,4458
|
25
|
+
chatterer-0.1.11.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
26
|
+
chatterer-0.1.11.dist-info/top_level.txt,sha256=7nSQKP0bHxPRc7HyzdbKsJdkvPgYD0214o6slRizv9s,10
|
27
|
+
chatterer-0.1.11.dist-info/RECORD,,
|
File without changes
|