chatterer 0.1.13__py3-none-any.whl → 0.1.16__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.
@@ -1,3 +1,4 @@
1
+ import re
1
2
  from typing import (
2
3
  TYPE_CHECKING,
3
4
  Any,
@@ -5,13 +6,13 @@ from typing import (
5
6
  Callable,
6
7
  Iterable,
7
8
  Iterator,
9
+ Literal,
8
10
  Optional,
9
11
  Self,
10
12
  Sequence,
11
13
  Type,
12
14
  TypeAlias,
13
15
  TypeVar,
14
- cast,
15
16
  overload,
16
17
  )
17
18
 
@@ -19,10 +20,11 @@ from langchain_core.language_models.base import LanguageModelInput
19
20
  from langchain_core.language_models.chat_models import BaseChatModel
20
21
  from langchain_core.runnables.base import Runnable
21
22
  from langchain_core.runnables.config import RunnableConfig
22
- from pydantic import BaseModel, Field
23
+ from langchain_core.utils.utils import secret_from_env
24
+ from pydantic import BaseModel, Field, SecretStr
23
25
 
24
- from .messages import AIMessage, BaseMessage, HumanMessage, SystemMessage
25
- from .utils.code_agent import CodeExecutionResult, FunctionSignature, get_default_repl_tool
26
+ from .messages import AIMessage, BaseMessage, HumanMessage, UsageMetadata
27
+ from .utils.code_agent import CodeExecutionResult, FunctionSignature, augment_prompt_for_toolcall
26
28
 
27
29
  if TYPE_CHECKING:
28
30
  from instructor import Partial
@@ -53,6 +55,8 @@ DEFAULT_FUNCTION_REFERENCE_PREFIX_PROMPT = (
53
55
  )
54
56
  DEFAULT_FUNCTION_REFERENCE_SEPARATOR = "\n---\n" # Separator to distinguish different function references
55
57
 
58
+ PYTHON_CODE_PATTERN: re.Pattern[str] = re.compile(r"```(?:python\s*\n)?(.*?)```", re.DOTALL)
59
+
56
60
 
57
61
  class Chatterer(BaseModel):
58
62
  """Language model for generating text from a given input."""
@@ -60,71 +64,82 @@ class Chatterer(BaseModel):
60
64
  client: BaseChatModel
61
65
  structured_output_kwargs: dict[str, Any] = Field(default_factory=dict)
62
66
 
63
- @overload
64
- def __call__(
65
- self,
66
- messages: LanguageModelInput,
67
- response_model: Type[PydanticModelT],
68
- config: Optional[RunnableConfig] = None,
69
- stop: Optional[list[str]] = None,
70
- **kwargs: Any,
71
- ) -> PydanticModelT: ...
72
-
73
- @overload
74
- def __call__(
75
- self,
76
- messages: LanguageModelInput,
77
- response_model: None = None,
78
- config: Optional[RunnableConfig] = None,
79
- stop: Optional[list[str]] = None,
80
- **kwargs: Any,
81
- ) -> str: ...
67
+ @classmethod
68
+ def from_provider(
69
+ cls, provider_and_model: str, structured_output_kwargs: Optional[dict[str, object]] = {"strict": True}
70
+ ) -> Self:
71
+ backend, model = provider_and_model.split(":", 1)
72
+ backends = cls.get_backends()
73
+ if func := backends.get(backend):
74
+ return func(model, structured_output_kwargs)
75
+ else:
76
+ raise ValueError(f"Unsupported provider: {backend}. Supported providers are: {', '.join(backends.keys())}.")
82
77
 
83
- def __call__(
84
- self,
85
- messages: LanguageModelInput,
86
- response_model: Optional[Type[PydanticModelT]] = None,
87
- config: Optional[RunnableConfig] = None,
88
- stop: Optional[list[str]] = None,
89
- **kwargs: Any,
90
- ) -> str | PydanticModelT:
91
- if response_model:
92
- return self.generate_pydantic(response_model, messages, config, stop, **kwargs)
93
- return self.client.invoke(input=messages, config=config, stop=stop, **kwargs).text()
78
+ @classmethod
79
+ def get_backends(cls) -> dict[str, Callable[[str, Optional[dict[str, object]]], Self]]:
80
+ return {
81
+ "openai": cls.openai,
82
+ "anthropic": cls.anthropic,
83
+ "google": cls.google,
84
+ "ollama": cls.ollama,
85
+ "openrouter": cls.open_router,
86
+ "xai": cls.xai,
87
+ }
94
88
 
95
89
  @classmethod
96
90
  def openai(
97
91
  cls,
98
- model: str = "gpt-4o-mini",
99
- structured_output_kwargs: Optional[dict[str, Any]] = {"strict": True},
92
+ model: str = "gpt-4.1",
93
+ structured_output_kwargs: Optional[dict[str, object]] = {"strict": True},
94
+ api_key: Optional[str] = None,
95
+ **kwargs: Any,
100
96
  ) -> Self:
101
97
  from langchain_openai import ChatOpenAI
102
98
 
103
- return cls(client=ChatOpenAI(model=model), structured_output_kwargs=structured_output_kwargs or {})
99
+ return cls(
100
+ client=ChatOpenAI(
101
+ model=model,
102
+ api_key=_get_api_key(api_key=api_key, env_key="OPENAI_API_KEY", raise_if_none=False),
103
+ **kwargs,
104
+ ),
105
+ structured_output_kwargs=structured_output_kwargs or {},
106
+ )
104
107
 
105
108
  @classmethod
106
109
  def anthropic(
107
110
  cls,
108
111
  model_name: str = "claude-3-7-sonnet-20250219",
109
- structured_output_kwargs: Optional[dict[str, Any]] = None,
112
+ structured_output_kwargs: Optional[dict[str, object]] = None,
113
+ api_key: Optional[str] = None,
114
+ **kwargs: Any,
110
115
  ) -> Self:
111
116
  from langchain_anthropic import ChatAnthropic
112
117
 
113
118
  return cls(
114
- client=ChatAnthropic(model_name=model_name, timeout=None, stop=None),
119
+ client=ChatAnthropic(
120
+ model_name=model_name,
121
+ api_key=_get_api_key(api_key=api_key, env_key="ANTHROPIC_API_KEY", raise_if_none=True),
122
+ **kwargs,
123
+ ),
115
124
  structured_output_kwargs=structured_output_kwargs or {},
116
125
  )
117
126
 
118
127
  @classmethod
119
128
  def google(
120
129
  cls,
121
- model: str = "gemini-2.0-flash",
122
- structured_output_kwargs: Optional[dict[str, Any]] = None,
130
+ model: str = "gemini-2.5-flash-preview-04-17",
131
+ structured_output_kwargs: Optional[dict[str, object]] = None,
132
+ api_key: Optional[str] = None,
133
+ **kwargs: Any,
123
134
  ) -> Self:
124
135
  from langchain_google_genai import ChatGoogleGenerativeAI
125
136
 
126
137
  return cls(
127
- client=ChatGoogleGenerativeAI(model=model),
138
+ client=ChatGoogleGenerativeAI(
139
+ model=model,
140
+ api_key=_get_api_key(api_key=api_key, env_key="GOOGLE_API_KEY", raise_if_none=False),
141
+ **kwargs,
142
+ ),
128
143
  structured_output_kwargs=structured_output_kwargs or {},
129
144
  )
130
145
 
@@ -132,15 +147,112 @@ class Chatterer(BaseModel):
132
147
  def ollama(
133
148
  cls,
134
149
  model: str = "deepseek-r1:1.5b",
135
- structured_output_kwargs: Optional[dict[str, Any]] = None,
150
+ structured_output_kwargs: Optional[dict[str, object]] = None,
151
+ **kwargs: Any,
136
152
  ) -> Self:
137
153
  from langchain_ollama import ChatOllama
138
154
 
139
155
  return cls(
140
- client=ChatOllama(model=model),
156
+ client=ChatOllama(model=model, **kwargs),
157
+ structured_output_kwargs=structured_output_kwargs or {},
158
+ )
159
+
160
+ @classmethod
161
+ def open_router(
162
+ cls,
163
+ model: str = "openrouter/quasar-alpha",
164
+ structured_output_kwargs: Optional[dict[str, object]] = None,
165
+ api_key: Optional[str] = None,
166
+ **kwargs: Any,
167
+ ) -> Self:
168
+ from langchain_openai import ChatOpenAI
169
+
170
+ return cls(
171
+ client=ChatOpenAI(
172
+ model=model,
173
+ base_url="https://openrouter.ai/api/v1",
174
+ api_key=_get_api_key(api_key=api_key, env_key="OPENROUTER_API_KEY", raise_if_none=False),
175
+ **kwargs,
176
+ ),
141
177
  structured_output_kwargs=structured_output_kwargs or {},
142
178
  )
143
179
 
180
+ @classmethod
181
+ def xai(
182
+ cls,
183
+ model: str = "grok-3-mini",
184
+ structured_output_kwargs: Optional[dict[str, object]] = None,
185
+ base_url: str = "https://api.x.ai/v1",
186
+ api_key: Optional[str] = None,
187
+ **kwargs: Any,
188
+ ) -> Self:
189
+ from langchain_openai import ChatOpenAI
190
+
191
+ return cls(
192
+ client=ChatOpenAI(
193
+ model=model,
194
+ base_url=base_url,
195
+ api_key=_get_api_key(api_key=api_key, env_key="XAI_API_KEY", raise_if_none=False),
196
+ **kwargs,
197
+ ),
198
+ structured_output_kwargs=structured_output_kwargs or {},
199
+ )
200
+
201
+ @property
202
+ def invoke(self):
203
+ return self.client.invoke
204
+
205
+ @property
206
+ def ainvoke(self):
207
+ return self.client.ainvoke
208
+
209
+ @property
210
+ def stream(self):
211
+ return self.client.stream
212
+
213
+ @property
214
+ def astream(self):
215
+ return self.client.astream
216
+
217
+ @property
218
+ def bind_tools(self): # pyright: ignore[reportUnknownParameterType]
219
+ return self.client.bind_tools # pyright: ignore[reportUnknownParameterType, reportUnknownVariableType, reportUnknownMemberType]
220
+
221
+ def __getattr__(self, name: str) -> Any:
222
+ return getattr(self.client, name)
223
+
224
+ @overload
225
+ def __call__(
226
+ self,
227
+ messages: LanguageModelInput,
228
+ response_model: Type[PydanticModelT],
229
+ config: Optional[RunnableConfig] = None,
230
+ stop: Optional[list[str]] = None,
231
+ **kwargs: Any,
232
+ ) -> PydanticModelT: ...
233
+
234
+ @overload
235
+ def __call__(
236
+ self,
237
+ messages: LanguageModelInput,
238
+ response_model: None = None,
239
+ config: Optional[RunnableConfig] = None,
240
+ stop: Optional[list[str]] = None,
241
+ **kwargs: Any,
242
+ ) -> str: ...
243
+
244
+ def __call__(
245
+ self,
246
+ messages: LanguageModelInput,
247
+ response_model: Optional[Type[PydanticModelT]] = None,
248
+ config: Optional[RunnableConfig] = None,
249
+ stop: Optional[list[str]] = None,
250
+ **kwargs: Any,
251
+ ) -> str | PydanticModelT:
252
+ if response_model:
253
+ return self.generate_pydantic(response_model, messages, config, stop, **kwargs)
254
+ return self.client.invoke(input=messages, config=config, stop=stop, **kwargs).text()
255
+
144
256
  def generate(
145
257
  self,
146
258
  messages: LanguageModelInput,
@@ -279,41 +391,32 @@ class Chatterer(BaseModel):
279
391
  )
280
392
  ])
281
393
 
282
- @staticmethod
283
- def get_num_tokens_from_message(message: BaseMessage) -> Optional[tuple[int, int]]:
284
- try:
285
- if isinstance(message, AIMessage) and (usage_metadata := message.usage_metadata):
286
- input_tokens = int(usage_metadata["input_tokens"])
287
- output_tokens = int(usage_metadata["output_tokens"])
394
+ def get_approximate_token_count(self, message: BaseMessage) -> int:
395
+ return self.client.get_num_tokens_from_messages([message]) # pyright: ignore[reportUnknownMemberType]
396
+
397
+ def get_usage_metadata(self, message: BaseMessage) -> UsageMetadata:
398
+ if isinstance(message, AIMessage):
399
+ usage_metadata = message.usage_metadata
400
+ if usage_metadata is not None:
401
+ input_tokens = usage_metadata["input_tokens"]
402
+ output_tokens = usage_metadata["output_tokens"]
403
+ return {
404
+ "input_tokens": input_tokens,
405
+ "output_tokens": output_tokens,
406
+ "total_tokens": input_tokens + output_tokens,
407
+ }
288
408
  else:
289
- # Dynamic extraction for unknown structures
290
- input_tokens: Optional[int] = None
291
- output_tokens: Optional[int] = None
292
-
293
- def _find_tokens(obj: object) -> None:
294
- nonlocal input_tokens, output_tokens
295
- if isinstance(obj, dict):
296
- for key, value in cast(dict[object, object], obj).items():
297
- if isinstance(value, int):
298
- if "input" in str(key) or "prompt" in str(key):
299
- input_tokens = value
300
- elif "output" in str(key) or "completion" in str(key):
301
- output_tokens = value
302
- else:
303
- _find_tokens(value)
304
- elif isinstance(obj, list):
305
- for item in cast(list[object], obj):
306
- _find_tokens(item)
307
-
308
- _find_tokens(message.model_dump())
309
-
310
- if input_tokens is None or output_tokens is None:
311
- return None
312
- return input_tokens, output_tokens
313
- except Exception:
314
- return None
315
-
316
- def invoke_code_execution(
409
+ approx_tokens = self.get_approximate_token_count(message)
410
+ return {"input_tokens": 0, "output_tokens": approx_tokens, "total_tokens": approx_tokens}
411
+ else:
412
+ approx_tokens = self.get_approximate_token_count(message)
413
+ return {
414
+ "input_tokens": approx_tokens,
415
+ "output_tokens": 0,
416
+ "total_tokens": approx_tokens,
417
+ }
418
+
419
+ def exec(
317
420
  self,
318
421
  messages: LanguageModelInput,
319
422
  repl_tool: Optional["PythonAstREPLTool"] = None,
@@ -347,7 +450,12 @@ class Chatterer(BaseModel):
347
450
  **kwargs,
348
451
  )
349
452
 
350
- async def ainvoke_code_execution(
453
+ @property
454
+ def invoke_code_execution(self) -> Callable[..., CodeExecutionResult]:
455
+ """Alias for exec method for backward compatibility."""
456
+ return self.exec
457
+
458
+ async def aexec(
351
459
  self,
352
460
  messages: LanguageModelInput,
353
461
  repl_tool: Optional["PythonAstREPLTool"] = None,
@@ -378,10 +486,24 @@ class Chatterer(BaseModel):
378
486
  **kwargs,
379
487
  )
380
488
 
489
+ @property
490
+ def ainvoke_code_execution(self):
491
+ """Alias for aexec method for backward compatibility."""
492
+ return self.aexec
493
+
381
494
 
382
495
  class PythonCodeToExecute(BaseModel):
383
496
  code: str = Field(description="Python code to execute")
384
497
 
498
+ def model_post_init(self, context: object) -> None:
499
+ super().model_post_init(context)
500
+
501
+ codes: list[str] = []
502
+ for match in PYTHON_CODE_PATTERN.finditer(self.code):
503
+ codes.append(match.group(1))
504
+ if codes:
505
+ self.code = "\n".join(codes)
506
+
385
507
 
386
508
  def _with_structured_output(
387
509
  client: BaseChatModel,
@@ -391,187 +513,21 @@ def _with_structured_output(
391
513
  return client.with_structured_output(schema=response_model, **structured_output_kwargs) # pyright: ignore[reportUnknownVariableType, reportUnknownMemberType]
392
514
 
393
515
 
394
- # def _add_message_last(messages: LanguageModelInput, prompt_to_add: str) -> LanguageModelInput:
395
- # if isinstance(messages, str):
396
- # messages += f"\n{prompt_to_add}"
397
- # elif isinstance(messages, Sequence):
398
- # messages = list(messages)
399
- # messages.append(SystemMessage(content=prompt_to_add))
400
- # else:
401
- # messages = messages.to_messages()
402
- # messages.append(SystemMessage(content=prompt_to_add))
403
- # return messages
404
-
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
-
418
- def augment_prompt_for_toolcall(
419
- function_signatures: Iterable[FunctionSignature],
420
- messages: LanguageModelInput,
421
- prompt_for_code_invoke: Optional[str] = DEFAULT_CODE_GENERATION_PROMPT,
422
- function_reference_prefix: Optional[str] = DEFAULT_FUNCTION_REFERENCE_PREFIX_PROMPT,
423
- function_reference_seperator: str = DEFAULT_FUNCTION_REFERENCE_SEPARATOR,
424
- ) -> LanguageModelInput:
425
- if function_signatures:
426
- messages = _add_message_first(
427
- messages=messages,
428
- prompt_to_add=FunctionSignature.as_prompt(
429
- function_signatures, function_reference_prefix, function_reference_seperator
430
- ),
431
- )
432
- if prompt_for_code_invoke:
433
- messages = _add_message_first(messages=messages, prompt_to_add=prompt_for_code_invoke)
434
- return messages
435
-
436
-
437
- def interactive_shell(
438
- chatterer: Chatterer = Chatterer.openai(),
439
- system_instruction: BaseMessage | Iterable[BaseMessage] = ([
440
- SystemMessage("You are an AI that can answer questions and execute Python code."),
441
- ]),
442
- repl_tool: Optional["PythonAstREPLTool"] = None,
443
- prompt_for_code_invoke: Optional[str] = DEFAULT_CODE_GENERATION_PROMPT,
444
- additional_callables: Optional[Callable[..., object] | Sequence[Callable[..., object]]] = None,
445
- function_reference_prefix: Optional[str] = DEFAULT_FUNCTION_REFERENCE_PREFIX_PROMPT,
446
- function_reference_seperator: str = DEFAULT_FUNCTION_REFERENCE_SEPARATOR,
447
- config: Optional[RunnableConfig] = None,
448
- stop: Optional[list[str]] = None,
449
- **kwargs: Any,
450
- ) -> None:
451
- from rich.console import Console
452
- from rich.prompt import Prompt
453
-
454
- # 코드 실행 필요 여부를 판단하는 모델
455
- class IsCodeExecutionNeeded(BaseModel):
456
- is_code_execution_needed: bool = Field(
457
- description="Whether Python tool calling is needed to answer user query."
458
- )
459
-
460
- # 추가 코드 실행 필요 여부를 판단하는 모델
461
- class IsFurtherCodeExecutionNeeded(BaseModel):
462
- review_on_code_execution: str = Field(description="Review on the code execution.")
463
- next_action: str = Field(description="Next action to take.")
464
- is_further_code_execution_needed: bool = Field(
465
- description="Whether further Python tool calling is needed to answer user query."
466
- )
467
-
468
- def respond(messages: list[BaseMessage]) -> str:
469
- # AI 응답 스트리밍 출력
470
- console.print("[bold blue]AI:[/bold blue] ", end="")
471
- response = ""
472
- for chunk in chatterer.generate_stream(messages=messages):
473
- response += chunk
474
- console.print(chunk, end="")
475
- console.print() # 응답 후 줄바꿈 추가
476
- return response.strip()
477
-
478
- def code_session_returning_end_of_turn() -> bool:
479
- code_session_messages: list[BaseMessage] = []
480
- while True:
481
- code_execution: CodeExecutionResult = chatterer.invoke_code_execution(
482
- messages=context,
483
- repl_tool=repl_tool,
484
- prompt_for_code_invoke=prompt_for_code_invoke,
485
- function_signatures=function_signatures,
486
- function_reference_prefix=function_reference_prefix,
487
- function_reference_seperator=function_reference_seperator,
488
- config=config,
489
- stop=stop,
490
- **kwargs,
491
- )
492
- if code_execution.code.strip() in ("", "quit", "exit", "pass"):
493
- return False
494
-
495
- last_tool_use_message = AIMessage(
496
- content=f"Executed code:\n```python\n{code_execution.code}\n```\nOutput:\n{code_execution.output}".strip()
497
- )
498
- code_session_messages.append(last_tool_use_message)
499
- console.print("[bold yellow]Executed code:[/bold yellow]")
500
- console.print(f"[code]{code_execution.code}[/code]")
501
- console.print("[bold yellow]Output:[/bold yellow]")
502
- console.print(code_execution.output)
503
-
504
- decision = chatterer.generate_pydantic(
505
- response_model=IsFurtherCodeExecutionNeeded,
506
- messages=augment_prompt_for_toolcall(
507
- function_signatures=function_signatures,
508
- messages=context + code_session_messages,
509
- prompt_for_code_invoke=prompt_for_code_invoke,
510
- function_reference_prefix=function_reference_prefix,
511
- function_reference_seperator=function_reference_seperator,
512
- ),
513
- )
514
- review_on_code_execution = decision.review_on_code_execution.strip()
515
- next_action = decision.next_action.strip()
516
- console.print("[bold blue]AI:[/bold blue]")
517
- console.print(f"-[bold yellow]Review on code execution:[/bold yellow] {review_on_code_execution}")
518
- console.print(f"-[bold yellow]Next Action:[/bold yellow] {next_action}")
519
- code_session_messages.append(
520
- AIMessage(
521
- content=f"- Review upon code execution: {review_on_code_execution}\n- Next Action: {next_action}".strip()
516
+ @overload
517
+ def _get_api_key(api_key: Optional[str], env_key: str, raise_if_none: Literal[True]) -> SecretStr: ...
518
+ @overload
519
+ def _get_api_key(api_key: Optional[str], env_key: str, raise_if_none: Literal[False]) -> Optional[SecretStr]: ...
520
+ def _get_api_key(api_key: Optional[str], env_key: str, raise_if_none: bool) -> Optional[SecretStr]:
521
+ if api_key is None:
522
+ api_key_found: SecretStr | None = secret_from_env(env_key, default=None)()
523
+ if raise_if_none and api_key_found is None:
524
+ raise ValueError(
525
+ (
526
+ f"Did not find API key, please add an environment variable"
527
+ f" `{env_key}` which contains it, or pass"
528
+ f" api_key as a named parameter."
522
529
  )
523
530
  )
524
- if not decision.is_further_code_execution_needed:
525
- response: str = respond(context + code_session_messages)
526
- context.append(last_tool_use_message)
527
- context.append(AIMessage(content=response))
528
- return True
529
-
530
- # REPL 도구 초기화
531
- if repl_tool is None:
532
- repl_tool = get_default_repl_tool()
533
-
534
- function_signatures: list[FunctionSignature] = FunctionSignature.from_callable(additional_callables)
535
- console = Console()
536
- context: list[BaseMessage] = []
537
- if system_instruction:
538
- if isinstance(system_instruction, BaseMessage):
539
- context.append(system_instruction)
540
- else:
541
- context.extend(system_instruction)
542
-
543
- # 환영 메시지
544
- console.print("[bold blue]Welcome to the Interactive Chatterer Shell![/bold blue]")
545
- console.print("Type 'quit' or 'exit' to end the conversation.")
546
-
547
- while True:
548
- # 사용자 입력 받기
549
- user_input = Prompt.ask("[bold green]You[/bold green]")
550
- if user_input.lower() in ["quit", "exit"]:
551
- console.print("[bold blue]Goodbye![/bold blue]")
552
- break
553
-
554
- context.append(HumanMessage(content=user_input))
555
-
556
- # 코드 실행 필요 여부 판단
557
- decision = chatterer.generate_pydantic(
558
- response_model=IsCodeExecutionNeeded,
559
- messages=augment_prompt_for_toolcall(
560
- function_signatures=function_signatures,
561
- messages=context,
562
- prompt_for_code_invoke=prompt_for_code_invoke,
563
- function_reference_prefix=function_reference_prefix,
564
- function_reference_seperator=function_reference_seperator,
565
- ),
566
- )
567
-
568
- # 코드 실행 처리
569
- if decision.is_code_execution_needed and code_session_returning_end_of_turn():
570
- continue
571
-
572
- # AI 응답 스트리밍 출력
573
- context.append(AIMessage(content=respond(context)))
574
-
575
-
576
- if __name__ == "__main__":
577
- interactive_shell()
531
+ return api_key_found
532
+ else:
533
+ return SecretStr(api_key)
chatterer/messages.py CHANGED
@@ -1,4 +1,13 @@
1
- from langchain_core.messages import AIMessage, BaseMessage, FunctionMessage, HumanMessage, SystemMessage
1
+ from langchain_core.language_models.base import LanguageModelInput
2
+ from langchain_core.messages import (
3
+ AIMessage,
4
+ BaseMessage,
5
+ BaseMessageChunk,
6
+ FunctionMessage,
7
+ HumanMessage,
8
+ SystemMessage,
9
+ )
10
+ from langchain_core.messages.ai import UsageMetadata
2
11
 
3
12
  __all__ = [
4
13
  "AIMessage",
@@ -6,4 +15,7 @@ __all__ = [
6
15
  "HumanMessage",
7
16
  "SystemMessage",
8
17
  "FunctionMessage",
18
+ "BaseMessageChunk",
19
+ "UsageMetadata",
20
+ "LanguageModelInput",
9
21
  ]
@@ -1,26 +1,24 @@
1
+ from .caption_markdown_images import MarkdownLink, acaption_markdown_images, caption_markdown_images
1
2
  from .citation_chunking import citation_chunker
3
+ from .convert_pdf_to_markdown import PdfToMarkdown, extract_text_from_pdf, open_pdf, render_pdf_as_image
2
4
  from .convert_to_text import (
5
+ CodeSnippets,
3
6
  anything_to_markdown,
4
7
  get_default_html_to_markdown_options,
5
8
  html_to_markdown,
6
9
  pdf_to_text,
7
10
  pyscripts_to_snippets,
8
11
  )
12
+ from .upstage_document_parser import UpstageDocumentParseParser
13
+ from .webpage_to_markdown import (
14
+ PlayWrightBot,
15
+ PlaywrightLaunchOptions,
16
+ PlaywrightOptions,
17
+ PlaywrightPersistencyOptions,
18
+ get_default_playwright_launch_options,
19
+ )
9
20
  from .youtube import get_youtube_video_details, get_youtube_video_subtitle
10
21
 
11
-
12
- def init_webpage_to_markdown():
13
- from . import webpage_to_markdown
14
-
15
- return webpage_to_markdown
16
-
17
-
18
- def init_upstage_document_parser():
19
- from . import upstage_document_parser
20
-
21
- return upstage_document_parser
22
-
23
-
24
22
  __all__ = [
25
23
  "html_to_markdown",
26
24
  "anything_to_markdown",
@@ -28,8 +26,21 @@ __all__ = [
28
26
  "get_default_html_to_markdown_options",
29
27
  "pyscripts_to_snippets",
30
28
  "citation_chunker",
31
- "init_webpage_to_markdown",
29
+ "webpage_to_markdown",
32
30
  "get_youtube_video_subtitle",
33
31
  "get_youtube_video_details",
34
- "init_upstage_document_parser",
32
+ "CodeSnippets",
33
+ "PlayWrightBot",
34
+ "PlaywrightLaunchOptions",
35
+ "PlaywrightOptions",
36
+ "PlaywrightPersistencyOptions",
37
+ "get_default_playwright_launch_options",
38
+ "UpstageDocumentParseParser",
39
+ "acaption_markdown_images",
40
+ "caption_markdown_images",
41
+ "MarkdownLink",
42
+ "PdfToMarkdown",
43
+ "extract_text_from_pdf",
44
+ "open_pdf",
45
+ "render_pdf_as_image",
35
46
  ]