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.
- youngjin_langchain_tools/handlers/streamlit_langgraph_handler.py +176 -17
- {youngjin_langchain_tools-0.1.0.dist-info → youngjin_langchain_tools-0.1.1.dist-info}/METADATA +1 -1
- {youngjin_langchain_tools-0.1.0.dist-info → youngjin_langchain_tools-0.1.1.dist-info}/RECORD +5 -5
- {youngjin_langchain_tools-0.1.0.dist-info → youngjin_langchain_tools-0.1.1.dist-info}/WHEEL +0 -0
- {youngjin_langchain_tools-0.1.0.dist-info → youngjin_langchain_tools-0.1.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -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
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
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:
|
{youngjin_langchain_tools-0.1.0.dist-info → youngjin_langchain_tools-0.1.1.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: youngjin-langchain-tools
|
|
3
|
-
Version: 0.1.
|
|
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
|
{youngjin_langchain_tools-0.1.0.dist-info → youngjin_langchain_tools-0.1.1.dist-info}/RECORD
RENAMED
|
@@ -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=
|
|
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.
|
|
7
|
-
youngjin_langchain_tools-0.1.
|
|
8
|
-
youngjin_langchain_tools-0.1.
|
|
9
|
-
youngjin_langchain_tools-0.1.
|
|
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,,
|
|
File without changes
|
|
File without changes
|