Update app.py
Browse files
app.py
CHANGED
@@ -1,3 +1,4 @@
|
|
|
|
1 |
import re
|
2 |
from http import HTTPStatus
|
3 |
from typing import Dict, List, Optional, Tuple
|
@@ -15,12 +16,10 @@ from bs4 import BeautifulSoup
|
|
15 |
import html2text
|
16 |
import json
|
17 |
import time
|
18 |
-
import os
|
19 |
|
20 |
import gradio as gr
|
21 |
from huggingface_hub import InferenceClient
|
22 |
from tavily import TavilyClient
|
23 |
-
import openai
|
24 |
|
25 |
# Gradio supported languages for syntax highlighting
|
26 |
GRADIO_SUPPORTED_LANGUAGES = [
|
@@ -115,41 +114,45 @@ Removing the paragraph...
|
|
115 |
|
116 |
# Available models
|
117 |
AVAILABLE_MODELS = [
|
|
|
|
|
|
|
|
|
|
|
118 |
{
|
119 |
"name": "DeepSeek V3",
|
120 |
"id": "deepseek-ai/DeepSeek-V3-0324",
|
121 |
-
"description": "DeepSeek V3 model for code generation"
|
122 |
},
|
123 |
{
|
124 |
-
"name": "DeepSeek R1",
|
125 |
"id": "deepseek-ai/DeepSeek-R1-0528",
|
126 |
-
"description": "DeepSeek R1 model for code generation"
|
127 |
},
|
128 |
{
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
# "provider": "openai"
|
133 |
-
#}, # Commented out to avoid requiring extra setup for all users
|
134 |
-
#{
|
135 |
-
"name": "Gemini 1.5 Pro",
|
136 |
-
"id": "gemini-1.5-pro-latest",
|
137 |
-
"description": "Google Gemini 1.5 Pro model for code generation and general tasks", "provider": "gemini"
|
138 |
},
|
139 |
{
|
140 |
-
"name": "
|
141 |
-
"id": "
|
142 |
-
"description": "
|
143 |
},
|
144 |
{
|
145 |
"name": "Qwen3-235B-A22B",
|
146 |
"id": "Qwen/Qwen3-235B-A22B",
|
147 |
-
"description": "Qwen3-235B-A22B model for code generation and general tasks"
|
148 |
},
|
149 |
{
|
150 |
-
|
151 |
-
|
152 |
-
|
|
|
|
|
|
|
|
|
|
|
153 |
}
|
154 |
]
|
155 |
|
@@ -213,51 +216,16 @@ DEMO_LIST = [
|
|
213 |
]
|
214 |
|
215 |
# HF Inference Client
|
216 |
-
HF_TOKEN = os.getenv(
|
217 |
-
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
|
218 |
-
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
|
219 |
-
DEEPSEEK_API_KEY = os.getenv("DEEPSEEK_API_KEY")
|
220 |
|
221 |
def get_inference_client(model_id):
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
if provider == "deepseek":
|
230 |
-
if not DEEPSEEK_API_KEY:
|
231 |
-
raise ValueError("DEEPSEEK_API_KEY environment variable not set.")
|
232 |
-
return "deepseek_client" # Return a string placeholder, logic is handled in generation_code
|
233 |
-
|
234 |
-
if provider == "groq":
|
235 |
-
return InferenceClient(
|
236 |
-
provider="groq",
|
237 |
-
api_key=HF_TOKEN, # Groq uses HF token as well
|
238 |
-
bill_to="huggingface" # Assuming billing through HF for Groq
|
239 |
-
)
|
240 |
-
elif provider == "huggingface":
|
241 |
-
if not HF_TOKEN:
|
242 |
-
raise ValueError("HF_TOKEN environment variable not set for Hugging Face models.")
|
243 |
-
return InferenceClient(
|
244 |
-
provider="auto", # Use HF's auto provider for other HF models
|
245 |
-
api_key=HF_TOKEN,
|
246 |
-
bill_to="huggingface"
|
247 |
-
)
|
248 |
-
elif provider == "openai":
|
249 |
-
if not OPENAI_API_KEY:
|
250 |
-
raise ValueError("OPENAI_API_KEY environment variable not set.")
|
251 |
-
openai.api_key = OPENAI_API_KEY
|
252 |
-
return openai
|
253 |
-
elif provider == "gemini":
|
254 |
-
if not GEMINI_API_KEY:
|
255 |
-
raise ValueError("GEMINI_API_KEY environment variable not set.")
|
256 |
-
import google.generativeai as genai
|
257 |
-
genai.configure(api_key=GEMINI_API_KEY)
|
258 |
-
return genai
|
259 |
-
else:
|
260 |
-
raise ValueError(f"Unsupported provider: {provider}")
|
261 |
|
262 |
# Type definitions
|
263 |
History = List[Tuple[str, str]]
|
@@ -283,7 +251,7 @@ def history_to_messages(history: History, system: str) -> Messages:
|
|
283 |
text_content = ""
|
284 |
for item in user_content:
|
285 |
if isinstance(item, dict) and item.get("type") == "text":
|
286 |
-
text_content +=
|
287 |
user_content = text_content if text_content else str(user_content)
|
288 |
|
289 |
messages.append({'role': 'user', 'content': user_content})
|
@@ -300,7 +268,7 @@ def messages_to_history(messages: Messages) -> Tuple[str, History]:
|
|
300 |
text_content = ""
|
301 |
for item in user_content:
|
302 |
if isinstance(item, dict) and item.get("type") == "text":
|
303 |
-
text_content +=
|
304 |
user_content = text_content if text_content else str(user_content)
|
305 |
|
306 |
history.append([user_content, r['content']])
|
@@ -315,7 +283,7 @@ def history_to_chatbot_messages(history: History) -> List[Dict[str, str]]:
|
|
315 |
text_content = ""
|
316 |
for item in user_msg:
|
317 |
if isinstance(item, dict) and item.get("type") == "text":
|
318 |
-
text_content +=
|
319 |
user_msg = text_content if text_content else str(user_msg)
|
320 |
|
321 |
messages.append({"role": "user", "content": user_msg})
|
@@ -1011,139 +979,41 @@ This will help me create a better design for you."""
|
|
1011 |
else:
|
1012 |
messages.append({'role': 'user', 'content': enhanced_query})
|
1013 |
try:
|
1014 |
-
|
1015 |
-
|
1016 |
-
|
1017 |
-
|
1018 |
-
|
1019 |
-
|
1020 |
-
|
1021 |
-
|
1022 |
-
|
1023 |
-
|
1024 |
-
|
1025 |
-
if
|
1026 |
-
|
1027 |
-
|
1028 |
-
if
|
1029 |
-
# ... (rest of the modification logic) ...
|
1030 |
-
if clean_code.strip().startswith("<!DOCTYPE html>") or clean_code.strip().startswith("<html"):
|
1031 |
-
yield {
|
1032 |
-
code_output: gr.update(value=clean_code, language=get_gradio_language(language)),
|
1033 |
-
history_output: history_to_chatbot_messages(_history),
|
1034 |
-
sandbox: send_to_sandbox(clean_code) if language == "html" else "<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>",
|
1035 |
-
}
|
1036 |
-
else:
|
1037 |
-
last_html = _history[-1][1] if _history else ""
|
1038 |
-
modified_html = apply_search_replace_changes(last_html, clean_code)
|
1039 |
-
clean_html = remove_code_block(modified_html)
|
1040 |
-
yield {
|
1041 |
-
code_output: gr.update(value=clean_html, language=get_gradio_language(language)),
|
1042 |
-
history_output: history_to_chatbot_messages(_history),
|
1043 |
-
sandbox: send_to_sandbox(clean_html) if language == "html" else "<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>",
|
1044 |
-
}
|
1045 |
-
else:
|
1046 |
yield {
|
1047 |
code_output: gr.update(value=clean_code, language=get_gradio_language(language)),
|
1048 |
history_output: history_to_chatbot_messages(_history),
|
1049 |
sandbox: send_to_sandbox(clean_code) if language == "html" else "<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>",
|
1050 |
}
|
1051 |
-
|
1052 |
-
|
1053 |
-
|
1054 |
-
|
1055 |
-
|
1056 |
-
|
1057 |
-
|
1058 |
-
|
1059 |
-
|
1060 |
-
response = chat.send_message(messages[-1]["content"], stream=True)
|
1061 |
-
content = ""
|
1062 |
-
for chunk in response:
|
1063 |
-
content += chunk.text
|
1064 |
-
clean_code = remove_code_block(content)
|
1065 |
-
if has_existing_html:
|
1066 |
-
# ... (rest of the modification logic) ...
|
1067 |
-
if clean_code.strip().startswith("<!DOCTYPE html>") or clean_code.strip().startswith("<html"):
|
1068 |
-
yield {
|
1069 |
-
code_output: gr.update(value=clean_code, language=get_gradio_language(language)),
|
1070 |
-
history_output: history_to_chatbot_messages(_history),
|
1071 |
-
sandbox: send_to_sandbox(clean_code) if language == "html" else "<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>",
|
1072 |
-
}
|
1073 |
-
else:
|
1074 |
-
last_html = _history[-1][1] if _history else ""
|
1075 |
-
modified_html = apply_search_replace_changes(last_html, clean_code)
|
1076 |
-
clean_html = remove_code_block(modified_html)
|
1077 |
-
yield {
|
1078 |
-
code_output: gr.update(value=clean_html, language=get_gradio_language(language)),
|
1079 |
-
history_output: history_to_chatbot_messages(_history),
|
1080 |
-
sandbox: send_to_sandbox(clean_html) if language == "html" else "<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>",
|
1081 |
-
}
|
1082 |
else:
|
1083 |
-
|
1084 |
-
|
1085 |
-
|
1086 |
-
|
1087 |
-
|
1088 |
-
elif _current_model["provider"] == "deepseek":
|
1089 |
-
# Use requests to call Deepseek API directly
|
1090 |
-
url = "https://api.deepseek.com/v1/chat/completions"
|
1091 |
-
headers = {
|
1092 |
-
"Authorization": f"Bearer {DEEPSEEK_API_KEY}",
|
1093 |
-
"Content-Type": "application/json"
|
1094 |
-
}
|
1095 |
-
payload = {
|
1096 |
-
"model": _current_model["id"], # Use the full model ID from AVAILABLE_MODELS
|
1097 |
-
"messages": [{"role": m["role"], "content": m["content"]} for m in messages],
|
1098 |
-
"stream": True,
|
1099 |
-
"max_tokens": 5000
|
1100 |
-
}
|
1101 |
-
|
1102 |
-
response = requests.post(url, headers=headers, json=payload, stream=True)
|
1103 |
-
response.raise_for_status()
|
1104 |
-
|
1105 |
-
content = ""
|
1106 |
-
for line in response.iter_lines():
|
1107 |
-
if line:
|
1108 |
-
line_str = line.decode('utf-8')
|
1109 |
-
if line_str.startswith('data: '):
|
1110 |
-
json_data = line_str[6:]
|
1111 |
-
if json_data.strip() != '[DONE]':
|
1112 |
-
chunk = json.loads(json_data)
|
1113 |
-
if chunk['choices'][0]['delta'].get('content'):
|
1114 |
-
content += chunk['choices'][0]['delta']['content']
|
1115 |
-
clean_code = remove_code_block(content)
|
1116 |
-
yield {
|
1117 |
-
code_output: gr.update(value=clean_code, language=get_gradio_language(language)),
|
1118 |
-
history_output: history_to_chatbot_messages(_history),
|
1119 |
-
sandbox: send_to_sandbox(clean_code) if language == "html" else "<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>",
|
1120 |
-
}
|
1121 |
-
|
1122 |
-
else:
|
1123 |
-
# Use Hugging Face Inference Client (or Groq) for other models
|
1124 |
-
completion = client.chat.completions.create(
|
1125 |
-
model=_current_model["id"],
|
1126 |
-
messages=messages,
|
1127 |
-
stream=True,
|
1128 |
-
max_tokens=5000
|
1129 |
-
)
|
1130 |
-
|
1131 |
-
content = ""
|
1132 |
-
for chunk in completion:
|
1133 |
-
if chunk.choices[0].delta.content:
|
1134 |
-
content += chunk.choices[0].delta.content
|
1135 |
-
clean_code = remove_code_block(content)
|
1136 |
-
if has_existing_html:
|
1137 |
-
# ... (rest of the modification logic) ...
|
1138 |
-
if clean_code.strip().startswith("<!DOCTYPE html>") or clean_code.strip().startswith("<html"):
|
1139 |
-
yield {
|
1140 |
-
code_output: gr.update(value=clean_code, language=get_gradio_language(language)),
|
1141 |
-
history_output: history_to_chatbot_messages(_history),
|
1142 |
-
sandbox: send_to_sandbox(clean_code) if language == "html" else "<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>",
|
1143 |
-
}
|
1144 |
-
else:
|
1145 |
-
last_html = _history[-1][1] if _history else ""
|
1146 |
-
modified_html = apply_search_replace_changes(last_html, clean_code)
|
1147 |
# Handle response based on whether this is a modification or new generation
|
1148 |
if has_existing_html:
|
1149 |
# Fallback: If the model returns a full HTML file, use it directly
|
@@ -1272,12 +1142,10 @@ with gr.Blocks(
|
|
1272 |
outputs=input
|
1273 |
)
|
1274 |
if not tavily_client:
|
1275 |
-
|
1276 |
else:
|
1277 |
-
|
1278 |
model_display = gr.Markdown(f"**Model:** {AVAILABLE_MODELS[0]['name']}", visible=True) # Moonshot Kimi-K2
|
1279 |
-
|
1280 |
-
|
1281 |
def on_model_change(model_name):
|
1282 |
for m in AVAILABLE_MODELS:
|
1283 |
if m['name'] == model_name:
|
|
|
1 |
+
import os
|
2 |
import re
|
3 |
from http import HTTPStatus
|
4 |
from typing import Dict, List, Optional, Tuple
|
|
|
16 |
import html2text
|
17 |
import json
|
18 |
import time
|
|
|
19 |
|
20 |
import gradio as gr
|
21 |
from huggingface_hub import InferenceClient
|
22 |
from tavily import TavilyClient
|
|
|
23 |
|
24 |
# Gradio supported languages for syntax highlighting
|
25 |
GRADIO_SUPPORTED_LANGUAGES = [
|
|
|
114 |
|
115 |
# Available models
|
116 |
AVAILABLE_MODELS = [
|
117 |
+
{
|
118 |
+
"name": "Moonshot Kimi-K2",
|
119 |
+
"id": "moonshotai/Kimi-K2-Instruct",
|
120 |
+
"description": "Moonshot AI Kimi-K2-Instruct model for code generation and general tasks"
|
121 |
+
},
|
122 |
{
|
123 |
"name": "DeepSeek V3",
|
124 |
"id": "deepseek-ai/DeepSeek-V3-0324",
|
125 |
+
"description": "DeepSeek V3 model for code generation"
|
126 |
},
|
127 |
{
|
128 |
+
"name": "DeepSeek R1",
|
129 |
"id": "deepseek-ai/DeepSeek-R1-0528",
|
130 |
+
"description": "DeepSeek R1 model for code generation"
|
131 |
},
|
132 |
{
|
133 |
+
"name": "ERNIE-4.5-VL",
|
134 |
+
"id": "baidu/ERNIE-4.5-VL-424B-A47B-Base-PT",
|
135 |
+
"description": "ERNIE-4.5-VL model for multimodal code generation with image support"
|
|
|
|
|
|
|
|
|
|
|
|
|
136 |
},
|
137 |
{
|
138 |
+
"name": "MiniMax M1",
|
139 |
+
"id": "MiniMaxAI/MiniMax-M1-80k",
|
140 |
+
"description": "MiniMax M1 model for code generation and general tasks"
|
141 |
},
|
142 |
{
|
143 |
"name": "Qwen3-235B-A22B",
|
144 |
"id": "Qwen/Qwen3-235B-A22B",
|
145 |
+
"description": "Qwen3-235B-A22B model for code generation and general tasks"
|
146 |
},
|
147 |
{
|
148 |
+
"name": "SmolLM3-3B",
|
149 |
+
"id": "HuggingFaceTB/SmolLM3-3B",
|
150 |
+
"description": "SmolLM3-3B model for code generation and general tasks"
|
151 |
+
},
|
152 |
+
{
|
153 |
+
"name": "GLM-4.1V-9B-Thinking",
|
154 |
+
"id": "THUDM/GLM-4.1V-9B-Thinking",
|
155 |
+
"description": "GLM-4.1V-9B-Thinking model for multimodal code generation with image support"
|
156 |
}
|
157 |
]
|
158 |
|
|
|
216 |
]
|
217 |
|
218 |
# HF Inference Client
|
219 |
+
HF_TOKEN = os.getenv('HF_TOKEN')
|
|
|
|
|
|
|
220 |
|
221 |
def get_inference_client(model_id):
|
222 |
+
"""Return an InferenceClient with provider based on model_id."""
|
223 |
+
provider = "groq" if model_id == "moonshotai/Kimi-K2-Instruct" else "auto"
|
224 |
+
return InferenceClient(
|
225 |
+
provider=provider,
|
226 |
+
api_key=HF_TOKEN,
|
227 |
+
bill_to="huggingface"
|
228 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
229 |
|
230 |
# Type definitions
|
231 |
History = List[Tuple[str, str]]
|
|
|
251 |
text_content = ""
|
252 |
for item in user_content:
|
253 |
if isinstance(item, dict) and item.get("type") == "text":
|
254 |
+
text_content += item.get("text", "")
|
255 |
user_content = text_content if text_content else str(user_content)
|
256 |
|
257 |
messages.append({'role': 'user', 'content': user_content})
|
|
|
268 |
text_content = ""
|
269 |
for item in user_content:
|
270 |
if isinstance(item, dict) and item.get("type") == "text":
|
271 |
+
text_content += item.get("text", "")
|
272 |
user_content = text_content if text_content else str(user_content)
|
273 |
|
274 |
history.append([user_content, r['content']])
|
|
|
283 |
text_content = ""
|
284 |
for item in user_msg:
|
285 |
if isinstance(item, dict) and item.get("type") == "text":
|
286 |
+
text_content += item.get("text", "")
|
287 |
user_msg = text_content if text_content else str(user_msg)
|
288 |
|
289 |
messages.append({"role": "user", "content": user_msg})
|
|
|
979 |
else:
|
980 |
messages.append({'role': 'user', 'content': enhanced_query})
|
981 |
try:
|
982 |
+
completion = client.chat.completions.create(
|
983 |
+
model=_current_model["id"],
|
984 |
+
messages=messages,
|
985 |
+
stream=True,
|
986 |
+
max_tokens=5000
|
987 |
+
)
|
988 |
+
content = ""
|
989 |
+
for chunk in completion:
|
990 |
+
if chunk.choices[0].delta.content:
|
991 |
+
content += chunk.choices[0].delta.content
|
992 |
+
clean_code = remove_code_block(content)
|
993 |
+
search_status = " (with web search)" if enable_search and tavily_client else ""
|
994 |
+
if has_existing_html:
|
995 |
+
# Fallback: If the model returns a full HTML file, use it directly
|
996 |
+
if clean_code.strip().startswith("<!DOCTYPE html>") or clean_code.strip().startswith("<html"):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
997 |
yield {
|
998 |
code_output: gr.update(value=clean_code, language=get_gradio_language(language)),
|
999 |
history_output: history_to_chatbot_messages(_history),
|
1000 |
sandbox: send_to_sandbox(clean_code) if language == "html" else "<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>",
|
1001 |
}
|
1002 |
+
else:
|
1003 |
+
last_html = _history[-1][1] if _history else ""
|
1004 |
+
modified_html = apply_search_replace_changes(last_html, clean_code)
|
1005 |
+
clean_html = remove_code_block(modified_html)
|
1006 |
+
yield {
|
1007 |
+
code_output: gr.update(value=clean_html, language=get_gradio_language(language)),
|
1008 |
+
history_output: history_to_chatbot_messages(_history),
|
1009 |
+
sandbox: send_to_sandbox(clean_html) if language == "html" else "<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>",
|
1010 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1011 |
else:
|
1012 |
+
yield {
|
1013 |
+
code_output: gr.update(value=clean_code, language=get_gradio_language(language)),
|
1014 |
+
history_output: history_to_chatbot_messages(_history),
|
1015 |
+
sandbox: send_to_sandbox(clean_code) if language == "html" else "<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>",
|
1016 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1017 |
# Handle response based on whether this is a modification or new generation
|
1018 |
if has_existing_html:
|
1019 |
# Fallback: If the model returns a full HTML file, use it directly
|
|
|
1142 |
outputs=input
|
1143 |
)
|
1144 |
if not tavily_client:
|
1145 |
+
gr.Markdown("⚠️ Web search unavailable", visible=True)
|
1146 |
else:
|
1147 |
+
gr.Markdown("✅ Web search available", visible=True)
|
1148 |
model_display = gr.Markdown(f"**Model:** {AVAILABLE_MODELS[0]['name']}", visible=True) # Moonshot Kimi-K2
|
|
|
|
|
1149 |
def on_model_change(model_name):
|
1150 |
for m in AVAILABLE_MODELS:
|
1151 |
if m['name'] == model_name:
|