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.
@@ -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 = f"{prompt_to_add}\n{messages}"
396
+ # messages += f"\n{prompt_to_add}"
411
397
  # elif isinstance(messages, Sequence):
412
398
  # messages = list(messages)
413
- # messages.insert(0, SystemMessage(content=prompt_to_add))
399
+ # messages.append(SystemMessage(content=prompt_to_add))
414
400
  # else:
415
401
  # messages = messages.to_messages()
416
- # messages.insert(0, SystemMessage(content=prompt_to_add))
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 = _add_message_last(
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 = _add_message_last(messages=messages, prompt_to_add=prompt_for_code_invoke)
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
- # Get default REPL tool if not provided.
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
- # Display welcome message
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
- # Get user input
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
- # Determine if code execution is needed
494
+ # 코드 실행 필요 여부 판단
503
495
  decision = chatterer.generate_pydantic(
504
- response_model=IsCodeExecutionNeeded, # Use response_model instead of pydantic_model
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 = SystemMessage(
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, # Use response_model instead of pydantic_model
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: {decision.review_on_code_execution}\n- Next Action: {decision.next_action}"
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
- # Add system message to context
560
+ # 코드 실행 결과 컨텍스트에 추가
570
561
  if tool_use_message:
571
562
  context.append(tool_use_message)
572
563
 
573
- # Generate and display chatbot response
574
- response = chatterer.generate(messages=context) # Use generate instead of generate_response
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(f"[bold blue]AI:[/bold blue] {response}")
577
+ console.print() # 응답 줄바꿈 추가
577
578
 
578
579
 
579
580
  if __name__ == "__main__":
@@ -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
- return next(iter(urllib.parse.parse_qs(urllib.parse.urlparse(suffix).query)["v"]), "")
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
- rf"data:image/({'|'.join(IMAGE_TYPES)});base64,[A-Za-z0-9+/]+={0, 2}$"
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,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: chatterer
3
- Version: 0.1.10
3
+ Version: 0.1.11
4
4
  Summary: The highest-level interface for various LLM APIs.
5
5
  Requires-Python: >=3.12
6
6
  Description-Content-Type: text/markdown
@@ -1,5 +1,5 @@
1
1
  chatterer/__init__.py,sha256=BPgCQ6VWGBXSh8xJr_0bpM0hcOOUz0KoxcKxOd9GYyI,1388
2
- chatterer/language_model.py,sha256=qnVC5_W4IYM0y0o1PTYMGXUlblRv5fsRk0zIiL_vT3Q,24491
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=5hwASZWA92d_7Y5RqlCK2tULRBQx8bGnE_0NCnvaKi0,5499
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=F3_D1677UDFlgp-UQBS_ChkNODzf_VOfjYNSUi02MaI,10852
24
- chatterer-0.1.10.dist-info/METADATA,sha256=qPx7b41yUvBG0XFH4ra89LIyOSUZUo_8gZ-adVkTKME,4458
25
- chatterer-0.1.10.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
26
- chatterer-0.1.10.dist-info/top_level.txt,sha256=7nSQKP0bHxPRc7HyzdbKsJdkvPgYD0214o6slRizv9s,10
27
- chatterer-0.1.10.dist-info/RECORD,,
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,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (77.0.3)
2
+ Generator: setuptools (78.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5