harvesthealth commited on
Commit
5abb71d
·
verified ·
1 Parent(s): 71baf0e

Upload folder using huggingface_hub

Browse files
Files changed (2) hide show
  1. app.py +64 -103
  2. requirements.txt +0 -1
app.py CHANGED
@@ -78,7 +78,7 @@ def patch_tinytroupe():
78
  # Modify the model call inside the loop
79
  old_call = "response = self._raw_model_call(model, chat_api_params)"
80
  new_call = """if parallel_retry:
81
- print("Attempting parallel call to alias-large and alias-huge.")
82
  response = self._raw_model_call_parallel(["alias-large", "alias-huge"], chat_api_params)
83
  if isinstance(response, Exception):
84
  raise response
@@ -87,10 +87,10 @@ def patch_tinytroupe():
87
  content = content.replace(old_call, new_call)
88
 
89
  # Update the 502 catch block
90
- pattern = r"if isinstance\(e, openai\.APIStatusError\) and e\.status_code == 502 and isinstance\(self, HelmholtzBlabladorClient\):.*?except Exception as fallback_e:.*?print\(f\"Fallback to OpenAI also failed: \{fallback_e\}\"\)"
91
 
92
  new_502_block = """if isinstance(e, openai.APIStatusError) and e.status_code == 502 and isinstance(self, HelmholtzBlabladorClient):
93
- print("Helmholtz API returned a 502 error. Waiting 35 seconds and enabling parallel retry...")
94
  parallel_retry = True
95
  time.sleep(35)"""
96
 
@@ -118,7 +118,7 @@ def setup_mkslides():
118
  content = content.replace('requires-python = ">=3.13"', 'requires-python = ">=3.12"')
119
  with open(pyproject_path, "w") as f:
120
  f.write(content)
121
-
122
  # Install dependencies and mkslides
123
  subprocess.run(["pip", "install", "./external/mkslides"])
124
  else:
@@ -126,13 +126,11 @@ def setup_mkslides():
126
 
127
  setup_mkslides()
128
 
 
129
  from github import Github, Auth
 
130
  from openai import OpenAI
131
- from fastapi import FastAPI
132
- import uvicorn
133
- import gradio as gr
134
- from gradio_logsview import LogsView, LogsViewRunner
135
-
136
 
137
  # Add external/TinyTroupe to sys.path
138
  TINYTROUPE_PATH = os.path.join(os.getcwd(), "external", "TinyTroupe")
@@ -241,10 +239,10 @@ def get_repo_branches(repo_full_name, github_client=None):
241
  # Fetch branches
242
  branches = list(repo.get_branches())
243
  add_log(f"Discovered {len(branches)} branches.")
244
-
245
  # Use ThreadPool to fetch commit dates in parallel to be MUCH faster
246
  branch_info = []
247
-
248
  def fetch_branch_date(b):
249
  try:
250
  commit = repo.get_commit(b.commit.sha)
@@ -254,7 +252,7 @@ def get_repo_branches(repo_full_name, github_client=None):
254
  date = commit.commit.author.date
255
  elif commit.commit and commit.commit.committer:
256
  date = commit.commit.committer.date
257
-
258
  if not date:
259
  date = datetime.min
260
  return (b.name, date)
@@ -263,14 +261,14 @@ def get_repo_branches(repo_full_name, github_client=None):
263
 
264
  with concurrent.futures.ThreadPoolExecutor(max_workers=20) as executor:
265
  branch_info = list(executor.map(fetch_branch_date, branches))
266
-
267
  # Sort by date descending
268
  branch_info.sort(key=lambda x: x[1], reverse=True)
269
  result = [b[0] for b in branch_info]
270
-
271
  if result:
272
  add_log(f"Successfully sorted {len(result)} branches. Latest: {result[0]}")
273
-
274
  return result
275
  except Exception as e:
276
  add_log(f"ERROR fetching branches: {e}")
@@ -443,7 +441,7 @@ def generate_persona_from_endpoint(theme, customer_profile):
443
  if not name:
444
  name_match = re.search(r"I am ([^,\.]+)", result)
445
  name = name_match.group(1) if name_match else f"User_{uuid.uuid4().hex[:4]}"
446
-
447
  return {
448
  "name": name,
449
  "minibio": result,
@@ -455,20 +453,20 @@ def generate_persona_from_endpoint(theme, customer_profile):
455
 
456
  def generate_personas(theme, customer_profile, num_personas):
457
  add_log(f"Generating {num_personas} personas...")
458
-
459
  # Try the new endpoint first
460
  final_personas = []
461
  for i in range(int(num_personas)):
462
  p = generate_persona_from_endpoint(theme, customer_profile)
463
  if p:
464
  final_personas.append(p)
465
-
466
  if len(final_personas) == int(num_personas):
467
  add_log("Successfully generated all personas from endpoint.")
468
  return final_personas
469
-
470
  add_log("Falling back to TinyTroupe logic for remaining personas...")
471
-
472
  # Ensure alias-large is used
473
  config_manager.update("model", "alias-large")
474
  config_manager.update("reasoning_model", "alias-large")
@@ -609,7 +607,6 @@ def start_and_monitor_sessions(personas, tasks, url):
609
  yield "Error: JULES_API_KEY not set.", ""
610
  return
611
 
612
- import requests # moved here as it was not globally imported
613
  with open("jules_template.md", "r") as f:
614
  template = f.read()
615
 
@@ -617,7 +614,7 @@ def start_and_monitor_sessions(personas, tasks, url):
617
  for persona in personas:
618
  # Generate unique report ID
619
  report_id = str(uuid.uuid4())[:8]
620
-
621
  # Format prompt
622
  prompt = template.replace("{{persona_context}}", json.dumps(persona))
623
  prompt = prompt.replace("{{tasks_list}}", json.dumps(tasks))
@@ -687,9 +684,9 @@ def get_reports_in_branch(repo_full_name, branch_name, filter_type=None):
687
  try:
688
  repo = gh.get_repo(repo_full_name)
689
  add_log(f"Scanning branch {branch_name} for reports (filter: {filter_type})...")
690
-
691
  exclude_files = {"jules_template.md", "readme.md", "contributing.md", "license.md"}
692
-
693
  # Method 1: Check user_experience_reports directory
694
  reports = []
695
  try:
@@ -699,16 +696,16 @@ def get_reports_in_branch(repo_full_name, branch_name, filter_type=None):
699
  if name.endswith(".md"):
700
  filename = name.lower()
701
  if filename in exclude_files: continue
702
-
703
  # Optional filtering
704
  if filter_type == "report" and "slide" in filename: continue
705
  if filter_type == "slides" and "report" in filename: continue
706
-
707
  path = f"user_experience_reports/{name}"
708
  reports.append(path)
709
  except:
710
  pass
711
-
712
  # Method 2: Recursive scan for ALL Markdown files
713
  add_log("Deep scanning repository for all Markdown files...")
714
  tree = repo.get_git_tree(branch_name, recursive=True).tree
@@ -718,14 +715,14 @@ def get_reports_in_branch(repo_full_name, branch_name, filter_type=None):
718
  filename = os.path.basename(path).lower()
719
  if filename in exclude_files:
720
  continue
721
-
722
  # Optional filtering
723
  if filter_type == "report" and "slide" in filename: continue
724
  if filter_type == "slides" and "report" in filename: continue
725
 
726
  if path not in reports:
727
  reports.append(path)
728
-
729
  # Sort by relevance
730
  def sort_key(path):
731
  p_lower = path.lower()
@@ -733,20 +730,20 @@ def get_reports_in_branch(repo_full_name, branch_name, filter_type=None):
733
  # Highest priority: specific report.md and slides.md in user_experience_reports
734
  if filter_type == "report" and p_lower == "user_experience_reports/report.md": score -= 1000
735
  if filter_type == "slides" and p_lower == "user_experience_reports/slides.md": score -= 1000
736
-
737
  # High priority: other files in user_experience_reports
738
  if "user_experience_reports" in p_lower: score -= 100
739
-
740
  # Medium priority: keywords in filename
741
  filename = os.path.basename(p_lower)
742
  if "report" in filename: score -= 50
743
  if "slide" in filename: score -= 30
744
  if "ux" in filename: score -= 20
745
-
746
  return (score, p_lower)
747
 
748
  reports.sort(key=sort_key)
749
-
750
  add_log(f"Discovered {len(reports)} potential Markdown files.")
751
  return reports
752
  except Exception as e:
@@ -775,7 +772,6 @@ def pull_report_from_pr(pr_url):
775
  if not gh:
776
  return "Error: GITHUB_TOKEN not set."
777
 
778
- import requests # moved here as it was not globally imported
779
  try:
780
  # Extract repo and PR number from URL
781
  match = re.search(r"github\.com/([^/]+/[^/]+)/pull/(\d+)", pr_url)
@@ -800,7 +796,7 @@ def pull_report_from_pr(pr_url):
800
  return content
801
  except:
802
  return "Report not found yet in this branch."
803
-
804
  # Get the first report found
805
  content = get_report_content(repo_full_name, branch_name, reports[0])
806
  processed_prs.add(pr_number)
@@ -815,11 +811,11 @@ def render_slides(repo_full_name, branch_name, report_path):
815
  return "Error: GitHub client not initialized. Check your token."
816
  if not repo_full_name or not branch_name or not report_path:
817
  return "Please select a repository, branch, and report."
818
-
819
  try:
820
  repo = gh.get_repo(repo_full_name)
821
  content = None
822
-
823
  # Method 1: Check for multi-file slides folder
824
  # We check this first if the report_path is in user_experience_reports or if it's default
825
  if "user_experience_reports" in report_path:
@@ -830,7 +826,7 @@ def render_slides(repo_full_name, branch_name, report_path):
830
  add_log(f"Multi-file slides folder found in branch {branch_name}. Merging...")
831
  slide_files = [c for c in folder_contents if c.name.endswith(".md")]
832
  slide_files.sort(key=lambda x: x.name)
833
-
834
  merged_content = ""
835
  for i, sf in enumerate(slide_files):
836
  file_data = repo.get_contents(sf.path, ref=branch_name)
@@ -838,7 +834,7 @@ def render_slides(repo_full_name, branch_name, report_path):
838
  if i > 0:
839
  merged_content += "\n\n---\n\n"
840
  merged_content += slide_text
841
-
842
  content = merged_content
843
  add_log(f"Successfully merged {len(slide_files)} slides.")
844
  except:
@@ -878,29 +874,29 @@ def render_slides(repo_full_name, branch_name, report_path):
878
  else:
879
  add_log(f"Error fetching slides: {e}")
880
  return f"Error fetching slides: {str(e)}"
881
-
882
  # Prepare workspace
883
  report_id = str(uuid.uuid4())[:8]
884
  work_dir = f"slides_work_{report_id}"
885
  os.makedirs(work_dir, exist_ok=True)
886
  with open(f"{work_dir}/index.md", "w") as f:
887
  f.write(content)
888
-
889
  # Run mkslides
890
  output_dir = f"slides_site_{report_id}"
891
  # Ensure we have a clean output dir
892
  if os.path.exists(output_dir):
893
  shutil.rmtree(output_dir)
894
-
895
  subprocess.run(["mkslides", "build", work_dir, "--site-dir", output_dir])
896
-
897
  if os.path.exists(f"{output_dir}/index.html"):
898
- # Return IFrame pointing to the generated site.
899
  # We use /file= prefix which Gradio uses to serve files in allowed_paths.
900
  return f'<iframe src="/file={os.path.abspath(output_dir)}/index.html" width="100%" height="600px"></iframe>'
901
  else:
902
  return "Failed to render slides."
903
-
904
  except Exception as e:
905
  print(f"Error rendering slides: {e}")
906
  return f"Error rendering slides: {str(e)}"
@@ -918,7 +914,7 @@ def monitor_repo_for_reports():
918
  new_content_found = False
919
  for branch_name in branches[:25]: # Check top 25 recent branches
920
  reports = get_reports_in_branch(REPO_NAME, branch_name, filter_type="report")
921
-
922
  for report_file in reports:
923
  report_key = f"{branch_name}/{report_file}"
924
  if report_key not in processed_prs:
@@ -931,7 +927,7 @@ def monitor_repo_for_reports():
931
  add_log(f"New report found: {report_file} in {branch_name}")
932
  except:
933
  continue
934
-
935
  if not new_content_found:
936
  add_log("No new reports found in recent branches.")
937
 
@@ -940,22 +936,6 @@ def monitor_repo_for_reports():
940
  add_log(f"Error monitoring repo: {e}")
941
  return all_discovered_reports
942
 
943
- # Fast API setup
944
- api_app = FastAPI()
945
-
946
- @api_app.get("/health")
947
- def health():
948
- return {"status": "running", "timestamp": datetime.now().isoformat()}
949
-
950
- @api_app.get("/api/repos")
951
- def api_get_repos():
952
- return {"repos": get_user_repos()}
953
-
954
- @api_app.post("/api/generate_tasks")
955
- def api_generate_tasks(theme: str, profile: str):
956
- tasks = generate_tasks(theme, profile)
957
- return {"tasks": tasks}
958
-
959
  # Gradio UI
960
  with gr.Blocks() as demo:
961
  gr.Markdown("# Jules UX Analysis Orchestrator")
@@ -985,15 +965,15 @@ with gr.Blocks() as demo:
985
  rv_repo_select = gr.Dropdown(label="Repository", choices=get_user_repos(), value=REPO_NAME)
986
  rv_branch_select = gr.Dropdown(label="Branch", choices=get_repo_branches(REPO_NAME))
987
  rv_refresh_branches_btn = gr.Button("Refresh Branches")
988
-
989
  with gr.Row():
990
  rv_report_select = gr.Dropdown(label="Select Report", choices=[], allow_custom_value=True)
991
  rv_load_report_btn = gr.Button("Load Report")
992
-
993
  rv_manual_path = gr.Textbox(label="Or enter manual path (e.g. docs/my_report.md)", placeholder="docs/my_report.md")
994
 
995
  rv_report_viewer = gr.Markdown(label="Report Content")
996
-
997
  def rv_update_branches(repo_name):
998
  branches = get_repo_branches(repo_name)
999
  latest = branches[0] if branches else "main"
@@ -1018,11 +998,11 @@ with gr.Blocks() as demo:
1018
  sl_repo_select = gr.Dropdown(label="Repository", choices=get_user_repos(), value=REPO_NAME)
1019
  sl_branch_select = gr.Dropdown(label="Branch", choices=get_repo_branches(REPO_NAME))
1020
  sl_refresh_branches_btn = gr.Button("Refresh Branches")
1021
-
1022
  with gr.Row():
1023
  sl_report_select = gr.Dropdown(label="Select Report/Slides File", choices=[], allow_custom_value=True)
1024
  sl_render_btn = gr.Button("Render Slideshow")
1025
-
1026
  sl_manual_path = gr.Textbox(label="Or enter manual path (e.g. docs/slides.md)", placeholder="docs/slides.md")
1027
 
1028
  slideshow_display = gr.HTML(label="Slideshow")
@@ -1046,17 +1026,14 @@ with gr.Blocks() as demo:
1046
  sl_render_btn.click(fn=sl_render_wrapper, inputs=[sl_repo_select, sl_branch_select, sl_report_select, sl_manual_path], outputs=[slideshow_display])
1047
 
1048
  with gr.Tab("System"):
1049
- gr.Markdown("### System Diagnostics & Real-time Logs")
1050
-
1051
  with gr.Row():
1052
- with gr.Column():
1053
- sys_token_input = gr.Textbox(label="GitHub Token (Leave blank for default)", type="password")
1054
- sys_repo_input = gr.Textbox(label="Repository (e.g., JsonLord/tiny_web)", value=REPO_NAME)
1055
- sys_test_btn = gr.Button("Test Connection & Fetch Branches")
1056
-
1057
- with gr.Column():
1058
- sys_status = gr.Textbox(label="Connection Status", interactive=False)
1059
- sys_branch_output = gr.JSON(label="Discovered Branches")
1060
 
1061
  def system_test(token, repo_name):
1062
  global gh, GITHUB_TOKEN
@@ -1070,21 +1047,21 @@ with gr.Blocks() as demo:
1070
  else:
1071
  add_log("ERROR: No token provided and default client is missing.")
1072
  return "Error: No GitHub client available. Please provide a token.", None
1073
-
1074
  user = test_gh.get_user().login
1075
  add_log(f"Successfully authenticated as {user}")
1076
-
1077
  # Update global client if token was provided
1078
  if token:
1079
  gh = test_gh
1080
  GITHUB_TOKEN = token
1081
  add_log("Global GitHub client updated with new token.")
1082
-
1083
  status = f"Success: Connected as {user} to {repo_name}"
1084
-
1085
  # Use existing optimized logic
1086
  branches = get_repo_branches(repo_name, github_client=test_gh)
1087
-
1088
  return status, branches
1089
  except Exception as e:
1090
  add_log(f"System Test Error: {str(e)}")
@@ -1092,26 +1069,12 @@ with gr.Blocks() as demo:
1092
 
1093
  sys_test_btn.click(fn=system_test, inputs=[sys_token_input, sys_repo_input], outputs=[sys_status, sys_branch_output])
1094
 
1095
- gr.Markdown("#### Process Logs")
1096
- logs_view = LogsView()
1097
-
1098
- def run_diagnostics():
1099
- runner = LogsViewRunner()
1100
- yield from runner.run_python(lambda: print("Running System Diagnostics..."))
1101
- yield from runner.run_python(lambda: print(f"GitHub Client: {'Initialized' if gh else 'Missing'}"))
1102
- yield from runner.run_python(lambda: print(f"OS Path: {os.getcwd()}"))
1103
- yield from runner.run_command(["pip", "show", "gradio"])
1104
- yield runner.log("Diagnostics complete.")
1105
-
1106
- diag_btn = gr.Button("Run Diagnostics & Show Logs")
1107
- diag_btn.click(fn=run_diagnostics, outputs=logs_view)
1108
-
1109
  with gr.Tab("Live Monitoring"):
1110
  gr.Markdown("### Live Monitoring of JsonLord/tiny_web for new UX reports")
1111
  live_log = gr.Textbox(label="GitHub Connection Logs", lines=5, interactive=False)
1112
  refresh_feed_btn = gr.Button("Refresh Feed Now")
1113
  global_feed = gr.Markdown(value="Waiting for new reports...")
1114
-
1115
  def monitor_and_log():
1116
  reports = monitor_repo_for_reports()
1117
  logs = "\n".join(github_logs[-20:])
@@ -1135,8 +1098,6 @@ with gr.Blocks() as demo:
1135
  outputs=[status_output, report_output]
1136
  )
1137
 
1138
- app = gr.mount_gradio_app(api_app, demo, path="/")
1139
-
1140
  if __name__ == "__main__":
1141
  # Startup connectivity check
1142
  print("--- STARTUP GITHUB CONNECTIVITY CHECK ---")
@@ -1145,7 +1106,7 @@ if __name__ == "__main__":
1145
  token_source = "GITHUB_TOKEN"
1146
  elif os.environ.get("GITHUB_API_TOKEN"):
1147
  token_source = "GITHUB_API_TOKEN"
1148
-
1149
  print(f"Token Source: {token_source}")
1150
 
1151
  if gh is None:
@@ -1154,7 +1115,7 @@ if __name__ == "__main__":
1154
  try:
1155
  user = gh.get_user().login
1156
  print(f"SUCCESS: Logged in to GitHub as: {user}")
1157
-
1158
  # Test branch fetching for REPO_NAME
1159
  print(f"Testing branch fetch for {REPO_NAME}...")
1160
  test_branches = get_repo_branches(REPO_NAME)
@@ -1164,4 +1125,4 @@ if __name__ == "__main__":
1164
  print("-----------------------------------------")
1165
 
1166
  # Allow current directory for file serving, specifically for slides_site_*
1167
- uvicorn.run(app, host="0.0.0.0", port=7860)
 
78
  # Modify the model call inside the loop
79
  old_call = "response = self._raw_model_call(model, chat_api_params)"
80
  new_call = """if parallel_retry:
81
+ logger.info("Attempting parallel call to alias-large and alias-huge.")
82
  response = self._raw_model_call_parallel(["alias-large", "alias-huge"], chat_api_params)
83
  if isinstance(response, Exception):
84
  raise response
 
87
  content = content.replace(old_call, new_call)
88
 
89
  # Update the 502 catch block
90
+ pattern = r"if isinstance\(e, openai\.APIStatusError\) and e\.status_code == 502 and isinstance\(self, HelmholtzBlabladorClient\):.*?except Exception as fallback_e:.*?logger\.error\(f\"Fallback to OpenAI also failed: \{fallback_e\}\"\)"
91
 
92
  new_502_block = """if isinstance(e, openai.APIStatusError) and e.status_code == 502 and isinstance(self, HelmholtzBlabladorClient):
93
+ logger.warning("Helmholtz API returned a 502 error. Waiting 35 seconds and enabling parallel retry...")
94
  parallel_retry = True
95
  time.sleep(35)"""
96
 
 
118
  content = content.replace('requires-python = ">=3.13"', 'requires-python = ">=3.12"')
119
  with open(pyproject_path, "w") as f:
120
  f.write(content)
121
+
122
  # Install dependencies and mkslides
123
  subprocess.run(["pip", "install", "./external/mkslides"])
124
  else:
 
126
 
127
  setup_mkslides()
128
 
129
+ import gradio as gr
130
  from github import Github, Auth
131
+ import requests
132
  from openai import OpenAI
133
+ import logging
 
 
 
 
134
 
135
  # Add external/TinyTroupe to sys.path
136
  TINYTROUPE_PATH = os.path.join(os.getcwd(), "external", "TinyTroupe")
 
239
  # Fetch branches
240
  branches = list(repo.get_branches())
241
  add_log(f"Discovered {len(branches)} branches.")
242
+
243
  # Use ThreadPool to fetch commit dates in parallel to be MUCH faster
244
  branch_info = []
245
+
246
  def fetch_branch_date(b):
247
  try:
248
  commit = repo.get_commit(b.commit.sha)
 
252
  date = commit.commit.author.date
253
  elif commit.commit and commit.commit.committer:
254
  date = commit.commit.committer.date
255
+
256
  if not date:
257
  date = datetime.min
258
  return (b.name, date)
 
261
 
262
  with concurrent.futures.ThreadPoolExecutor(max_workers=20) as executor:
263
  branch_info = list(executor.map(fetch_branch_date, branches))
264
+
265
  # Sort by date descending
266
  branch_info.sort(key=lambda x: x[1], reverse=True)
267
  result = [b[0] for b in branch_info]
268
+
269
  if result:
270
  add_log(f"Successfully sorted {len(result)} branches. Latest: {result[0]}")
271
+
272
  return result
273
  except Exception as e:
274
  add_log(f"ERROR fetching branches: {e}")
 
441
  if not name:
442
  name_match = re.search(r"I am ([^,\.]+)", result)
443
  name = name_match.group(1) if name_match else f"User_{uuid.uuid4().hex[:4]}"
444
+
445
  return {
446
  "name": name,
447
  "minibio": result,
 
453
 
454
  def generate_personas(theme, customer_profile, num_personas):
455
  add_log(f"Generating {num_personas} personas...")
456
+
457
  # Try the new endpoint first
458
  final_personas = []
459
  for i in range(int(num_personas)):
460
  p = generate_persona_from_endpoint(theme, customer_profile)
461
  if p:
462
  final_personas.append(p)
463
+
464
  if len(final_personas) == int(num_personas):
465
  add_log("Successfully generated all personas from endpoint.")
466
  return final_personas
467
+
468
  add_log("Falling back to TinyTroupe logic for remaining personas...")
469
+
470
  # Ensure alias-large is used
471
  config_manager.update("model", "alias-large")
472
  config_manager.update("reasoning_model", "alias-large")
 
607
  yield "Error: JULES_API_KEY not set.", ""
608
  return
609
 
 
610
  with open("jules_template.md", "r") as f:
611
  template = f.read()
612
 
 
614
  for persona in personas:
615
  # Generate unique report ID
616
  report_id = str(uuid.uuid4())[:8]
617
+
618
  # Format prompt
619
  prompt = template.replace("{{persona_context}}", json.dumps(persona))
620
  prompt = prompt.replace("{{tasks_list}}", json.dumps(tasks))
 
684
  try:
685
  repo = gh.get_repo(repo_full_name)
686
  add_log(f"Scanning branch {branch_name} for reports (filter: {filter_type})...")
687
+
688
  exclude_files = {"jules_template.md", "readme.md", "contributing.md", "license.md"}
689
+
690
  # Method 1: Check user_experience_reports directory
691
  reports = []
692
  try:
 
696
  if name.endswith(".md"):
697
  filename = name.lower()
698
  if filename in exclude_files: continue
699
+
700
  # Optional filtering
701
  if filter_type == "report" and "slide" in filename: continue
702
  if filter_type == "slides" and "report" in filename: continue
703
+
704
  path = f"user_experience_reports/{name}"
705
  reports.append(path)
706
  except:
707
  pass
708
+
709
  # Method 2: Recursive scan for ALL Markdown files
710
  add_log("Deep scanning repository for all Markdown files...")
711
  tree = repo.get_git_tree(branch_name, recursive=True).tree
 
715
  filename = os.path.basename(path).lower()
716
  if filename in exclude_files:
717
  continue
718
+
719
  # Optional filtering
720
  if filter_type == "report" and "slide" in filename: continue
721
  if filter_type == "slides" and "report" in filename: continue
722
 
723
  if path not in reports:
724
  reports.append(path)
725
+
726
  # Sort by relevance
727
  def sort_key(path):
728
  p_lower = path.lower()
 
730
  # Highest priority: specific report.md and slides.md in user_experience_reports
731
  if filter_type == "report" and p_lower == "user_experience_reports/report.md": score -= 1000
732
  if filter_type == "slides" and p_lower == "user_experience_reports/slides.md": score -= 1000
733
+
734
  # High priority: other files in user_experience_reports
735
  if "user_experience_reports" in p_lower: score -= 100
736
+
737
  # Medium priority: keywords in filename
738
  filename = os.path.basename(p_lower)
739
  if "report" in filename: score -= 50
740
  if "slide" in filename: score -= 30
741
  if "ux" in filename: score -= 20
742
+
743
  return (score, p_lower)
744
 
745
  reports.sort(key=sort_key)
746
+
747
  add_log(f"Discovered {len(reports)} potential Markdown files.")
748
  return reports
749
  except Exception as e:
 
772
  if not gh:
773
  return "Error: GITHUB_TOKEN not set."
774
 
 
775
  try:
776
  # Extract repo and PR number from URL
777
  match = re.search(r"github\.com/([^/]+/[^/]+)/pull/(\d+)", pr_url)
 
796
  return content
797
  except:
798
  return "Report not found yet in this branch."
799
+
800
  # Get the first report found
801
  content = get_report_content(repo_full_name, branch_name, reports[0])
802
  processed_prs.add(pr_number)
 
811
  return "Error: GitHub client not initialized. Check your token."
812
  if not repo_full_name or not branch_name or not report_path:
813
  return "Please select a repository, branch, and report."
814
+
815
  try:
816
  repo = gh.get_repo(repo_full_name)
817
  content = None
818
+
819
  # Method 1: Check for multi-file slides folder
820
  # We check this first if the report_path is in user_experience_reports or if it's default
821
  if "user_experience_reports" in report_path:
 
826
  add_log(f"Multi-file slides folder found in branch {branch_name}. Merging...")
827
  slide_files = [c for c in folder_contents if c.name.endswith(".md")]
828
  slide_files.sort(key=lambda x: x.name)
829
+
830
  merged_content = ""
831
  for i, sf in enumerate(slide_files):
832
  file_data = repo.get_contents(sf.path, ref=branch_name)
 
834
  if i > 0:
835
  merged_content += "\n\n---\n\n"
836
  merged_content += slide_text
837
+
838
  content = merged_content
839
  add_log(f"Successfully merged {len(slide_files)} slides.")
840
  except:
 
874
  else:
875
  add_log(f"Error fetching slides: {e}")
876
  return f"Error fetching slides: {str(e)}"
877
+
878
  # Prepare workspace
879
  report_id = str(uuid.uuid4())[:8]
880
  work_dir = f"slides_work_{report_id}"
881
  os.makedirs(work_dir, exist_ok=True)
882
  with open(f"{work_dir}/index.md", "w") as f:
883
  f.write(content)
884
+
885
  # Run mkslides
886
  output_dir = f"slides_site_{report_id}"
887
  # Ensure we have a clean output dir
888
  if os.path.exists(output_dir):
889
  shutil.rmtree(output_dir)
890
+
891
  subprocess.run(["mkslides", "build", work_dir, "--site-dir", output_dir])
892
+
893
  if os.path.exists(f"{output_dir}/index.html"):
894
+ # Return IFrame pointing to the generated site.
895
  # We use /file= prefix which Gradio uses to serve files in allowed_paths.
896
  return f'<iframe src="/file={os.path.abspath(output_dir)}/index.html" width="100%" height="600px"></iframe>'
897
  else:
898
  return "Failed to render slides."
899
+
900
  except Exception as e:
901
  print(f"Error rendering slides: {e}")
902
  return f"Error rendering slides: {str(e)}"
 
914
  new_content_found = False
915
  for branch_name in branches[:25]: # Check top 25 recent branches
916
  reports = get_reports_in_branch(REPO_NAME, branch_name, filter_type="report")
917
+
918
  for report_file in reports:
919
  report_key = f"{branch_name}/{report_file}"
920
  if report_key not in processed_prs:
 
927
  add_log(f"New report found: {report_file} in {branch_name}")
928
  except:
929
  continue
930
+
931
  if not new_content_found:
932
  add_log("No new reports found in recent branches.")
933
 
 
936
  add_log(f"Error monitoring repo: {e}")
937
  return all_discovered_reports
938
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
939
  # Gradio UI
940
  with gr.Blocks() as demo:
941
  gr.Markdown("# Jules UX Analysis Orchestrator")
 
965
  rv_repo_select = gr.Dropdown(label="Repository", choices=get_user_repos(), value=REPO_NAME)
966
  rv_branch_select = gr.Dropdown(label="Branch", choices=get_repo_branches(REPO_NAME))
967
  rv_refresh_branches_btn = gr.Button("Refresh Branches")
968
+
969
  with gr.Row():
970
  rv_report_select = gr.Dropdown(label="Select Report", choices=[], allow_custom_value=True)
971
  rv_load_report_btn = gr.Button("Load Report")
972
+
973
  rv_manual_path = gr.Textbox(label="Or enter manual path (e.g. docs/my_report.md)", placeholder="docs/my_report.md")
974
 
975
  rv_report_viewer = gr.Markdown(label="Report Content")
976
+
977
  def rv_update_branches(repo_name):
978
  branches = get_repo_branches(repo_name)
979
  latest = branches[0] if branches else "main"
 
998
  sl_repo_select = gr.Dropdown(label="Repository", choices=get_user_repos(), value=REPO_NAME)
999
  sl_branch_select = gr.Dropdown(label="Branch", choices=get_repo_branches(REPO_NAME))
1000
  sl_refresh_branches_btn = gr.Button("Refresh Branches")
1001
+
1002
  with gr.Row():
1003
  sl_report_select = gr.Dropdown(label="Select Report/Slides File", choices=[], allow_custom_value=True)
1004
  sl_render_btn = gr.Button("Render Slideshow")
1005
+
1006
  sl_manual_path = gr.Textbox(label="Or enter manual path (e.g. docs/slides.md)", placeholder="docs/slides.md")
1007
 
1008
  slideshow_display = gr.HTML(label="Slideshow")
 
1026
  sl_render_btn.click(fn=sl_render_wrapper, inputs=[sl_repo_select, sl_branch_select, sl_report_select, sl_manual_path], outputs=[slideshow_display])
1027
 
1028
  with gr.Tab("System"):
1029
+ gr.Markdown("### System Diagnostics & Manual Connection")
 
1030
  with gr.Row():
1031
+ sys_token_input = gr.Textbox(label="GitHub Token (Leave blank for default)", type="password")
1032
+ sys_repo_input = gr.Textbox(label="Repository (e.g., JsonLord/tiny_web)", value=REPO_NAME)
1033
+ sys_test_btn = gr.Button("Test Connection & Fetch Branches")
1034
+
1035
+ sys_status = gr.Textbox(label="Connection Status", interactive=False)
1036
+ sys_branch_output = gr.JSON(label="Discovered Branches")
 
 
1037
 
1038
  def system_test(token, repo_name):
1039
  global gh, GITHUB_TOKEN
 
1047
  else:
1048
  add_log("ERROR: No token provided and default client is missing.")
1049
  return "Error: No GitHub client available. Please provide a token.", None
1050
+
1051
  user = test_gh.get_user().login
1052
  add_log(f"Successfully authenticated as {user}")
1053
+
1054
  # Update global client if token was provided
1055
  if token:
1056
  gh = test_gh
1057
  GITHUB_TOKEN = token
1058
  add_log("Global GitHub client updated with new token.")
1059
+
1060
  status = f"Success: Connected as {user} to {repo_name}"
1061
+
1062
  # Use existing optimized logic
1063
  branches = get_repo_branches(repo_name, github_client=test_gh)
1064
+
1065
  return status, branches
1066
  except Exception as e:
1067
  add_log(f"System Test Error: {str(e)}")
 
1069
 
1070
  sys_test_btn.click(fn=system_test, inputs=[sys_token_input, sys_repo_input], outputs=[sys_status, sys_branch_output])
1071
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1072
  with gr.Tab("Live Monitoring"):
1073
  gr.Markdown("### Live Monitoring of JsonLord/tiny_web for new UX reports")
1074
  live_log = gr.Textbox(label="GitHub Connection Logs", lines=5, interactive=False)
1075
  refresh_feed_btn = gr.Button("Refresh Feed Now")
1076
  global_feed = gr.Markdown(value="Waiting for new reports...")
1077
+
1078
  def monitor_and_log():
1079
  reports = monitor_repo_for_reports()
1080
  logs = "\n".join(github_logs[-20:])
 
1098
  outputs=[status_output, report_output]
1099
  )
1100
 
 
 
1101
  if __name__ == "__main__":
1102
  # Startup connectivity check
1103
  print("--- STARTUP GITHUB CONNECTIVITY CHECK ---")
 
1106
  token_source = "GITHUB_TOKEN"
1107
  elif os.environ.get("GITHUB_API_TOKEN"):
1108
  token_source = "GITHUB_API_TOKEN"
1109
+
1110
  print(f"Token Source: {token_source}")
1111
 
1112
  if gh is None:
 
1115
  try:
1116
  user = gh.get_user().login
1117
  print(f"SUCCESS: Logged in to GitHub as: {user}")
1118
+
1119
  # Test branch fetching for REPO_NAME
1120
  print(f"Testing branch fetch for {REPO_NAME}...")
1121
  test_branches = get_repo_branches(REPO_NAME)
 
1125
  print("-----------------------------------------")
1126
 
1127
  # Allow current directory for file serving, specifically for slides_site_*
1128
+ demo.launch(allowed_paths=[os.getcwd()])
requirements.txt CHANGED
@@ -26,4 +26,3 @@ huggingface-hub
26
  lxml_html_clean
27
  beautifulsoup4
28
  playwright
29
- huggingface_hub==0.19.4
 
26
  lxml_html_clean
27
  beautifulsoup4
28
  playwright