MoHamdyy commited on
Commit
59c2194
Β·
1 Parent(s): 1689930

Add application file

Browse files
Files changed (1) hide show
  1. app.py +280 -0
app.py ADDED
@@ -0,0 +1,280 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr # type:ignore
2
+ import os
3
+ from core.github_client import fetch_beginner_issues
4
+ from core.llm_handler import get_simple_issue_suggestion, plan_onboarding_kit_components
5
+ from core.kit_generator import generate_kit_from_plan
6
+ import utils.config_loader
7
+
8
+ # --- NEW/UPDATED CONSTANTS ---
9
+ # (Incorporating your suggestions and expanding slightly)
10
+ CURATED_TOPIC_SLUGS = sorted(list(set([
11
+ # Your suggestions (some are single, some multi-word)
12
+ "javascript", "css", "config", "python", "html", "cli", "typescript", "tailwindcss", "github config", "llm", # "github config"
13
+ "deep neural networks", "deep learning", "neural network", # Changed to spaces
14
+ "tensorflow", "pytorch", "ml",
15
+ "distributed systems", # Changed to spaces
16
+
17
+ # Broad Categories (changed to spaces where appropriate)
18
+ "web development", "mobile development", "game development", "machine learning",
19
+ "data science", "artificial intelligence", "devops", "cybersecurity", "blockchain",
20
+ "iot", "cloud computing", "big data", "robotics", "bioinformatics", "ar vr", # "ar vr" might be better as "augmented reality", "virtual reality" or keep as is if it's a common tag
21
+ "natural language processing", "computer vision", "data visualization",
22
+ # Specific Technologies & Frameworks
23
+ "react", "angular", "vue", "nextjs", "nodejs", "svelte",
24
+ "django", "flask", "spring", "dotnet", "ruby on rails", # "ruby on rails"
25
+ "android", "ios", "flutter", "react native", # "react native"
26
+ "scikit learn", "keras", "pandas", "numpy", # "scikit learn"
27
+ "docker", "kubernetes", "aws", "azure", "google cloud platform", "serverless", # "google cloud platform"
28
+ "sql", "nosql", "mongodb", "postgresql", "mysql", "graphql",
29
+ "api", "gui", "testing", "documentation", "education", "accessibility",
30
+ "raspberry pi", "arduino", "linux", "windows", "macos", "gaming", "graphics", "fintech" # "raspberry pi"
31
+ ])))
32
+
33
+ CURATED_LANGUAGE_SLUGS = sorted([
34
+ "python", "javascript", "java", "c#", "c++", "c", "go", "rust", "ruby", "php",
35
+ "swift", "kotlin", "typescript", "html", "css", "sql", "r", "perl", "scala",
36
+ "haskell", "lua", "dart", "elixir", "clojure", "objective-c", "shell", "powershell",
37
+ "assembly", "matlab", "groovy", "julia", "ocaml", "pascal", "fortran", "lisp",
38
+ "prolog", "erlang", "f#", "zig", "nim", "crystal", "svelte", "vue" # Svelte/Vue also as languages for their specific file types
39
+ ])
40
+ # --- END NEW/UPDATED CONSTANTS ---
41
+
42
+
43
+ # --- MODIFIED FUNCTION: find_and_suggest_issues ---
44
+ def find_and_suggest_issues(
45
+ selected_language: str | None, # From language dropdown
46
+ selected_curated_topics: list[str] | None, # From topics dropdown (multiselect)
47
+ custom_topics_str: str | None # From topics textbox
48
+ ):
49
+ print(f"Gradio app received language: '{selected_language}', curated_topics: {selected_curated_topics}, custom_topics: '{custom_topics_str}'")
50
+
51
+ # --- Default error/empty returns for 8 outputs ---
52
+ # issues_markdown, llm_suggestion, raw_issues_state,
53
+ # dropdown_update, button_update, controls_section_update, display_section_update,
54
+ # language_searched_state
55
+ empty_error_return = (
56
+ "Error or no input.", None, None,
57
+ gr.update(choices=[], value=None, visible=False), gr.update(visible=False),
58
+ gr.update(visible=False), gr.update(visible=False),
59
+ "" # language_searched_state
60
+ )
61
+ no_issues_found_return_factory = lambda lang, topics_str: (
62
+ f"No beginner-friendly issues found for '{lang}'" +
63
+ (f" with topics '{topics_str}'" if topics_str else "") +
64
+ " using current labels. Try different criteria.",
65
+ None, None,
66
+ gr.update(choices=[], value=None, visible=False), gr.update(visible=False),
67
+ gr.update(visible=False), gr.update(visible=False),
68
+ lang or ""
69
+ )
70
+ # ---
71
+
72
+ if not selected_language: # Language is now from a dropdown, should always have a value if user interacts
73
+ return ("Please select a programming language.", None, None,
74
+ gr.update(choices=[], value=None, visible=False), gr.update(visible=False),
75
+ gr.update(visible=False), gr.update(visible=False),
76
+ "")
77
+
78
+ language_to_search = selected_language.strip().lower() # Already a slug from dropdown
79
+
80
+ # --- Combine curated and custom topics ---
81
+ final_topics_set = set()
82
+ if selected_curated_topics: # This will be a list from multiselect dropdown
83
+ for topic in selected_curated_topics:
84
+ if topic and topic.strip():
85
+ final_topics_set.add(topic.strip().lower()) # Already slugs
86
+ if custom_topics_str:
87
+ custom_topics_list = [ct.strip().lower() for ct in custom_topics_str.split(',') if ct.strip()]
88
+ for topic in custom_topics_list:
89
+ final_topics_set.add(topic) # Add directly, github_client handles quoting if needed
90
+
91
+ final_topics_list = list(final_topics_set) if final_topics_set else None
92
+ print(f"Final parsed topics for search: {final_topics_list}")
93
+ # --- End Combine topics ---
94
+
95
+ # --- REMOVED: is_common_language and language_warning_for_llm logic ---
96
+ # Since language comes from a curated dropdown, we assume it's "common" or valid.
97
+ # The GitHub API will be the ultimate judge if it finds anything.
98
+
99
+ fetched_issues_list = fetch_beginner_issues(
100
+ language_to_search,
101
+ topics=final_topics_list,
102
+ per_page=5 # Fetch 5 issues
103
+ )
104
+
105
+ if fetched_issues_list is None: # GitHub API call failed
106
+ return ("Error: Could not fetch issues from GitHub. Check server logs.", None, None,
107
+ gr.update(choices=[], value=None, visible=False), gr.update(visible=False),
108
+ gr.update(visible=False), gr.update(visible=False),
109
+ language_to_search)
110
+
111
+ if not fetched_issues_list: # No issues found
112
+ return no_issues_found_return_factory(language_to_search, ", ".join(final_topics_list) if final_topics_list else None)
113
+
114
+ # --- REMOVED: issues_markdown_prefix related to uncommon language ---
115
+ # This is no longer needed if language is from a curated dropdown.
116
+
117
+ issues_display_list = []
118
+ issue_titles_for_dropdown = []
119
+ for i, issue in enumerate(fetched_issues_list[:5]): # Display up to 5
120
+ title = issue.get('title', 'N/A')
121
+ issues_display_list.append(
122
+ f"{i+1}. **{title}**\n"
123
+ f" - Repo: [{issue.get('repository_html_url', '#')}]({issue.get('repository_html_url', '#')})\n"
124
+ f" - URL: [{issue.get('html_url', '#')}]({issue.get('html_url', '#')})\n"
125
+ f" - Labels: {', '.join(issue.get('labels', []))}\n"
126
+ )
127
+ issue_titles_for_dropdown.append(f"{i+1}. {title}")
128
+ issues_markdown = "\n---\n".join(issues_display_list)
129
+
130
+ issues_for_llm = fetched_issues_list[:3]
131
+ llm_suggestion_text = "Could not get LLM suggestion at this moment."
132
+ if issues_for_llm and utils.config_loader.OPENAI_API_KEY:
133
+ suggestion = get_simple_issue_suggestion( # Pass language_to_search
134
+ issues_for_llm, language_to_search, target_count=1
135
+ # additional_prompt_context for uncommon language is removed
136
+ )
137
+ if suggestion: llm_suggestion_text = f"**πŸ€– AI Navigator's Suggestion:**\n\n{suggestion}"
138
+ else: llm_suggestion_text = "LLM processed the request but gave an empty response or an error occurred."
139
+ elif not utils.config_loader.OPENAI_API_KEY:
140
+ llm_suggestion_text = "OpenAI API Key not configured. LLM suggestion skipped."
141
+ elif not issues_for_llm :
142
+ llm_suggestion_text = "No issues were available to provide a suggestion for."
143
+
144
+ kit_dropdown_update = gr.update(choices=issue_titles_for_dropdown, value=issue_titles_for_dropdown[0] if issue_titles_for_dropdown else None, visible=True)
145
+ kit_button_visibility_update = gr.update(visible=True)
146
+ kit_controls_section_update = gr.update(visible=True)
147
+ kit_display_section_update = gr.update(visible=True)
148
+
149
+ return (issues_markdown, llm_suggestion_text, fetched_issues_list,
150
+ kit_dropdown_update, kit_button_visibility_update,
151
+ kit_controls_section_update, kit_display_section_update,
152
+ language_to_search) # Return the searched language for state
153
+ # --- END MODIFIED FUNCTION ---
154
+
155
+
156
+ # handle_kit_generation function (This function should be your last correct version)
157
+ # ... (Ensure your full handle_kit_generation is here)
158
+ def handle_kit_generation(selected_issue_title_with_num: str, current_issues_state: list[dict], language_searched_state: str ):
159
+ checklist_update_on_error = gr.update(value=[], visible=False)
160
+ if not selected_issue_title_with_num or not current_issues_state:
161
+ return "Please select an issue first...", checklist_update_on_error
162
+ if not language_searched_state:
163
+ language_searched_state = "the project's primary language"
164
+ selected_issue_obj = None
165
+ try:
166
+ for i, issue_in_state in enumerate(current_issues_state):
167
+ numbered_title_in_state = f"{i+1}. {issue_in_state.get('title', 'N/A')}"
168
+ if numbered_title_in_state == selected_issue_title_with_num:
169
+ selected_issue_obj = issue_in_state
170
+ break
171
+ if not selected_issue_obj:
172
+ return f"Error: Could not find data for issue '{selected_issue_title_with_num}'.", checklist_update_on_error
173
+ plan_response = plan_onboarding_kit_components(selected_issue_obj, language_searched_state)
174
+ if not plan_response or "error" in plan_response:
175
+ error_detail = plan_response.get("details", "") if plan_response else "Planner None"
176
+ return f"Error planning kit: {plan_response.get('error', 'Unknown')}. {error_detail}", checklist_update_on_error
177
+ components_to_include = plan_response.get("include_components", [])
178
+ if not components_to_include:
179
+ return "AI planner decided no kit components needed.", checklist_update_on_error
180
+ kit_markdown_content = generate_kit_from_plan(selected_issue_obj, language_searched_state, components_to_include)
181
+ checklist_update_on_success = gr.update(value=[], visible=True)
182
+ return kit_markdown_content, checklist_update_on_success
183
+ except Exception as e:
184
+ import traceback
185
+ traceback.print_exc()
186
+ return f"Unexpected error generating kit: {str(e)}", checklist_update_on_error
187
+
188
+
189
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
190
+ gr.Markdown("# πŸ€– ContribNavigator: Your AI Guide to Open Source Contributions")
191
+ gr.Markdown("Select a programming language and optional topics to find beginner-friendly open source issues.") # MODIFIED
192
+
193
+ with gr.Row():
194
+ with gr.Column(scale=1): # Input column
195
+ # --- MODIFIED Language Input to Dropdown ---
196
+ lang_dropdown_input = gr.Dropdown(
197
+ label="Programming Language (*)",
198
+ choices=CURATED_LANGUAGE_SLUGS,
199
+ value=CURATED_LANGUAGE_SLUGS[CURATED_LANGUAGE_SLUGS.index("python")] if "python" in CURATED_LANGUAGE_SLUGS else CURATED_LANGUAGE_SLUGS[0] if CURATED_LANGUAGE_SLUGS else None, # Default to python or first in list
200
+ interactive=True,
201
+ # allow_custom_value=True # Consider this if you want users to type languages not in the list
202
+ )
203
+ # --- END MODIFIED Language Input ---
204
+
205
+ # --- NEW/MODIFIED Topics Input ---
206
+ curated_topics_dropdown = gr.Dropdown(
207
+ label="Select Common Topics (Optional, Multi-Select)",
208
+ choices=CURATED_TOPIC_SLUGS,
209
+ multiselect=True,
210
+ interactive=True
211
+ )
212
+ custom_topics_input = gr.Textbox(
213
+ label="Or, Add Custom Topics (Optional, comma-separated slugs)",
214
+ placeholder="e.g., my-niche-topic, another-custom-tag"
215
+ )
216
+ # --- END NEW/MODIFIED Topics Input ---
217
+
218
+ find_button = gr.Button("πŸ” Find Beginner Issues", variant="primary")
219
+
220
+ with gr.Column(visible=False) as kit_controls_section:
221
+ selected_issue_dropdown = gr.Dropdown(
222
+ label="Select an Issue to Generate Kit:", choices=[], interactive=True, visible=True
223
+ )
224
+ generate_kit_button = gr.Button("πŸ› οΈ Generate Onboarding Kit", visible=False)
225
+
226
+ with gr.Column(scale=2): # Output column
227
+ gr.Markdown("## Recommended Issues:")
228
+ issues_output = gr.Markdown(value="Your recommended issues will appear here...")
229
+ gr.Markdown("## Navigator's Insights:")
230
+ llm_suggestion_output = gr.Markdown(value="AI-powered suggestions will appear here...")
231
+
232
+ with gr.Column(visible=False) as kit_display_section:
233
+ gr.Markdown("## πŸ“– Your Onboarding Kit:")
234
+ kit_output = gr.Markdown("Your onboarding kit will appear here...")
235
+ # --- Using INITIAL_CHECKLIST_ITEMS constant for choices ---
236
+ INITIAL_CHECKLIST_ITEMS = [
237
+ "Understand the Issue: Read the issue description carefully.",
238
+ "Explore the Repository: Use the 'Quick Look' section in the kit to get familiar.",
239
+ "Read Contribution Guidelines: Review the project's contribution rules and setup (see kit).",
240
+ "Clone the Repository: Get the code on your local machine (see kit for command).",
241
+ "Set Up Development Environment: Follow any setup instructions in the guidelines.",
242
+ "Create a New Branch: For your changes (e.g., `git checkout -b my-fix-for-issue-123`).",
243
+ "Make Initial Contact (Optional but good): Leave a comment on the GitHub issue expressing your interest.",
244
+ "Start Investigating/Coding!",
245
+ "Ask Questions: If you're stuck, don't hesitate to ask for help on the issue or project's communication channels."
246
+ ]
247
+ checklist_group_output = gr.CheckboxGroup(
248
+ label="βœ… Your First Steps Checklist:",
249
+ choices=INITIAL_CHECKLIST_ITEMS,
250
+ value=[],
251
+ interactive=True,
252
+ visible=False # Starts hidden
253
+ )
254
+ # --- END Using INITIAL_CHECKLIST_ITEMS ---
255
+
256
+ raw_issues_state = gr.State([])
257
+ language_searched_state = gr.State("")
258
+
259
+ # --- MODIFIED find_button.click inputs ---
260
+ find_button.click(
261
+ fn=find_and_suggest_issues,
262
+ inputs=[lang_dropdown_input, curated_topics_dropdown, custom_topics_input], # UPDATED
263
+ outputs=[
264
+ issues_output, llm_suggestion_output, raw_issues_state,
265
+ selected_issue_dropdown, generate_kit_button,
266
+ kit_controls_section, kit_display_section,
267
+ language_searched_state
268
+ ]
269
+ )
270
+ # --- END MODIFIED find_button.click ---
271
+
272
+ generate_kit_button.click(
273
+ fn=handle_kit_generation,
274
+ inputs=[selected_issue_dropdown, raw_issues_state, language_searched_state],
275
+ outputs=[kit_output, checklist_group_output] # Targets CheckboxGroup
276
+ )
277
+
278
+ if __name__ == "__main__":
279
+ print("Launching ContribNavigator Gradio App...")
280
+ demo.launch()