-
Notifications
You must be signed in to change notification settings - Fork 4.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1964 from Lukapetro/feature/add-client-instagram
feat: add instagram client
- Loading branch information
Showing
19 changed files
with
1,667 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
# @elizaos/client-instagram | ||
|
||
An Instagram client implementation for ElizaOS, enabling Instagram integration with support for media posting, comment handling, and interaction management. | ||
|
||
## Features | ||
|
||
- Instagram API integration using instagram-private-api | ||
- Media post creation and scheduling | ||
- Comment and interaction handling | ||
- Profile management | ||
- Media processing utilities | ||
- Rate limiting and request queuing | ||
- Session management and caching | ||
|
||
## Installation | ||
|
||
As this is a workspace package, it's installed as part of the ElizaOS monorepo: | ||
|
||
```bash | ||
pnpm install | ||
``` | ||
|
||
## Configuration | ||
|
||
The client requires the following environment variables: | ||
|
||
```bash | ||
# Instagram Credentials | ||
INSTAGRAM_USERNAME=your_username | ||
INSTAGRAM_PASSWORD=your_password | ||
INSTAGRAM_APP_ID=your_app_id | ||
INSTAGRAM_APP_SECRET=your_app_secret | ||
|
||
# Optional Business Account | ||
INSTAGRAM_BUSINESS_ACCOUNT_ID=your_business_account_id | ||
|
||
# Posting Configuration | ||
POST_INTERVAL_MIN=90 # Minimum interval between posts (minutes) | ||
POST_INTERVAL_MAX=180 # Maximum interval between posts (minutes) | ||
ENABLE_ACTION_PROCESSING=true | ||
ACTION_INTERVAL=5 # Minutes between action processing | ||
MAX_ACTIONS_PROCESSING=1 # Maximum actions to process per interval | ||
``` | ||
|
||
## Usage | ||
|
||
### Basic Initialization | ||
|
||
```typescript | ||
import { InstagramClientInterface } from '@elizaos/client-instagram'; | ||
|
||
// Initialize the client | ||
const instagramManager = await InstagramClientInterface.start(runtime); | ||
``` | ||
|
||
### Posting Content | ||
|
||
All posts on Instagram must include media (image, video, or carousel): | ||
|
||
```typescript | ||
// Post a single image | ||
await instagramManager.post.createPost({ | ||
media: [{ | ||
type: 'IMAGE', | ||
url: 'path/to/image.jpg' | ||
}], | ||
caption: 'Hello Instagram!' | ||
}); | ||
|
||
// Post a carousel | ||
await instagramManager.post.createPost({ | ||
media: [ | ||
{ type: 'IMAGE', url: 'path/to/image1.jpg' }, | ||
{ type: 'IMAGE', url: 'path/to/image2.jpg' } | ||
], | ||
caption: 'Check out these photos!' | ||
}); | ||
``` | ||
|
||
### Handling Interactions | ||
|
||
```typescript | ||
// Handle comments | ||
await instagramManager.interaction.handleComment({ | ||
mediaId: 'media-123', | ||
comment: 'Great post!', | ||
userId: 'user-123' | ||
}); | ||
|
||
// Like media | ||
await instagramManager.interaction.likeMedia('media-123'); | ||
``` | ||
|
||
## Key Components | ||
|
||
1. ClientBase | ||
- Handles authentication and session management | ||
- Manages API rate limiting | ||
- Provides core API functionality | ||
|
||
|
||
2. PostClient | ||
- Manages media uploads | ||
- Handles post scheduling | ||
- Processes media before upload | ||
|
||
|
||
3. InteractionClient | ||
- Handles comments and likes | ||
- Manages user interactions | ||
- Processes notifications | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
{ | ||
"name": "@elizaos/client-instagram", | ||
"version": "0.1.0", | ||
"type": "module", | ||
"main": "dist/index.js", | ||
"module": "dist/index.js", | ||
"types": "dist/index.d.ts", | ||
"exports": { | ||
"./package.json": "./package.json", | ||
".": { | ||
"import": { | ||
"@elizaos/source": "./src/index.ts", | ||
"types": "./dist/index.d.ts", | ||
"default": "./dist/index.js" | ||
} | ||
} | ||
}, | ||
"files": [ | ||
"dist" | ||
], | ||
"dependencies": { | ||
"@elizaos/core": "workspace:*", | ||
"zod": "3.23.8", | ||
"instagram-private-api": "^1.45.3", | ||
"sharp": "^0.33.2", | ||
"glob": "11.0.0" | ||
}, | ||
"devDependencies": { | ||
"tsup": "8.3.5", | ||
"@types/sharp": "^0.32.0" | ||
}, | ||
"scripts": { | ||
"build": "tsup --format esm --dts", | ||
"dev": "tsup --format esm --dts --watch", | ||
"lint": "eslint --fix --cache ." | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
import { | ||
IAgentRuntime, | ||
parseBooleanFromText, | ||
} from "@elizaos/core"; | ||
import { z } from "zod"; | ||
|
||
export const DEFAULT_POST_INTERVAL_MIN = 60; | ||
export const DEFAULT_POST_INTERVAL_MAX = 120; | ||
export const DEFAULT_ACTION_INTERVAL = 5; | ||
export const DEFAULT_MAX_ACTIONS = 1; | ||
|
||
// Define validation schemas for Instagram usernames and other fields | ||
const instagramUsernameSchema = z | ||
.string() | ||
.min(1, "An Instagram Username must be at least 1 character long") | ||
.max(30, "An Instagram Username cannot exceed 30 characters") | ||
.refine((username) => { | ||
// Instagram usernames can contain letters, numbers, periods, and underscores | ||
return /^[A-Za-z0-9._]+$/.test(username); | ||
}, "An Instagram Username can only contain letters, numbers, periods, and underscores"); | ||
|
||
/** | ||
* Environment configuration schema for Instagram client | ||
*/ | ||
export const instagramEnvSchema = z.object({ | ||
INSTAGRAM_DRY_RUN: z.boolean(), | ||
INSTAGRAM_USERNAME: instagramUsernameSchema, | ||
INSTAGRAM_PASSWORD: z.string().min(1, "Instagram password is required"), | ||
|
||
// Instagram API credentials | ||
INSTAGRAM_APP_ID: z.string().min(1, "Instagram App ID is required"), | ||
INSTAGRAM_APP_SECRET: z.string().min(1, "Instagram App Secret is required"), | ||
|
||
// Optional Business Account ID for additional features | ||
INSTAGRAM_BUSINESS_ACCOUNT_ID: z.string().optional(), | ||
|
||
// Posting configuration | ||
INSTAGRAM_POST_INTERVAL_MIN: z.number().int().default(DEFAULT_POST_INTERVAL_MIN), | ||
INSTAGRAM_POST_INTERVAL_MAX: z.number().int().default(DEFAULT_POST_INTERVAL_MAX), | ||
|
||
// Action processing configuration | ||
INSTAGRAM_ENABLE_ACTION_PROCESSING: z.boolean().default(false), | ||
INSTAGRAM_ACTION_INTERVAL: z.number().int().default(DEFAULT_ACTION_INTERVAL), | ||
INSTAGRAM_MAX_ACTIONS: z.number().int().default(DEFAULT_MAX_ACTIONS), | ||
}); | ||
|
||
export type InstagramConfig = z.infer<typeof instagramEnvSchema>; | ||
|
||
/** | ||
* Validates and constructs an InstagramConfig object using zod, | ||
* taking values from the IAgentRuntime or process.env as needed. | ||
*/ | ||
export async function validateInstagramConfig( | ||
runtime: IAgentRuntime | ||
): Promise<InstagramConfig> { | ||
try { | ||
const instagramConfig = { | ||
INSTAGRAM_DRY_RUN: parseBooleanFromText( | ||
runtime.getSetting("INSTAGRAM_DRY_RUN") || | ||
process.env.INSTAGRAM_DRY_RUN | ||
) ?? false, | ||
|
||
INSTAGRAM_USERNAME: runtime.getSetting("INSTAGRAM_USERNAME") || | ||
process.env.INSTAGRAM_USERNAME, | ||
|
||
INSTAGRAM_PASSWORD: runtime.getSetting("INSTAGRAM_PASSWORD") || | ||
process.env.INSTAGRAM_PASSWORD, | ||
|
||
INSTAGRAM_APP_ID: runtime.getSetting("INSTAGRAM_APP_ID") || | ||
process.env.INSTAGRAM_APP_ID, | ||
|
||
INSTAGRAM_APP_SECRET: runtime.getSetting("INSTAGRAM_APP_SECRET") || | ||
process.env.INSTAGRAM_APP_SECRET, | ||
|
||
INSTAGRAM_BUSINESS_ACCOUNT_ID: runtime.getSetting("INSTAGRAM_BUSINESS_ACCOUNT_ID") || | ||
process.env.INSTAGRAM_BUSINESS_ACCOUNT_ID, | ||
|
||
INSTAGRAM_POST_INTERVAL_MIN: parseInt( | ||
runtime.getSetting("INSTAGRAM_POST_INTERVAL_MIN") || | ||
process.env.INSTAGRAM_POST_INTERVAL_MIN || | ||
DEFAULT_POST_INTERVAL_MIN.toString(), | ||
10 | ||
), | ||
|
||
INSTAGRAM_POST_INTERVAL_MAX: parseInt( | ||
runtime.getSetting("INSTAGRAM_POST_INTERVAL_MAX") || | ||
process.env.INSTAGRAM_POST_INTERVAL_MAX || | ||
DEFAULT_POST_INTERVAL_MAX.toString(), | ||
10 | ||
), | ||
|
||
INSTAGRAM_ENABLE_ACTION_PROCESSING: parseBooleanFromText( | ||
runtime.getSetting("INSTAGRAM_ENABLE_ACTION_PROCESSING") || | ||
process.env.INSTAGRAM_ENABLE_ACTION_PROCESSING | ||
) ?? false, | ||
|
||
INSTAGRAM_ACTION_INTERVAL: parseInt( | ||
runtime.getSetting("INSTAGRAM_ACTION_INTERVAL") || | ||
process.env.INSTAGRAM_ACTION_INTERVAL || | ||
DEFAULT_ACTION_INTERVAL.toString(), | ||
10 | ||
), | ||
|
||
INSTAGRAM_MAX_ACTIONS: parseInt( | ||
runtime.getSetting("MAX_ACTIONS_PROCESSING") || | ||
process.env.MAX_ACTIONS_PROCESSING || | ||
DEFAULT_MAX_ACTIONS.toString(), | ||
10 | ||
), | ||
}; | ||
|
||
return instagramEnvSchema.parse(instagramConfig); | ||
} catch (error) { | ||
if (error instanceof z.ZodError) { | ||
const errorMessages = error.errors | ||
.map((err) => `${err.path.join(".")}: ${err.message}`) | ||
.join("\n"); | ||
throw new Error( | ||
`Instagram configuration validation failed:\n${errorMessages}` | ||
); | ||
} | ||
throw error; | ||
} | ||
} |
Oops, something went wrong.