Skip to content

Commit

Permalink
Merge pull request #13 from camel-ai/add_naive_e-mall
Browse files Browse the repository at this point in the history
Add Naive Electricon Mall
  • Loading branch information
yiyiyi0817 authored Dec 5, 2024
2 parents e0d4d6b + f9db00f commit d1acee7
Show file tree
Hide file tree
Showing 13 changed files with 500 additions and 7 deletions.
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

0 comments on commit d1acee7

Please sign in to comment.