Spaces:
Paused
Paused
Upload folder using huggingface_hub
Browse files- app.py +135 -24
- test_fetch_readme.py +47 -0
app.py
CHANGED
|
@@ -713,7 +713,36 @@ async def handle_background_polling(mentor_history, planning_history):
|
|
| 713 |
|
| 714 |
return updated_mentor, updated_planning
|
| 715 |
|
| 716 |
-
async def
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 717 |
"""Handle chat using run_manual_agent directly to support streaming tool calls."""
|
| 718 |
all_tools = await get_all_tools(include_jules=False)
|
| 719 |
|
|
@@ -739,10 +768,15 @@ async def handle_chat(message, history, persona="planning"):
|
|
| 739 |
base_system_message = MENTOR_SYSTEM_PROMPT if persona == "mentor" else PLANNING_SYSTEM_PROMPT
|
| 740 |
p_state = json.dumps(initial_project_state)
|
| 741 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 742 |
system_message = (
|
| 743 |
f"{base_system_message}\n\n"
|
| 744 |
f"Long-Term Memory/Context: {ltm_context}\n"
|
| 745 |
f"Project State: {p_state}"
|
|
|
|
| 746 |
)
|
| 747 |
|
| 748 |
lc_messages = convert_to_langchain_messages(history)
|
|
@@ -768,7 +802,7 @@ async def handle_chat(message, history, persona="planning"):
|
|
| 768 |
# Update memory at the end
|
| 769 |
await update_memory(long_term_store, namespace, lc_messages + [AIMessage(content=final_output)], ltm_context)
|
| 770 |
|
| 771 |
-
async def handle_close_ideate(history, persona="planning"):
|
| 772 |
if not history:
|
| 773 |
folders = get_ideation_logs()
|
| 774 |
# Returns: chat_col, structured_col, desc, tasks, repos, expect, api, prof, space, token, status, dropdown, dropdown_comm
|
|
@@ -778,7 +812,7 @@ async def handle_close_ideate(history, persona="planning"):
|
|
| 778 |
|
| 779 |
# 1. Extraction using alias-large (granular requests)
|
| 780 |
fields_config = {
|
| 781 |
-
"project_description": "
|
| 782 |
"tasks_tests": """Extract the Tasks and Tests following this EXACT 7-point template:
|
| 783 |
1. Estimation of Project Scope from 1-10 and with a presentation of the core parts
|
| 784 |
2. Project Description w/ vision for the project, concrete goals what it should be capable of, and future use cases, and future integrations into other projects,
|
|
@@ -804,7 +838,11 @@ async def handle_close_ideate(history, persona="planning"):
|
|
| 804 |
|
| 805 |
for key, instruction in fields_config.items():
|
| 806 |
try:
|
| 807 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 808 |
logger.info(f"Extracting {key} for {persona}...")
|
| 809 |
response = await ainvoke_with_retry(extraction_llm, prompt)
|
| 810 |
content = response.content
|
|
@@ -829,6 +867,8 @@ async def handle_close_ideate(history, persona="planning"):
|
|
| 829 |
f.write(str(content))
|
| 830 |
|
| 831 |
save_file("chat_log.txt", chat_text)
|
|
|
|
|
|
|
| 832 |
save_file("project_description.txt", extracted.get("project_description", ""))
|
| 833 |
save_file("tasks_tests.txt", extracted.get("tasks_tests", ""))
|
| 834 |
save_file("github_repos.txt", extracted.get("github_repos", ""))
|
|
@@ -843,6 +883,14 @@ async def handle_close_ideate(history, persona="planning"):
|
|
| 843 |
}
|
| 844 |
with open(os.path.join(folder_path, "hf_deployment_data.json"), "w") as f:
|
| 845 |
json.dump(hf_data, f)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 846 |
|
| 847 |
folders = get_ideation_logs()
|
| 848 |
|
|
@@ -943,9 +991,16 @@ async def handle_github_prep(idea_description, log_file, target_repo_input, hf_p
|
|
| 943 |
if os.path.exists(src):
|
| 944 |
shutil.copy2(src, os.path.join(jules_temp_dir, fname))
|
| 945 |
|
| 946 |
-
# Write
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 947 |
with open(os.path.join(jules_temp_dir, "project_context.md"), 'w') as f:
|
| 948 |
-
f.write(
|
| 949 |
|
| 950 |
# 5. Generate/Append to AGENTS.md
|
| 951 |
existing_agents_content = ""
|
|
@@ -1455,8 +1510,17 @@ async def update_fields_from_log(log_file):
|
|
| 1455 |
if "space_name" in params and not space: space = params["space_name"]
|
| 1456 |
|
| 1457 |
token = params.get("hf_token", "")
|
| 1458 |
-
|
| 1459 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1460 |
except: pass
|
| 1461 |
else:
|
| 1462 |
# Fallback to old file-based
|
|
@@ -1757,6 +1821,10 @@ with gr.Blocks() as demo:
|
|
| 1757 |
|
| 1758 |
with gr.Tab("Mentor Session"):
|
| 1759 |
with gr.Column(visible=True) as mentor_chat_col:
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1760 |
mentor_chatbot = gr.Chatbot()
|
| 1761 |
mentor_msg = gr.Textbox(label="Enter your idea or question")
|
| 1762 |
with gr.Row():
|
|
@@ -1780,15 +1848,19 @@ with gr.Blocks() as demo:
|
|
| 1780 |
|
| 1781 |
mentor_status = gr.Textbox(label="Session Status", interactive=False)
|
| 1782 |
|
| 1783 |
-
async def mentor_respond(message, chat_history):
|
| 1784 |
-
async for updated_history in handle_chat(message, chat_history, persona="mentor"):
|
| 1785 |
yield "", updated_history
|
| 1786 |
-
mentor_submit_btn.click(mentor_respond, [mentor_msg, mentor_chatbot], [mentor_msg, mentor_chatbot])
|
| 1787 |
-
mentor_msg.submit(mentor_respond, [mentor_msg, mentor_chatbot], [mentor_msg, mentor_chatbot])
|
| 1788 |
mentor_back_btn.click(lambda: (gr.update(visible=True), gr.update(visible=False)), None, [mentor_chat_col, mentor_structured_col])
|
| 1789 |
|
| 1790 |
with gr.Tab("Planning Session"):
|
| 1791 |
with gr.Column(visible=True) as planning_chat_col:
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1792 |
chatbot = gr.Chatbot()
|
| 1793 |
msg = gr.Textbox(label="Enter your idea or question")
|
| 1794 |
with gr.Row():
|
|
@@ -1812,12 +1884,12 @@ with gr.Blocks() as demo:
|
|
| 1812 |
|
| 1813 |
ideate_status = gr.Textbox(label="Session Status", interactive=False)
|
| 1814 |
|
| 1815 |
-
async def respond(message, chat_history):
|
| 1816 |
-
async for updated_history in handle_chat(message, chat_history, persona="planning"):
|
| 1817 |
yield "", updated_history
|
| 1818 |
|
| 1819 |
-
p_click = submit_btn.click(respond, [msg, chatbot], [msg, chatbot])
|
| 1820 |
-
p_submit = msg.submit(respond, [msg, chatbot], [msg, chatbot])
|
| 1821 |
plan_back_btn.click(lambda: (gr.update(visible=True), gr.update(visible=False)), None, [planning_chat_col, planning_structured_col])
|
| 1822 |
|
| 1823 |
with gr.Tab("Push Files") as push_files_tab:
|
|
@@ -1921,15 +1993,22 @@ with gr.Blocks() as demo:
|
|
| 1921 |
nudge_btn.click(handle_supervisor_nudge, inputs=[mon_session_id, log_dropdown_comm], outputs=[nudge_output])
|
| 1922 |
|
| 1923 |
# End Session Logic
|
| 1924 |
-
async def mentor_close_wrap(h):
|
| 1925 |
-
return await handle_close_ideate(h, persona="mentor")
|
| 1926 |
|
| 1927 |
-
async def planning_close_wrap(h):
|
| 1928 |
-
return await handle_close_ideate(h, persona="planning")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1929 |
|
| 1930 |
mentor_close_btn.click(
|
| 1931 |
mentor_close_wrap,
|
| 1932 |
-
[mentor_chatbot],
|
| 1933 |
[mentor_chat_col, mentor_structured_col, mentor_proj_desc, mentor_tasks_tests, mentor_repos, mentor_expectations, mentor_endpoints, mentor_prof, mentor_space, mentor_token, mentor_status, log_dropdown, log_dropdown_comm]
|
| 1934 |
)
|
| 1935 |
|
|
@@ -1937,13 +2016,26 @@ with gr.Blocks() as demo:
|
|
| 1937 |
|
| 1938 |
close_btn.click(
|
| 1939 |
planning_close_wrap,
|
| 1940 |
-
[chatbot],
|
| 1941 |
planning_outputs
|
| 1942 |
)
|
| 1943 |
|
| 1944 |
# Planning session auto-pipeline (trigger close after final answer)
|
| 1945 |
-
p_click.then(planning_close_wrap, [chatbot], planning_outputs)
|
| 1946 |
-
p_submit.then(planning_close_wrap, [chatbot], planning_outputs)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1947 |
|
| 1948 |
# Log Refresh Logic
|
| 1949 |
refresh_logs_btn_1.click(refresh_logs_ui, outputs=[log_dropdown, log_dropdown_comm])
|
|
@@ -1969,6 +2061,25 @@ with gr.Blocks() as demo:
|
|
| 1969 |
outputs=[repo_input]
|
| 1970 |
).then(fn=None, js="() => { document.querySelectorAll('button').forEach(b => { if(b.textContent.includes('Jules Communication')) b.click(); }); }")
|
| 1971 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1972 |
with gr.Tab("Upload"):
|
| 1973 |
hf_space_id_in = gr.Textbox(label="Hugging Face Space ID ({hf_profileID}/{spaceID})")
|
| 1974 |
with gr.Row():
|
|
|
|
| 713 |
|
| 714 |
return updated_mentor, updated_planning
|
| 715 |
|
| 716 |
+
async def fetch_readme(repo_url_input, branch="main"):
|
| 717 |
+
"""Fetch README.md from a GitHub repository."""
|
| 718 |
+
if not repo_url_input:
|
| 719 |
+
return ""
|
| 720 |
+
|
| 721 |
+
owner, repo = parse_github_repo_id(repo_url_input)
|
| 722 |
+
if not repo:
|
| 723 |
+
return ""
|
| 724 |
+
if not owner:
|
| 725 |
+
owner = "JsonLord"
|
| 726 |
+
|
| 727 |
+
github_token = get_github_token(owner)
|
| 728 |
+
# Use raw content to avoid base64 decoding manually if possible, or just use the standard API
|
| 729 |
+
headers = {"Authorization": f"token {github_token}", "Accept": "application/vnd.github.v3.raw"}
|
| 730 |
+
|
| 731 |
+
# Try different common README names
|
| 732 |
+
for name in ["README.md", "README", "readme.md"]:
|
| 733 |
+
url = f"https://api.github.com/repos/{owner}/{repo}/contents/{name}?ref={branch}"
|
| 734 |
+
try:
|
| 735 |
+
response = requests.get(url, headers=headers)
|
| 736 |
+
if response.status_code == 200:
|
| 737 |
+
logger.info(f"Successfully fetched {name} for {owner}/{repo} (branch: {branch})")
|
| 738 |
+
return response.text
|
| 739 |
+
except Exception as e:
|
| 740 |
+
logger.error(f"Error fetching {name} for {owner}/{repo}: {e}")
|
| 741 |
+
|
| 742 |
+
logger.warning(f"Could not find README for {owner}/{repo} (branch: {branch})")
|
| 743 |
+
return ""
|
| 744 |
+
|
| 745 |
+
async def handle_chat(message, history, persona="planning", readme_content=""):
|
| 746 |
"""Handle chat using run_manual_agent directly to support streaming tool calls."""
|
| 747 |
all_tools = await get_all_tools(include_jules=False)
|
| 748 |
|
|
|
|
| 768 |
base_system_message = MENTOR_SYSTEM_PROMPT if persona == "mentor" else PLANNING_SYSTEM_PROMPT
|
| 769 |
p_state = json.dumps(initial_project_state)
|
| 770 |
|
| 771 |
+
readme_context = ""
|
| 772 |
+
if readme_content:
|
| 773 |
+
readme_context = f"\n\n### ORIGINAL PROJECT CONTEXT (README.md)\nYou are helping to adapt and improve the following existing project:\n{readme_content}"
|
| 774 |
+
|
| 775 |
system_message = (
|
| 776 |
f"{base_system_message}\n\n"
|
| 777 |
f"Long-Term Memory/Context: {ltm_context}\n"
|
| 778 |
f"Project State: {p_state}"
|
| 779 |
+
f"{readme_context}"
|
| 780 |
)
|
| 781 |
|
| 782 |
lc_messages = convert_to_langchain_messages(history)
|
|
|
|
| 802 |
# Update memory at the end
|
| 803 |
await update_memory(long_term_store, namespace, lc_messages + [AIMessage(content=final_output)], ltm_context)
|
| 804 |
|
| 805 |
+
async def handle_close_ideate(history, persona="planning", readme_content="", repo_url="", branch="main"):
|
| 806 |
if not history:
|
| 807 |
folders = get_ideation_logs()
|
| 808 |
# Returns: chat_col, structured_col, desc, tasks, repos, expect, api, prof, space, token, status, dropdown, dropdown_comm
|
|
|
|
| 812 |
|
| 813 |
# 1. Extraction using alias-large (granular requests)
|
| 814 |
fields_config = {
|
| 815 |
+
"project_description": "Based on the original README (if provided) and the chat log, extract the Project Description. Focus on how the project is being adapted and improved. Include the vision, concrete goals, future use cases, and potential integrations.",
|
| 816 |
"tasks_tests": """Extract the Tasks and Tests following this EXACT 7-point template:
|
| 817 |
1. Estimation of Project Scope from 1-10 and with a presentation of the core parts
|
| 818 |
2. Project Description w/ vision for the project, concrete goals what it should be capable of, and future use cases, and future integrations into other projects,
|
|
|
|
| 838 |
|
| 839 |
for key, instruction in fields_config.items():
|
| 840 |
try:
|
| 841 |
+
readme_context = ""
|
| 842 |
+
if readme_content:
|
| 843 |
+
readme_context = f"ORIGINAL PROJECT README:\n{readme_content}\n\n"
|
| 844 |
+
|
| 845 |
+
prompt = f"{readme_context}{instruction}\n\nCHAT LOG:\n{chat_text}\n\nRespond ONLY with the extracted content for this field. Do not add conversational filler."
|
| 846 |
logger.info(f"Extracting {key} for {persona}...")
|
| 847 |
response = await ainvoke_with_retry(extraction_llm, prompt)
|
| 848 |
content = response.content
|
|
|
|
| 867 |
f.write(str(content))
|
| 868 |
|
| 869 |
save_file("chat_log.txt", chat_text)
|
| 870 |
+
if readme_content:
|
| 871 |
+
save_file("original_readme.md", readme_content)
|
| 872 |
save_file("project_description.txt", extracted.get("project_description", ""))
|
| 873 |
save_file("tasks_tests.txt", extracted.get("tasks_tests", ""))
|
| 874 |
save_file("github_repos.txt", extracted.get("github_repos", ""))
|
|
|
|
| 883 |
}
|
| 884 |
with open(os.path.join(folder_path, "hf_deployment_data.json"), "w") as f:
|
| 885 |
json.dump(hf_data, f)
|
| 886 |
+
|
| 887 |
+
# Repo Info
|
| 888 |
+
repo_info = {
|
| 889 |
+
"repo_url": repo_url,
|
| 890 |
+
"branch": branch
|
| 891 |
+
}
|
| 892 |
+
with open(os.path.join(folder_path, "repo_info.json"), "w") as f:
|
| 893 |
+
json.dump(repo_info, f)
|
| 894 |
|
| 895 |
folders = get_ideation_logs()
|
| 896 |
|
|
|
|
| 991 |
if os.path.exists(src):
|
| 992 |
shutil.copy2(src, os.path.join(jules_temp_dir, fname))
|
| 993 |
|
| 994 |
+
# Write Project_Context.md. Preference: original README, else bundled context.
|
| 995 |
+
final_context = context_md
|
| 996 |
+
readme_path = os.path.join(log_path, "original_readme.md")
|
| 997 |
+
if os.path.exists(readme_path):
|
| 998 |
+
with open(readme_path, "r") as f:
|
| 999 |
+
final_context = f.read()
|
| 1000 |
+
logger.info("Using original_readme.md for Project_Context.md")
|
| 1001 |
+
|
| 1002 |
with open(os.path.join(jules_temp_dir, "project_context.md"), 'w') as f:
|
| 1003 |
+
f.write(final_context)
|
| 1004 |
|
| 1005 |
# 5. Generate/Append to AGENTS.md
|
| 1006 |
existing_agents_content = ""
|
|
|
|
| 1510 |
if "space_name" in params and not space: space = params["space_name"]
|
| 1511 |
|
| 1512 |
token = params.get("hf_token", "")
|
| 1513 |
+
except: pass
|
| 1514 |
+
|
| 1515 |
+
repo_info_path = os.path.join(log_path, "repo_info.json")
|
| 1516 |
+
if os.path.exists(repo_info_path):
|
| 1517 |
+
try:
|
| 1518 |
+
with open(repo_info_path, "r") as f:
|
| 1519 |
+
rparams = json.load(f)
|
| 1520 |
+
target_repo = rparams.get("repo_url", "")
|
| 1521 |
+
# We can also update the default owner if we parse it
|
| 1522 |
+
if "/" in target_repo:
|
| 1523 |
+
github_owner = target_repo.split("/")[-2]
|
| 1524 |
except: pass
|
| 1525 |
else:
|
| 1526 |
# Fallback to old file-based
|
|
|
|
| 1821 |
|
| 1822 |
with gr.Tab("Mentor Session"):
|
| 1823 |
with gr.Column(visible=True) as mentor_chat_col:
|
| 1824 |
+
with gr.Row():
|
| 1825 |
+
mentor_repo_url = gr.Textbox(label="Project Repo (owner/repo or URL)", scale=3)
|
| 1826 |
+
mentor_branch = gr.Dropdown(label="Branch", choices=["main"], value="main", scale=1, allow_custom_value=True)
|
| 1827 |
+
mentor_readme_state = gr.State("")
|
| 1828 |
mentor_chatbot = gr.Chatbot()
|
| 1829 |
mentor_msg = gr.Textbox(label="Enter your idea or question")
|
| 1830 |
with gr.Row():
|
|
|
|
| 1848 |
|
| 1849 |
mentor_status = gr.Textbox(label="Session Status", interactive=False)
|
| 1850 |
|
| 1851 |
+
async def mentor_respond(message, chat_history, readme):
|
| 1852 |
+
async for updated_history in handle_chat(message, chat_history, persona="mentor", readme_content=readme):
|
| 1853 |
yield "", updated_history
|
| 1854 |
+
mentor_submit_btn.click(mentor_respond, [mentor_msg, mentor_chatbot, mentor_readme_state], [mentor_msg, mentor_chatbot])
|
| 1855 |
+
mentor_msg.submit(mentor_respond, [mentor_msg, mentor_chatbot, mentor_readme_state], [mentor_msg, mentor_chatbot])
|
| 1856 |
mentor_back_btn.click(lambda: (gr.update(visible=True), gr.update(visible=False)), None, [mentor_chat_col, mentor_structured_col])
|
| 1857 |
|
| 1858 |
with gr.Tab("Planning Session"):
|
| 1859 |
with gr.Column(visible=True) as planning_chat_col:
|
| 1860 |
+
with gr.Row():
|
| 1861 |
+
plan_repo_url = gr.Textbox(label="Project Repo (owner/repo or URL)", scale=3)
|
| 1862 |
+
plan_branch = gr.Dropdown(label="Branch", choices=["main"], value="main", scale=1, allow_custom_value=True)
|
| 1863 |
+
plan_readme_state = gr.State("")
|
| 1864 |
chatbot = gr.Chatbot()
|
| 1865 |
msg = gr.Textbox(label="Enter your idea or question")
|
| 1866 |
with gr.Row():
|
|
|
|
| 1884 |
|
| 1885 |
ideate_status = gr.Textbox(label="Session Status", interactive=False)
|
| 1886 |
|
| 1887 |
+
async def respond(message, chat_history, readme):
|
| 1888 |
+
async for updated_history in handle_chat(message, chat_history, persona="planning", readme_content=readme):
|
| 1889 |
yield "", updated_history
|
| 1890 |
|
| 1891 |
+
p_click = submit_btn.click(respond, [msg, chatbot, plan_readme_state], [msg, chatbot])
|
| 1892 |
+
p_submit = msg.submit(respond, [msg, chatbot, plan_readme_state], [msg, chatbot])
|
| 1893 |
plan_back_btn.click(lambda: (gr.update(visible=True), gr.update(visible=False)), None, [planning_chat_col, planning_structured_col])
|
| 1894 |
|
| 1895 |
with gr.Tab("Push Files") as push_files_tab:
|
|
|
|
| 1993 |
nudge_btn.click(handle_supervisor_nudge, inputs=[mon_session_id, log_dropdown_comm], outputs=[nudge_output])
|
| 1994 |
|
| 1995 |
# End Session Logic
|
| 1996 |
+
async def mentor_close_wrap(h, readme):
|
| 1997 |
+
return await handle_close_ideate(h, persona="mentor", readme_content=readme)
|
| 1998 |
|
| 1999 |
+
async def planning_close_wrap(h, readme):
|
| 2000 |
+
return await handle_close_ideate(h, persona="planning", readme_content=readme)
|
| 2001 |
+
|
| 2002 |
+
# End Session Logic
|
| 2003 |
+
async def mentor_close_wrap(h, readme, repo, branch):
|
| 2004 |
+
return await handle_close_ideate(h, persona="mentor", readme_content=readme, repo_url=repo, branch=branch)
|
| 2005 |
+
|
| 2006 |
+
async def planning_close_wrap(h, readme, repo, branch):
|
| 2007 |
+
return await handle_close_ideate(h, persona="planning", readme_content=readme, repo_url=repo, branch=branch)
|
| 2008 |
|
| 2009 |
mentor_close_btn.click(
|
| 2010 |
mentor_close_wrap,
|
| 2011 |
+
[mentor_chatbot, mentor_readme_state, mentor_repo_url, mentor_branch],
|
| 2012 |
[mentor_chat_col, mentor_structured_col, mentor_proj_desc, mentor_tasks_tests, mentor_repos, mentor_expectations, mentor_endpoints, mentor_prof, mentor_space, mentor_token, mentor_status, log_dropdown, log_dropdown_comm]
|
| 2013 |
)
|
| 2014 |
|
|
|
|
| 2016 |
|
| 2017 |
close_btn.click(
|
| 2018 |
planning_close_wrap,
|
| 2019 |
+
[chatbot, plan_readme_state, plan_repo_url, plan_branch],
|
| 2020 |
planning_outputs
|
| 2021 |
)
|
| 2022 |
|
| 2023 |
# Planning session auto-pipeline (trigger close after final answer)
|
| 2024 |
+
p_click.then(planning_close_wrap, [chatbot, plan_readme_state, plan_repo_url, plan_branch], planning_outputs)
|
| 2025 |
+
p_submit.then(planning_close_wrap, [chatbot, plan_readme_state, plan_repo_url, plan_branch], planning_outputs)
|
| 2026 |
+
|
| 2027 |
+
# Readme and Branch Loading Logic
|
| 2028 |
+
async def update_readme_state(repo, branch):
|
| 2029 |
+
content = await fetch_readme(repo, branch)
|
| 2030 |
+
return content
|
| 2031 |
+
|
| 2032 |
+
mentor_repo_url.change(load_github_branches, inputs=[mentor_repo_url], outputs=[mentor_branch])
|
| 2033 |
+
mentor_repo_url.change(update_readme_state, [mentor_repo_url, mentor_branch], [mentor_readme_state])
|
| 2034 |
+
mentor_branch.change(update_readme_state, [mentor_repo_url, mentor_branch], [mentor_readme_state])
|
| 2035 |
+
|
| 2036 |
+
plan_repo_url.change(load_github_branches, inputs=[plan_repo_url], outputs=[plan_branch])
|
| 2037 |
+
plan_repo_url.change(update_readme_state, [plan_repo_url, plan_branch], [plan_readme_state])
|
| 2038 |
+
plan_branch.change(update_readme_state, [plan_repo_url, plan_branch], [plan_readme_state])
|
| 2039 |
|
| 2040 |
# Log Refresh Logic
|
| 2041 |
refresh_logs_btn_1.click(refresh_logs_ui, outputs=[log_dropdown, log_dropdown_comm])
|
|
|
|
| 2061 |
outputs=[repo_input]
|
| 2062 |
).then(fn=None, js="() => { document.querySelectorAll('button').forEach(b => { if(b.textContent.includes('Jules Communication')) b.click(); }); }")
|
| 2063 |
|
| 2064 |
+
# Synchronization Logic for Repo and Branch across all tabs
|
| 2065 |
+
def sync_repo_val(val):
|
| 2066 |
+
return val, val, val, val
|
| 2067 |
+
|
| 2068 |
+
def sync_branch_val(val):
|
| 2069 |
+
return val, val, val, val
|
| 2070 |
+
|
| 2071 |
+
# Sync Repo URL
|
| 2072 |
+
mentor_repo_url.change(sync_repo_val, [mentor_repo_url], [plan_repo_url, target_repo, repo_input, mentor_repo_url])
|
| 2073 |
+
plan_repo_url.change(sync_repo_val, [plan_repo_url], [mentor_repo_url, target_repo, repo_input, plan_repo_url])
|
| 2074 |
+
target_repo.change(sync_repo_val, [target_repo], [mentor_repo_url, plan_repo_url, repo_input, target_repo])
|
| 2075 |
+
repo_input.change(sync_repo_val, [repo_input], [mentor_repo_url, plan_repo_url, target_repo, repo_input])
|
| 2076 |
+
|
| 2077 |
+
# Sync Branch
|
| 2078 |
+
mentor_branch.change(sync_branch_val, [mentor_branch], [plan_branch, target_branch, branch_dropdown, mentor_branch])
|
| 2079 |
+
plan_branch.change(sync_branch_val, [plan_branch], [mentor_branch, target_branch, branch_dropdown, plan_branch])
|
| 2080 |
+
target_branch.change(sync_branch_val, [target_branch], [mentor_branch, plan_branch, branch_dropdown, target_branch])
|
| 2081 |
+
branch_dropdown.change(sync_branch_val, [branch_dropdown], [mentor_branch, plan_branch, target_branch, branch_dropdown])
|
| 2082 |
+
|
| 2083 |
with gr.Tab("Upload"):
|
| 2084 |
hf_space_id_in = gr.Textbox(label="Hugging Face Space ID ({hf_profileID}/{spaceID})")
|
| 2085 |
with gr.Row():
|
test_fetch_readme.py
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import asyncio
|
| 2 |
+
import os
|
| 3 |
+
import requests
|
| 4 |
+
|
| 5 |
+
def parse_github_repo_id(input_str):
|
| 6 |
+
if not input_str: return "", ""
|
| 7 |
+
input_str = input_str.strip().strip("/")
|
| 8 |
+
if "github.com/" in input_str:
|
| 9 |
+
import re
|
| 10 |
+
match = re.search(r'github\.com/([^/\s]+)/([^/\s.]+)', input_str)
|
| 11 |
+
if match:
|
| 12 |
+
repo = match.group(2)
|
| 13 |
+
if repo.endswith(".git"): repo = repo[:-4]
|
| 14 |
+
return match.group(1), repo
|
| 15 |
+
if "/" in input_str:
|
| 16 |
+
parts = input_str.split("/")
|
| 17 |
+
if len(parts) >= 2:
|
| 18 |
+
repo = parts[-1]
|
| 19 |
+
if repo.endswith(".git"): repo = repo[:-4]
|
| 20 |
+
return parts[-2], repo
|
| 21 |
+
return "", input_str.replace(".git", "")
|
| 22 |
+
|
| 23 |
+
async def fetch_readme(repo_url_input, branch="main"):
|
| 24 |
+
owner, repo = parse_github_repo_id(repo_url_input)
|
| 25 |
+
headers = {"Accept": "application/vnd.github.v3.raw"}
|
| 26 |
+
token = os.environ.get("GITHUB_TOKEN")
|
| 27 |
+
if token:
|
| 28 |
+
headers["Authorization"] = f"token {token}"
|
| 29 |
+
|
| 30 |
+
url = f"https://api.github.com/repos/{owner}/{repo}/contents/README.md?ref={branch}"
|
| 31 |
+
print(f"Fetching {url}...")
|
| 32 |
+
response = requests.get(url, headers=headers)
|
| 33 |
+
if response.status_code == 200:
|
| 34 |
+
return response.text
|
| 35 |
+
else:
|
| 36 |
+
print(f"Status: {response.status_code}, Text: {response.text[:100]}")
|
| 37 |
+
return ""
|
| 38 |
+
|
| 39 |
+
async def main():
|
| 40 |
+
content = await fetch_readme("langchain-ai/langchain")
|
| 41 |
+
if content:
|
| 42 |
+
print("Success!")
|
| 43 |
+
else:
|
| 44 |
+
print("Failed.")
|
| 45 |
+
|
| 46 |
+
if __name__ == "__main__":
|
| 47 |
+
asyncio.run(main())
|