Spaces:
Sleeping
Sleeping
Upload folder using huggingface_hub
Browse files- server/app.py +42 -130
server/app.py
CHANGED
|
@@ -36,6 +36,17 @@ sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
| 36 |
|
| 37 |
try:
|
| 38 |
from openenv.core.env_server.http_server import create_app
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 39 |
except Exception as e:
|
| 40 |
raise ImportError(
|
| 41 |
"openenv is required for the web interface. Install dependencies with '\n uv sync\n'"
|
|
@@ -62,7 +73,6 @@ def build_custom_gradio_ui(
|
|
| 62 |
readme_content = _load_readme_content(metadata)
|
| 63 |
display_title = metadata.name if metadata else title
|
| 64 |
|
| 65 |
-
# Custom Quick Start (override OpenEnv default which uses port 8000)
|
| 66 |
custom_quick_start_md = """### Connect to this environment
|
| 67 |
|
| 68 |
Connect from Python using `ProcureRLEnv`:
|
|
@@ -86,15 +96,6 @@ Access the visual playground at `/web` to:
|
|
| 86 |
- **Watch Agent**: See a strategic agent negotiate step-by-step
|
| 87 |
- **Instructions**: Learn how to play and what each field means
|
| 88 |
|
| 89 |
-
### API Endpoints
|
| 90 |
-
|
| 91 |
-
| Endpoint | Method | Description |
|
| 92 |
-
|----------|--------|-------------|
|
| 93 |
-
| `/reset` | POST | Reset environment with task_id and seed |
|
| 94 |
-
| `/step` | POST | Execute an action |
|
| 95 |
-
| `/state` | GET | Get current negotiation state |
|
| 96 |
-
| `/health` | GET | Health check |
|
| 97 |
-
|
| 98 |
### Quick Tips
|
| 99 |
|
| 100 |
- Use **collaborative language** ("partnership", "mutual") to increase rapport
|
|
@@ -102,7 +103,6 @@ Access the visual playground at `/web` to:
|
|
| 102 |
- In **adversarial**, avoid 2+ consecutive concessions or opponent hardens
|
| 103 |
"""
|
| 104 |
|
| 105 |
-
# Example actions for the Example tab
|
| 106 |
EXAMPLE_1 = {
|
| 107 |
"move_type": "make_offer",
|
| 108 |
"terms": {"price": 48000},
|
|
@@ -115,28 +115,11 @@ Access the visual playground at `/web` to:
|
|
| 115 |
"message": "We appreciate your flexibility. Here's our counter-offer to move us closer to a mutual agreement.",
|
| 116 |
}
|
| 117 |
|
| 118 |
-
# Agent strategies for auto-play
|
| 119 |
AGENT_STRATEGY = [
|
| 120 |
-
(
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
),
|
| 125 |
-
(
|
| 126 |
-
"make_offer",
|
| 127 |
-
{"price": 46000},
|
| 128 |
-
"I appreciate your movement. Let's see if we can meet in the middle.",
|
| 129 |
-
),
|
| 130 |
-
(
|
| 131 |
-
"make_offer",
|
| 132 |
-
{"price": 44000},
|
| 133 |
-
"We're getting closer. I think we can finalize this at a fair price for both parties.",
|
| 134 |
-
),
|
| 135 |
-
(
|
| 136 |
-
"make_offer",
|
| 137 |
-
{"price": 42000},
|
| 138 |
-
"I believe we've found a good deal. Let's accept these terms.",
|
| 139 |
-
),
|
| 140 |
("accept", {}, ""),
|
| 141 |
]
|
| 142 |
|
|
@@ -160,7 +143,6 @@ Access the visual playground at `/web` to:
|
|
| 160 |
action_data = {"move_type": move_type, "terms": terms, "message": message}
|
| 161 |
data = await web_manager.step_environment(action_data)
|
| 162 |
|
| 163 |
-
# Update conversation
|
| 164 |
new_conv = conversation_state.copy() if conversation_state else []
|
| 165 |
new_conv.append(
|
| 166 |
{
|
|
@@ -169,6 +151,7 @@ Access the visual playground at `/web` to:
|
|
| 169 |
"terms": terms,
|
| 170 |
}
|
| 171 |
)
|
|
|
|
| 172 |
if not data.get("observation", {}).get("done"):
|
| 173 |
supplier_msg = data.get("observation", {}).get("supplier_message", "")
|
| 174 |
new_conv.append(
|
|
@@ -179,11 +162,8 @@ Access the visual playground at `/web` to:
|
|
| 179 |
}
|
| 180 |
)
|
| 181 |
|
| 182 |
-
# Get price info for chart
|
| 183 |
obs = data.get("observation", {})
|
| 184 |
current_price = obs.get("current_offer", {}).get("price", 0)
|
| 185 |
-
opponent_opening = 52000 # Will be extracted from state
|
| 186 |
-
|
| 187 |
reward = obs.get("reward")
|
| 188 |
done = obs.get("done", False)
|
| 189 |
status_msg = f"Step complete! Round {obs.get('round_number', 0)}/{obs.get('max_rounds', 6)}"
|
|
@@ -207,9 +187,7 @@ Access the visual playground at `/web` to:
|
|
| 207 |
|
| 208 |
async def run_agent_example(task_id="single_issue", seed=42):
|
| 209 |
try:
|
| 210 |
-
# Reset first
|
| 211 |
await web_manager.reset_environment({"task_id": task_id, "seed": seed})
|
| 212 |
-
|
| 213 |
conv = []
|
| 214 |
steps_log = []
|
| 215 |
price_points = []
|
|
@@ -225,7 +203,6 @@ Access the visual playground at `/web` to:
|
|
| 225 |
|
| 226 |
current_price = obs.get("current_offer", {}).get("price", 0)
|
| 227 |
price_points.append(current_price)
|
| 228 |
-
|
| 229 |
conv.append(
|
| 230 |
{
|
| 231 |
"role": "you",
|
|
@@ -265,17 +242,9 @@ Access the visual playground at `/web` to:
|
|
| 265 |
"โ
Agent demo complete!",
|
| 266 |
)
|
| 267 |
except Exception as e:
|
| 268 |
-
return f"Error: {e}", "", f"Error: {e}"
|
| 269 |
-
|
| 270 |
-
def apply_example(example_data):
|
| 271 |
-
return (
|
| 272 |
-
example_data["move_type"],
|
| 273 |
-
json.dumps(example_data["terms"]),
|
| 274 |
-
example_data["message"],
|
| 275 |
-
)
|
| 276 |
|
| 277 |
def _format_observation_full(data):
|
| 278 |
-
"""Format observation as rich markdown."""
|
| 279 |
if not data:
|
| 280 |
return "No data"
|
| 281 |
obs = data.get("observation", data)
|
|
@@ -319,7 +288,6 @@ Access the visual playground at `/web` to:
|
|
| 319 |
return "๐"
|
| 320 |
|
| 321 |
def _build_conversation_hist(conv):
|
| 322 |
-
"""Build conversation history HTML."""
|
| 323 |
if not conv:
|
| 324 |
return "**Conversation will appear here...**\n\nMake your first offer to start the negotiation!"
|
| 325 |
lines = ["## ๐ฌ Conversation History\n"]
|
|
@@ -333,7 +301,6 @@ Access the visual playground at `/web` to:
|
|
| 333 |
return "\n".join(lines)
|
| 334 |
|
| 335 |
def _build_price_display(round_num, current_price, target, opening):
|
| 336 |
-
"""Build price tracker display."""
|
| 337 |
range_price = opening - target
|
| 338 |
progress = (
|
| 339 |
((opening - current_price) / range_price * 100) if range_price > 0 else 0
|
|
@@ -351,10 +318,11 @@ Access the visual playground at `/web` to:
|
|
| 351 |
return "\n".join(lines)
|
| 352 |
|
| 353 |
def _build_agent_demo_result(steps_log, conv, price_points):
|
| 354 |
-
|
| 355 |
-
|
| 356 |
-
|
| 357 |
-
|
|
|
|
| 358 |
lines.extend(steps_log)
|
| 359 |
lines.append("\n### ๐ฌ Full Conversation:")
|
| 360 |
for msg in conv:
|
|
@@ -371,14 +339,11 @@ Access the visual playground at `/web` to:
|
|
| 371 |
gr.Markdown(f"# ๐ค {display_title}")
|
| 372 |
gr.Markdown("### Interactive Procurement Negotiation Simulation")
|
| 373 |
|
| 374 |
-
with gr.Tabs()
|
| 375 |
with gr.TabItem("๐ฎ Play Now"):
|
| 376 |
-
"""Interactive tab where user plays against the opponent."""
|
| 377 |
with gr.Row():
|
| 378 |
with gr.Column(scale=2):
|
| 379 |
-
conversation_display = gr.Markdown(
|
| 380 |
-
"*Click Reset to start a new negotiation!*"
|
| 381 |
-
)
|
| 382 |
price_tracker = gr.Markdown(
|
| 383 |
"## ๐ Price Tracker\n*Reset to see price tracker*"
|
| 384 |
)
|
|
@@ -389,27 +354,21 @@ Access the visual playground at `/web` to:
|
|
| 389 |
choices=["single_issue", "multi_issue", "adversarial"],
|
| 390 |
value="single_issue",
|
| 391 |
label="Task",
|
| 392 |
-
info="Choose which negotiation scenario",
|
| 393 |
-
)
|
| 394 |
-
seed_input = gr.Number(
|
| 395 |
-
value=42,
|
| 396 |
-
label="Seed",
|
| 397 |
-
info="Random seed for reproducibility",
|
| 398 |
)
|
|
|
|
| 399 |
move_type_input = gr.Textbox(
|
| 400 |
label="Move Type",
|
| 401 |
-
info="make_offer | accept | reject | bundle",
|
| 402 |
value="make_offer",
|
|
|
|
| 403 |
)
|
| 404 |
terms_input = gr.Textbox(
|
| 405 |
label="Terms (JSON)",
|
| 406 |
-
info='Example: {"price": 45000}',
|
| 407 |
value='{"price": 48000}',
|
|
|
|
| 408 |
)
|
| 409 |
message_input = gr.Textbox(
|
| 410 |
label="Your Message",
|
| 411 |
-
|
| 412 |
-
value="I value our partnership and believe we can reach a fair agreement.",
|
| 413 |
lines=2,
|
| 414 |
)
|
| 415 |
|
|
@@ -433,27 +392,25 @@ Access the visual playground at `/web` to:
|
|
| 433 |
status_output = gr.Textbox(
|
| 434 |
label="Status", interactive=False, lines=1
|
| 435 |
)
|
| 436 |
-
|
| 437 |
with gr.Accordion("๐ Raw JSON", open=False):
|
| 438 |
raw_json = gr.Code(
|
| 439 |
label="", language="json", interactive=False, lines=10
|
| 440 |
)
|
| 441 |
|
| 442 |
-
# Example messages for quick fill
|
| 443 |
FRIENDLY_EX = (
|
| 444 |
"make_offer",
|
| 445 |
'{"price": 48000}',
|
| 446 |
-
"I truly value our partnership and believe we can find a fair solution
|
| 447 |
)
|
| 448 |
PROF_EX = (
|
| 449 |
"make_offer",
|
| 450 |
'{"price": 46000}',
|
| 451 |
-
"Based on market research and our long-term relationship
|
| 452 |
)
|
| 453 |
COUNTER_EX = (
|
| 454 |
"make_offer",
|
| 455 |
'{"price": 44000}',
|
| 456 |
-
"We've made good progress. I can meet you at $44,000
|
| 457 |
)
|
| 458 |
|
| 459 |
def get_friendly():
|
|
@@ -470,8 +427,7 @@ Access the visual playground at `/web` to:
|
|
| 470 |
outputs=[move_type_input, terms_input, message_input],
|
| 471 |
)
|
| 472 |
eg2_btn.click(
|
| 473 |
-
fn=get_prof,
|
| 474 |
-
outputs=[move_type_input, terms_input, message_input],
|
| 475 |
)
|
| 476 |
eg3_btn.click(
|
| 477 |
fn=get_counter,
|
|
@@ -523,10 +479,9 @@ Access the visual playground at `/web` to:
|
|
| 523 |
)
|
| 524 |
|
| 525 |
with gr.TabItem("๐ค Watch Agent"):
|
| 526 |
-
"""Example tab showing agent negotiation demo."""
|
| 527 |
gr.Markdown("### Watch a Strategic Agent Negotiate")
|
| 528 |
gr.Markdown(
|
| 529 |
-
"This demo shows how
|
| 530 |
)
|
| 531 |
with gr.Row():
|
| 532 |
task_selector = gr.Dropdown(
|
|
@@ -556,7 +511,6 @@ Access the visual playground at `/web` to:
|
|
| 556 |
)
|
| 557 |
|
| 558 |
with gr.TabItem("๐ Instructions"):
|
| 559 |
-
"""Instructions tab."""
|
| 560 |
gr.Markdown("""
|
| 561 |
## ๐ฎ How to Play
|
| 562 |
|
|
@@ -566,34 +520,28 @@ Access the visual playground at `/web` to:
|
|
| 566 |
- **adversarial**: Negotiate price + payment + support (hardest)
|
| 567 |
|
| 568 |
### 2. Make Offers
|
| 569 |
-
- **Move Type**: `make_offer` to propose
|
| 570 |
-
- **Terms**: JSON with your offered price
|
| 571 |
-
- **Message**: Be collaborative
|
| 572 |
|
| 573 |
### 3. Watch the Response
|
| 574 |
-
-
|
| 575 |
-
- Your **rapport** changes based on your language quality
|
| 576 |
- Higher rapport โ opponent gives better concessions
|
| 577 |
|
| 578 |
### 4. Goal
|
| 579 |
-
- Get
|
| 580 |
-
- Use fewer rounds for
|
| 581 |
- **Don't make 2+ consecutive concessions** in adversarial mode!
|
| 582 |
|
| 583 |
## ๐ฏ Quick Tips
|
| 584 |
|
| 585 |
| Do | Don't |
|
| 586 |
|---|---|
|
| 587 |
-
| Use collaborative language | Use aggressive language
|
| 588 |
-
| Make strategic concessions | Concede every round
|
| 589 |
-
| Offer Net-30 payment
|
| 590 |
-
| Accept when terms are good | Wait until max rounds |
|
| 591 |
-
|
| 592 |
-
## ๐ค Agent Demo
|
| 593 |
-
The "Watch Agent" tab shows how a strategic agent negotiates step-by-step.
|
| 594 |
""")
|
| 595 |
|
| 596 |
-
# Quick Start and README accordions
|
| 597 |
with gr.Accordion("๐ Quick Start Guide", open=False):
|
| 598 |
gr.Markdown(custom_quick_start_md)
|
| 599 |
with gr.Accordion("๐ Full README", open=False):
|
|
@@ -603,7 +551,6 @@ Access the visual playground at `/web` to:
|
|
| 603 |
|
| 604 |
|
| 605 |
def _load_readme_content(metadata):
|
| 606 |
-
"""Load README content from metadata or filesystem."""
|
| 607 |
if metadata and hasattr(metadata, "readme_content") and metadata.readme_content:
|
| 608 |
return metadata.readme_content
|
| 609 |
try:
|
|
@@ -617,41 +564,6 @@ def _load_readme_content(metadata):
|
|
| 617 |
return "No README available."
|
| 618 |
|
| 619 |
|
| 620 |
-
def _format_observation(data):
|
| 621 |
-
"""Format observation as markdown for display."""
|
| 622 |
-
if not data:
|
| 623 |
-
return "No data"
|
| 624 |
-
|
| 625 |
-
obs = data.get("observation", data)
|
| 626 |
-
lines = []
|
| 627 |
-
|
| 628 |
-
task_id = obs.get("task_id", "")
|
| 629 |
-
round_num = obs.get("round_number", 0)
|
| 630 |
-
max_rounds = obs.get("max_rounds", 0)
|
| 631 |
-
done = obs.get("done", False)
|
| 632 |
-
reward = obs.get("reward")
|
| 633 |
-
|
| 634 |
-
lines.append(f"### Round {round_num}/{max_rounds}")
|
| 635 |
-
lines.append(f"**Task:** {task_id}")
|
| 636 |
-
lines.append(f"**Done:** {done}")
|
| 637 |
-
|
| 638 |
-
if reward is not None:
|
| 639 |
-
lines.append(f"**Reward:** {reward:.4f}")
|
| 640 |
-
|
| 641 |
-
supplier_msg = obs.get("supplier_message", "")
|
| 642 |
-
if supplier_msg:
|
| 643 |
-
lines.append(f"\n**Supplier:** {supplier_msg}")
|
| 644 |
-
|
| 645 |
-
current_offer = obs.get("current_offer", {})
|
| 646 |
-
if current_offer:
|
| 647 |
-
lines.append(f"\n**Current Offer:** {json.dumps(current_offer)}")
|
| 648 |
-
|
| 649 |
-
rapport = obs.get("rapport_hint", "neutral")
|
| 650 |
-
lines.append(f"\n**Rapport:** {rapport}")
|
| 651 |
-
|
| 652 |
-
return "\n".join(lines)
|
| 653 |
-
|
| 654 |
-
|
| 655 |
app = create_app(
|
| 656 |
lambda: _env_instance,
|
| 657 |
NegotiationAction,
|
|
|
|
| 36 |
|
| 37 |
try:
|
| 38 |
from openenv.core.env_server.http_server import create_app
|
| 39 |
+
import openenv.core.env_server.web_interface as _mod
|
| 40 |
+
|
| 41 |
+
_orig = _mod.get_quick_start_markdown
|
| 42 |
+
|
| 43 |
+
def _fixed(md, ac, oc):
|
| 44 |
+
return _orig(md, ac, oc).replace(
|
| 45 |
+
"http://localhost:8000", "http://localhost:7860"
|
| 46 |
+
)
|
| 47 |
+
|
| 48 |
+
_mod.get_quick_start_markdown = _fixed
|
| 49 |
+
|
| 50 |
except Exception as e:
|
| 51 |
raise ImportError(
|
| 52 |
"openenv is required for the web interface. Install dependencies with '\n uv sync\n'"
|
|
|
|
| 73 |
readme_content = _load_readme_content(metadata)
|
| 74 |
display_title = metadata.name if metadata else title
|
| 75 |
|
|
|
|
| 76 |
custom_quick_start_md = """### Connect to this environment
|
| 77 |
|
| 78 |
Connect from Python using `ProcureRLEnv`:
|
|
|
|
| 96 |
- **Watch Agent**: See a strategic agent negotiate step-by-step
|
| 97 |
- **Instructions**: Learn how to play and what each field means
|
| 98 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 99 |
### Quick Tips
|
| 100 |
|
| 101 |
- Use **collaborative language** ("partnership", "mutual") to increase rapport
|
|
|
|
| 103 |
- In **adversarial**, avoid 2+ consecutive concessions or opponent hardens
|
| 104 |
"""
|
| 105 |
|
|
|
|
| 106 |
EXAMPLE_1 = {
|
| 107 |
"move_type": "make_offer",
|
| 108 |
"terms": {"price": 48000},
|
|
|
|
| 115 |
"message": "We appreciate your flexibility. Here's our counter-offer to move us closer to a mutual agreement.",
|
| 116 |
}
|
| 117 |
|
|
|
|
| 118 |
AGENT_STRATEGY = [
|
| 119 |
+
("make_offer", {"price": 48000}, "I value our partnership."),
|
| 120 |
+
("make_offer", {"price": 46000}, "I appreciate your movement."),
|
| 121 |
+
("make_offer", {"price": 44000}, "We're getting closer."),
|
| 122 |
+
("make_offer", {"price": 42000}, "I believe we've found a good deal."),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 123 |
("accept", {}, ""),
|
| 124 |
]
|
| 125 |
|
|
|
|
| 143 |
action_data = {"move_type": move_type, "terms": terms, "message": message}
|
| 144 |
data = await web_manager.step_environment(action_data)
|
| 145 |
|
|
|
|
| 146 |
new_conv = conversation_state.copy() if conversation_state else []
|
| 147 |
new_conv.append(
|
| 148 |
{
|
|
|
|
| 151 |
"terms": terms,
|
| 152 |
}
|
| 153 |
)
|
| 154 |
+
|
| 155 |
if not data.get("observation", {}).get("done"):
|
| 156 |
supplier_msg = data.get("observation", {}).get("supplier_message", "")
|
| 157 |
new_conv.append(
|
|
|
|
| 162 |
}
|
| 163 |
)
|
| 164 |
|
|
|
|
| 165 |
obs = data.get("observation", {})
|
| 166 |
current_price = obs.get("current_offer", {}).get("price", 0)
|
|
|
|
|
|
|
| 167 |
reward = obs.get("reward")
|
| 168 |
done = obs.get("done", False)
|
| 169 |
status_msg = f"Step complete! Round {obs.get('round_number', 0)}/{obs.get('max_rounds', 6)}"
|
|
|
|
| 187 |
|
| 188 |
async def run_agent_example(task_id="single_issue", seed=42):
|
| 189 |
try:
|
|
|
|
| 190 |
await web_manager.reset_environment({"task_id": task_id, "seed": seed})
|
|
|
|
| 191 |
conv = []
|
| 192 |
steps_log = []
|
| 193 |
price_points = []
|
|
|
|
| 203 |
|
| 204 |
current_price = obs.get("current_offer", {}).get("price", 0)
|
| 205 |
price_points.append(current_price)
|
|
|
|
| 206 |
conv.append(
|
| 207 |
{
|
| 208 |
"role": "you",
|
|
|
|
| 242 |
"โ
Agent demo complete!",
|
| 243 |
)
|
| 244 |
except Exception as e:
|
| 245 |
+
return f"Error: {e}", "", f"Error: {e}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 246 |
|
| 247 |
def _format_observation_full(data):
|
|
|
|
| 248 |
if not data:
|
| 249 |
return "No data"
|
| 250 |
obs = data.get("observation", data)
|
|
|
|
| 288 |
return "๐"
|
| 289 |
|
| 290 |
def _build_conversation_hist(conv):
|
|
|
|
| 291 |
if not conv:
|
| 292 |
return "**Conversation will appear here...**\n\nMake your first offer to start the negotiation!"
|
| 293 |
lines = ["## ๐ฌ Conversation History\n"]
|
|
|
|
| 301 |
return "\n".join(lines)
|
| 302 |
|
| 303 |
def _build_price_display(round_num, current_price, target, opening):
|
|
|
|
| 304 |
range_price = opening - target
|
| 305 |
progress = (
|
| 306 |
((opening - current_price) / range_price * 100) if range_price > 0 else 0
|
|
|
|
| 318 |
return "\n".join(lines)
|
| 319 |
|
| 320 |
def _build_agent_demo_result(steps_log, conv, price_points):
|
| 321 |
+
lines = [
|
| 322 |
+
"## ๐ค Agent Negotiation Demo\n",
|
| 323 |
+
"Watch how a strategic agent negotiates:\n",
|
| 324 |
+
"### ๐ Steps:",
|
| 325 |
+
]
|
| 326 |
lines.extend(steps_log)
|
| 327 |
lines.append("\n### ๐ฌ Full Conversation:")
|
| 328 |
for msg in conv:
|
|
|
|
| 339 |
gr.Markdown(f"# ๐ค {display_title}")
|
| 340 |
gr.Markdown("### Interactive Procurement Negotiation Simulation")
|
| 341 |
|
| 342 |
+
with gr.Tabs():
|
| 343 |
with gr.TabItem("๐ฎ Play Now"):
|
|
|
|
| 344 |
with gr.Row():
|
| 345 |
with gr.Column(scale=2):
|
| 346 |
+
conversation_display = gr.Markdown("*Click Reset to start!*")
|
|
|
|
|
|
|
| 347 |
price_tracker = gr.Markdown(
|
| 348 |
"## ๐ Price Tracker\n*Reset to see price tracker*"
|
| 349 |
)
|
|
|
|
| 354 |
choices=["single_issue", "multi_issue", "adversarial"],
|
| 355 |
value="single_issue",
|
| 356 |
label="Task",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 357 |
)
|
| 358 |
+
seed_input = gr.Number(value=42, label="Seed")
|
| 359 |
move_type_input = gr.Textbox(
|
| 360 |
label="Move Type",
|
|
|
|
| 361 |
value="make_offer",
|
| 362 |
+
info="make_offer | accept | reject | bundle",
|
| 363 |
)
|
| 364 |
terms_input = gr.Textbox(
|
| 365 |
label="Terms (JSON)",
|
|
|
|
| 366 |
value='{"price": 48000}',
|
| 367 |
+
info='Example: {"price": 45000}',
|
| 368 |
)
|
| 369 |
message_input = gr.Textbox(
|
| 370 |
label="Your Message",
|
| 371 |
+
value="I value our partnership.",
|
|
|
|
| 372 |
lines=2,
|
| 373 |
)
|
| 374 |
|
|
|
|
| 392 |
status_output = gr.Textbox(
|
| 393 |
label="Status", interactive=False, lines=1
|
| 394 |
)
|
|
|
|
| 395 |
with gr.Accordion("๐ Raw JSON", open=False):
|
| 396 |
raw_json = gr.Code(
|
| 397 |
label="", language="json", interactive=False, lines=10
|
| 398 |
)
|
| 399 |
|
|
|
|
| 400 |
FRIENDLY_EX = (
|
| 401 |
"make_offer",
|
| 402 |
'{"price": 48000}',
|
| 403 |
+
"I truly value our partnership and believe we can find a fair solution.",
|
| 404 |
)
|
| 405 |
PROF_EX = (
|
| 406 |
"make_offer",
|
| 407 |
'{"price": 46000}',
|
| 408 |
+
"Based on market research and our long-term relationship, I believe $46,000 is fair.",
|
| 409 |
)
|
| 410 |
COUNTER_EX = (
|
| 411 |
"make_offer",
|
| 412 |
'{"price": 44000}',
|
| 413 |
+
"We've made good progress. I can meet you at $44,000.",
|
| 414 |
)
|
| 415 |
|
| 416 |
def get_friendly():
|
|
|
|
| 427 |
outputs=[move_type_input, terms_input, message_input],
|
| 428 |
)
|
| 429 |
eg2_btn.click(
|
| 430 |
+
fn=get_prof, outputs=[move_type_input, terms_input, message_input]
|
|
|
|
| 431 |
)
|
| 432 |
eg3_btn.click(
|
| 433 |
fn=get_counter,
|
|
|
|
| 479 |
)
|
| 480 |
|
| 481 |
with gr.TabItem("๐ค Watch Agent"):
|
|
|
|
| 482 |
gr.Markdown("### Watch a Strategic Agent Negotiate")
|
| 483 |
gr.Markdown(
|
| 484 |
+
"This demo shows how a strategic agent approaches the negotiation."
|
| 485 |
)
|
| 486 |
with gr.Row():
|
| 487 |
task_selector = gr.Dropdown(
|
|
|
|
| 511 |
)
|
| 512 |
|
| 513 |
with gr.TabItem("๐ Instructions"):
|
|
|
|
| 514 |
gr.Markdown("""
|
| 515 |
## ๐ฎ How to Play
|
| 516 |
|
|
|
|
| 520 |
- **adversarial**: Negotiate price + payment + support (hardest)
|
| 521 |
|
| 522 |
### 2. Make Offers
|
| 523 |
+
- **Move Type**: `make_offer` to propose, `accept` to take deal, `reject` to walk away
|
| 524 |
+
- **Terms**: JSON with your offered price
|
| 525 |
+
- **Message**: Be collaborative for better rapport!
|
| 526 |
|
| 527 |
### 3. Watch the Response
|
| 528 |
+
- Your **rapport** changes based on language quality
|
|
|
|
| 529 |
- Higher rapport โ opponent gives better concessions
|
| 530 |
|
| 531 |
### 4. Goal
|
| 532 |
+
- Get price close to your target
|
| 533 |
+
- Use fewer rounds for better efficiency score
|
| 534 |
- **Don't make 2+ consecutive concessions** in adversarial mode!
|
| 535 |
|
| 536 |
## ๐ฏ Quick Tips
|
| 537 |
|
| 538 |
| Do | Don't |
|
| 539 |
|---|---|
|
| 540 |
+
| Use collaborative language | Use aggressive language |
|
| 541 |
+
| Make strategic concessions | Concede every round |
|
| 542 |
+
| Offer Net-30 payment | Ignore payment terms |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 543 |
""")
|
| 544 |
|
|
|
|
| 545 |
with gr.Accordion("๐ Quick Start Guide", open=False):
|
| 546 |
gr.Markdown(custom_quick_start_md)
|
| 547 |
with gr.Accordion("๐ Full README", open=False):
|
|
|
|
| 551 |
|
| 552 |
|
| 553 |
def _load_readme_content(metadata):
|
|
|
|
| 554 |
if metadata and hasattr(metadata, "readme_content") and metadata.readme_content:
|
| 555 |
return metadata.readme_content
|
| 556 |
try:
|
|
|
|
| 564 |
return "No README available."
|
| 565 |
|
| 566 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 567 |
app = create_app(
|
| 568 |
lambda: _env_instance,
|
| 569 |
NegotiationAction,
|