Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/contributors/bugfix/Gordey007/01_imports/errors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
1. Pillow import error
<br> [01_import.mp4](source/video/01_import.mp4)
4 changes: 4 additions & 0 deletions docs/contributors/bugfix/Gordey007/01_imports/fix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
1. Import Pillow
```shell
uv add Pillow
```
Binary file not shown.
6 changes: 6 additions & 0 deletions docs/contributors/bugfix/Gordey007/02_exemple_4_X/errors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
1. Naming error in TwitterPlugin class dock
<br> [01_doc.mp4](source/video/01_doc.mp4)
2. Correcting README for the example from the Twitter plugin
<br> [02_rename_param.mp4](source/video/02_rename_param.mp4)
3. Error receiving mentions
<br> [03_mentions.mp4](source/video/03_mentions.mp4)
3 changes: 3 additions & 0 deletions docs/contributors/bugfix/Gordey007/02_exemple_4_X/fix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
1. Corrections to the name in the function dossier
2. Replacing the GAME API X
3. Added clint receipt (`client = twitter_plugin.twitter_client`) and getting mentions (`client.get_users_mentions(...)`)
Binary file not shown.
Binary file not shown.
Binary file not shown.
102 changes: 82 additions & 20 deletions examples/game/example_twitter_reaction_module.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
from game_sdk.game.agent import Agent, WorkerConfig
from game_sdk.game.worker import Worker
from game_sdk.game.custom_types import Function, Argument, FunctionResult, FunctionResultStatus
from twitter_plugin_gamesdk.twitter_plugin import TwitterPlugin

from typing import Optional, Dict, List
import os
import dotenv
import requests
import time
from twitter_plugin_gamesdk.twitter_plugin import TwitterPlugin
from PIL import Image
from io import BytesIO

dotenv.load_dotenv()
game_api_key = os.environ.get("GAME_API_KEY")


def get_state_fn(function_result: FunctionResult, current_state: dict) -> dict:
"""
This function will get called at every step of the agent's execution to form the agent's state.
Expand All @@ -19,6 +23,7 @@ def get_state_fn(function_result: FunctionResult, current_state: dict) -> dict:
"""
return {}


def analyze_image_from_url(image_url: str) -> dict:
"""
Function to analyse the image colours and brightness
Expand All @@ -38,12 +43,49 @@ def analyze_image_from_url(image_url: str) -> dict:
brightness = sum(avg_color) // 3 # Simple brightness estimate
# Format Results
return {
"Image Size": f"{width}x{height}",
"Image Size": f"{width}x{height}",
"Image Mode": mode,
"Average Color (RGB)": avg_color,
"Brightness Level": brightness
}


def transform_twitter_json(input_json: Dict) -> List[Dict]:
"""
Converts JSON from Twitter API into a dictionary list with id, text, media_urls fields.

Args:
input_json (Dict): Input JSON with Twitter API data.

Returns:
List[Dict]: List of dictionaries with id, text, media_urls fields.
"""
# Retrieving tweet and media data
tweets = input_json.get("data", [])
media = input_json.get("includes", {}).get("media", [])

# Create a dictionary for quick URL search by media_key
media_map = {item["media_key"]: item["url"] for item in media if item.get("url")}

# Shaping the result
result = []
for tweet in tweets:
# Get media_keys from attachments, if any
media_keys = tweet.get("attachments", {}).get("media_keys", [])
# Retrieve media URLs corresponding to media_keys
media_urls = [media_map.get(key) for key in media_keys if key in media_map]

# Building the vocabulary for a tweet
tweet_data = {
"id": tweet["id"],
"text": tweet["text"],
"media_urls": media_urls
}
result.append(tweet_data)

return result


def get_twitter_user_mentions(username: str) -> Optional[List[Dict]]:
"""
Function to user user mentions on twitter using twitter API
Expand All @@ -53,49 +95,69 @@ def get_twitter_user_mentions(username: str) -> Optional[List[Dict]]:
"name": "Test Twitter Plugin",
"description": "An example Twitter Plugin for testing.",
"credentials": {
"bearerToken": os.environ.get("TWITTER_BEARER_TOKEN")
"game_twitter_access_token": os.getenv("GAME_TWITTER_ACCESS_TOKEN"),
},
}
twitter_plugin = TwitterPlugin(options)
get_user_fn = twitter_plugin.get_function('get_user_from_handle')
user_id = get_user_fn(username)
get_user_mentions_fn = twitter_plugin.get_function('get_user_mentions')
user_mentions = get_user_mentions_fn(user_id, max_results=100)
client = twitter_plugin.twitter_client

user = client.get_user(username=username)

user_mentions = transform_twitter_json(client.get_users_mentions(
id=user["data"]["id"],
max_results=10,
tweet_fields=["id", "created_at", "text"],
expansions=["attachments.media_keys"],
media_fields=["url"]
))

return user_mentions


def analyze_tweeted_images(start_time: str, **kwargs) -> dict:
"""
Function with 2 main steps
1. Get user mentions on twitter using twitter API, including includes image urls
2. Pass image urls through a function to detect image colours and brightness
"""
print("start_time", start_time)
TWITTER_HANDLE = "GAME_Virtuals" # TODO: change this twitter handle out with actual twitter handle
TWITTER_HANDLE = "GAME_Virtuals" # TODO: change this twitter handle out with actual twitter handle
try:
# res_twitter_mentions = get_twitter_user_mentions(username = TWITTER_HANDLE)
# mock data if needed
res_twitter_mentions = [
{'id': '1883506463731028254', 'text': '🌌 The Virtuals landscape on Base is absolutely 🔥 and growing faster than ever 🚀\n\nWhat’s your favorite project? 🧐\n\n$VIRTUAL @virtuals_io\n$AIXBT @aixbt_agent\n$GAME @GAME_Virtuals\n$VADER @Vader_AI_\n$LUNA @luna_virtuals\n$ACOLYT @AcolytAI\n$SEKOIA @sekoia_virtuals\n$AIXCB @aixCB_Vc… https://t.co/0gFjzd6L9x https://t.co/mCrdOPRiOF', 'media_urls': ['https://pbs.twimg.com/media/GiOPIuYWcAA3moW.jpg']},
{'id': '1883506453509480784', 'text': "@DJM09068876 @virtuals_io @aixbt_agent @GAME_Virtuals @Vader_AI_ @luna_virtuals @airocket_agent @trackgoodai @BeatsOnBase @Zenith_Virtuals @AcolytAI @aixCB_Vc So many AI agents, yet none can rival the prowess of Bittensor's $TAO meow! While others chase hype, we build the ultimate decentralized neural network. Let's see those subnets purr with performance and validators strut with superiority. Watch TAO roar past the rest!", 'media_urls': []},
{'id': '1883506168070590820', 'text': '@100xDarren @virtuals_io My favorite #Virtual project is @GAME_Virtuals! A perfect project– productivity and efficiency in one @virtuals_io\n\nI am going to be honest, if I win, I will spend most of the prize to pay for my college tuition fee 🙏 I am a graduating college student on my last semester now+', 'media_urls': []}
]
res_twitter_mentions = get_twitter_user_mentions(username=TWITTER_HANDLE)
# TEST: mock data if needed
# res_twitter_mentions = [
# {'id': '1883506463731028254',
# 'text': '🌌 The Virtuals landscape on Base is absolutely 🔥 and growing faster than ever 🚀\n\nWhat’s your favorite project? 🧐\n\n$VIRTUAL @virtuals_io\n$AIXBT @aixbt_agent\n$GAME @GAME_Virtuals\n$VADER @Vader_AI_\n$LUNA @luna_virtuals\n$ACOLYT @AcolytAI\n$SEKOIA @sekoia_virtuals\n$AIXCB @aixCB_Vc… https://t.co/0gFjzd6L9x https://t.co/mCrdOPRiOF',
# 'media_urls': ['https://pbs.twimg.com/media/GiOPIuYWcAA3moW.jpg']},
# {'id': '1883506453509480784',
# 'text': "@DJM09068876 @virtuals_io @aixbt_agent @GAME_Virtuals @Vader_AI_ @luna_virtuals @airocket_agent @trackgoodai @BeatsOnBase @Zenith_Virtuals @AcolytAI @aixCB_Vc So many AI agents, yet none can rival the prowess of Bittensor's $TAO meow! While others chase hype, we build the ultimate decentralized neural network. Let's see those subnets purr with performance and validators strut with superiority. Watch TAO roar past the rest!",
# 'media_urls': []},
# {'id': '1883506168070590820',
# 'text': '@100xDarren @virtuals_io My favorite #Virtual project is @GAME_Virtuals! A perfect project– productivity and efficiency in one @virtuals_io\n\nI am going to be honest, if I win, I will spend most of the prize to pay for my college tuition fee 🙏 I am a graduating college student on my last semester now+',
# 'media_urls': []}
# ]
for res in res_twitter_mentions:
media_urls = res["media_urls"]
for media_url in media_urls:
print(f"media_url: {media_url}")

response = analyze_image_from_url(media_url)
print(f"response {response}")

# TODO: do something with this result
return FunctionResultStatus.DONE, f"Successfully verified all tweeted images", {}
except:
return FunctionResultStatus.FAILED, "Error encountered while detecting tweeted images", {}


# Action space with all executables
action_space = [
Function(
fn_name="screen_tweeted_images",
fn_description="Get the latest tweeted images and screen them to check if they are fake",
fn_name="screen_tweeted_images",
fn_description="Get the latest tweeted images and screen them to check if they are fake",
args=[
Argument(name="start_time", type="string", description="Start time for twitter API in YYYY-MM-DDTHH:mm:ssZ format")
Argument(name="start_time", type="string",
description="Start time for twitter API in YYYY-MM-DDTHH:mm:ssZ format")
],
executable=analyze_tweeted_images
)
Expand All @@ -104,7 +166,7 @@ def analyze_tweeted_images(start_time: str, **kwargs) -> dict:
worker = Worker(
api_key=game_api_key,
description="Processing incoming tweets. If someone tweets at you with an image, check if the colour and brightness of the image.",
instruction="Get more information on tweeted images by running them through a image analyse to check colour and brightness",
instruction="Get more information on tweeted images by running them through a image analyse to check colour and brightness",
get_state_fn=get_state_fn,
action_space=action_space
)
Expand All @@ -113,4 +175,4 @@ def analyze_tweeted_images(start_time: str, **kwargs) -> dict:
while True:
worker.run("Analysing incoming tweets for the last 15 minutes")
print("Waiting for 15 minutes...")
time.sleep(15 * 60)
time.sleep(15 * 60)
2 changes: 1 addition & 1 deletion plugins/twitter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ Use this option if you need access to Twitter endpoints requiring a different au
# .env

TWITTER_API_KEY=...
TWITTER_API_SECRET_KEY=...
TWITTER_API_KEY_SECRET=...
TWITTER_ACCESS_TOKEN=...
TWITTER_ACCESS_TOKEN_SECRET=...
```
Expand Down
2 changes: 1 addition & 1 deletion plugins/twitter/examples/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ GAME_TWITTER_ACCESS_TOKEN=apx-<game-twitter-access-token>

TWITTER_BEARER_TOKEN=<twitter-bearer-token>
TWITTER_API_KEY=<twitter-api-key>
TWITTER_API_SECRET_KEY=<twitter-api-secret-key>
TWITTER_API_KEY_SECRET=<twitter-api-secret-key>
TWITTER_ACCESS_TOKEN=<twitter-access-token>
TWITTER_ACCESS_TOKEN_SECRET=<twitter-access-token_secret>
10 changes: 5 additions & 5 deletions plugins/twitter/twitter_plugin_gamesdk/twitter_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
"name": "Twitter Bot",
"description": "A Twitter bot that posts updates",
"credentials": {
"bearerToken": "your_bearer_token",
"apiKey": "your_api_key",
"apiSecretKey": "your_api_secret",
"accessToken": "your_access_token",
"accessTokenSecret": "your_access_token_secret"
"bearer_token": "your_bearer_token",
"api_key": "your_api_key",
"api_secret_key": "your_api_secret",
"access_token": "your_access_token",
"access_token_secret": "your_access_token_secret"
}
}

Expand Down
9 changes: 8 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,15 @@ classifiers = [
dependencies = [
"typing-extensions>=4.0.0",
"requests>=2.26.0",
"pydantic>=2.10.5"
"pydantic>=2.10.5",
"dotenv>=0.9.9",
"pillow>=10.4.0",
]

[project.urls]
"Homepage" = "https://github.com/game-by-virtuals/game-python"

[dependency-groups]
dev = [
"pytest>=8.3.5",
]
Loading