intentkit 0.8.16.dev1__py3-none-any.whl → 0.8.17.dev2__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.

Files changed (274) hide show
  1. intentkit/__init__.py +1 -1
  2. intentkit/abstracts/agent.py +4 -5
  3. intentkit/abstracts/engine.py +5 -5
  4. intentkit/abstracts/graph.py +6 -5
  5. intentkit/abstracts/skill.py +5 -5
  6. intentkit/abstracts/twitter.py +4 -5
  7. intentkit/clients/cdp.py +19 -77
  8. intentkit/clients/twitter.py +26 -34
  9. intentkit/clients/web3.py +1 -3
  10. intentkit/config/config.py +4 -0
  11. intentkit/core/agent.py +15 -15
  12. intentkit/core/asset.py +1 -2
  13. intentkit/core/client.py +1 -1
  14. intentkit/core/credit.py +19 -20
  15. intentkit/core/engine.py +2 -4
  16. intentkit/core/node.py +2 -1
  17. intentkit/core/prompt.py +3 -4
  18. intentkit/core/scheduler.py +1 -1
  19. intentkit/core/statistics.py +6 -7
  20. intentkit/models/agent.py +125 -92
  21. intentkit/models/agent_data.py +62 -36
  22. intentkit/models/app_setting.py +6 -6
  23. intentkit/models/chat.py +27 -24
  24. intentkit/models/conversation.py +8 -8
  25. intentkit/models/credit.py +62 -64
  26. intentkit/models/db.py +8 -7
  27. intentkit/models/db_mig.py +2 -2
  28. intentkit/models/llm.py +12 -14
  29. intentkit/models/redis.py +2 -3
  30. intentkit/models/skill.py +25 -27
  31. intentkit/models/skills.csv +29 -28
  32. intentkit/models/user.py +21 -22
  33. intentkit/skills/acolyt/ask.py +3 -4
  34. intentkit/skills/acolyt/base.py +1 -3
  35. intentkit/skills/aixbt/base.py +1 -3
  36. intentkit/skills/aixbt/projects.py +13 -13
  37. intentkit/skills/allora/base.py +1 -3
  38. intentkit/skills/allora/price.py +2 -3
  39. intentkit/skills/base.py +15 -22
  40. intentkit/skills/basename/__init__.py +3 -5
  41. intentkit/skills/carv/__init__.py +7 -8
  42. intentkit/skills/carv/base.py +6 -6
  43. intentkit/skills/carv/fetch_news.py +3 -3
  44. intentkit/skills/carv/onchain_query.py +4 -4
  45. intentkit/skills/carv/token_info_and_price.py +5 -5
  46. intentkit/skills/casino/base.py +1 -3
  47. intentkit/skills/casino/deck_draw.py +1 -2
  48. intentkit/skills/casino/deck_shuffle.py +1 -2
  49. intentkit/skills/casino/dice_roll.py +1 -2
  50. intentkit/skills/cdp/__init__.py +3 -5
  51. intentkit/skills/cdp/base.py +1 -3
  52. intentkit/skills/chainlist/base.py +1 -3
  53. intentkit/skills/chainlist/chain_lookup.py +18 -18
  54. intentkit/skills/common/base.py +1 -3
  55. intentkit/skills/common/current_time.py +1 -2
  56. intentkit/skills/cookiefun/base.py +1 -2
  57. intentkit/skills/cookiefun/get_account_details.py +7 -7
  58. intentkit/skills/cookiefun/get_account_feed.py +19 -19
  59. intentkit/skills/cookiefun/get_account_smart_followers.py +7 -7
  60. intentkit/skills/cookiefun/get_sectors.py +3 -3
  61. intentkit/skills/cookiefun/search_accounts.py +9 -9
  62. intentkit/skills/cryptocompare/api.py +2 -3
  63. intentkit/skills/cryptocompare/base.py +6 -6
  64. intentkit/skills/cryptocompare/fetch_news.py +3 -4
  65. intentkit/skills/cryptocompare/fetch_price.py +5 -6
  66. intentkit/skills/cryptocompare/fetch_top_exchanges.py +3 -4
  67. intentkit/skills/cryptocompare/fetch_top_market_cap.py +3 -4
  68. intentkit/skills/cryptocompare/fetch_top_volume.py +3 -4
  69. intentkit/skills/cryptocompare/fetch_trading_signals.py +4 -5
  70. intentkit/skills/cryptopanic/__init__.py +4 -4
  71. intentkit/skills/cryptopanic/base.py +1 -3
  72. intentkit/skills/cryptopanic/fetch_crypto_news.py +3 -5
  73. intentkit/skills/cryptopanic/fetch_crypto_sentiment.py +3 -3
  74. intentkit/skills/dapplooker/base.py +1 -3
  75. intentkit/skills/dapplooker/dapplooker_token_data.py +7 -7
  76. intentkit/skills/defillama/api.py +6 -9
  77. intentkit/skills/defillama/base.py +5 -6
  78. intentkit/skills/defillama/coins/fetch_batch_historical_prices.py +6 -8
  79. intentkit/skills/defillama/coins/fetch_block.py +4 -6
  80. intentkit/skills/defillama/coins/fetch_current_prices.py +6 -8
  81. intentkit/skills/defillama/coins/fetch_first_price.py +5 -7
  82. intentkit/skills/defillama/coins/fetch_historical_prices.py +7 -9
  83. intentkit/skills/defillama/coins/fetch_price_chart.py +7 -9
  84. intentkit/skills/defillama/coins/fetch_price_percentage.py +5 -7
  85. intentkit/skills/defillama/config/chains.py +1 -3
  86. intentkit/skills/defillama/fees/fetch_fees_overview.py +22 -24
  87. intentkit/skills/defillama/stablecoins/fetch_stablecoin_chains.py +14 -16
  88. intentkit/skills/defillama/stablecoins/fetch_stablecoin_charts.py +6 -8
  89. intentkit/skills/defillama/stablecoins/fetch_stablecoin_prices.py +3 -5
  90. intentkit/skills/defillama/stablecoins/fetch_stablecoins.py +5 -7
  91. intentkit/skills/defillama/tests/api_integration.test.py +1 -1
  92. intentkit/skills/defillama/tvl/fetch_chain_historical_tvl.py +2 -4
  93. intentkit/skills/defillama/tvl/fetch_chains.py +7 -9
  94. intentkit/skills/defillama/tvl/fetch_historical_tvl.py +2 -4
  95. intentkit/skills/defillama/tvl/fetch_protocol.py +30 -36
  96. intentkit/skills/defillama/tvl/fetch_protocol_current_tvl.py +1 -3
  97. intentkit/skills/defillama/tvl/fetch_protocols.py +35 -43
  98. intentkit/skills/defillama/volumes/fetch_dex_overview.py +40 -46
  99. intentkit/skills/defillama/volumes/fetch_dex_summary.py +33 -35
  100. intentkit/skills/defillama/volumes/fetch_options_overview.py +22 -26
  101. intentkit/skills/defillama/yields/fetch_pool_chart.py +8 -10
  102. intentkit/skills/defillama/yields/fetch_pools.py +24 -28
  103. intentkit/skills/dexscreener/__init__.py +2 -2
  104. intentkit/skills/dexscreener/base.py +3 -3
  105. intentkit/skills/dexscreener/get_pair_info.py +2 -2
  106. intentkit/skills/dexscreener/get_token_pairs.py +2 -2
  107. intentkit/skills/dexscreener/get_tokens_info.py +5 -5
  108. intentkit/skills/dexscreener/model/search_token_response.py +80 -82
  109. intentkit/skills/dexscreener/search_token.py +182 -182
  110. intentkit/skills/dexscreener/utils.py +15 -14
  111. intentkit/skills/dune_analytics/__init__.py +4 -4
  112. intentkit/skills/dune_analytics/base.py +1 -3
  113. intentkit/skills/dune_analytics/fetch_kol_buys.py +4 -4
  114. intentkit/skills/dune_analytics/fetch_nation_metrics.py +5 -5
  115. intentkit/skills/elfa/base.py +1 -3
  116. intentkit/skills/elfa/mention.py +19 -21
  117. intentkit/skills/elfa/stats.py +4 -4
  118. intentkit/skills/elfa/tokens.py +12 -12
  119. intentkit/skills/elfa/utils.py +25 -27
  120. intentkit/skills/enso/__init__.py +2 -2
  121. intentkit/skills/enso/base.py +5 -8
  122. intentkit/skills/enso/best_yield.py +4 -6
  123. intentkit/skills/enso/networks.py +1 -2
  124. intentkit/skills/enso/prices.py +1 -3
  125. intentkit/skills/enso/route.py +1 -3
  126. intentkit/skills/enso/tokens.py +1 -3
  127. intentkit/skills/enso/wallet.py +5 -5
  128. intentkit/skills/erc20/__init__.py +4 -6
  129. intentkit/skills/erc721/__init__.py +4 -6
  130. intentkit/skills/firecrawl/base.py +1 -3
  131. intentkit/skills/firecrawl/clear.py +1 -2
  132. intentkit/skills/firecrawl/crawl.py +9 -10
  133. intentkit/skills/firecrawl/query.py +1 -2
  134. intentkit/skills/firecrawl/scrape.py +7 -8
  135. intentkit/skills/firecrawl/utils.py +13 -13
  136. intentkit/skills/github/base.py +1 -3
  137. intentkit/skills/github/github_search.py +1 -2
  138. intentkit/skills/heurist/base.py +1 -3
  139. intentkit/skills/heurist/image_generation_animagine_xl.py +7 -8
  140. intentkit/skills/heurist/image_generation_arthemy_comics.py +7 -8
  141. intentkit/skills/heurist/image_generation_arthemy_real.py +7 -8
  142. intentkit/skills/heurist/image_generation_braindance.py +7 -8
  143. intentkit/skills/heurist/image_generation_cyber_realistic_xl.py +7 -8
  144. intentkit/skills/heurist/image_generation_flux_1_dev.py +7 -8
  145. intentkit/skills/heurist/image_generation_sdxl.py +7 -8
  146. intentkit/skills/http/base.py +1 -3
  147. intentkit/skills/http/get.py +7 -7
  148. intentkit/skills/http/post.py +9 -9
  149. intentkit/skills/http/put.py +9 -9
  150. intentkit/skills/lifi/__init__.py +4 -4
  151. intentkit/skills/lifi/base.py +1 -3
  152. intentkit/skills/lifi/token_execute.py +13 -13
  153. intentkit/skills/lifi/token_quote.py +6 -6
  154. intentkit/skills/lifi/utils.py +16 -16
  155. intentkit/skills/moralis/__init__.py +3 -3
  156. intentkit/skills/moralis/api.py +6 -7
  157. intentkit/skills/moralis/base.py +2 -4
  158. intentkit/skills/moralis/fetch_chain_portfolio.py +10 -11
  159. intentkit/skills/moralis/fetch_nft_portfolio.py +22 -22
  160. intentkit/skills/moralis/fetch_solana_portfolio.py +11 -12
  161. intentkit/skills/moralis/fetch_wallet_portfolio.py +8 -9
  162. intentkit/skills/morpho/__init__.py +4 -6
  163. intentkit/skills/nation/__init__.py +2 -2
  164. intentkit/skills/nation/base.py +1 -3
  165. intentkit/skills/nation/nft_check.py +3 -4
  166. intentkit/skills/onchain.py +2 -6
  167. intentkit/skills/openai/base.py +1 -3
  168. intentkit/skills/openai/dalle_image_generation.py +1 -3
  169. intentkit/skills/openai/gpt_image_generation.py +2 -3
  170. intentkit/skills/openai/gpt_image_to_image.py +2 -3
  171. intentkit/skills/openai/image_to_text.py +1 -2
  172. intentkit/skills/portfolio/base.py +6 -6
  173. intentkit/skills/portfolio/token_balances.py +21 -21
  174. intentkit/skills/portfolio/wallet_approvals.py +7 -7
  175. intentkit/skills/portfolio/wallet_defi_positions.py +3 -3
  176. intentkit/skills/portfolio/wallet_history.py +21 -21
  177. intentkit/skills/portfolio/wallet_net_worth.py +13 -13
  178. intentkit/skills/portfolio/wallet_nfts.py +19 -19
  179. intentkit/skills/portfolio/wallet_profitability.py +7 -7
  180. intentkit/skills/portfolio/wallet_profitability_summary.py +5 -5
  181. intentkit/skills/portfolio/wallet_stats.py +3 -3
  182. intentkit/skills/portfolio/wallet_swaps.py +19 -19
  183. intentkit/skills/pyth/__init__.py +3 -5
  184. intentkit/skills/slack/base.py +2 -4
  185. intentkit/skills/slack/get_channel.py +8 -8
  186. intentkit/skills/slack/get_message.py +9 -9
  187. intentkit/skills/slack/schedule_message.py +5 -5
  188. intentkit/skills/slack/send_message.py +3 -5
  189. intentkit/skills/supabase/base.py +1 -3
  190. intentkit/skills/supabase/delete_data.py +4 -4
  191. intentkit/skills/supabase/fetch_data.py +12 -12
  192. intentkit/skills/supabase/insert_data.py +4 -4
  193. intentkit/skills/supabase/invoke_function.py +6 -6
  194. intentkit/skills/supabase/update_data.py +6 -6
  195. intentkit/skills/supabase/upsert_data.py +4 -4
  196. intentkit/skills/superfluid/__init__.py +4 -6
  197. intentkit/skills/system/add_autonomous_task.py +8 -10
  198. intentkit/skills/system/edit_autonomous_task.py +12 -14
  199. intentkit/skills/system/list_autonomous_tasks.py +1 -3
  200. intentkit/skills/tavily/base.py +1 -3
  201. intentkit/skills/tavily/tavily_extract.py +1 -2
  202. intentkit/skills/tavily/tavily_search.py +1 -3
  203. intentkit/skills/token/base.py +5 -5
  204. intentkit/skills/token/erc20_transfers.py +19 -19
  205. intentkit/skills/token/token_analytics.py +3 -3
  206. intentkit/skills/token/token_price.py +13 -13
  207. intentkit/skills/token/token_search.py +9 -9
  208. intentkit/skills/twitter/base.py +3 -4
  209. intentkit/skills/twitter/follow_user.py +1 -2
  210. intentkit/skills/twitter/get_mentions.py +3 -4
  211. intentkit/skills/twitter/get_timeline.py +1 -2
  212. intentkit/skills/twitter/get_user_by_username.py +1 -2
  213. intentkit/skills/twitter/get_user_tweets.py +2 -3
  214. intentkit/skills/twitter/like_tweet.py +1 -2
  215. intentkit/skills/twitter/post_tweet.py +3 -4
  216. intentkit/skills/twitter/reply_tweet.py +3 -4
  217. intentkit/skills/twitter/retweet.py +1 -2
  218. intentkit/skills/twitter/search_tweets.py +1 -2
  219. intentkit/skills/unrealspeech/base.py +1 -3
  220. intentkit/skills/unrealspeech/text_to_speech.py +8 -8
  221. intentkit/skills/venice_audio/__init__.py +8 -9
  222. intentkit/skills/venice_audio/base.py +3 -4
  223. intentkit/skills/venice_audio/input.py +41 -41
  224. intentkit/skills/venice_audio/venice_audio.py +6 -6
  225. intentkit/skills/venice_image/__init__.py +5 -5
  226. intentkit/skills/venice_image/api.py +138 -138
  227. intentkit/skills/venice_image/base.py +3 -3
  228. intentkit/skills/venice_image/config.py +33 -35
  229. intentkit/skills/venice_image/image_enhance/image_enhance.py +2 -3
  230. intentkit/skills/venice_image/image_enhance/image_enhance_base.py +21 -23
  231. intentkit/skills/venice_image/image_enhance/image_enhance_input.py +38 -40
  232. intentkit/skills/venice_image/image_generation/image_generation_base.py +9 -9
  233. intentkit/skills/venice_image/image_generation/image_generation_fluently_xl.py +26 -26
  234. intentkit/skills/venice_image/image_generation/image_generation_flux_dev.py +27 -27
  235. intentkit/skills/venice_image/image_generation/image_generation_flux_dev_uncensored.py +26 -26
  236. intentkit/skills/venice_image/image_generation/image_generation_input.py +158 -158
  237. intentkit/skills/venice_image/image_generation/image_generation_lustify_sdxl.py +26 -26
  238. intentkit/skills/venice_image/image_generation/image_generation_pony_realism.py +26 -26
  239. intentkit/skills/venice_image/image_generation/image_generation_stable_diffusion_3_5.py +28 -28
  240. intentkit/skills/venice_image/image_generation/image_generation_venice_sd35.py +28 -28
  241. intentkit/skills/venice_image/image_upscale/image_upscale.py +3 -3
  242. intentkit/skills/venice_image/image_upscale/image_upscale_base.py +21 -23
  243. intentkit/skills/venice_image/image_upscale/image_upscale_input.py +22 -22
  244. intentkit/skills/venice_image/image_vision/image_vision.py +2 -2
  245. intentkit/skills/venice_image/image_vision/image_vision_base.py +17 -17
  246. intentkit/skills/venice_image/image_vision/image_vision_input.py +9 -9
  247. intentkit/skills/venice_image/utils.py +77 -78
  248. intentkit/skills/web_scraper/base.py +1 -3
  249. intentkit/skills/web_scraper/document_indexer.py +1 -2
  250. intentkit/skills/web_scraper/scrape_and_index.py +4 -5
  251. intentkit/skills/web_scraper/utils.py +25 -26
  252. intentkit/skills/web_scraper/website_indexer.py +10 -11
  253. intentkit/skills/weth/__init__.py +4 -6
  254. intentkit/skills/wow/__init__.py +4 -6
  255. intentkit/skills/x402/__init__.py +11 -3
  256. intentkit/skills/x402/ask_agent.py +12 -78
  257. intentkit/skills/x402/base.py +90 -0
  258. intentkit/skills/x402/http_request.py +117 -0
  259. intentkit/skills/x402/schema.json +15 -10
  260. intentkit/skills/xmtp/base.py +3 -3
  261. intentkit/skills/xmtp/price.py +2 -2
  262. intentkit/skills/xmtp/swap.py +2 -4
  263. intentkit/skills/xmtp/transfer.py +4 -6
  264. intentkit/utils/error.py +2 -2
  265. intentkit/utils/logging.py +2 -4
  266. intentkit/utils/s3.py +8 -9
  267. intentkit/utils/schema.py +5 -5
  268. intentkit/utils/slack_alert.py +7 -8
  269. {intentkit-0.8.16.dev1.dist-info → intentkit-0.8.17.dev2.dist-info}/METADATA +3 -4
  270. intentkit-0.8.17.dev2.dist-info/RECORD +464 -0
  271. intentkit/models/generator.py +0 -347
  272. intentkit-0.8.16.dev1.dist-info/RECORD +0 -464
  273. {intentkit-0.8.16.dev1.dist-info → intentkit-0.8.17.dev2.dist-info}/WHEEL +0 -0
  274. {intentkit-0.8.16.dev1.dist-info → intentkit-0.8.17.dev2.dist-info}/licenses/LICENSE +0 -0
@@ -1,138 +1,138 @@
1
- """
2
- This module encapsulates all interactions with the Venice AI API.
3
- It provides a function, make_venice_api_request, to make POST requests
4
- to the API and handles the responses, including error handling,
5
- content type checking, and image storage via S3. This separation
6
- of concerns keeps the core skill logic cleaner and easier to maintain.
7
- """
8
-
9
- import hashlib
10
- import logging
11
- from typing import Any, Dict, Optional, Tuple
12
-
13
- import httpx
14
-
15
- from intentkit.utils.s3 import store_image_bytes
16
-
17
- logger = logging.getLogger(__name__)
18
-
19
-
20
- async def make_venice_api_request(
21
- api_key: str,
22
- path: str,
23
- payload: Dict[str, Any],
24
- category: str,
25
- tool_name: str,
26
- ) -> Tuple[Dict[str, Any], Optional[Dict[str, Any]]]:
27
- """
28
- Makes a POST request to the Venice AI API, handling all aspects
29
- of the API interaction. This includes:
30
-
31
- 1. Constructing the API URL using a base URL and the provided path.
32
- 2. Adding the required authorization header with the provided API key.
33
- 3. Sending the POST request with the given payload.
34
- 4. Handling potential connection and HTTP errors.
35
- 5. Calling the internal _handle_response function to process the API's
36
- response, which might be JSON or an image.
37
-
38
- Args:
39
- api_key: The Venice AI API key for authentication.
40
- path: The API endpoint path (e.g., "/api/v1/image/generate"). Should *not* start with the base URL.
41
- payload: The data to send in the request body (as JSON).
42
- category: The category of the skill making the request (e.g., "venice_image"). Used for S3 storage and logging purpose.
43
- tool_name: The name of the tool or skill making the request (e.g., "image_generation"). Used for S3 storage and logging purpose.
44
-
45
- Returns:
46
- A tuple: (success_data, error_data).
47
- - success_data: A dictionary containing the parsed JSON response from the API if the request was successful
48
- (or a dictionary containing the S3 URL if the response is an image).
49
- - error_data: A dictionary containing information about any errors that occurred,
50
- or None if the request was successful. The dictionary includes an 'error' key.
51
- """
52
-
53
- venice_base_url = "https://api.venice.ai" # Venice AI API base URL
54
-
55
- if not path.startswith("/"):
56
- path = "/" + path
57
-
58
- api_url = f"{venice_base_url}{path}"
59
-
60
- headers = {
61
- "Authorization": f"Bearer {api_key}",
62
- "Content-Type": "application/json",
63
- "Accept": "image/*, application/json",
64
- }
65
-
66
- logger.info(
67
- f"[{category}/{tool_name}] Sending request to {api_url} with payload: {payload}"
68
- )
69
-
70
- try:
71
- async with httpx.AsyncClient(timeout=180.0) as client:
72
- response = await client.post(api_url, json=payload, headers=headers)
73
- return await _handle_response(response, category, tool_name)
74
-
75
- except httpx.RequestError as e:
76
- error_msg = f"Connection error: {e}"
77
- logger.error(f"[{category}/{tool_name}] {error_msg}")
78
- return {}, {"success": False, "error": error_msg}
79
- except Exception as e:
80
- error_msg = f"Unexpected error: {e}"
81
- logger.error(f"[{category}/{tool_name}] {error_msg}", exc_info=True)
82
- return {}, {"success": False, "error": error_msg}
83
-
84
-
85
- async def _handle_response(
86
- response: httpx.Response, category: str, tool_name: str
87
- ) -> Tuple[Dict[str, Any], Optional[Dict[str, Any]]]:
88
- """
89
- Handles the API response, differentiating between JSON and image responses.
90
-
91
- If the response is an image (based on the 'content-type' header),
92
- it stores the image in S3 and returns the S3 URL.
93
- If the response is JSON, it parses the JSON and returns it.
94
- If any errors occur, it returns an error dictionary.
95
- """
96
-
97
- content_type = str(response.headers.get("content-type", "")).lower()
98
-
99
- if response.status_code == 200 and content_type.startswith("image/"):
100
- try:
101
- upscaled_image_bytes = response.content
102
- image_hash = hashlib.sha256(upscaled_image_bytes).hexdigest()
103
- file_extension = content_type.split("/")[-1].split("+")[0] or "png"
104
-
105
- key = f"{category}/{tool_name}/{image_hash}.{file_extension}"
106
-
107
- logger.info(f"[{category}/{tool_name}] Storing image with key: {key}")
108
-
109
- stored_url = await store_image_bytes(
110
- upscaled_image_bytes, key, content_type=content_type
111
- )
112
-
113
- return {"success": True, "result": stored_url}, None
114
-
115
- except Exception as e:
116
- error_msg = f"Error processing image response: {e}"
117
- logger.error(f"[{category}/{tool_name}] {error_msg}", exc_info=True)
118
- return {}, {"success": False, "error": error_msg}
119
-
120
- elif response.status_code == 200:
121
- try:
122
- logger.info(f"[{category}/{tool_name}] Received successful JSON response.")
123
- return response.json(), None
124
- except Exception as json_err:
125
- error_msg = f"Failed to parse JSON response: {json_err} - {response.text}"
126
- logger.error(f"[{category}/{tool_name}] {error_msg}")
127
- return {}, {"success": False, "error": error_msg}
128
-
129
- else:
130
- try:
131
- error_data = response.json()
132
- error_msg = f"API returned error: {error_data.get('message', error_data.get('detail', response.text))}"
133
- logger.error(f"[{category}/{tool_name}] {error_msg}")
134
- return {}, {"success": False, "error": error_msg}
135
- except Exception:
136
- error_msg = f"API returned status code {response.status_code} with text: {response.text}"
137
- logger.error(f"[{category}/{tool_name}] {error_msg}")
138
- return {}, {"success": False, "error": error_msg}
1
+ """
2
+ This module encapsulates all interactions with the Venice AI API.
3
+ It provides a function, make_venice_api_request, to make POST requests
4
+ to the API and handles the responses, including error handling,
5
+ content type checking, and image storage via S3. This separation
6
+ of concerns keeps the core skill logic cleaner and easier to maintain.
7
+ """
8
+
9
+ import hashlib
10
+ import logging
11
+ from typing import Any
12
+
13
+ import httpx
14
+
15
+ from intentkit.utils.s3 import store_image_bytes
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+
20
+ async def make_venice_api_request(
21
+ api_key: str,
22
+ path: str,
23
+ payload: dict[str, Any],
24
+ category: str,
25
+ tool_name: str,
26
+ ) -> tuple[dict[str, Any], dict[str, Any] | None]:
27
+ """
28
+ Makes a POST request to the Venice AI API, handling all aspects
29
+ of the API interaction. This includes:
30
+
31
+ 1. Constructing the API URL using a base URL and the provided path.
32
+ 2. Adding the required authorization header with the provided API key.
33
+ 3. Sending the POST request with the given payload.
34
+ 4. Handling potential connection and HTTP errors.
35
+ 5. Calling the internal _handle_response function to process the API's
36
+ response, which might be JSON or an image.
37
+
38
+ Args:
39
+ api_key: The Venice AI API key for authentication.
40
+ path: The API endpoint path (e.g., "/api/v1/image/generate"). Should *not* start with the base URL.
41
+ payload: The data to send in the request body (as JSON).
42
+ category: The category of the skill making the request (e.g., "venice_image"). Used for S3 storage and logging purpose.
43
+ tool_name: The name of the tool or skill making the request (e.g., "image_generation"). Used for S3 storage and logging purpose.
44
+
45
+ Returns:
46
+ A tuple: (success_data, error_data).
47
+ - success_data: A dictionary containing the parsed JSON response from the API if the request was successful
48
+ (or a dictionary containing the S3 URL if the response is an image).
49
+ - error_data: A dictionary containing information about any errors that occurred,
50
+ or None if the request was successful. The dictionary includes an 'error' key.
51
+ """
52
+
53
+ venice_base_url = "https://api.venice.ai" # Venice AI API base URL
54
+
55
+ if not path.startswith("/"):
56
+ path = "/" + path
57
+
58
+ api_url = f"{venice_base_url}{path}"
59
+
60
+ headers = {
61
+ "Authorization": f"Bearer {api_key}",
62
+ "Content-Type": "application/json",
63
+ "Accept": "image/*, application/json",
64
+ }
65
+
66
+ logger.info(
67
+ f"[{category}/{tool_name}] Sending request to {api_url} with payload: {payload}"
68
+ )
69
+
70
+ try:
71
+ async with httpx.AsyncClient(timeout=180.0) as client:
72
+ response = await client.post(api_url, json=payload, headers=headers)
73
+ return await _handle_response(response, category, tool_name)
74
+
75
+ except httpx.RequestError as e:
76
+ error_msg = f"Connection error: {e}"
77
+ logger.error(f"[{category}/{tool_name}] {error_msg}")
78
+ return {}, {"success": False, "error": error_msg}
79
+ except Exception as e:
80
+ error_msg = f"Unexpected error: {e}"
81
+ logger.error(f"[{category}/{tool_name}] {error_msg}", exc_info=True)
82
+ return {}, {"success": False, "error": error_msg}
83
+
84
+
85
+ async def _handle_response(
86
+ response: httpx.Response, category: str, tool_name: str
87
+ ) -> tuple[dict[str, Any], dict[str, Any] | None]:
88
+ """
89
+ Handles the API response, differentiating between JSON and image responses.
90
+
91
+ If the response is an image (based on the 'content-type' header),
92
+ it stores the image in S3 and returns the S3 URL.
93
+ If the response is JSON, it parses the JSON and returns it.
94
+ If any errors occur, it returns an error dictionary.
95
+ """
96
+
97
+ content_type = str(response.headers.get("content-type", "")).lower()
98
+
99
+ if response.status_code == 200 and content_type.startswith("image/"):
100
+ try:
101
+ upscaled_image_bytes = response.content
102
+ image_hash = hashlib.sha256(upscaled_image_bytes).hexdigest()
103
+ file_extension = content_type.split("/")[-1].split("+")[0] or "png"
104
+
105
+ key = f"{category}/{tool_name}/{image_hash}.{file_extension}"
106
+
107
+ logger.info(f"[{category}/{tool_name}] Storing image with key: {key}")
108
+
109
+ stored_url = await store_image_bytes(
110
+ upscaled_image_bytes, key, content_type=content_type
111
+ )
112
+
113
+ return {"success": True, "result": stored_url}, None
114
+
115
+ except Exception as e:
116
+ error_msg = f"Error processing image response: {e}"
117
+ logger.error(f"[{category}/{tool_name}] {error_msg}", exc_info=True)
118
+ return {}, {"success": False, "error": error_msg}
119
+
120
+ elif response.status_code == 200:
121
+ try:
122
+ logger.info(f"[{category}/{tool_name}] Received successful JSON response.")
123
+ return response.json(), None
124
+ except Exception as json_err:
125
+ error_msg = f"Failed to parse JSON response: {json_err} - {response.text}"
126
+ logger.error(f"[{category}/{tool_name}] {error_msg}")
127
+ return {}, {"success": False, "error": error_msg}
128
+
129
+ else:
130
+ try:
131
+ error_data = response.json()
132
+ error_msg = f"API returned error: {error_data.get('message', error_data.get('detail', response.text))}"
133
+ logger.error(f"[{category}/{tool_name}] {error_msg}")
134
+ return {}, {"success": False, "error": error_msg}
135
+ except Exception:
136
+ error_msg = f"API returned status code {response.status_code} with text: {response.text}"
137
+ logger.error(f"[{category}/{tool_name}] {error_msg}")
138
+ return {}, {"success": False, "error": error_msg}
@@ -1,5 +1,5 @@
1
1
  import logging
2
- from typing import Any, Dict, Optional, Tuple
2
+ from typing import Any
3
3
 
4
4
  from langchain_core.tools.base import ToolException
5
5
 
@@ -155,8 +155,8 @@ class VeniceImageBaseTool(IntentKitSkill):
155
155
  raise ToolException(f"Failed to apply Venice rate limit: {str(e)}") from e
156
156
 
157
157
  async def post(
158
- self, path: str, payload: Dict[str, Any], context
159
- ) -> Tuple[Dict[str, Any], Optional[Dict[str, Any]]]:
158
+ self, path: str, payload: dict[str, Any], context
159
+ ) -> tuple[dict[str, Any], dict[str, Any] | None]:
160
160
  """
161
161
  Makes a POST request to the Venice AI API using the `make_venice_api_request`
162
162
  function from the `skills.venice_image.api` module.
@@ -1,35 +1,33 @@
1
- from typing import Optional
2
-
3
- from pydantic import BaseModel, Field
4
-
5
-
6
- class VeniceImageConfig(BaseModel):
7
- """Skill Config for Venice Image."""
8
-
9
- api_key_provider: str = Field(
10
- default="agent_owner",
11
- description="Provider of the API Key, could be agent_owner or platform",
12
- )
13
- safe_mode: bool = Field(
14
- default=True,
15
- description="Whether to use safe mode. If enabled, this will blur images that are classified as having adult content",
16
- )
17
- hide_watermark: bool = Field(
18
- default=True,
19
- description="Whether to hide the Venice watermark. Venice may ignore this parameter for certain generated content.",
20
- )
21
- embed_exif_metadata: bool = Field(
22
- default=False, description="Whether to embed EXIF metadata in the image."
23
- )
24
- negative_prompt: str = Field(
25
- default="(worst quality: 1.4), bad quality, nsfw",
26
- description="The default negative prompt used when no other prompt is provided.",
27
- )
28
- rate_limit_number: Optional[int] = Field(
29
- default=None,
30
- description="Maximum number of allowed calls within the specified time window.",
31
- )
32
- rate_limit_minutes: Optional[int] = Field(
33
- default=None,
34
- description="Duration of the time window (in minutes) for rate limiting.",
35
- )
1
+ from pydantic import BaseModel, Field
2
+
3
+
4
+ class VeniceImageConfig(BaseModel):
5
+ """Skill Config for Venice Image."""
6
+
7
+ api_key_provider: str = Field(
8
+ default="agent_owner",
9
+ description="Provider of the API Key, could be agent_owner or platform",
10
+ )
11
+ safe_mode: bool = Field(
12
+ default=True,
13
+ description="Whether to use safe mode. If enabled, this will blur images that are classified as having adult content",
14
+ )
15
+ hide_watermark: bool = Field(
16
+ default=True,
17
+ description="Whether to hide the Venice watermark. Venice may ignore this parameter for certain generated content.",
18
+ )
19
+ embed_exif_metadata: bool = Field(
20
+ default=False, description="Whether to embed EXIF metadata in the image."
21
+ )
22
+ negative_prompt: str = Field(
23
+ default="(worst quality: 1.4), bad quality, nsfw",
24
+ description="The default negative prompt used when no other prompt is provided.",
25
+ )
26
+ rate_limit_number: int | None = Field(
27
+ default=None,
28
+ description="Maximum number of allowed calls within the specified time window.",
29
+ )
30
+ rate_limit_minutes: int | None = Field(
31
+ default=None,
32
+ description="Duration of the time window (in minutes) for rate limiting.",
33
+ )
@@ -1,5 +1,4 @@
1
1
  import logging
2
- from typing import Optional
3
2
 
4
3
  from pydantic import HttpUrl
5
4
 
@@ -30,8 +29,8 @@ class ImageEnhance(VeniceImageEnhanceBaseTool):
30
29
  self,
31
30
  image_url: HttpUrl,
32
31
  enhancePrompt: str,
33
- replication: Optional[float] = 0.35,
34
- enhanceCreativity: Optional[float] = 0.5,
32
+ replication: float | None = 0.35,
33
+ enhanceCreativity: float | None = 0.5,
35
34
  **kwargs,
36
35
  ) -> dict:
37
36
  """
@@ -1,23 +1,21 @@
1
- from typing import Type
2
-
3
- from pydantic import BaseModel, Field
4
-
5
- # Import the generic base and shared input
6
- from intentkit.skills.venice_image.base import VeniceImageBaseTool
7
- from intentkit.skills.venice_image.image_enhance.image_enhance_input import (
8
- VeniceImageEnhanceInput,
9
- )
10
-
11
-
12
- class VeniceImageEnhanceBaseTool(VeniceImageBaseTool):
13
- """
14
- Base class for Venice AI *Image Enchanching* tools.
15
- Inherits from VeniceAIBaseTool and handles specifics of the
16
- /image/upscale endpoint
17
- """
18
-
19
- args_schema: Type[BaseModel] = VeniceImageEnhanceInput
20
- name: str = Field(description="The unique name of the image Enchanching tool.")
21
- description: str = Field(
22
- description="A description of what the image Enchanching tool does."
23
- )
1
+ from pydantic import BaseModel, Field
2
+
3
+ # Import the generic base and shared input
4
+ from intentkit.skills.venice_image.base import VeniceImageBaseTool
5
+ from intentkit.skills.venice_image.image_enhance.image_enhance_input import (
6
+ VeniceImageEnhanceInput,
7
+ )
8
+
9
+
10
+ class VeniceImageEnhanceBaseTool(VeniceImageBaseTool):
11
+ """
12
+ Base class for Venice AI *Image Enchanching* tools.
13
+ Inherits from VeniceAIBaseTool and handles specifics of the
14
+ /image/upscale endpoint
15
+ """
16
+
17
+ args_schema: type[BaseModel] = VeniceImageEnhanceInput
18
+ name: str = Field(description="The unique name of the image Enchanching tool.")
19
+ description: str = Field(
20
+ description="A description of what the image Enchanching tool does."
21
+ )
@@ -1,40 +1,38 @@
1
- from typing import Optional
2
-
3
- from pydantic import BaseModel, Field
4
-
5
-
6
- class VeniceImageEnhanceInput(BaseModel):
7
- """Input for Venice Image Enhance tool (scale=1, enhance=True)."""
8
-
9
- image_url: str = Field(
10
- description="The URL of the image to enhance. Must be a publicly accessible URL."
11
- )
12
-
13
- enhancePrompt: str = Field(
14
- ...,
15
- max_length=1500,
16
- description=(
17
- "Required prompt describing the desired enhancement style. "
18
- "Best used with short descriptors like 'gold', 'marble', or 'angry, menacing'."
19
- ),
20
- )
21
-
22
- replication: Optional[float] = Field(
23
- default=0.35,
24
- ge=0.1,
25
- le=1.0,
26
- description=(
27
- "How strongly lines and noise in the base image are preserved. "
28
- "Higher values retain more noise and detail but are less smooth."
29
- ),
30
- )
31
-
32
- enhanceCreativity: float = Field(
33
- default=0.5,
34
- ge=0.0,
35
- le=1.0,
36
- description=(
37
- "How much the enhancement AI is allowed to change the image. "
38
- "0 = minimal change, 1 = generate a new image entirely."
39
- ),
40
- )
1
+ from pydantic import BaseModel, Field
2
+
3
+
4
+ class VeniceImageEnhanceInput(BaseModel):
5
+ """Input for Venice Image Enhance tool (scale=1, enhance=True)."""
6
+
7
+ image_url: str = Field(
8
+ description="The URL of the image to enhance. Must be a publicly accessible URL."
9
+ )
10
+
11
+ enhancePrompt: str = Field(
12
+ ...,
13
+ max_length=1500,
14
+ description=(
15
+ "Required prompt describing the desired enhancement style. "
16
+ "Best used with short descriptors like 'gold', 'marble', or 'angry, menacing'."
17
+ ),
18
+ )
19
+
20
+ replication: float | None = Field(
21
+ default=0.35,
22
+ ge=0.1,
23
+ le=1.0,
24
+ description=(
25
+ "How strongly lines and noise in the base image are preserved. "
26
+ "Higher values retain more noise and detail but are less smooth."
27
+ ),
28
+ )
29
+
30
+ enhanceCreativity: float = Field(
31
+ default=0.5,
32
+ ge=0.0,
33
+ le=1.0,
34
+ description=(
35
+ "How much the enhancement AI is allowed to change the image. "
36
+ "0 = minimal change, 1 = generate a new image entirely."
37
+ ),
38
+ )
@@ -1,7 +1,7 @@
1
1
  import base64
2
2
  import hashlib
3
3
  import logging
4
- from typing import Any, Dict, Literal, Optional, Type
4
+ from typing import Any, Literal
5
5
 
6
6
  from pydantic import BaseModel, Field
7
7
 
@@ -24,7 +24,7 @@ class VeniceImageGenerationBaseTool(VeniceImageBaseTool):
24
24
  """
25
25
 
26
26
  # --- Attributes specific to Image Generation ---
27
- args_schema: Type[BaseModel] = VeniceImageGenerationInput
27
+ args_schema: type[BaseModel] = VeniceImageGenerationInput
28
28
 
29
29
  # --- Attributes Subclasses MUST Define ---
30
30
  name: str = Field(description="The unique name of the image generation tool/model.")
@@ -38,15 +38,15 @@ class VeniceImageGenerationBaseTool(VeniceImageBaseTool):
38
38
  async def _arun(
39
39
  self,
40
40
  prompt: str,
41
- seed: Optional[int] = None,
42
- negative_prompt: Optional[str] = None,
43
- width: Optional[int] = 1024,
44
- height: Optional[int] = 1024,
41
+ seed: int | None = None,
42
+ negative_prompt: str | None = None,
43
+ width: int | None = 1024,
44
+ height: int | None = 1024,
45
45
  format: Literal["png", "jpeg", "webp"] = "png",
46
- cfg_scale: Optional[float] = 7.5,
47
- style_preset: Optional[str] = "Photographic",
46
+ cfg_scale: float | None = 7.5,
47
+ style_preset: str | None = "Photographic",
48
48
  **kwargs,
49
- ) -> Dict[str, Any]:
49
+ ) -> dict[str, Any]:
50
50
  try:
51
51
  context = self.get_context()
52
52
  skillConfig = self.getSkillConfig(context)
@@ -1,26 +1,26 @@
1
- from intentkit.skills.venice_image.image_generation.image_generation_base import (
2
- VeniceImageGenerationBaseTool,
3
- )
4
- from intentkit.skills.venice_image.image_generation.image_generation_input import (
5
- STYLE_PRESETS,
6
- )
7
-
8
-
9
- class ImageGenerationFluentlyXL(VeniceImageGenerationBaseTool):
10
- """
11
- Tool for generating images using the Fluently-XL model via Venice AI.
12
- Known for aesthetics, lighting, realism, and correct anatomy.
13
- """
14
-
15
- # --- Model Specific Configuration ---
16
- name: str = "venice_image_generation_fluently_xl"
17
- description: str = (
18
- "Generate images using the Fluently-XL model (via Venice AI).\n"
19
- "Aims for improved aesthetics, lighting, realism, and anatomy. Good for professional-quality images.\n"
20
- "Provide a text prompt describing the image (up to 1500 chars).\n"
21
- f"Optionally specify a style preset from the list: {', '.join(STYLE_PRESETS)}.\n"
22
- "Supports dimensions up to 2048x2048 (multiple of 8)."
23
- )
24
- model_id: str = "fluently-xl"
25
-
26
- # args_schema and _arun are inherited from VeniceImageGenerationBaseTool
1
+ from intentkit.skills.venice_image.image_generation.image_generation_base import (
2
+ VeniceImageGenerationBaseTool,
3
+ )
4
+ from intentkit.skills.venice_image.image_generation.image_generation_input import (
5
+ STYLE_PRESETS,
6
+ )
7
+
8
+
9
+ class ImageGenerationFluentlyXL(VeniceImageGenerationBaseTool):
10
+ """
11
+ Tool for generating images using the Fluently-XL model via Venice AI.
12
+ Known for aesthetics, lighting, realism, and correct anatomy.
13
+ """
14
+
15
+ # --- Model Specific Configuration ---
16
+ name: str = "venice_image_generation_fluently_xl"
17
+ description: str = (
18
+ "Generate images using the Fluently-XL model (via Venice AI).\n"
19
+ "Aims for improved aesthetics, lighting, realism, and anatomy. Good for professional-quality images.\n"
20
+ "Provide a text prompt describing the image (up to 1500 chars).\n"
21
+ f"Optionally specify a style preset from the list: {', '.join(STYLE_PRESETS)}.\n"
22
+ "Supports dimensions up to 2048x2048 (multiple of 8)."
23
+ )
24
+ model_id: str = "fluently-xl"
25
+
26
+ # args_schema and _arun are inherited from VeniceImageGenerationBaseTool