mgbam commited on
Commit
1bd1ac4
Β·
verified Β·
1 Parent(s): 98ea765

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +133 -93
app.py CHANGED
@@ -1,140 +1,180 @@
1
  # app.py
2
- # ──────────────────────────────────────────────────────────────────────────────
3
  """
4
- AnyCoderΒ /Β ShashaΒ AI – Gradio back‑end
5
 
6
- β€’ Serves the custom front‑end located in static/index.html (+Β static/style.css,
7
- static/index.js).
8
- β€’ Exposes ONE httpΒ POST endpoint β†’ /run/predict (Gradio api_name="predict")
9
- that the browser JS calls to run the model and get generated code.
10
-
11
- All heavy lifting (model registry, provider routing, web‑search, etc.) lives in
12
- β€’ models.py, inference.py, utils.py, deploy.py …
13
  """
14
 
 
 
15
  from pathlib import Path
16
- from typing import List, Tuple, Dict
17
 
18
  import gradio as gr
19
 
20
- # ── Local helpers ────────────────────────────────────────────────────────────
21
- from inference import chat_completion
 
22
  from tavily_search import enhance_query_with_search
23
- from deploy import send_to_sandbox
24
- from models import AVAILABLE_MODELS, find_model, ModelInfo
25
- from utils import (
26
  extract_text_from_file,
27
  extract_website_content,
28
  history_to_messages,
 
29
  apply_search_replace_changes,
30
  remove_code_block,
31
  parse_transformers_js_output,
32
  format_transformers_js_output,
33
  )
 
 
 
 
 
 
 
 
 
 
34
 
35
- # ── System prompts keyed by language ────────────────────────────────────────
36
  SYSTEM_PROMPTS = {
37
  "html": (
38
- "ONLY USE HTML, CSS AND JAVASCRIPT. Return exactly ONE file wrapped in "
39
- "```html ...```."
40
  ),
41
  "transformers.js": (
42
- "Generate THREE separate files (index.html β€’ index.js β€’ style.css) each "
43
- "inside its own fenced block."
44
  ),
45
  }
46
 
47
- # ── Output‑history data structure ───────────────────────────────────────────
48
- History = List[Tuple[str, str]] #Β [(user_query, generated_code), …]
49
 
50
- # ════════════════════════════════════════════════════════════════════════════
51
- # 1. Backend callback hit by the JS front‑end
52
- # ════════════════════════════════════════════════════════════════════════════
53
- def generate(
54
  prompt: str,
55
  file_path: str | None,
56
  website_url: str | None,
57
- model_id: str,
 
58
  language: str,
59
- web_search: bool,
60
- history: History | None,
61
- ) -> Dict[str, str]:
62
- """
63
- The only public API. Returns: { "code": <string> }
64
- """
65
- history = history or []
66
-
67
- # ---- Build system + user messages --------------------------------------
68
- sys_prompt = SYSTEM_PROMPTS.get(language, f"You are an expert {language} developer.")
69
- messages = history_to_messages(history, sys_prompt)
70
 
71
- ctx: list[str] = [prompt.strip()]
 
 
72
 
 
73
  if file_path:
74
- ctx.append("[File]")
75
- ctx.append(extract_text_from_file(file_path)[:5_000])
76
-
77
  if website_url:
78
  html = extract_website_content(website_url)
79
  if not html.startswith("Error"):
80
- ctx.append("[Website]")
81
- ctx.append(html[:8_000])
82
 
83
- user_query = "\n\n".join(filter(None, ctx))
84
- user_query = enhance_query_with_search(user_query, web_search)
85
- messages.append({"role": "user", "content": user_query})
86
 
87
- # ---- Call model --------------------------------------------------------
88
- model: ModelInfo = find_model(model_id) or AVAILABLE_MODELS[0]
89
- assistant = chat_completion(model.id, messages)
 
 
 
 
 
90
 
91
- # ---- Post‑process output ----------------------------------------------
92
  if language == "transformers.js":
93
- files = parse_transformers_js_output(assistant)
94
  code = format_transformers_js_output(files)
 
95
  else:
96
- clean = remove_code_block(assistant)
97
- if history and not history[-1][1].startswith("❌"):
98
- clean = apply_search_replace_changes(history[-1][1], clean)
99
- code = clean
100
-
101
- # (preview iframe is rendered entirely client‑side from code)
102
- return {"code": code}
103
-
104
-
105
- # ════════════════════════════════════════════════════════════════════════════
106
- # 2. Gradio wrapper
107
- # ════════════════════════════════════════════════════════════════════════════
108
- # Read static front‑end
109
- INDEX_HTML = Path("static/index.html").read_text(encoding="utf-8")
110
-
111
- with gr.Blocks(css="body{margin:0}", title="AnyCoderΒ AI") as demo:
112
- # 2‑a Β Serve the custom UI
113
- gr.HTML(INDEX_HTML)
114
-
115
- # 2‑b Invisible components acting as our JSON REST API
116
- with gr.Group(visible=False) as backend:
117
- prompt_in = gr.Textbox()
118
- file_in = gr.File()
119
- url_in = gr.Textbox()
120
- model_in = gr.Textbox()
121
- lang_in = gr.Textbox()
122
- search_in = gr.Checkbox()
123
- hist_state = gr.State([]) # persists conversation on server
124
-
125
- code_out = gr.JSON(label="code") # returns {"code": "..."} to the JS
126
-
127
- trigger = gr.Button(visible=False)
128
- trigger.click(
129
- fn=generate,
130
- inputs=[
131
- prompt_in, file_in, url_in,
132
- model_in, lang_in, search_in, hist_state
133
- ],
134
- outputs=[code_out],
135
- api_name="predict", # <─ POST /run/predict
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
  )
137
 
138
- # ---------------------------------------------------------------------------
139
  if __name__ == "__main__":
140
  demo.queue().launch()
 
1
  # app.py
2
+ # ────────────────────────────────────────────────────────────────
3
  """
4
+ AnyCoderΒ /Β ShashaΒ AI – lightweight Gradio front‑end
5
 
6
+ β€’ Pick an AI model from models.py ➜ AVAILABLE_MODELS
7
+ β€’ Provide context (prompt / file / website)
8
+ β€’ Choose a target language from 25+ options
9
+ β€’ Optional Tavily web‑search enrichment
10
+ β€’ Generate code & live‑preview HTML
 
 
11
  """
12
 
13
+ from __future__ import annotations
14
+
15
  from pathlib import Path
16
+ from typing import List, Tuple, Dict, Any, Optional
17
 
18
  import gradio as gr
19
 
20
+ # ── local helpers ───────────────────────────────────────────────
21
+ from models import AVAILABLE_MODELS, find_model, ModelInfo
22
+ from inference import chat_completion
23
  from tavily_search import enhance_query_with_search
24
+ from utils import (
 
 
25
  extract_text_from_file,
26
  extract_website_content,
27
  history_to_messages,
28
+ history_to_chatbot_messages,
29
  apply_search_replace_changes,
30
  remove_code_block,
31
  parse_transformers_js_output,
32
  format_transformers_js_output,
33
  )
34
+ from deploy import send_to_sandbox
35
+
36
+ # ── constants ───────────────────────────────────────────────────
37
+ SUPPORTED_LANGUAGES = [
38
+ "python", "c", "cpp", "markdown", "latex", "json", "html", "css",
39
+ "javascript", "jinja2", "typescript", "yaml", "dockerfile", "shell",
40
+ "r", "sql", "sql-msSQL", "sql-mySQL", "sql-mariaDB", "sql-sqlite",
41
+ "sql-cassandra", "sql-plSQL", "sql-hive", "sql-pgSQL", "sql-gql",
42
+ "sql-gpSQL", "sql-sparkSQL", "sql-esper",
43
+ ]
44
 
 
45
  SYSTEM_PROMPTS = {
46
  "html": (
47
+ "ONLY USE HTML, CSS AND JAVASCRIPT. Produce ONE complete HTML file "
48
+ "wrapped in ```html ...```."
49
  ),
50
  "transformers.js": (
51
+ "Generate THREE fenced blocks (index.html / index.js / style.css) "
52
+ "for a transformers.js web‑app."
53
  ),
54
  }
55
 
56
+ History = List[Tuple[str, str]]
 
57
 
58
+
59
+ # ── core callback ───────────────────────────────────────────────
60
+ def generate_code(
 
61
  prompt: str,
62
  file_path: str | None,
63
  website_url: str | None,
64
+ model_name: str,
65
+ enable_search: bool,
66
  language: str,
67
+ hist: History | None,
68
+ ) -> Tuple[str, History, str, List[Dict[str, str]]]:
69
+ """Back‑end for the β€˜Generate Code’ button."""
70
+ hist = hist or []
71
+ prompt = (prompt or "").strip()
 
 
 
 
 
 
72
 
73
+ # 1Β build messages
74
+ sys_prompt = SYSTEM_PROMPTS.get(language, f"You are an expert {language} developer.")
75
+ messages = history_to_messages(hist, sys_prompt)
76
 
77
+ ctx_parts: list[str] = [prompt]
78
  if file_path:
79
+ ctx_parts += ["[File]", extract_text_from_file(file_path)[:5000]]
 
 
80
  if website_url:
81
  html = extract_website_content(website_url)
82
  if not html.startswith("Error"):
83
+ ctx_parts += ["[Website]", html[:8000]]
 
84
 
85
+ user_msg = enhance_query_with_search("\n\n".join(ctx_parts), enable_search)
86
+ messages.append({"role": "user", "content": user_msg})
 
87
 
88
+ # 2Β run model (provider selection handled in inference.chat_completion)
89
+ model: ModelInfo = find_model(model_name) or AVAILABLE_MODELS[0]
90
+ try:
91
+ raw_out = chat_completion(model.id, messages)
92
+ except Exception as exc: # pragma: no cover
93
+ err = f"❌ **Error**\n```{exc}```"
94
+ hist.append((prompt, err))
95
+ return "", hist, "", history_to_chatbot_messages(hist)
96
 
97
+ # 3Β post‑process
98
  if language == "transformers.js":
99
+ files = parse_transformers_js_output(raw_out)
100
  code = format_transformers_js_output(files)
101
+ preview = send_to_sandbox(files.get("index.html", ""))
102
  else:
103
+ cleaned = remove_code_block(raw_out)
104
+ if hist and not hist[-1][1].startswith("❌"):
105
+ cleaned = apply_search_replace_changes(hist[-1][1], cleaned)
106
+ code = cleaned
107
+ preview = send_to_sandbox(cleaned) if language == "html" else ""
108
+
109
+ hist.append((prompt, code))
110
+ chat_view = history_to_chatbot_messages(hist)
111
+ return code, hist, preview, chat_view
112
+
113
+
114
+ # ── UI ──────────────────────────────────────────────────────────
115
+ THEME = gr.themes.Soft(primary_hue="indigo")
116
+ custom_css = """
117
+ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; }
118
+ #main_title { text-align:center;font-size:2.4rem;margin-top:1rem }
119
+ #subtitle { text-align:center;color:#5a6475;margin-bottom:2rem }
120
+ """
121
+
122
+ with gr.Blocks(title="AnyCoderΒ AI", theme=THEME, css=custom_css) as demo:
123
+ state_hist: gr.State[History] = gr.State([])
124
+
125
+ gr.Markdown("## πŸš€β€―AnyCoderΒ AI", elem_id="main_title")
126
+ gr.Markdown("Your AI partner for generating, modifying & understanding code.", elem_id="subtitle")
127
+
128
+ with gr.Row():
129
+ # ────────── inputs (sidebar) ──────────
130
+ with gr.Column(scale=1):
131
+ gr.Markdown("#### 1β€―Β·β€―Selectβ€―Model")
132
+ model_dd = gr.Dropdown(
133
+ choices=[m.name for m in AVAILABLE_MODELS],
134
+ value=AVAILABLE_MODELS[0].name,
135
+ label="AIΒ Model",
136
+ )
137
+
138
+ gr.Markdown("#### 2β€―Β·β€―Provideβ€―Context")
139
+ with gr.Tabs():
140
+ with gr.Tab("Prompt"):
141
+ prompt_box = gr.Textbox(lines=6, placeholder="Describe what you want…")
142
+ with gr.Tab("File"):
143
+ file_box = gr.File(type="filepath")
144
+ with gr.Tab("Website"):
145
+ url_box = gr.Textbox(placeholder="https://example.com")
146
+
147
+ gr.Markdown("#### 3β€―Β·β€―Configureβ€―Output")
148
+ lang_dd = gr.Dropdown(SUPPORTED_LANGUAGES, value="html", label="TargetΒ Language")
149
+ search_ck = gr.Checkbox(label="EnableΒ TavilyΒ WebΒ Search")
150
+
151
+ with gr.Row():
152
+ clear_btn = gr.Button("Clear Session", variant="secondary")
153
+ gen_btn = gr.Button("GenerateΒ Code", variant="primary")
154
+
155
+ # ────────── outputs (main panel) ─────
156
+ with gr.Column(scale=2):
157
+ with gr.Tabs():
158
+ with gr.Tab("Code"):
159
+ code_out = gr.Code(interactive=True)
160
+ with gr.Tab("Liveβ€―Preview"):
161
+ preview_out = gr.HTML()
162
+ with gr.Tab("History"):
163
+ chat_out = gr.Chatbot(type="messages")
164
+
165
+ # ── wiring ───────────────────────────────────────────
166
+ gen_btn.click(
167
+ generate_code,
168
+ inputs=[prompt_box, file_box, url_box, model_dd, search_ck, lang_dd, state_hist],
169
+ outputs=[code_out, state_hist, preview_out, chat_out],
170
+ )
171
+
172
+ clear_btn.click(
173
+ lambda: ("", None, "", "html", False, [], [], "", ""),
174
+ outputs=[prompt_box, file_box, url_box, lang_dd, search_ck,
175
+ state_hist, code_out, preview_out, chat_out],
176
+ queue=False,
177
  )
178
 
 
179
  if __name__ == "__main__":
180
  demo.queue().launch()