File size: 5,385 Bytes
ae4412d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
import json
import gradio as gr
from server.environment import RevOpsEnvironment
from models import RevOpsAction, ActionType

env = RevOpsEnvironment()
env.reset(task_id="task_easy")

def format_lead(obs):
    if not obs or not hasattr(obs, 'lead'):
         return "No lead data."
    lead = obs.lead
    return f"""### Current Lead
**ID**: {lead.id}
**Name**: {lead.name}
**Title**: {lead.title}
**Email**: {lead.email}
**Company**: {lead.company}
**Source**: {lead.source}
**Message**: {lead.message}
**Score**: {lead.score}"""

def format_enrichment(obs):
    if not obs or not obs.enrichment.enriched:
         return "Not Enriched Yet."
    e = obs.enrichment
    return f"""### Firmographic Data
**Company Size**: {e.company_size}
**Revenue**: {e.revenue}
**Industry**: {e.industry}
**Region**: {e.region}
**Tier**: {e.tier}"""

def format_crm(obs):
    if not obs or not obs.crm.checked:
         return "CRM Not Checked."
    accounts = obs.crm.existing_accounts
    opps = obs.crm.opportunities
    
    res = "### CRM Match Results\n"
    if not accounts and not opps:
         return res + "No existing CRM records found."
    
    if accounts:
         res += "#### Existing Accounts:\n"
         for a in accounts:
              res += f"- {a.get('name')} (ID: {a.get('account_id')})\n"
    
    if opps:
         res += "\n#### Opportunities:\n"
         for o in opps:
              res += f"- Opp ID: {o.opportunity_id} | Status: {o.status} | Amount: ${o.amount} | Assigned Rep: {o.assigned_rep_id}\n"
    return res

def refresh_ui():
    st = env.get_full_state()
    obs = env._get_observation()
    done = obs.done if hasattr(obs, 'done') else False
    
    feedback = st.get("last_feedback", "")
    score = st.get("grader_score")
    
    status_text = f"**Status**: {'DONE' if done else 'IN PROGRESS'}\n\n**Accumulated Reward**: {st.get('accumulated_reward', 0.0):.2f}"
    if score is not None:
         status_text += f"\n\n**Final Grader Score**: {score}"
         
    return (
        format_lead(obs),
        format_enrichment(obs),
        format_crm(obs),
        feedback,
        status_text
    )

def reset_task(task_id):
    env.reset(task_id=task_id)
    return refresh_ui()

def perform_action(action_type, score, rep_id, account_id, opportunity_id, disqualification_reason):
    st = env.get_full_state()
    if st.get("current_lead_index", 0) >= len(st.get("leads", [])):
         return refresh_ui() # Already done
         
    # Convert string action back to enum safely
    action_val = ActionType(action_type)
    
    action = RevOpsAction(
        action_type=action_val,
        score=int(score) if score else None,
        rep_id=rep_id if rep_id else None,
        account_id=account_id if account_id else None,
        opportunity_id=opportunity_id if opportunity_id else None,
        disqualification_reason=disqualification_reason if disqualification_reason else None
    )
    
    env.step(action)
    return refresh_ui()

# --- Gradio UI Layout ---
with gr.Blocks(title="RevOps CRM Agent Desktop", theme=gr.themes.Soft()) as demo:
    gr.Markdown("# 🏢 RevOps-Agent Live Dashboard")
    gr.Markdown("Interact with the OpenEnv OpenEnv backend as a human operator, or watch your agent's live states.")
    
    with gr.Row():
        with gr.Column(scale=2):
            task_dropdown = gr.Dropdown(choices=["task_easy", "task_medium", "task_hard"], value="task_easy", label="Select Simulation Scenario")
            reset_btn = gr.Button("Reset Environment", variant="primary")
            
        with gr.Column(scale=1):
            status_box = gr.Markdown(value="**Status**: IN PROGRESS\n**Accumulated Reward**: 0.00")
            
    with gr.Row():
        with gr.Column(scale=1):
            lead_box = gr.Markdown()
        with gr.Column(scale=1):
            enrichment_box = gr.Markdown()
        with gr.Column(scale=1):
            crm_box = gr.Markdown()
            
    with gr.Row():
        feedback_box = gr.Textbox(label="Last Action Feedback", interactive=False)
            
    gr.Markdown("---")
    gr.Markdown("### ⚡ Action Console")
    with gr.Row():
        with gr.Column(scale=1):
            action_dropdown = gr.Dropdown(choices=[e.value for e in ActionType], value="enrich_lead", label="Action Type")
            btn_submit = gr.Button("Execute Action", variant="primary")
            
        with gr.Column(scale=2):
            score_input = gr.Number(label="Score (0-100) - For update_lead_score")
            rep_id_input = gr.Textbox(label="Rep ID - For route_to_rep (e.g., rep_amer_mm, rep_emea_ent)")
            account_id_input = gr.Textbox(label="Account ID - For merge_with_account")
            opp_id_input = gr.Textbox(label="Opportunity ID - For flag_reengagement")
            disqualify_input = gr.Textbox(label="Disqualification Reason - For disqualify")

    # Wire events
    outputs = [lead_box, enrichment_box, crm_box, feedback_box, status_box]
    
    demo.load(refresh_ui, inputs=None, outputs=outputs)
    
    reset_btn.click(reset_task, inputs=[task_dropdown], outputs=outputs)
    
    btn_submit.click(
        perform_action, 
        inputs=[action_dropdown, score_input, rep_id_input, account_id_input, opp_id_input, disqualify_input],
        outputs=outputs
    )

if __name__ == "__main__":
    demo.launch(server_name="0.0.0.0", server_port=7860)