youngjin-langchain-tools 0.1.0__py3-none-any.whl → 0.1.1__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.
@@ -10,6 +10,127 @@ Replaces the deprecated StreamlitCallbackHandler for LangGraph-based agents.
10
10
 
11
11
  from typing import Any, Dict, List, Optional, Union, Generator
12
12
  from dataclasses import dataclass, field
13
+ import logging
14
+ import re
15
+
16
+ # Configure logging
17
+ logger = logging.getLogger(__name__)
18
+
19
+
20
+ # ============================================================
21
+ # Error Patterns for User-Friendly Messages
22
+ # ============================================================
23
+ ERROR_PATTERNS = {
24
+ # OpenAI errors
25
+ r"AuthenticationError.*API key": {
26
+ "title": "🔑 API Key 오류",
27
+ "message": "API 키가 설정되지 않았거나 유효하지 않습니다.",
28
+ "solution": [
29
+ "1. `.env` 파일에 `OPENAI_API_KEY=sk-...` 형태로 키를 설정하세요.",
30
+ "2. 또는 코드 상단에 직접 API 키를 입력하세요.",
31
+ "3. API 키는 https://platform.openai.com/api-keys 에서 발급받을 수 있습니다.",
32
+ ],
33
+ },
34
+ r"RateLimitError|rate_limit|429": {
35
+ "title": "⏱️ Rate Limit 초과",
36
+ "message": "API 요청 한도를 초과했습니다.",
37
+ "solution": [
38
+ "1. 잠시 후 다시 시도해주세요.",
39
+ "2. API 사용량을 확인하세요: https://platform.openai.com/usage",
40
+ "3. 필요시 요금제를 업그레이드하세요.",
41
+ ],
42
+ },
43
+ r"InsufficientQuotaError|insufficient_quota|billing": {
44
+ "title": "💳 크레딧 부족",
45
+ "message": "API 크레딧이 부족합니다.",
46
+ "solution": [
47
+ "1. 결제 정보를 확인하세요: https://platform.openai.com/account/billing",
48
+ "2. 크레딧을 충전하세요.",
49
+ ],
50
+ },
51
+ r"InvalidRequestError|invalid_request": {
52
+ "title": "❌ 잘못된 요청",
53
+ "message": "API 요청 형식이 올바르지 않습니다.",
54
+ "solution": [
55
+ "1. 입력 데이터를 확인하세요.",
56
+ "2. 모델명이 올바른지 확인하세요.",
57
+ ],
58
+ },
59
+ # Anthropic errors
60
+ r"anthropic.*authentication|ANTHROPIC_API_KEY": {
61
+ "title": "🔑 Anthropic API Key 오류",
62
+ "message": "Anthropic API 키가 설정되지 않았거나 유효하지 않습니다.",
63
+ "solution": [
64
+ "1. `.env` 파일에 `ANTHROPIC_API_KEY=sk-ant-...` 형태로 키를 설정하세요.",
65
+ "2. API 키는 https://console.anthropic.com/ 에서 발급받을 수 있습니다.",
66
+ ],
67
+ },
68
+ # Google errors
69
+ r"google.*api.*key|GOOGLE_API_KEY": {
70
+ "title": "🔑 Google API Key 오류",
71
+ "message": "Google API 키가 설정되지 않았거나 유효하지 않습니다.",
72
+ "solution": [
73
+ "1. `.env` 파일에 `GOOGLE_API_KEY=...` 형태로 키를 설정하세요.",
74
+ "2. API 키는 https://aistudio.google.com/apikey 에서 발급받을 수 있습니다.",
75
+ ],
76
+ },
77
+ # Network errors
78
+ r"ConnectionError|connection.*refused|network": {
79
+ "title": "🌐 네트워크 오류",
80
+ "message": "API 서버에 연결할 수 없습니다.",
81
+ "solution": [
82
+ "1. 인터넷 연결을 확인하세요.",
83
+ "2. 방화벽/프록시 설정을 확인하세요.",
84
+ "3. API 서버 상태를 확인하세요.",
85
+ ],
86
+ },
87
+ r"TimeoutError|timeout|timed out": {
88
+ "title": "⏰ 시간 초과",
89
+ "message": "API 요청이 시간 초과되었습니다.",
90
+ "solution": [
91
+ "1. 네트워크 연결을 확인하세요.",
92
+ "2. 잠시 후 다시 시도해주세요.",
93
+ "3. 요청 크기를 줄여보세요.",
94
+ ],
95
+ },
96
+ # Model errors
97
+ r"model.*not.*found|does not exist|invalid.*model": {
98
+ "title": "🤖 모델 오류",
99
+ "message": "지정된 모델을 찾을 수 없습니다.",
100
+ "solution": [
101
+ "1. 모델명이 올바른지 확인하세요.",
102
+ "2. 해당 모델에 대한 접근 권한이 있는지 확인하세요.",
103
+ "3. 사용 가능한 모델 목록을 확인하세요.",
104
+ ],
105
+ },
106
+ }
107
+
108
+
109
+ def _parse_error(error: Exception) -> Dict[str, Any]:
110
+ """Parse an exception and return user-friendly error information."""
111
+ error_str = str(error)
112
+ error_type = type(error).__name__
113
+ full_error = f"{error_type}: {error_str}"
114
+
115
+ # Try to match known error patterns
116
+ for pattern, info in ERROR_PATTERNS.items():
117
+ if re.search(pattern, full_error, re.IGNORECASE):
118
+ return {
119
+ "matched": True,
120
+ "title": info["title"],
121
+ "message": info["message"],
122
+ "solution": info["solution"],
123
+ "original_error": error_str[:500], # Truncate for display
124
+ }
125
+
126
+ # Unknown error - return generic info
127
+ return {
128
+ "matched": False,
129
+ "title": "❗ 오류 발생",
130
+ "message": f"{error_type}",
131
+ "solution": ["에러 메시지를 확인하고 문제를 해결해주세요."],
132
+ "original_error": error_str[:500],
133
+ }
13
134
 
14
135
 
15
136
  @dataclass
@@ -231,25 +352,63 @@ class StreamlitLanggraphHandler:
231
352
  )
232
353
  self._response_placeholder = st.empty()
233
354
 
234
- # Stream from agent
355
+ # Stream from agent with error handling
235
356
  config = config or {}
236
357
 
237
- for stream_mode, data in agent.stream(
238
- input,
239
- config=config,
240
- stream_mode=["messages", "updates"]
241
- ):
242
- if stream_mode == "updates":
243
- yield from self._handle_updates(data)
244
- elif stream_mode == "messages":
245
- yield from self._handle_messages(data)
246
-
247
- # Mark as complete
248
- self._status_container.update(
249
- label=self._config.complete_label,
250
- state="complete",
251
- expanded=False
252
- )
358
+ try:
359
+ for stream_mode, data in agent.stream(
360
+ input,
361
+ config=config,
362
+ stream_mode=["messages", "updates"]
363
+ ):
364
+ if stream_mode == "updates":
365
+ yield from self._handle_updates(data)
366
+ elif stream_mode == "messages":
367
+ yield from self._handle_messages(data)
368
+
369
+ # Mark as complete
370
+ self._status_container.update(
371
+ label=self._config.complete_label,
372
+ state="complete",
373
+ expanded=False
374
+ )
375
+
376
+ except Exception as e:
377
+ # Parse error and display user-friendly message
378
+ error_info = _parse_error(e)
379
+
380
+ # Update status to show error
381
+ self._status_container.update(
382
+ label="❌ 오류 발생",
383
+ state="error",
384
+ expanded=True
385
+ )
386
+
387
+ # Display error in status container
388
+ with self._status_container:
389
+ st.error(f"**{error_info['title']}**")
390
+ st.markdown(f"_{error_info['message']}_")
391
+
392
+ st.markdown("**해결 방법:**")
393
+ for solution in error_info["solution"]:
394
+ st.markdown(f" {solution}")
395
+
396
+ with st.expander("🔍 상세 에러 메시지", expanded=False):
397
+ st.code(error_info["original_error"], language="text")
398
+
399
+ # Log the full error for debugging
400
+ logger.error(f"Agent execution error: {e}", exc_info=True)
401
+
402
+ # Yield error event
403
+ yield {
404
+ "type": "error",
405
+ "data": {
406
+ "error_type": type(e).__name__,
407
+ "error_info": error_info,
408
+ "original_error": str(e),
409
+ }
410
+ }
411
+ return # Stop further processing
253
412
 
254
413
  # Final render without cursor
255
414
  if self._final_response:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: youngjin-langchain-tools
3
- Version: 0.1.0
3
+ Version: 0.1.1
4
4
  Summary: LangGraph utilities for Streamlit - StreamlitLanggraphHandler and more
5
5
  Project-URL: Homepage, https://github.com/yourusername/youngjin-langchain-tools
6
6
  Project-URL: Documentation, https://github.com/yourusername/youngjin-langchain-tools#readme
@@ -1,9 +1,9 @@
1
1
  youngjin_langchain_tools/__init__.py,sha256=S5GJtbYymhDuGtTibEG61Li9UvwvoFtnKm4mxjWNgnU,1310
2
2
  youngjin_langchain_tools/handlers/__init__.py,sha256=-vGk-m1fqOipJSe02ogcScE0K3pdVwO9A_EqBovPRxo,397
3
- youngjin_langchain_tools/handlers/streamlit_langgraph_handler.py,sha256=2josz-hgarSDlHjBhak-S5U2aijg6TF8GU1vtxhgcl8,12157
3
+ youngjin_langchain_tools/handlers/streamlit_langgraph_handler.py,sha256=hd509HM1SjAhPRxXqZh1we_ynDRetXrrB9TFSENJWY8,18423
4
4
  youngjin_langchain_tools/utils/__init__.py,sha256=LgSd7Gz2n5WgIhxaKHqpmQVUaBUDT_TTTw63hzoWGgM,272
5
5
  youngjin_langchain_tools/utils/config.py,sha256=hHvdxsn5ZFWRJvR6N7ODy94JbCkeJocsS58hmvxoK5I,1640
6
- youngjin_langchain_tools-0.1.0.dist-info/METADATA,sha256=ON9jSdJIFjEyP96zgy5ETlJ-KXNHkCIKK1jVsYUeyq4,6920
7
- youngjin_langchain_tools-0.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
8
- youngjin_langchain_tools-0.1.0.dist-info/licenses/LICENSE,sha256=fENUlkDDxJEn5c0u8mhVcz5ek-rTg2L4Kby1tMNchI8,11342
9
- youngjin_langchain_tools-0.1.0.dist-info/RECORD,,
6
+ youngjin_langchain_tools-0.1.1.dist-info/METADATA,sha256=3KyJIb5zWwslYNBXcZFRbyOT_CZP2q-0sx3DzMSAYoI,6920
7
+ youngjin_langchain_tools-0.1.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
8
+ youngjin_langchain_tools-0.1.1.dist-info/licenses/LICENSE,sha256=fENUlkDDxJEn5c0u8mhVcz5ek-rTg2L4Kby1tMNchI8,11342
9
+ youngjin_langchain_tools-0.1.1.dist-info/RECORD,,