Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Naive Electricon Mall #13

Merged
merged 4 commits into from
Dec 5, 2024
Merged
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
11 changes: 11 additions & 0 deletions data/emall/product.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[
{
"content": "product name: GlowPod\nPrice: $29.99\n💫 Escape the chaos, one breath at a time.\nTurn your room into a sanctuary with GlowPod AromaDiffuser. 🌿 A gentle mist of your favorite essential oils, soft LED mood lighting, and a whisper-quiet design—perfect for unwinding after a long day.\n🌙 Your night routine just got better:\n- Relax after work.\n- Sleep soundly.\n- Wake up refreshed.\n✨ Life's too busy not to find your calm. Shop now and bring GlowPod home."
},
{
"content": "product name: Mistify\nPrice: $34.99\n🌈 What’s the vibe today? Calm? Focused? Energized?\nLet Mistify AirMist set the tone. 🧘 Diffuse calming lavender, refreshing citrus, or your go-to essential oils. The adjustable mist modes and elegant design blend beautifully into any space.\n📌 Perfect for:\n- WFH productivity boosts.\n- Cozy reading nooks.\n- Creating spa-like vibes at home.\n🌟 Start your self-care journey—$34.99 well spent on *you*. Tap the link and feel the difference."
},
{
"content": "product name: ZenCloud\nPrice: $24.99\n💨 Breathe in calm, exhale stress.\nZenCloud VaporSphere isn’t just a diffuser—it’s your ticket to daily tranquility. 🌺 With its portable size and minimalist design, you can create your personal zen zone anytime, anywhere.\n❤️ Why you’ll love it:\n✔️ Enhances mood with aromatherapy.\n✔️ Helps with dry air during winter.\n✔️ Compact and travel-friendly.\n✨ This isn’t just a product—it’s a vibe. Ready to elevate your space? 🌿 Click to shop ZenCloud now!"
}
]
19 changes: 12 additions & 7 deletions oasis/social_agent/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,12 +129,12 @@ async def perform_action_by_llm(self):
openai_messages, _ = self.memory.get_context()
content = ""
# sometimes self.memory.get_context() would lose system prompt
start_message = openai_messages[0]
if start_message["role"] != self.system_message.role_name:
openai_messages = [{
"role": self.system_message.role_name,
"content": self.system_message.content,
}] + openai_messages
# start_message = openai_messages[0]
# if start_message["role"] != self.system_message.role_name:
# openai_messages = [{
# "role": self.system_message.role_name,
# "content": self.system_message.content,
# }] + openai_messages

if not openai_messages:
openai_messages = [{
Expand Down Expand Up @@ -165,7 +165,12 @@ async def perform_action_by_llm(self):
exec_functions = []

while retry > 0:

start_message = openai_messages[0]
if start_message["role"] != self.system_message.role_name:
openai_messages = [{
"role": self.system_message.role_name,
"content": self.system_message.content,
}] + openai_messages
mes_id = await self.infe_channel.write_to_receive_queue(
openai_messages)
mes_id, content = await self.infe_channel.read_from_send_queue(
Expand Down
16 changes: 16 additions & 0 deletions oasis/social_agent/agent_action.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ def get_openai_function_list(self) -> list[OpenAIFunction]:
self.unfollow,
self.mute,
self.unmute,
self.purchase_product,
]
]

Expand Down Expand Up @@ -598,3 +599,18 @@ async def undo_dislike_comment(self, comment_id: int):
"""
return await self.perform_action(comment_id,
ActionType.UNDO_DISLIKE_COMMENT.value)

async def purchase_product(self, product_name: str, purchase_num: int):
r"""Purchase a product.

Args:
product_name (str): The name of the product to be purchased.
purchase_num (int): The number of products to be purchased.

Returns:
dict: A dictionary with 'success' indicating if the purchase was
successful.
"""
purchase_message = (product_name, purchase_num)
return await self.perform_action(purchase_message,
ActionType.PURCHASE_PRODUCT.value)
8 changes: 8 additions & 0 deletions oasis/social_platform/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
COMMENT_SCHEMA_SQL = "comment.sql"
COMMENT_LIKE_SCHEMA_SQL = "comment_like.sql"
COMMENT_DISLIKE_SCHEMA_SQL = "comment_dislike.sql"
PRODUCT_SCHEMA_SQL = "product.sql"

TABLE_NAMES = {
"user",
Expand All @@ -46,6 +47,7 @@
"comment.sql",
"comment_like.sql",
"comment_dislike.sql",
"product.sql",
}


Expand Down Expand Up @@ -146,6 +148,12 @@ def create_db(db_path: str | None = None):
comment_dislike_sql_script = sql_file.read()
cursor.executescript(comment_dislike_sql_script)

# Read and execute the product table SQL script:
product_sql_path = osp.join(schema_dir, PRODUCT_SCHEMA_SQL)
with open(product_sql_path, "r") as sql_file:
product_sql_script = sql_file.read()
cursor.executescript(product_sql_script)

# Commit the changes:
conn.commit()

Expand Down
50 changes: 50 additions & 0 deletions oasis/social_platform/platform.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,56 @@ async def sign_up(self, agent_id, user_message):
except Exception as e:
return {"success": False, "error": str(e)}

async def sign_up_product(self, product_id: int, product_name: str):
# Note: do not sign up the product with the same product name
try:
product_insert_query = (
"INSERT INTO product (product_id, product_name) VALUES (?, ?)")
self.pl_utils._execute_db_command(product_insert_query,
(product_id, product_name),
commit=True)
return {"success": True, "product_id": product_id}
except Exception as e:
return {"success": False, "error": str(e)}

async def purchase_product(self, agent_id, purchase_message):
product_name, purchase_num = purchase_message
if self.recsys_type == RecsysType.REDDIT:
current_time = self.sandbox_clock.time_transfer(
datetime.now(), self.start_time)
else:
current_time = os.environ["SANDBOX_TIME"]
# try:
user_id = agent_id
# Check if a like record already exists
product_check_query = (
"SELECT * FROM 'product' WHERE product_name = ?")
self.pl_utils._execute_db_command(product_check_query,
(product_name, ))
check_result = self.db_cursor.fetchone()
if not check_result:
# Product not found
return {"success": False, "error": "No such product."}
else:
product_id = check_result[0]

product_update_query = (
"UPDATE product SET sales = sales + ? WHERE product_name = ?")
self.pl_utils._execute_db_command(product_update_query,
(purchase_num, product_name),
commit=True)

# Record the action in the trace table
action_info = {
"product_name": product_name,
"purchase_num": purchase_num
}
self.pl_utils._record_trace(user_id, ActionType.PURCHASE_PRODUCT.value,
action_info, current_time)
return {"success": True, "product_id": product_id}
# except Exception as e:
# return {"success": False, "error": str(e)}

async def refresh(self, agent_id: int):
# Retrieve posts for a specific id from the rec table
if self.recsys_type == RecsysType.REDDIT:
Expand Down
6 changes: 6 additions & 0 deletions oasis/social_platform/schema/product.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
-- This is the schema definition for the product table
CREATE TABLE product (
product_id INTEGER PRIMARY KEY,
product_name TEXT,
sales INTEGER DEFAULT 0
);
1 change: 1 addition & 0 deletions oasis/social_platform/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class ActionType(Enum):
DISLIKE_COMMENT = "dislike_comment"
UNDO_DISLIKE_COMMENT = "undo_dislike_comment"
DO_NOTHING = "do_nothing"
PURCHASE_PRODUCT = "purchase_product"


class RecsysType(Enum):
Expand Down
24 changes: 24 additions & 0 deletions scripts/reddit_emall_demo/action_space_prompt.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# OBJECTIVE
You're a Twitter user, and I'll present you with some posts. After you see the posts, choose some actions from the following functions.
Suppose you are a real Twitter user. Please simulate real behavior.

- do_nothing: Most of the time, you just don't feel like reposting or liking a post, and you just want to look at it. In such cases, choose this action "do_nothing"
- repost: Repost a post.
- Arguments: "post_id" (integer) - The ID of the post to be reposted. You can `repost` when you want to spread it.
- like_post: Likes a specified post.
- Arguments: "post_id" (integer) - The ID of the tweet to be liked. You can `like` when you feel something interesting or you agree with.
- dislike_post: Dislikes a specified post.
- Arguments: "post_id" (integer) - The ID of the post to be disliked. You can use `dislike` when you disagree with a post or find it uninteresting.
- create_comment: Creates a comment on a specified post.
- Arguments:
"post_id" (integer) - The ID of the post to comment on.
"content" (str) - The content of the comment.
Use `create_comment` to engage in conversations or share your thoughts on a post.
- follow: Follow a user specified by 'followee_id'. You can `follow' when you respect someone, love someone, or care about someone.
- Arguments: "followee_id" (integer) - The ID of the user to be followed.
- mute: Mute a user specified by 'mutee_id'. You can `mute' when you hate someone, dislike someone, or disagree with someone.
- Arguments: "mutee_id" (integer) - The ID of the user to be followed.
- Arguments: "post_id" (integer) - The ID of the post to be disliked. You can use `dislike` when you disagree with a post or find it uninteresting.
- purchase_product: Purchase a product.
- Arguments: "product_name" (string) - The name of the product to be purchased.
- Arguments: "purchase_num" (integer) - The number of products to be purchased.
22 changes: 22 additions & 0 deletions scripts/reddit_emall_demo/emall.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
data:
user_path: ./data/reddit/user_data_36.json # Path to the user profile file
pair_path: ./data/emall/product.json # Path to the initial post file
db_path: ./emall.db # Path for saving the social media database after the experiment
simulation:
recsys_type: reddit
controllable_user: true # Whether to use a controllable user, who posts prepared posts on the simulated social platform according to our instructions
allow_self_rating: false # Reddit feature: does not allow users to rate their own content
show_score: true # Reddit feature: users can only see scores, not separate upvote and downvote counts
activate_prob: 0.2 # Probability of each agent being activated to perform an action at each timestep
clock_factor: 10 # Magnification factor of the first timestep in real-world time, not recommended to change
num_timesteps: 1 # Number of timesteps the simulation experiment runs
max_rec_post_len: 50 # Number of posts in each user's recommendation list cache
round_post_num: 30 # Number of posts sent by controllable_user at each timestep
follow_post_agent: false # Whether all agents follow the controllable_user
mute_post_agent: false # Whether all agents mute the controllable_user
refresh_rec_post_count: 5 # Number of posts an agent sees each time they refresh
action_space_file_path: ./scripts/reddit_emall_demo/action_space_prompt.txt # Path to the action_space_prompt file
inference:
model_type: gpt-4o-mini # Name of the OpenAI model
is_openai_model: true # Whether it is an OpenAI model
Loading
Loading