mgbam commited on
Commit
20491fe
·
verified ·
1 Parent(s): e33fbba

Upload 4 files

Browse files
Files changed (4) hide show
  1. app.py +30 -20
  2. chat_processing.py +4 -0
  3. ux_components.py +24 -0
  4. web_extraction.py +18 -2
app.py CHANGED
@@ -1,10 +1,11 @@
1
  import os
2
  from typing import Dict, List, Optional, Tuple
 
3
 
4
  import gradio as gr
5
 
6
  from config import (
7
- AVAILABLE_MODELS, DEMO_LIST, HTML_SYSTEM_PROMPT
8
  )
9
  from api_clients import generation_code, tavily_client
10
  from chat_processing import (
@@ -13,6 +14,10 @@ from chat_processing import (
13
  )
14
  from file_processing import create_multimodal_message
15
  from web_extraction import enhance_query_with_search
 
 
 
 
16
 
17
 
18
  def demo_card_click(e: gr.EventData):
@@ -41,7 +46,7 @@ def demo_card_click(e: gr.EventData):
41
  # Return the first demo description as fallback
42
  return DEMO_LIST[0]['description']
43
 
44
- # Main application
45
  with gr.Blocks(
46
  theme=gr.themes.Base(
47
  primary_hue="blue",
@@ -109,17 +114,8 @@ with gr.Blocks(
109
  visible=True # Always visible
110
  )
111
  gr.Markdown("**Quick start**", visible=True)
112
- with gr.Column(visible=True) as quick_examples_col:
113
- for i, demo_item in enumerate(DEMO_LIST[:3]):
114
- demo_card = gr.Button(
115
- value=demo_item['title'],
116
- variant="secondary",
117
- size="sm"
118
- )
119
- demo_card.click(
120
- fn=lambda idx=i: gr.update(value=DEMO_LIST[idx]['description']),
121
- outputs=input
122
- )
123
  if not tavily_client:
124
  gr.Markdown("⚠️ Web search unavailable", visible=True)
125
  else:
@@ -130,6 +126,7 @@ with gr.Blocks(
130
  if m['name'] == model_name:
131
  return m, f"**Model:** {m['name']}", update_image_input_visibility(m)
132
  return AVAILABLE_MODELS[0], f"**Model:** {AVAILABLE_MODELS[0]['name']}", update_image_input_visibility(AVAILABLE_MODELS[0]) # Moonshot Kimi-K2 fallback
 
133
  def save_prompt(input):
134
  return {setting: {"system": input}}
135
  model_dropdown.change(
@@ -160,7 +157,7 @@ with gr.Blocks(
160
  with gr.Tab("History"):
161
  history_output = gr.Chatbot(show_label=False, height=400, type="messages")
162
 
163
- # Event handlers
164
  def update_code_language(language):
165
  return gr.update(language=get_gradio_language(language))
166
 
@@ -170,17 +167,30 @@ with gr.Blocks(
170
  if language == "html":
171
  return send_to_sandbox(code)
172
  else:
173
- return "<div style='padding:1em;color:#888;text-align:center;'>Preview is only available for HTML. Please download your code using the download button above.</div>"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
174
 
175
- btn.click(
176
- generation_code,
177
- inputs=[input, image_input, file_input, website_url_input, setting, history, current_model, search_toggle, language_dropdown],
178
- outputs=[code_output, history, sandbox, history_output]
179
- )
180
  # Update preview when code or language changes
181
  code_output.change(preview_logic, inputs=[code_output, language_dropdown], outputs=sandbox)
182
  language_dropdown.change(preview_logic, inputs=[code_output, language_dropdown], outputs=sandbox)
183
  clear_btn.click(clear_history, outputs=[history, history_output, file_input, website_url_input])
184
 
 
 
 
 
185
  if __name__ == "__main__":
186
  demo.queue(api_open=False, default_concurrency_limit=20).launch(ssr_mode=True, mcp_server=False, show_api=False)
 
1
  import os
2
  from typing import Dict, List, Optional, Tuple
3
+ import asyncio
4
 
5
  import gradio as gr
6
 
7
  from config import (
8
+ AVAILABLE_MODELS, DEMO_LIST, HTML_SYSTEM_PROMPT,
9
  )
10
  from api_clients import generation_code, tavily_client
11
  from chat_processing import (
 
14
  )
15
  from file_processing import create_multimodal_message
16
  from web_extraction import enhance_query_with_search
17
+ from ux_components import create_demo_card, create_top_demo_cards
18
+
19
+ # --- Gradio App UI ---
20
+
21
 
22
 
23
  def demo_card_click(e: gr.EventData):
 
46
  # Return the first demo description as fallback
47
  return DEMO_LIST[0]['description']
48
 
49
+
50
  with gr.Blocks(
51
  theme=gr.themes.Base(
52
  primary_hue="blue",
 
114
  visible=True # Always visible
115
  )
116
  gr.Markdown("**Quick start**", visible=True)
117
+ quick_examples_col = create_top_demo_cards(input)
118
+
 
 
 
 
 
 
 
 
 
119
  if not tavily_client:
120
  gr.Markdown("⚠️ Web search unavailable", visible=True)
121
  else:
 
126
  if m['name'] == model_name:
127
  return m, f"**Model:** {m['name']}", update_image_input_visibility(m)
128
  return AVAILABLE_MODELS[0], f"**Model:** {AVAILABLE_MODELS[0]['name']}", update_image_input_visibility(AVAILABLE_MODELS[0]) # Moonshot Kimi-K2 fallback
129
+
130
  def save_prompt(input):
131
  return {setting: {"system": input}}
132
  model_dropdown.change(
 
157
  with gr.Tab("History"):
158
  history_output = gr.Chatbot(show_label=False, height=400, type="messages")
159
 
160
+ # --- Event Handlers ---
161
  def update_code_language(language):
162
  return gr.update(language=get_gradio_language(language))
163
 
 
167
  if language == "html":
168
  return send_to_sandbox(code)
169
  else:
170
+ return "<div style='padding:1em;color:#888;text-align:center;'>Preview is only available for HTML.</div>"
171
+
172
+
173
+ # Use asyncio.create_task to ensure the generation_code coroutine is properly awaited
174
+ def submit_query(*args):
175
+ task = asyncio.create_task(generation_code(*args)) # Create a task
176
+ async def wrapper():
177
+ async for update in task:
178
+ yield update
179
+ return wrapper() # Return the wrapper function
180
+
181
+ btn.click(fn=submit_query,
182
+ inputs=[input, image_input, file_input, website_url_input, setting, history, current_model, search_toggle, language_dropdown],
183
+ outputs=[code_output, history, sandbox, history_output])
184
+
185
 
 
 
 
 
 
186
  # Update preview when code or language changes
187
  code_output.change(preview_logic, inputs=[code_output, language_dropdown], outputs=sandbox)
188
  language_dropdown.change(preview_logic, inputs=[code_output, language_dropdown], outputs=sandbox)
189
  clear_btn.click(clear_history, outputs=[history, history_output, file_input, website_url_input])
190
 
191
+
192
+ if __name__ == "__main__":
193
+ demo.queue(api_open=False, default_concurrency_limit=20).launch(ssr_mode=True, mcp_server=False, show_api=False)
194
+
195
  if __name__ == "__main__":
196
  demo.queue(api_open=False, default_concurrency_limit=20).launch(ssr_mode=True, mcp_server=False, show_api=False)
chat_processing.py CHANGED
@@ -88,6 +88,10 @@ def update_image_input_visibility(model):
88
  is_glm_vl = model.get("id") == "THUDM/GLM-4.1V-9B-Thinking"
89
  return gr.update(visible=is_ernie_vl or is_glm_vl)
90
 
 
 
 
 
91
  def create_multimodal_message(text, image=None):
92
  """Create a multimodal message with text and optional image"""
93
  if image is None:
 
88
  is_glm_vl = model.get("id") == "THUDM/GLM-4.1V-9B-Thinking"
89
  return gr.update(visible=is_ernie_vl or is_glm_vl)
90
 
91
+ def update_submit_button(query):
92
+ """Enable submit button if query is not empty"""
93
+ return gr.update(interactive=bool(query))
94
+
95
  def create_multimodal_message(text, image=None):
96
  """Create a multimodal message with text and optional image"""
97
  if image is None:
ux_components.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from config import DEMO_LIST
3
+
4
+ def create_top_demo_cards(input_textbox):
5
+ """Creates a Gradio Column with buttons for the top 3 demo examples."""
6
+ with gr.Column(visible=True) as quick_examples_col:
7
+ for i, demo_item in enumerate(DEMO_LIST[:3]):
8
+ demo_card = gr.Button(
9
+ value=demo_item['title'],
10
+ variant="secondary",
11
+ size="sm",
12
+ elem_id=f"demo_card_{i}" # Add an ID for potential styling
13
+ )
14
+ demo_card.click(
15
+ fn=lambda idx=i: gr.update(value=DEMO_LIST[idx]['description']),
16
+ outputs=input_textbox,
17
+ )
18
+ return quick_examples_col
19
+
20
+ if __name__ == "__main__":
21
+ with gr.Blocks() as demo:
22
+ input_textbox = gr.Textbox(label="Input")
23
+ create_top_demo_cards(input_textbox)
24
+ demo.launch()
web_extraction.py CHANGED
@@ -1,5 +1,5 @@
1
  import requests
2
- from urllib.parse import urlparse, urljoin
3
  from bs4 import BeautifulSoup
4
  import re
5
  from tavily import TavilyClient
@@ -8,6 +8,7 @@ import os
8
  tavily_client = None
9
  TAVILY_API_KEY = os.getenv('TAVILY_API_KEY')
10
  if TAVILY_API_KEY:
 
11
  try:
12
  tavily_client = TavilyClient(api_key=TAVILY_API_KEY)
13
  except Exception as e:
@@ -74,6 +75,21 @@ def extract_website_content(url: str) -> str:
74
  return "Error: Invalid URL provided"
75
 
76
  # Set comprehensive headers to mimic a real browser request
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  headers = {
78
  'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
79
  'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
@@ -99,7 +115,7 @@ def extract_website_content(url: str) -> str:
99
  try:
100
  response = session.get(url, timeout=15, allow_redirects=True)
101
  response.raise_for_status()
102
- break
103
  except requests.exceptions.HTTPError as e:
104
  if e.response.status_code == 403 and attempt < max_retries - 1:
105
  # Try with different User-Agent on 403
 
1
  import requests
2
+ from urllib.parse import urlparse, urljoin, ParseResult
3
  from bs4 import BeautifulSoup
4
  import re
5
  from tavily import TavilyClient
 
8
  tavily_client = None
9
  TAVILY_API_KEY = os.getenv('TAVILY_API_KEY')
10
  if TAVILY_API_KEY:
11
+ import logging
12
  try:
13
  tavily_client = TavilyClient(api_key=TAVILY_API_KEY)
14
  except Exception as e:
 
75
  return "Error: Invalid URL provided"
76
 
77
  # Set comprehensive headers to mimic a real browser request
78
+ scheme = parsed_url.scheme
79
+ netloc = parsed_url.netloc
80
+ path = parsed_url.path if parsed_url.path else "/"
81
+ params = parsed_url.params
82
+ query = parsed_url.query
83
+ fragment = parsed_url.fragment
84
+ reconstructed_url = ParseResult(scheme, netloc, path, params, query, fragment).geturl()
85
+
86
+ logging.info(f"Extracting content from: {reconstructed_url}")
87
+
88
+ if reconstructed_url != url:
89
+ logging.info(f"Original URL: {url}")
90
+ logging.info(f"Reconstructed URL: {reconstructed_url}")
91
+
92
+
93
  headers = {
94
  'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
95
  'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
 
115
  try:
116
  response = session.get(url, timeout=15, allow_redirects=True)
117
  response.raise_for_status()
118
+ break # Exit the loop if successful
119
  except requests.exceptions.HTTPError as e:
120
  if e.response.status_code == 403 and attempt < max_retries - 1:
121
  # Try with different User-Agent on 403