File size: 6,401 Bytes
2649124
 
7164d93
c634ddd
 
 
13087f9
7164d93
dceac9e
 
1bef274
13087f9
df9bd09
1bef274
dceac9e
 
7164d93
dceac9e
7164d93
 
dceac9e
7164d93
dceac9e
 
7164d93
dceac9e
 
 
 
 
c3c50fa
dceac9e
 
 
 
c3c50fa
dceac9e
c3c50fa
 
c2053e6
dceac9e
 
c2053e6
dceac9e
 
 
2649124
41d7bd8
df9bd09
 
 
 
7164d93
dceac9e
c2053e6
df9bd09
c634ddd
15af633
c634ddd
 
 
 
 
 
 
 
 
 
 
 
 
 
7164d93
dceac9e
 
7164d93
dceac9e
 
 
 
 
 
 
c634ddd
c2053e6
 
c634ddd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15af633
 
df9bd09
15af633
 
df9bd09
15af633
df9bd09
 
15af633
 
 
c634ddd
7164d93
 
 
 
 
 
 
 
dceac9e
 
7164d93
dceac9e
c2053e6
 
7164d93
c634ddd
15af633
 
7164d93
 
 
 
 
 
dceac9e
c2053e6
dceac9e
c2053e6
7164d93
dceac9e
7164d93
 
15af633
baec467
2649124
 
15af633
176f4b7
2649124
 
15af633
 
 
 
973ef52
15af633
7164d93
 
15af633
c634ddd
 
15af633
 
2649124
15af633
c634ddd
15af633
2649124
 
7164d93
 
 
 
 
 
 
15af633
 
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
import gradio as gr
from chatbot_simulator import ChatbotSimulation
from huggingface_hub import HfApi, create_repo
from datasets import load_dataset
import json_repair
import random
import os
import re
import firebase_admin
from firebase_admin import credentials, firestore
import json
os.environ["TOKENIZERS_PARALLELISM"] = "false"

cred = credentials.Certificate(json.loads(os.getenv("Firebase_JSON")))
firebase_admin.initialize_app(cred)
db = firestore.client()

openai_api_key = os.getenv("OPENAI_API_KEY")


def find_smallest_incomplete_task(app_name):

    collection_ref = db.collection(app_name)
    docs = collection_ref.stream()

    smallest_incomplete_idx = None
    for doc in docs:
        doc_id = doc.id
        _, idx = doc_id.split('_')
        idx = int(idx)

        task_data = doc.to_dict()
        if task_data['task_completed'] is None and task_data['task_completed_steps'] is None:
            if smallest_incomplete_idx is None or idx < smallest_incomplete_idx:
                smallest_incomplete_idx = idx

    return smallest_incomplete_idx


def write_task_data(app_name, idx, task, task_complete, task_completed_step):
    doc_ref = db.collection(app_name).document(f"{app_name}_{idx}")
    doc_ref.set({
        "task": task,
        "task_completed": task_complete,
        "task_completed_steps": task_completed_step
    })


class AppSimulator:
    def __init__(self, openai_api_key):
        self.simulation = None
        self.openai_api_key = openai_api_key
        self.app_name = None
        self.smallest_index = None
        self.task = None

    def initialize_simulator(self, sitemap_url, progress=gr.Progress(track_tqdm=True)):
        """Initialize the simulator with retries and elapsed time tracking."""
        synthetic_sitemap = load_dataset(sitemap_url, "sitemap", split='train')
        app_name, sitemap, page_details, user_state, system_data = None, None, None, None, None
        for row in synthetic_sitemap:
            if row['name'] == 'app_name':
                app_name = row['value']  # Use `eval` to convert the string to a list
            elif row['name'] == 'sitemap':
                sitemap = json_repair.loads(row['value'])
            elif row['name'] == 'page_details':
                page_details = json_repair.loads(row['value'])
            elif row['name'] == 'user_state':
                user_state = json_repair.loads(row['value'])
            elif row['name'] == 'system_data':
                system_data = json_repair.loads(row['value'])

        self.app_name = app_name
        smallest_index = find_smallest_incomplete_task(app_name)
        if smallest_index is None:
            return "All tasks in this app have been completed!"
        self.smallest_index = smallest_index

        synthetic_tasks = load_dataset(sitemap_url, "tasks", split='train')
        incomplete_task = synthetic_tasks[smallest_index]
        task = incomplete_task["tasks"]
        solution = incomplete_task["steps"]
        user_data = incomplete_task["attributes"]["user_data"]

        self.task = task

        self.simulation = ChatbotSimulation(
            app_name=app_name,
            site_map=sitemap,
            page_details=page_details,
            user_state=user_state,
            system_data=system_data,
            user_data=user_data,
            task=task,
            solution=solution,
            log_location=f'conversation_log_{app_name}.txt',
            openai_api_key=openai_api_key,
            agent='llm'
        )

        initial_message = self.simulation.start_conversation()
        progress.update("Initialization Successful")
        return initial_message  # Return the initial assistant message for chat

    def chat_interaction(self, user_input, history):
        """Handle one round of conversation."""
        return self.simulation.one_conversation_round(user_input)


# Initialize the simulator
simulator_app = AppSimulator(openai_api_key=openai_api_key)


def chat(user_input, history):
    """Chat handler that validates input and interacts with the simulator."""
    response = simulator_app.chat_interaction(user_input, history)

    # Initialize variables for task completion and steps

    # Define the pattern for matching the response
    pattern = r"Task completed! You took (\d+) steps\."
    match = re.match(pattern, response)

    if match:
        task_complete = 1
        task_completed_step = int(match.group(1))
        app_name = simulator_app.app_name
        idx = simulator_app.smallest_index
        task = simulator_app.task
        write_task_data(app_name, idx, task, task_complete, task_completed_step)

    return response


def give_up():
    """Handle the Give-Up action by marking the first incomplete task as abandoned."""
    task_completed = 0
    task_completed_steps = 0

    app_name = simulator_app.app_name
    idx = simulator_app.smallest_index
    task = simulator_app.task

    write_task_data(app_name, idx, task, task_completed, task_completed_steps)

    return "Task marked as abandoned (Give-Up action)."


# Gradio Interface using ChatInterface
with gr.Blocks(fill_height=True) as demo:
    gr.Markdown("## Simulator Setup")

    # Input fields for initialization
    sitemap_input = gr.Textbox(label="Sitemap", placeholder="Enter the Hugging Face link to sitemap... (eg.jjz5463/AppStore_synthetic_sitemap)")
    initialize_button = gr.Button("Initialize Simulator")

    # Status block to display initialization progress with elapsed time
    status = gr.Textbox(label="Status", interactive=False)

    # Chat interface to handle user interactions
    chat_interface = gr.ChatInterface(fn=chat, type='messages')

    give_up_button = gr.Button("Give Up")

    # Define the callback function to initialize the simulator and update status
    def initialize_and_start_chat(sitemap):
        return simulator_app.initialize_simulator(sitemap)  # Use progress tracking

    # Set up the button click to initialize simulator and update status only
    initialize_button.click(
        fn=initialize_and_start_chat,
        inputs=[sitemap_input],
        outputs=status  # Update only the status block
    )

    # Set up the Give-Up button click to update the dataset
    give_up_button.click(
        fn=give_up,
        inputs=[],
        outputs=status  # Update the status with the give-up message
    )

# Launch the app
demo.launch()