mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
feat(tools): added reddit hot subreddit posts tool/block
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
import { RedditIcon } from '@/components/icons'
|
||||
import { RedditHotPostsResponse } from '@/tools/reddit/types'
|
||||
import { BlockConfig } from '../types'
|
||||
|
||||
export const RedditBlock: BlockConfig<RedditHotPostsResponse> = {
|
||||
type: 'reddit',
|
||||
name: 'Reddit',
|
||||
description: 'Fetch popular posts from Reddit',
|
||||
longDescription:
|
||||
'Access Reddit data to retrieve the most popular (hot) posts from any subreddit. Get post titles, content, authors, scores, and more.',
|
||||
category: 'tools',
|
||||
bgColor: '#FF5700',
|
||||
icon: RedditIcon,
|
||||
subBlocks: [
|
||||
// Subreddit input
|
||||
{
|
||||
id: 'subreddit',
|
||||
title: 'Subreddit',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: 'Enter subreddit name (without r/)',
|
||||
},
|
||||
// Limit input
|
||||
{
|
||||
id: 'limit',
|
||||
title: 'Number of Posts',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: '10',
|
||||
},
|
||||
],
|
||||
tools: {
|
||||
access: ['reddit_hot_posts'],
|
||||
config: {
|
||||
tool: () => 'reddit_hot_posts',
|
||||
},
|
||||
},
|
||||
inputs: {
|
||||
subreddit: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'The name of the subreddit to fetch posts from (without the r/ prefix)',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
description: 'Maximum number of posts to return (default: 10, max: 100)',
|
||||
},
|
||||
},
|
||||
outputs: {
|
||||
response: {
|
||||
type: {
|
||||
subreddit: 'string',
|
||||
posts: 'json',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import { JinaBlock } from './blocks/jina'
|
||||
import { NotionBlock } from './blocks/notion'
|
||||
import { OpenAIBlock } from './blocks/openai'
|
||||
import { PineconeBlock } from './blocks/pinecone'
|
||||
import { RedditBlock } from './blocks/reddit'
|
||||
import { RouterBlock } from './blocks/router'
|
||||
import { SerperBlock } from './blocks/serper'
|
||||
import { SlackBlock } from './blocks/slack'
|
||||
@@ -47,6 +48,7 @@ export {
|
||||
PineconeBlock,
|
||||
OpenAIBlock,
|
||||
ExaBlock,
|
||||
RedditBlock,
|
||||
}
|
||||
|
||||
// Registry of all block configurations, alphabetically sorted
|
||||
@@ -65,6 +67,7 @@ const blocks: Record<string, BlockConfig> = {
|
||||
notion: NotionBlock,
|
||||
openai: OpenAIBlock,
|
||||
pinecone: PineconeBlock,
|
||||
reddit: RedditBlock,
|
||||
router: RouterBlock,
|
||||
serper: SerperBlock,
|
||||
slack: SlackBlock,
|
||||
|
||||
@@ -1445,3 +1445,22 @@ export function ExaAIIcon(props: SVGProps<SVGSVGElement>) {
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function RedditIcon(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg
|
||||
{...props}
|
||||
width="100px"
|
||||
height="100px"
|
||||
viewBox="0 0 50 50"
|
||||
fill="#FFFFFF"
|
||||
role="img"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M 29 3 C 26.894531 3 24.433594 4.652344 24.0625 12.03125 C 24.375 12.023438 24.683594 12 25 12 C 25.351563 12 25.714844 12.019531 26.0625 12.03125 C 26.300781 7.597656 27.355469 5 29 5 C 29.703125 5 30.101563 5.382813 30.84375 6.1875 C 31.710938 7.128906 32.84375 8.351563 35.0625 8.8125 C 35.027344 8.550781 35 8.269531 35 8 C 35 7.578125 35.042969 7.179688 35.125 6.78125 C 33.75 6.40625 33.023438 5.613281 32.3125 4.84375 C 31.519531 3.984375 30.609375 3 29 3 Z M 41 4 C 38.792969 4 37 5.796875 37 8 C 37 10.203125 38.792969 12 41 12 C 43.207031 12 45 10.203125 45 8 C 45 5.796875 43.207031 4 41 4 Z M 25 14 C 12.867188 14 3 20.179688 3 29 C 3 37.820313 12.867188 45 25 45 C 37.132813 45 47 37.820313 47 29 C 47 20.179688 37.132813 14 25 14 Z M 7.5 14.9375 C 6.039063 14.9375 4.652344 15.535156 3.59375 16.59375 C 1.871094 18.316406 1.515625 20.792969 2.5 22.84375 C 4.011719 19.917969 6.613281 17.421875 9.96875 15.5625 C 9.207031 15.175781 8.363281 14.9375 7.5 14.9375 Z M 42.5 14.9375 C 41.636719 14.9375 40.792969 15.175781 40.03125 15.5625 C 43.386719 17.421875 45.988281 19.917969 47.5 22.84375 C 48.484375 20.792969 48.128906 18.316406 46.40625 16.59375 C 45.347656 15.535156 43.960938 14.9375 42.5 14.9375 Z M 17 23 C 18.65625 23 20 24.34375 20 26 C 20 27.65625 18.65625 29 17 29 C 15.34375 29 14 27.65625 14 26 C 14 24.34375 15.34375 23 17 23 Z M 33 23 C 34.65625 23 36 24.34375 36 26 C 36 27.65625 34.65625 29 33 29 C 31.34375 29 30 27.65625 30 26 C 30 24.34375 31.34375 23 33 23 Z M 16.0625 34 C 16.3125 34.042969 16.558594 34.183594 16.71875 34.40625 C 16.824219 34.554688 19.167969 37.6875 25 37.6875 C 30.910156 37.6875 33.257813 34.46875 33.28125 34.4375 C 33.597656 33.988281 34.234375 33.867188 34.6875 34.1875 C 35.136719 34.503906 35.222656 35.109375 34.90625 35.5625 C 34.789063 35.730469 31.9375 39.6875 25 39.6875 C 18.058594 39.6875 15.210938 35.730469 15.09375 35.5625 C 14.777344 35.109375 14.859375 34.503906 15.3125 34.1875 C 15.539063 34.027344 15.8125 33.957031 16.0625 34 Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import { generateEmbeddingsTool as pineconeGenerateEmbeddingsTool } from './pine
|
||||
import { searchTextTool as pineconeSearchTextTool } from './pinecone/searchText'
|
||||
import { searchVectorTool as pineconeSearchVectorTool } from './pinecone/searchVector'
|
||||
import { upsertTextTool as pineconeUpsertTextTool } from './pinecone/upsertText'
|
||||
import { hotPostsTool as redditHotPosts } from './reddit/hot'
|
||||
import { opportunitiesTool as salesforceOpportunities } from './salesforce/opportunities'
|
||||
import { searchTool as serperSearch } from './serper/search'
|
||||
import { slackMessageTool } from './slack/message'
|
||||
@@ -75,6 +76,7 @@ export const tools: Record<string, ToolConfig> = {
|
||||
exa_get_contents: exaGetContents,
|
||||
exa_find_similar_links: exaFindSimilarLinks,
|
||||
exa_answer: exaAnswer,
|
||||
reddit_hot_posts: redditHotPosts,
|
||||
}
|
||||
|
||||
// Get a tool by its ID
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
import { ToolConfig, ToolResponse } from '../types'
|
||||
import { RedditHotPostsResponse, RedditPost } from './types'
|
||||
|
||||
interface HotPostsParams {
|
||||
subreddit: string
|
||||
limit?: number
|
||||
}
|
||||
|
||||
export const hotPostsTool: ToolConfig<HotPostsParams, RedditHotPostsResponse> = {
|
||||
id: 'reddit_hot_posts',
|
||||
name: 'Reddit Hot Posts',
|
||||
description: 'Fetch the most popular (hot) posts from a specified subreddit.',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
subreddit: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'The name of the subreddit to fetch posts from (without the r/ prefix)',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
description: 'Maximum number of posts to return (default: 10, max: 100)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) =>
|
||||
`https://www.reddit.com/r/${params.subreddit}/hot.json?limit=${params.limit || 10}`,
|
||||
method: 'GET',
|
||||
headers: () => ({
|
||||
'User-Agent': 'SimStudio/1.0.0',
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data.message || 'Failed to fetch Reddit posts')
|
||||
}
|
||||
|
||||
if (data.error) {
|
||||
throw new Error(data.message || 'Reddit API error')
|
||||
}
|
||||
|
||||
const posts: RedditPost[] = data.data.children.map((child: any) => {
|
||||
const post = child.data
|
||||
return {
|
||||
id: post.id,
|
||||
title: post.title,
|
||||
author: post.author,
|
||||
url: post.url,
|
||||
permalink: `https://www.reddit.com${post.permalink}`,
|
||||
created_utc: post.created_utc,
|
||||
score: post.score,
|
||||
num_comments: post.num_comments,
|
||||
selftext: post.selftext,
|
||||
thumbnail:
|
||||
post.thumbnail !== 'self' && post.thumbnail !== 'default' ? post.thumbnail : undefined,
|
||||
is_self: post.is_self,
|
||||
subreddit: post.subreddit,
|
||||
subreddit_name_prefixed: post.subreddit_name_prefixed,
|
||||
}
|
||||
})
|
||||
|
||||
// Extract the subreddit name from the response data
|
||||
const subreddit =
|
||||
data.data?.children?.[0]?.data?.subreddit || (posts.length > 0 ? posts[0].subreddit : '')
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
subreddit,
|
||||
posts,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
transformError: (error) => {
|
||||
return error instanceof Error ? error.message : 'An error occurred while fetching Reddit posts'
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import { ToolResponse } from '../types'
|
||||
|
||||
export interface RedditPost {
|
||||
id: string
|
||||
title: string
|
||||
author: string
|
||||
url: string
|
||||
permalink: string
|
||||
created_utc: number
|
||||
score: number
|
||||
num_comments: number
|
||||
selftext?: string
|
||||
thumbnail?: string
|
||||
is_self: boolean
|
||||
subreddit: string
|
||||
subreddit_name_prefixed: string
|
||||
}
|
||||
|
||||
export interface RedditHotPostsResponse extends ToolResponse {
|
||||
output: {
|
||||
subreddit: string
|
||||
posts: RedditPost[]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user