Skip to content

Commit

Permalink
Merge pull request #1964 from Lukapetro/feature/add-client-instagram
Browse files Browse the repository at this point in the history
feat: add instagram client
  • Loading branch information
odilitime authored Jan 16, 2025
2 parents 7b13d77 + 3c09d90 commit fbb18ba
Show file tree
Hide file tree
Showing 19 changed files with 1,667 additions and 3 deletions.
13 changes: 13 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -602,3 +602,16 @@ AKASH_MANIFEST_VALIDATION_LEVEL=strict
# Quai Network Ecosystem
QUAI_PRIVATE_KEY=
QUAI_RPC_URL=https://rpc.quai.network

# Instagram Configuration
INSTAGRAM_DRY_RUN=false
INSTAGRAM_USERNAME= # Account username
INSTAGRAM_PASSWORD= # Account password
INSTAGRAM_APP_ID= # Instagram App ID is required
INSTAGRAM_APP_SECRET= # Instagram App Secret is required
INSTAGRAM_BUSINESS_ACCOUNT_ID= # Optional Business Account ID for additional features
INSTAGRAM_POST_INTERVAL_MIN=60 # Default: 60 minutes
INSTAGRAM_POST_INTERVAL_MAX=120 # Default: 120 minutes
INSTAGRAM_ENABLE_ACTION_PROCESSING=false # Enable/disable action processing
INSTAGRAM_ACTION_INTERVAL=5 # Interval between actions in minutes
INSTAGRAM_MAX_ACTIONS=1 # Maximum number of actions to process at once
1 change: 1 addition & 0 deletions agent/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"@elizaos/client-lens": "workspace:*",
"@elizaos/client-telegram": "workspace:*",
"@elizaos/client-twitter": "workspace:*",
"@elizaos/client-instagram": "workspace:*",
"@elizaos/client-slack": "workspace:*",
"@elizaos/core": "workspace:*",
"@elizaos/plugin-0g": "workspace:*",
Expand Down
14 changes: 11 additions & 3 deletions agent/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ import { SqliteDatabaseAdapter } from "@elizaos/adapter-sqlite";
import { SupabaseDatabaseAdapter } from "@elizaos/adapter-supabase";
import { AutoClientInterface } from "@elizaos/client-auto";
import { DiscordClientInterface } from "@elizaos/client-discord";
import { FarcasterClientInterface } from "@elizaos/client-farcaster";
import { InstagramClientInterface } from "@elizaos/client-instagram";
import { LensAgentClient } from "@elizaos/client-lens";
import { SlackClientInterface } from "@elizaos/client-slack";
import { TelegramClientInterface } from "@elizaos/client-telegram";
import { TwitterClientInterface } from "@elizaos/client-twitter";
import { FarcasterClientInterface } from "@elizaos/client-farcaster";
// import { ReclaimAdapter } from "@elizaos/plugin-reclaim";
import { PrimusAdapter } from "@elizaos/plugin-primus";

Expand All @@ -29,10 +30,10 @@ import {
IDatabaseAdapter,
IDatabaseCacheAdapter,
ModelProviderName,
parseBooleanFromText,
settings,
stringToUuid,
validateCharacterConfig,
parseBooleanFromText,
} from "@elizaos/core";
import { zgPlugin } from "@elizaos/plugin-0g";

Expand Down Expand Up @@ -87,6 +88,7 @@ import { quaiPlugin } from "@elizaos/plugin-quai";
import { sgxPlugin } from "@elizaos/plugin-sgx";
import { solanaPlugin } from "@elizaos/plugin-solana";
import { solanaAgentkitPlguin } from "@elizaos/plugin-solana-agentkit";
import { squidRouterPlugin } from "@elizaos/plugin-squid-router";
import { stargazePlugin } from "@elizaos/plugin-stargaze";
import { storyPlugin } from "@elizaos/plugin-story";
import { suiPlugin } from "@elizaos/plugin-sui";
Expand All @@ -96,7 +98,6 @@ import { teeMarlinPlugin } from "@elizaos/plugin-tee-marlin";
import { verifiableLogPlugin } from "@elizaos/plugin-tee-verifiable-log";
import { thirdwebPlugin } from "@elizaos/plugin-thirdweb";
import { tonPlugin } from "@elizaos/plugin-ton";
import { squidRouterPlugin } from "@elizaos/plugin-squid-router";
import { webSearchPlugin } from "@elizaos/plugin-web-search";
import { echoChambersPlugin } from "@elizaos/plugin-echochambers";
import { dexScreenerPlugin } from "@elizaos/plugin-dexscreener";
Expand Down Expand Up @@ -612,6 +613,13 @@ export async function initializeClients(
}
}

if (clientTypes.includes(Clients.INSTAGRAM)) {
const instagramClient = await InstagramClientInterface.start(runtime);
if (instagramClient) {
clients.instagram = instagramClient;
}
}

if (clientTypes.includes(Clients.FARCASTER)) {
const farcasterClient = await FarcasterClientInterface.start(runtime);
if (farcasterClient) {
Expand Down
113 changes: 113 additions & 0 deletions packages/client-instagram/README.md
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


37 changes: 37 additions & 0 deletions packages/client-instagram/package.json
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 ."
}
}
124 changes: 124 additions & 0 deletions packages/client-instagram/src/environment.ts
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;
}
}
Loading

0 comments on commit fbb18ba

Please sign in to comment.