App_Simulator / app.py
jjz5463's picture
random pick an incomplete task instead of go with sequential order
700f11b
import gradio as gr
from chatbot_simulator import ChatbotSimulation
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_random_incomplete_task(app_name):
collection_ref = db.collection(app_name)
incomplete_indices = []
for doc in collection_ref.stream():
task_data = doc.to_dict()
if task_data['task_completed'] is None and task_data['task_completed_steps'] is None:
_, idx = doc.id.split('_')
idx = int(idx)
incomplete_indices.append(idx)
# Check if any incomplete tasks found
if not incomplete_indices:
return None
# Pick a random incomplete index from the list
random_idx = random.choice(incomplete_indices)
return random_idx
def write_task_data(app_name, idx, task, task_complete, task_completed_step, trajectory):
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,
"trajectory": trajectory
})
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, "schema", split='train')
app_name, app_description, sitemap, relevant_tables_per_page, jinjia_prerender_page = None, None, None, None, None
for row in synthetic_sitemap:
if row['name'] == 'app_name':
app_name = row['value']
elif row['name'] == 'app_description':
app_description = row['value']
elif row['name'] == 'sitemap':
sitemap = json_repair.loads(row['value'])
elif row['name'] == 'relevant_tables_per_page':
relevant_tables_per_page = json_repair.loads(row['value'])
elif row['name'] == 'jinjia_prerender_pages':
jinjia_prerender_page = json_repair.loads(row['value'])
self.app_name = app_name
smallest_index = find_random_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')
random_index = random.randint(0, len(synthetic_tasks) - 1) # Generate a random index
random_row = synthetic_tasks[random_index]
task = random_row['task']
solution = random_row['solution']
database = random_row['database']
self.task = task
self.simulation = ChatbotSimulation(
app_name=app_name,
app_description=app_description,
site_map=sitemap,
relevant_tables_per_page=relevant_tables_per_page,
database=database,
jinjia_prerender_page=jinjia_prerender_page,
task=task,
solution=solution,
log_location=f'conversation_log_{app_name}.txt',
openai_api_key=openai_api_key,
agent='Human'
)
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)
def chat(user_input, history, simulator_app):
"""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
trajectory = simulator_app.simulation.trajectory
write_task_data(app_name, idx, task, task_complete, task_completed_step, trajectory)
return response
def give_up(simulator_app):
"""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
trajectory = simulator_app.simulation.trajectory
write_task_data(app_name, idx, task, task_completed, task_completed_steps, trajectory)
return "Task marked as abandoned (Give-Up action)."
# Gradio Interface using ChatInterface
with gr.Blocks(fill_height=True) as demo:
# Simulator instance stored in gr.State for each session
simulator_state = gr.State(AppSimulator(openai_api_key=openai_api_key))
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",
additional_inputs=[simulator_state]
)
give_up_button = gr.Button("Give Up")
# Define the callback function to initialize the simulator and update status
def initialize_and_start_chat(sitemap, simulator_app):
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, simulator_state],
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=[simulator_state],
outputs=status # Update the status with the give-up message
)
# Launch the app
demo.launch()