intentkit 0.6.9.dev2__py3-none-any.whl → 0.6.10.dev1__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.
Potentially problematic release.
This version of intentkit might be problematic. Click here for more details.
- intentkit/__init__.py +1 -1
- intentkit/abstracts/graph.py +17 -2
- intentkit/core/engine.py +29 -30
- intentkit/core/node.py +10 -20
- intentkit/models/agent.py +3 -0
- intentkit/models/chat.py +9 -1
- intentkit/skills/acolyt/ask.py +2 -5
- intentkit/skills/acolyt/base.py +16 -6
- intentkit/skills/aixbt/__init__.py +3 -7
- intentkit/skills/aixbt/projects.py +12 -36
- intentkit/skills/allora/base.py +16 -6
- intentkit/skills/allora/price.py +2 -4
- intentkit/skills/base.py +8 -1
- intentkit/skills/carv/base.py +12 -10
- intentkit/skills/carv/fetch_news.py +90 -92
- intentkit/skills/carv/onchain_query.py +162 -164
- intentkit/skills/carv/token_info_and_price.py +108 -110
- intentkit/skills/chainlist/chain_lookup.py +1 -2
- intentkit/skills/common/current_time.py +1 -2
- intentkit/skills/cookiefun/base.py +20 -12
- intentkit/skills/cookiefun/get_account_details.py +1 -3
- intentkit/skills/cookiefun/get_account_feed.py +1 -3
- intentkit/skills/cookiefun/get_account_smart_followers.py +1 -3
- intentkit/skills/cookiefun/get_sectors.py +2 -3
- intentkit/skills/cookiefun/search_accounts.py +1 -3
- intentkit/skills/cryptocompare/fetch_news.py +3 -4
- intentkit/skills/cryptocompare/fetch_price.py +3 -4
- intentkit/skills/cryptocompare/fetch_top_exchanges.py +3 -4
- intentkit/skills/cryptocompare/fetch_top_market_cap.py +3 -4
- intentkit/skills/cryptocompare/fetch_top_volume.py +3 -4
- intentkit/skills/cryptocompare/fetch_trading_signals.py +3 -4
- intentkit/skills/cryptopanic/base.py +13 -9
- intentkit/skills/cryptopanic/fetch_crypto_news.py +150 -153
- intentkit/skills/cryptopanic/fetch_crypto_sentiment.py +133 -136
- intentkit/skills/dapplooker/base.py +16 -6
- intentkit/skills/dapplooker/dapplooker_token_data.py +2 -4
- intentkit/skills/defillama/coins/fetch_batch_historical_prices.py +2 -3
- intentkit/skills/defillama/coins/fetch_block.py +2 -3
- intentkit/skills/defillama/coins/fetch_current_prices.py +2 -5
- intentkit/skills/defillama/coins/fetch_first_price.py +2 -5
- intentkit/skills/defillama/coins/fetch_historical_prices.py +2 -3
- intentkit/skills/defillama/coins/fetch_price_chart.py +2 -5
- intentkit/skills/defillama/coins/fetch_price_percentage.py +2 -5
- intentkit/skills/defillama/fees/fetch_fees_overview.py +2 -3
- intentkit/skills/defillama/stablecoins/fetch_stablecoin_chains.py +2 -3
- intentkit/skills/defillama/stablecoins/fetch_stablecoin_charts.py +2 -3
- intentkit/skills/defillama/stablecoins/fetch_stablecoin_prices.py +2 -3
- intentkit/skills/defillama/stablecoins/fetch_stablecoins.py +2 -3
- intentkit/skills/defillama/tvl/fetch_chain_historical_tvl.py +2 -5
- intentkit/skills/defillama/tvl/fetch_chains.py +2 -3
- intentkit/skills/defillama/tvl/fetch_historical_tvl.py +2 -3
- intentkit/skills/defillama/tvl/fetch_protocol.py +2 -5
- intentkit/skills/defillama/tvl/fetch_protocol_current_tvl.py +2 -5
- intentkit/skills/defillama/tvl/fetch_protocols.py +2 -3
- intentkit/skills/defillama/volumes/fetch_dex_overview.py +2 -3
- intentkit/skills/defillama/volumes/fetch_dex_summary.py +2 -5
- intentkit/skills/defillama/volumes/fetch_options_overview.py +2 -3
- intentkit/skills/defillama/yields/fetch_pool_chart.py +2 -5
- intentkit/skills/defillama/yields/fetch_pools.py +2 -3
- intentkit/skills/dune_analytics/base.py +15 -9
- intentkit/skills/dune_analytics/fetch_kol_buys.py +125 -128
- intentkit/skills/dune_analytics/fetch_nation_metrics.py +234 -237
- intentkit/skills/elfa/base.py +16 -6
- intentkit/skills/elfa/mention.py +2 -7
- intentkit/skills/elfa/stats.py +2 -6
- intentkit/skills/elfa/tokens.py +1 -4
- intentkit/skills/enso/base.py +25 -13
- intentkit/skills/enso/best_yield.py +1 -4
- intentkit/skills/enso/networks.py +2 -5
- intentkit/skills/enso/prices.py +1 -5
- intentkit/skills/enso/route.py +2 -5
- intentkit/skills/enso/tokens.py +1 -4
- intentkit/skills/enso/wallet.py +3 -9
- intentkit/skills/firecrawl/base.py +16 -6
- intentkit/skills/firecrawl/clear.py +1 -3
- intentkit/skills/firecrawl/crawl.py +7 -8
- intentkit/skills/firecrawl/query.py +7 -9
- intentkit/skills/firecrawl/scrape.py +7 -8
- intentkit/skills/github/github_search.py +1 -3
- intentkit/skills/heurist/base.py +15 -0
- intentkit/skills/heurist/image_generation_animagine_xl.py +3 -4
- intentkit/skills/heurist/image_generation_arthemy_comics.py +3 -4
- intentkit/skills/heurist/image_generation_arthemy_real.py +3 -4
- intentkit/skills/heurist/image_generation_braindance.py +3 -4
- intentkit/skills/heurist/image_generation_cyber_realistic_xl.py +3 -4
- intentkit/skills/heurist/image_generation_flux_1_dev.py +3 -4
- intentkit/skills/heurist/image_generation_sdxl.py +3 -4
- intentkit/skills/http/get.py +0 -2
- intentkit/skills/http/post.py +0 -2
- intentkit/skills/http/put.py +0 -2
- intentkit/skills/lifi/token_execute.py +1 -3
- intentkit/skills/lifi/token_quote.py +0 -2
- intentkit/skills/moralis/base.py +15 -1
- intentkit/skills/nation/nft_check.py +2 -5
- intentkit/skills/openai/base.py +14 -5
- intentkit/skills/openai/dalle_image_generation.py +6 -5
- intentkit/skills/openai/gpt_image_generation.py +6 -5
- intentkit/skills/openai/gpt_image_to_image.py +6 -5
- intentkit/skills/openai/image_to_text.py +6 -6
- intentkit/skills/portfolio/base.py +4 -3
- intentkit/skills/portfolio/token_balances.py +2 -4
- intentkit/skills/portfolio/wallet_approvals.py +2 -4
- intentkit/skills/portfolio/wallet_defi_positions.py +3 -4
- intentkit/skills/portfolio/wallet_history.py +2 -4
- intentkit/skills/portfolio/wallet_net_worth.py +2 -4
- intentkit/skills/portfolio/wallet_nfts.py +2 -4
- intentkit/skills/portfolio/wallet_profitability.py +2 -4
- intentkit/skills/portfolio/wallet_profitability_summary.py +2 -4
- intentkit/skills/portfolio/wallet_stats.py +2 -4
- intentkit/skills/portfolio/wallet_swaps.py +2 -4
- intentkit/skills/slack/base.py +18 -0
- intentkit/skills/slack/get_channel.py +3 -4
- intentkit/skills/slack/get_message.py +3 -4
- intentkit/skills/slack/schedule_message.py +3 -4
- intentkit/skills/slack/send_message.py +3 -4
- intentkit/skills/supabase/delete_data.py +3 -6
- intentkit/skills/supabase/fetch_data.py +3 -6
- intentkit/skills/supabase/insert_data.py +3 -6
- intentkit/skills/supabase/invoke_function.py +3 -6
- intentkit/skills/supabase/update_data.py +3 -6
- intentkit/skills/supabase/upsert_data.py +3 -6
- intentkit/skills/system/add_autonomous_task.py +1 -3
- intentkit/skills/system/delete_autonomous_task.py +1 -3
- intentkit/skills/system/edit_autonomous_task.py +1 -3
- intentkit/skills/system/list_autonomous_tasks.py +1 -3
- intentkit/skills/system/read_agent_api_key.py +2 -3
- intentkit/skills/system/regenerate_agent_api_key.py +2 -5
- intentkit/skills/tavily/base.py +14 -5
- intentkit/skills/tavily/tavily_extract.py +7 -8
- intentkit/skills/tavily/tavily_search.py +11 -9
- intentkit/skills/token/base.py +4 -6
- intentkit/skills/token/erc20_transfers.py +2 -4
- intentkit/skills/token/token_analytics.py +2 -4
- intentkit/skills/token/token_price.py +2 -4
- intentkit/skills/token/token_search.py +2 -4
- intentkit/skills/twitter/base.py +41 -0
- intentkit/skills/twitter/follow_user.py +4 -4
- intentkit/skills/twitter/get_mentions.py +4 -4
- intentkit/skills/twitter/get_timeline.py +4 -4
- intentkit/skills/twitter/get_user_by_username.py +4 -4
- intentkit/skills/twitter/get_user_tweets.py +4 -4
- intentkit/skills/twitter/like_tweet.py +4 -4
- intentkit/skills/twitter/post_tweet.py +3 -4
- intentkit/skills/twitter/reply_tweet.py +3 -4
- intentkit/skills/twitter/retweet.py +4 -4
- intentkit/skills/twitter/search_tweets.py +4 -4
- intentkit/skills/unrealspeech/base.py +16 -0
- intentkit/skills/unrealspeech/text_to_speech.py +4 -4
- intentkit/skills/venice_audio/base.py +11 -9
- intentkit/skills/venice_audio/venice_audio.py +238 -240
- intentkit/skills/venice_image/base.py +23 -19
- intentkit/skills/venice_image/image_enhance/image_enhance.py +78 -80
- intentkit/skills/venice_image/image_generation/image_generation_base.py +115 -117
- intentkit/skills/venice_image/image_upscale/image_upscale.py +88 -90
- intentkit/skills/venice_image/image_vision/image_vision.py +98 -100
- intentkit/skills/web_scraper/document_indexer.py +3 -5
- intentkit/skills/web_scraper/scrape_and_index.py +14 -17
- intentkit/skills/web_scraper/website_indexer.py +8 -10
- intentkit/skills/xmtp/README.md +110 -0
- intentkit/skills/xmtp/__init__.py +82 -0
- intentkit/skills/xmtp/base.py +13 -0
- intentkit/skills/xmtp/schema.json +41 -0
- intentkit/skills/xmtp/transfer.py +170 -0
- intentkit/skills/xmtp/xmtp.svg +26 -0
- {intentkit-0.6.9.dev2.dist-info → intentkit-0.6.10.dev1.dist-info}/METADATA +3 -3
- {intentkit-0.6.9.dev2.dist-info → intentkit-0.6.10.dev1.dist-info}/RECORD +168 -162
- {intentkit-0.6.9.dev2.dist-info → intentkit-0.6.10.dev1.dist-info}/WHEEL +0 -0
- {intentkit-0.6.9.dev2.dist-info → intentkit-0.6.10.dev1.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,240 +1,238 @@
|
|
|
1
|
-
import hashlib
|
|
2
|
-
import json
|
|
3
|
-
import logging
|
|
4
|
-
from typing import Any, Dict, Optional, Type
|
|
5
|
-
|
|
6
|
-
import httpx
|
|
7
|
-
from
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
from intentkit.
|
|
11
|
-
from intentkit.skills.venice_audio.
|
|
12
|
-
from intentkit.
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
On
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
""
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
"
|
|
76
|
-
"
|
|
77
|
-
"
|
|
78
|
-
"
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
)
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
"
|
|
91
|
-
"
|
|
92
|
-
"
|
|
93
|
-
"
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
"
|
|
103
|
-
"
|
|
104
|
-
"
|
|
105
|
-
"
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
"
|
|
147
|
-
"
|
|
148
|
-
"
|
|
149
|
-
"
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
"
|
|
174
|
-
"
|
|
175
|
-
"
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
"
|
|
186
|
-
"
|
|
187
|
-
"
|
|
188
|
-
"
|
|
189
|
-
"
|
|
190
|
-
"
|
|
191
|
-
"
|
|
192
|
-
"
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
"
|
|
211
|
-
"
|
|
212
|
-
"
|
|
213
|
-
"
|
|
214
|
-
"
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
)
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
"
|
|
235
|
-
"
|
|
236
|
-
"
|
|
237
|
-
"
|
|
238
|
-
|
|
239
|
-
"requested_format": final_response_format,
|
|
240
|
-
}
|
|
1
|
+
import hashlib
|
|
2
|
+
import json
|
|
3
|
+
import logging
|
|
4
|
+
from typing import Any, Dict, Optional, Type
|
|
5
|
+
|
|
6
|
+
import httpx
|
|
7
|
+
from pydantic import BaseModel, Field
|
|
8
|
+
|
|
9
|
+
from intentkit.abstracts.skill import SkillStoreABC
|
|
10
|
+
from intentkit.skills.venice_audio.base import VeniceAudioBaseTool
|
|
11
|
+
from intentkit.skills.venice_audio.input import AllowedAudioFormat, VeniceAudioInput
|
|
12
|
+
from intentkit.utils.s3 import FileType, store_file_bytes
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
base_url = "https://api.venice.ai"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class VeniceAudioTool(VeniceAudioBaseTool):
|
|
20
|
+
"""
|
|
21
|
+
Tool for generating audio using the Venice AI Text-to-Speech API (/audio/speech).
|
|
22
|
+
It requires a specific 'voice_model' to be configured for the instance.
|
|
23
|
+
Handles API calls, rate limiting, storage, and returns results or API errors as dictionaries.
|
|
24
|
+
|
|
25
|
+
On successful audio generation, returns a dictionary with audio details.
|
|
26
|
+
On Venice API error (non-200 status), returns a dictionary containing
|
|
27
|
+
the error details from the API response instead of raising an exception.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
name: str = "venice_audio_text_to_speech"
|
|
31
|
+
description: str = (
|
|
32
|
+
"Converts text to speech using a configured Venice AI voice model. "
|
|
33
|
+
"Requires input text. Optional parameters include speed (0.25-4.0, default 1.0) "
|
|
34
|
+
"and audio format (mp3, opus, aac, flac, wav, pcm, default mp3)."
|
|
35
|
+
)
|
|
36
|
+
args_schema: Type[BaseModel] = VeniceAudioInput
|
|
37
|
+
skill_store: SkillStoreABC = Field(
|
|
38
|
+
description="The skill store instance for accessing system/agent configurations and persisting data."
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
async def _arun(
|
|
42
|
+
self,
|
|
43
|
+
input: str,
|
|
44
|
+
voice_model: str,
|
|
45
|
+
speed: Optional[float] = 1.0,
|
|
46
|
+
response_format: Optional[AllowedAudioFormat] = "mp3",
|
|
47
|
+
**kwargs, # type: ignore
|
|
48
|
+
) -> Dict[str, Any]:
|
|
49
|
+
"""
|
|
50
|
+
Generates audio using the configured voice model via Venice AI TTS /audio/speech endpoint.
|
|
51
|
+
Stores the resulting audio using store_file_bytes.
|
|
52
|
+
Returns a dictionary containing audio details on success, or API error details on failure.
|
|
53
|
+
"""
|
|
54
|
+
context = self.get_context()
|
|
55
|
+
final_response_format = response_format if response_format else "mp3"
|
|
56
|
+
tts_model_id = "tts-kokoro" # API model used
|
|
57
|
+
|
|
58
|
+
try:
|
|
59
|
+
# --- Setup Checks ---
|
|
60
|
+
api_key = self.get_api_key()
|
|
61
|
+
|
|
62
|
+
_, error_info = self.validate_voice_model(context, voice_model)
|
|
63
|
+
if error_info:
|
|
64
|
+
return error_info
|
|
65
|
+
|
|
66
|
+
if not api_key:
|
|
67
|
+
message = (
|
|
68
|
+
f"Venice AI API key configuration missing for skill '{self.name}'."
|
|
69
|
+
)
|
|
70
|
+
details = f"API key not found for category '{self.category}'. Please configure it."
|
|
71
|
+
logger.error(message)
|
|
72
|
+
return {
|
|
73
|
+
"error": True,
|
|
74
|
+
"error_type": "ConfigurationError",
|
|
75
|
+
"message": message,
|
|
76
|
+
"details": details,
|
|
77
|
+
"voice_model": voice_model,
|
|
78
|
+
"requested_format": final_response_format,
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if not voice_model:
|
|
82
|
+
message = (
|
|
83
|
+
f"Instance of {self.name} was created without a 'voice_model'."
|
|
84
|
+
)
|
|
85
|
+
details = "Voice model must be specified for this tool instance."
|
|
86
|
+
logger.error(message)
|
|
87
|
+
return {
|
|
88
|
+
"error": True,
|
|
89
|
+
"error_type": "ConfigurationError",
|
|
90
|
+
"message": message,
|
|
91
|
+
"details": details,
|
|
92
|
+
"voice_model": voice_model,
|
|
93
|
+
"requested_format": final_response_format,
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
await self.apply_rate_limit(context)
|
|
97
|
+
|
|
98
|
+
# --- Prepare API Call ---
|
|
99
|
+
payload: Dict[str, Any] = {
|
|
100
|
+
"model": tts_model_id,
|
|
101
|
+
"input": input,
|
|
102
|
+
"voice": voice_model,
|
|
103
|
+
"response_format": final_response_format,
|
|
104
|
+
"speed": speed if speed is not None else 1.0,
|
|
105
|
+
"streaming": False,
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
payload = {k: v for k, v in payload.items() if v is not None}
|
|
109
|
+
|
|
110
|
+
logger.debug(
|
|
111
|
+
f"Venice Audio API Call: Voice='{voice_model}', Format='{final_response_format}', Payload='{payload}'"
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
headers = {
|
|
115
|
+
"Authorization": f"Bearer {api_key}",
|
|
116
|
+
"Content-Type": "application/json",
|
|
117
|
+
}
|
|
118
|
+
api_url = f"{base_url}/api/v1/audio/speech"
|
|
119
|
+
|
|
120
|
+
# --- Execute API Call ---
|
|
121
|
+
async with httpx.AsyncClient(timeout=120.0) as client:
|
|
122
|
+
response = await client.post(api_url, json=payload, headers=headers)
|
|
123
|
+
logger.debug(
|
|
124
|
+
f"Venice Audio API Response: Voice='{voice_model}', Format='{final_response_format}', Status={response.status_code}"
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
content_type_header = str(
|
|
128
|
+
response.headers.get("content-type", "")
|
|
129
|
+
).lower()
|
|
130
|
+
|
|
131
|
+
# --- Handle API Success or Error from Response Body ---
|
|
132
|
+
if response.status_code == 200 and content_type_header.startswith(
|
|
133
|
+
"audio/"
|
|
134
|
+
):
|
|
135
|
+
audio_bytes = response.content
|
|
136
|
+
if not audio_bytes:
|
|
137
|
+
message = (
|
|
138
|
+
"API returned success status but response body was empty."
|
|
139
|
+
)
|
|
140
|
+
logger.warning(
|
|
141
|
+
f"Venice Audio API (Voice: {voice_model}) returned 200 OK but empty audio content."
|
|
142
|
+
)
|
|
143
|
+
return {
|
|
144
|
+
"error": True,
|
|
145
|
+
"error_type": "NoContentError",
|
|
146
|
+
"message": message,
|
|
147
|
+
"status_code": response.status_code,
|
|
148
|
+
"voice_model": voice_model,
|
|
149
|
+
"requested_format": final_response_format,
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
# --- Store Audio ---
|
|
153
|
+
file_extension = final_response_format
|
|
154
|
+
audio_hash = hashlib.sha256(audio_bytes).hexdigest()
|
|
155
|
+
key = f"{self.category}/{voice_model}/{audio_hash}.{file_extension}"
|
|
156
|
+
|
|
157
|
+
size_limit = 1024 * 20 # 20Mb Size limit
|
|
158
|
+
stored_url = await store_file_bytes(
|
|
159
|
+
file_bytes=audio_bytes,
|
|
160
|
+
key=key,
|
|
161
|
+
file_type=FileType.AUDIO,
|
|
162
|
+
size_limit_bytes=size_limit,
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
if not stored_url:
|
|
166
|
+
message = "Failed to store audio: S3 storage is not configured."
|
|
167
|
+
logger.error(
|
|
168
|
+
f"Failed to store audio (Voice: {voice_model}): S3 storage is not configured."
|
|
169
|
+
)
|
|
170
|
+
return {
|
|
171
|
+
"error": True,
|
|
172
|
+
"error_type": "StorageConfigurationError",
|
|
173
|
+
"message": message,
|
|
174
|
+
"voice_model": voice_model,
|
|
175
|
+
"requested_format": final_response_format,
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
logger.info(
|
|
179
|
+
f"Venice TTS success: Voice='{voice_model}', Format='{final_response_format}', Stored='{stored_url}'"
|
|
180
|
+
)
|
|
181
|
+
# --- Return Success Dictionary ---
|
|
182
|
+
return {
|
|
183
|
+
"audio_url": stored_url,
|
|
184
|
+
"audio_bytes_sha256": audio_hash,
|
|
185
|
+
"content_type": content_type_header,
|
|
186
|
+
"voice_model": voice_model,
|
|
187
|
+
"tts_engine": tts_model_id,
|
|
188
|
+
"speed": speed if speed is not None else 1.0,
|
|
189
|
+
"response_format": final_response_format,
|
|
190
|
+
"input_text_length": len(input),
|
|
191
|
+
"error": False,
|
|
192
|
+
"status_code": response.status_code,
|
|
193
|
+
}
|
|
194
|
+
else:
|
|
195
|
+
# Non-200 API response or non-audio content
|
|
196
|
+
error_details: Any = f"Raw error response text: {response.text}"
|
|
197
|
+
try:
|
|
198
|
+
parsed_details = response.json()
|
|
199
|
+
error_details = parsed_details
|
|
200
|
+
except json.JSONDecodeError:
|
|
201
|
+
pass # Keep raw text if JSON parsing fails
|
|
202
|
+
|
|
203
|
+
message = "Venice Audio API returned a non-success status or unexpected content type."
|
|
204
|
+
logger.error(
|
|
205
|
+
f"Venice Audio API Error: Voice='{voice_model}', Format='{final_response_format}', Status={response.status_code}, Details: {error_details}"
|
|
206
|
+
)
|
|
207
|
+
return {
|
|
208
|
+
"error": True,
|
|
209
|
+
"error_type": "APIError",
|
|
210
|
+
"message": message,
|
|
211
|
+
"status_code": response.status_code,
|
|
212
|
+
"details": error_details,
|
|
213
|
+
"voice_model": voice_model,
|
|
214
|
+
"requested_format": final_response_format,
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
except Exception as e:
|
|
218
|
+
# Global exception handling for any uncaught error
|
|
219
|
+
error_type = type(
|
|
220
|
+
e
|
|
221
|
+
).__name__ # Gets the class name of the exception (e.g., 'TimeoutException', 'ToolException')
|
|
222
|
+
message = f"An unexpected error occurred during audio generation for voice {voice_model}."
|
|
223
|
+
details = str(e) # The string representation of the exception
|
|
224
|
+
|
|
225
|
+
# Log the error with full traceback for debugging
|
|
226
|
+
logger.error(
|
|
227
|
+
f"Venice Audio Tool Global Error ({error_type}): {message} | Details: {details}",
|
|
228
|
+
exc_info=True,
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
return {
|
|
232
|
+
"error": True,
|
|
233
|
+
"error_type": error_type, # e.g., "TimeoutException", "ToolException", "ClientError", "ValueError"
|
|
234
|
+
"message": message,
|
|
235
|
+
"details": details,
|
|
236
|
+
"voice_model": voice_model,
|
|
237
|
+
"requested_format": final_response_format,
|
|
238
|
+
}
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from typing import Any, Dict, Optional, Tuple
|
|
3
3
|
|
|
4
|
+
from langchain.tools.base import ToolException
|
|
4
5
|
from pydantic import Field
|
|
5
6
|
|
|
6
7
|
from intentkit.abstracts.skill import SkillStoreABC
|
|
7
|
-
from intentkit.skills.base import
|
|
8
|
-
IntentKitSkill,
|
|
9
|
-
SkillContext,
|
|
10
|
-
ToolException,
|
|
11
|
-
)
|
|
8
|
+
from intentkit.skills.base import IntentKitSkill
|
|
12
9
|
from intentkit.skills.venice_image.api import (
|
|
13
10
|
make_venice_api_request,
|
|
14
11
|
)
|
|
@@ -47,7 +44,7 @@ class VeniceImageBaseTool(IntentKitSkill):
|
|
|
47
44
|
description="The skill store for persisting data and configs."
|
|
48
45
|
)
|
|
49
46
|
|
|
50
|
-
def getSkillConfig(self, context
|
|
47
|
+
def getSkillConfig(self, context) -> VeniceImageConfig:
|
|
51
48
|
"""
|
|
52
49
|
Creates a VeniceImageConfig instance from a dictionary of configuration values.
|
|
53
50
|
|
|
@@ -58,19 +55,20 @@ class VeniceImageBaseTool(IntentKitSkill):
|
|
|
58
55
|
A VeniceImageConfig object.
|
|
59
56
|
"""
|
|
60
57
|
|
|
58
|
+
skill_config = context.agent.skill_config(self.category)
|
|
61
59
|
return VeniceImageConfig(
|
|
62
|
-
api_key_provider=
|
|
63
|
-
safe_mode=
|
|
64
|
-
hide_watermark=
|
|
65
|
-
embed_exif_metadata=
|
|
66
|
-
negative_prompt=
|
|
60
|
+
api_key_provider=skill_config.get("api_key_provider", "agent_owner"),
|
|
61
|
+
safe_mode=skill_config.get("safe_mode", True),
|
|
62
|
+
hide_watermark=skill_config.get("hide_watermark", True),
|
|
63
|
+
embed_exif_metadata=skill_config.get("embed_exif_metadata", False),
|
|
64
|
+
negative_prompt=skill_config.get(
|
|
67
65
|
"negative_prompt", "(worst quality: 1.4), bad quality, nsfw"
|
|
68
66
|
),
|
|
69
|
-
rate_limit_number=
|
|
70
|
-
rate_limit_minutes=
|
|
67
|
+
rate_limit_number=skill_config.get("rate_limit_number"),
|
|
68
|
+
rate_limit_minutes=skill_config.get("rate_limit_minutes"),
|
|
71
69
|
)
|
|
72
70
|
|
|
73
|
-
def get_api_key(self
|
|
71
|
+
def get_api_key(self) -> str:
|
|
74
72
|
"""
|
|
75
73
|
Retrieves the Venice AI API key based on the api_key_provider setting.
|
|
76
74
|
|
|
@@ -81,9 +79,11 @@ class VeniceImageBaseTool(IntentKitSkill):
|
|
|
81
79
|
ToolException: If the API key is not found or provider is invalid.
|
|
82
80
|
"""
|
|
83
81
|
try:
|
|
82
|
+
context = self.get_context()
|
|
84
83
|
skillConfig = self.getSkillConfig(context=context)
|
|
85
84
|
if skillConfig.api_key_provider == "agent_owner":
|
|
86
|
-
|
|
85
|
+
skill_config = context.agent.skill_config(self.category)
|
|
86
|
+
agent_api_key = skill_config.get("api_key")
|
|
87
87
|
if agent_api_key:
|
|
88
88
|
logger.debug(
|
|
89
89
|
f"Using agent-specific Venice API key for skill {self.name} in category {self.category}"
|
|
@@ -112,7 +112,7 @@ class VeniceImageBaseTool(IntentKitSkill):
|
|
|
112
112
|
except Exception as e:
|
|
113
113
|
raise ToolException(f"Failed to retrieve Venice API key: {str(e)}") from e
|
|
114
114
|
|
|
115
|
-
async def apply_venice_rate_limit(self, context
|
|
115
|
+
async def apply_venice_rate_limit(self, context) -> None:
|
|
116
116
|
"""
|
|
117
117
|
Applies rate limiting to prevent exceeding the Venice AI API's rate limits.
|
|
118
118
|
|
|
@@ -121,7 +121,7 @@ class VeniceImageBaseTool(IntentKitSkill):
|
|
|
121
121
|
- 'platform': uses system-wide configuration.
|
|
122
122
|
"""
|
|
123
123
|
try:
|
|
124
|
-
user_id
|
|
124
|
+
# Get user_id from the agent context (venice_image only supports agent_owner)
|
|
125
125
|
skillConfig = self.getSkillConfig(context=context)
|
|
126
126
|
|
|
127
127
|
if skillConfig.api_key_provider == "agent_owner":
|
|
@@ -129,6 +129,8 @@ class VeniceImageBaseTool(IntentKitSkill):
|
|
|
129
129
|
limit_min = skillConfig.rate_limit_minutes
|
|
130
130
|
|
|
131
131
|
if limit_num and limit_min:
|
|
132
|
+
# For agent_owner, use agent.id as user_id for rate limiting
|
|
133
|
+
user_id = context.agent.id
|
|
132
134
|
logger.debug(
|
|
133
135
|
f"Applying Agent rate limit ({limit_num}/{limit_min} min) for user {user_id} on {self.name}"
|
|
134
136
|
)
|
|
@@ -145,6 +147,8 @@ class VeniceImageBaseTool(IntentKitSkill):
|
|
|
145
147
|
)
|
|
146
148
|
|
|
147
149
|
if system_limit_num and system_limit_min:
|
|
150
|
+
# For platform, use agent.id as user_id for rate limiting
|
|
151
|
+
user_id = context.agent.id
|
|
148
152
|
logger.debug(
|
|
149
153
|
f"Applying System rate limit ({system_limit_num}/{system_limit_min} min) for user {user_id} on {self.name}"
|
|
150
154
|
)
|
|
@@ -158,7 +162,7 @@ class VeniceImageBaseTool(IntentKitSkill):
|
|
|
158
162
|
raise ToolException(f"Failed to apply Venice rate limit: {str(e)}") from e
|
|
159
163
|
|
|
160
164
|
async def post(
|
|
161
|
-
self, path: str, payload: Dict[str, Any], context
|
|
165
|
+
self, path: str, payload: Dict[str, Any], context
|
|
162
166
|
) -> Tuple[Dict[str, Any], Optional[Dict[str, Any]]]:
|
|
163
167
|
"""
|
|
164
168
|
Makes a POST request to the Venice AI API using the `make_venice_api_request`
|
|
@@ -181,7 +185,7 @@ class VeniceImageBaseTool(IntentKitSkill):
|
|
|
181
185
|
- If successful, success contains the JSON response from the API.
|
|
182
186
|
- If an error occurs, success is an empty dictionary, and error contains error details.
|
|
183
187
|
"""
|
|
184
|
-
api_key = self.get_api_key(
|
|
188
|
+
api_key = self.get_api_key()
|
|
185
189
|
|
|
186
190
|
return await make_venice_api_request(
|
|
187
191
|
api_key, path, payload, self.category, self.name
|