Engr-Usman-Ali commited on
Commit
916eef9
ยท
verified ยท
1 Parent(s): 0f01a50

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +171 -82
app.py CHANGED
@@ -3,12 +3,14 @@ from groq import Groq
3
  import requests
4
  import html
5
 
 
6
  # Page config
 
7
  st.set_page_config(page_title="CodeCraft AI", layout="wide")
8
 
9
- # =======================
10
  # API Clients Initialization
11
- # =======================
12
  groq_client = None
13
  groq_status = "โŒ"
14
  if "GROQ_API_KEY" in st.secrets:
@@ -25,19 +27,24 @@ hf_status = "โŒ"
25
  if huggingface_api_key:
26
  try:
27
  headers = {"Authorization": f"Bearer {huggingface_api_key}"}
28
- response = requests.get("https://api-inference.huggingface.co/status", headers=headers, timeout=10)
 
 
 
 
29
  if response.status_code in [200, 401, 403]:
30
  hf_status = "โœ…"
31
  except Exception:
32
  hf_status = "โŒ"
33
 
34
- # =======================
35
  # CSS layout & styling
36
- # =======================
37
- SIDEBAR_WIDTH_PX = 260
38
  st.markdown(
39
  f"""
40
  <style>
 
41
  [data-testid="stSidebar"] {{
42
  width: {SIDEBAR_WIDTH_PX}px;
43
  min-width: {SIDEBAR_WIDTH_PX}px;
@@ -46,70 +53,117 @@ st.markdown(
46
  top: 0;
47
  bottom: 0;
48
  overflow-y: auto;
 
 
 
49
  }}
 
 
50
  .block-container {{
51
  margin-left: {SIDEBAR_WIDTH_PX + 20}px;
52
- padding-top: 8px;
53
  }}
 
 
54
  .chat-panel {{
55
- height: calc(100vh - 180px);
56
  overflow-y: auto;
57
- padding: 8px 12px;
58
  background: transparent;
59
  }}
 
 
60
  .msg-row {{ display:flex; margin:8px 0; }}
61
  .msg-user {{ justify-content:flex-end; }}
62
  .msg-assistant {{ justify-content:flex-start; }}
63
  .bubble {{
64
  max-width: 75%;
65
- padding:10px 12px;
66
- border-radius:12px;
67
  white-space:pre-wrap;
68
  word-wrap:break-word;
69
- font-size:14px;
70
- line-height:1.45;
 
 
 
 
 
 
71
  }}
72
- .bubble-user {{ background:#0b1020; color:#fff; border-radius:12px 12px 6px 12px; }}
73
- .bubble-assistant {{ background:#f0f0f0; color:#111; border-radius:12px 12px 12px 6px; }}
74
- .code-block {{ background:#1e1e1e; color:#e6e6e6; padding:10px; border-radius:6px; overflow:auto; font-family:monospace; }}
75
- div[data-testid="stChatInput"] {{
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  position: fixed !important;
77
  bottom: 36px !important;
78
  left: {SIDEBAR_WIDTH_PX + 24}px !important;
79
  right: 24px !important;
80
- z-index: 9999;
81
- background: #0e1117 !important;
 
 
 
82
  }}
 
 
83
  .cc-footer {{
84
  position: fixed;
85
  bottom: 0;
86
  left: {SIDEBAR_WIDTH_PX + 24}px;
87
  right: 24px;
88
  text-align: center;
89
- font-size: 12px;
90
  color: gray;
91
- padding: 4px 0;
92
- background: transparent;
93
- z-index: 9998;
 
94
  }}
95
- footer {{visibility:hidden;}}
 
96
  </style>
97
  """,
98
  unsafe_allow_html=True,
99
  )
100
 
101
- # =======================
102
- # Sidebar content
103
- # =======================
104
  st.sidebar.title("โš™๏ธ Settings")
105
  st.sidebar.markdown(f"**Groq API Status:** {groq_status}")
106
  st.sidebar.markdown(f"**HuggingFace API Status:** {hf_status}")
107
- api_priority = st.sidebar.radio("Choose API Priority", ["Groq First", "HuggingFace First"], index=0)
108
- model_choice = st.sidebar.selectbox("Choose Model", ["llama-3.1-8b-instant", "llama-3.1-70b-versatile", "mixtral-8x7b-32768"])
 
 
 
 
 
 
 
 
 
 
 
 
109
  st.sidebar.markdown("---")
110
  st.sidebar.markdown("### ๐Ÿ’ฌ Chats")
111
 
112
- # init chats
113
  if "chats" not in st.session_state:
114
  st.session_state.chats = {"Chat 1": {"generate": [], "debug": [], "explain": []}}
115
  if "active_chat" not in st.session_state:
@@ -117,133 +171,163 @@ if "active_chat" not in st.session_state:
117
  if "menu_open" not in st.session_state:
118
  st.session_state.menu_open = {}
119
 
120
- # New Chat
121
  if st.sidebar.button("โž• New Chat"):
122
  idx = len(st.session_state.chats) + 1
123
- name = f"Chat {idx}"
124
- st.session_state.chats[name] = {"generate": [], "debug": [], "explain": []}
125
- st.session_state.active_chat = name
126
  st.rerun()
127
 
128
- # Chat list with menus
129
  for chat_name in list(st.session_state.chats.keys()):
130
  c1, c2 = st.sidebar.columns([7, 1])
131
  if c1.button(chat_name, key=f"select_{chat_name}"):
132
  st.session_state.active_chat = chat_name
133
  st.rerun()
134
  if c2.button("โ‹ฎ", key=f"menu_{chat_name}"):
135
- st.session_state.menu_open[chat_name] = not st.session_state.menu_open.get(chat_name, False)
 
 
136
  st.rerun()
 
137
  if st.session_state.menu_open.get(chat_name, False):
138
- action = st.sidebar.radio(f"{chat_name} options", ["None", "Rename", "Delete"], key=f"opt_{chat_name}")
 
 
139
  if action == "Rename":
140
- new_label = st.sidebar.text_input("New name:", value=chat_name, key=f"rename_{chat_name}")
 
 
141
  if st.sidebar.button("Save", key=f"save_{chat_name}"):
142
- st.session_state.chats[new_label] = st.session_state.chats.pop(chat_name)
143
- if st.session_state.active_chat == chat_name:
144
- st.session_state.active_chat = new_label
145
- st.session_state.menu_open[new_label] = False
146
- st.rerun()
 
 
 
147
  elif action == "Delete":
148
  if st.sidebar.button("Confirm delete", key=f"del_{chat_name}"):
149
- st.session_state.chats.pop(chat_name)
150
- st.session_state.menu_open.pop(chat_name, None)
151
  if st.session_state.active_chat == chat_name:
152
- keys = list(st.session_state.chats.keys())
153
- st.session_state.active_chat = keys[0] if keys else None
154
  st.rerun()
155
 
156
- st.sidebar.caption("Tip: use โ‹ฎ to rename/delete chats.")
157
-
158
  active_chat = st.session_state.active_chat
159
 
160
- # =======================
161
  # API helpers
162
- # =======================
163
  def call_groq(system_prompt, chat_history):
164
  if not groq_client:
165
  return None
166
  try:
167
- resp = groq_client.chat.completions.create(
168
  model=model_choice,
169
  messages=[{"role": "system", "content": system_prompt}]
170
- + [{"role": r, "content": m} for r, m in chat_history],
171
- temperature=0.4,
 
 
172
  )
173
- return resp.choices[0].message.content
174
  except Exception:
175
  return None
176
 
177
- def call_hf(system_prompt, chat_history):
 
178
  if not huggingface_api_key:
179
  return None
180
  try:
181
  headers = {"Authorization": f"Bearer {huggingface_api_key}"}
182
  prompt = system_prompt + "\n\n" + "\n".join([f"{r}: {m}" for r, m in chat_history])
183
- payload = {"inputs": prompt, "parameters": {"temperature": 0.5, "max_new_tokens": 400}}
184
- resp = requests.post(f"https://api-inference.huggingface.co/models/{model_choice}", headers=headers, json=payload, timeout=60)
185
- if resp.status_code == 200:
186
- data = resp.json()
187
- if isinstance(data, list) and "generated_text" in data[0]:
 
 
 
 
 
 
 
 
188
  return data[0]["generated_text"]
189
  if isinstance(data, dict) and "generated_text" in data:
190
  return data["generated_text"]
 
191
  return None
192
  except Exception:
193
  return None
194
 
 
195
  def get_ai_response(system_prompt, chat_history):
 
196
  if api_priority == "Groq First":
197
- ai = call_groq(system_prompt, chat_history) or call_hf(system_prompt, chat_history)
 
 
198
  else:
199
- ai = call_hf(system_prompt, chat_history) or call_groq(system_prompt, chat_history)
200
- return ai or "โŒ Both APIs failed."
 
 
201
 
202
- # =======================
203
  # Render messages
204
- # =======================
205
  def render_messages_html(messages):
206
  parts = ['<div class="chat-panel">']
207
  for role, msg in messages:
208
  safe = html.escape(msg)
209
  if "```" in msg:
210
- segs = msg.split("```")
211
  content_html = ""
212
- for i, seg in enumerate(segs):
213
- if i % 2 == 1:
214
  lines = seg.split("\n")
215
  code = "\n".join(lines[1:]) if len(lines) > 1 else ""
216
- content_html += f'<pre class="code-block"><code>{html.escape(code)}</code></pre>'
 
 
217
  else:
218
  if seg.strip():
219
  content_html += f"<div>{html.escape(seg)}</div>"
220
  else:
221
  content_html = f"<div>{safe}</div>"
 
222
  if role == "user":
223
- parts.append(f'<div class="msg-row msg-user"><div class="bubble bubble-user">{content_html}</div></div>')
 
 
224
  else:
225
- parts.append(f'<div class="msg-row msg-assistant"><div class="bubble bubble-assistant">{content_html}</div></div>')
 
 
226
  parts.append("</div>")
227
  return "\n".join(parts)
228
 
229
- # =======================
230
  # Main UI
231
- # =======================
232
- st.markdown("<h1 style='margin-bottom:6px'>๐Ÿค– CodeCraft AI - Mini Copilot</h1>", unsafe_allow_html=True)
233
 
234
  tab_labels = ["๐Ÿ’ก Generate Code", "๐Ÿ›  Debug Code", "๐Ÿ“˜ Explain Code"]
235
  tabs = st.tabs(tab_labels)
236
  prompt_map = {
237
- "generate": "You are a helpful coding assistant. Generate code + short explanation.",
238
- "debug": "You are a debugger. Fix code and explain the fixes simply.",
239
- "explain": "You are a teacher. Explain the pasted code step by step.",
240
  }
241
  tab_keys = ["generate", "debug", "explain"]
242
 
243
  for i, key in enumerate(tab_keys):
244
  with tabs[i]:
245
  messages = st.session_state.chats[active_chat][key]
246
- st.markdown(render_messages_html(messages), unsafe_allow_html=True)
 
247
 
248
  user_input = st.chat_input("Type your message...", key=f"{active_chat}_{key}_input")
249
  if user_input:
@@ -254,7 +338,12 @@ for i, key in enumerate(tab_keys):
254
  st.session_state.chats[active_chat][key] = messages
255
  st.rerun()
256
 
257
- # =======================
258
  # Footer
259
- # =======================
260
- st.markdown('<div class="cc-footer">โš ๏ธ CodeCraft AI can make mistakes. Verify important code.</div>', unsafe_allow_html=True)
 
 
 
 
 
 
3
  import requests
4
  import html
5
 
6
+ # -----------------------------
7
  # Page config
8
+ # -----------------------------
9
  st.set_page_config(page_title="CodeCraft AI", layout="wide")
10
 
11
+ # -----------------------------
12
  # API Clients Initialization
13
+ # -----------------------------
14
  groq_client = None
15
  groq_status = "โŒ"
16
  if "GROQ_API_KEY" in st.secrets:
 
27
  if huggingface_api_key:
28
  try:
29
  headers = {"Authorization": f"Bearer {huggingface_api_key}"}
30
+ response = requests.get(
31
+ "https://api-inference.huggingface.co/status",
32
+ headers=headers,
33
+ timeout=10,
34
+ )
35
  if response.status_code in [200, 401, 403]:
36
  hf_status = "โœ…"
37
  except Exception:
38
  hf_status = "โŒ"
39
 
40
+ # -----------------------------
41
  # CSS layout & styling
42
+ # -----------------------------
43
+ SIDEBAR_WIDTH_PX = 300
44
  st.markdown(
45
  f"""
46
  <style>
47
+ /* Sidebar */
48
  [data-testid="stSidebar"] {{
49
  width: {SIDEBAR_WIDTH_PX}px;
50
  min-width: {SIDEBAR_WIDTH_PX}px;
 
53
  top: 0;
54
  bottom: 0;
55
  overflow-y: auto;
56
+ padding: 20px 12px !important;
57
+ background: #f7f9fc;
58
+ border-right: 1px solid #e0e0e0;
59
  }}
60
+
61
+ /* Main content */
62
  .block-container {{
63
  margin-left: {SIDEBAR_WIDTH_PX + 20}px;
64
+ padding-top: 16px;
65
  }}
66
+
67
+ /* Chat panel full height */
68
  .chat-panel {{
69
+ height: calc(100vh - 170px);
70
  overflow-y: auto;
71
+ padding: 12px 16px;
72
  background: transparent;
73
  }}
74
+
75
+ /* Message bubbles */
76
  .msg-row {{ display:flex; margin:8px 0; }}
77
  .msg-user {{ justify-content:flex-end; }}
78
  .msg-assistant {{ justify-content:flex-start; }}
79
  .bubble {{
80
  max-width: 75%;
81
+ padding:10px 14px;
82
+ border-radius:14px;
83
  white-space:pre-wrap;
84
  word-wrap:break-word;
85
+ font-size:15px;
86
+ line-height:1.5;
87
+ box-shadow: 0 1px 3px rgba(0,0,0,0.1);
88
+ }}
89
+ .bubble-user {{
90
+ background:#0b1020;
91
+ color:#fff;
92
+ border-radius:14px 14px 6px 14px;
93
  }}
94
+ .bubble-assistant {{
95
+ background:#eef0f2;
96
+ color:#111;
97
+ border-radius:14px 14px 14px 6px;
98
+ }}
99
+
100
+ /* Code block */
101
+ .code-block {{
102
+ background:#0b0b0b;
103
+ color:#e6e6e6;
104
+ padding:10px;
105
+ border-radius:6px;
106
+ overflow:auto;
107
+ font-family:monospace;
108
+ }}
109
+
110
+ /* Fixed input */
111
+ div[data-testid="stChatInput"], .stChatInput {{
112
  position: fixed !important;
113
  bottom: 36px !important;
114
  left: {SIDEBAR_WIDTH_PX + 24}px !important;
115
  right: 24px !important;
116
+ z-index: 99999;
117
+ background: #fff !important;
118
+ border-radius: 12px;
119
+ box-shadow: 0 2px 6px rgba(0,0,0,0.08);
120
+ padding: 6px 12px !important;
121
  }}
122
+
123
+ /* Footer */
124
  .cc-footer {{
125
  position: fixed;
126
  bottom: 0;
127
  left: {SIDEBAR_WIDTH_PX + 24}px;
128
  right: 24px;
129
  text-align: center;
130
+ font-size: 13px;
131
  color: gray;
132
+ padding: 6px 0;
133
+ background: #fafafa;
134
+ border-top: 1px solid #e0e0e0;
135
+ z-index: 99998;
136
  }}
137
+
138
+ footer {{ visibility: hidden; }}
139
  </style>
140
  """,
141
  unsafe_allow_html=True,
142
  )
143
 
144
+ # -----------------------------
145
+ # Sidebar: Settings + Sliders + Chats
146
+ # -----------------------------
147
  st.sidebar.title("โš™๏ธ Settings")
148
  st.sidebar.markdown(f"**Groq API Status:** {groq_status}")
149
  st.sidebar.markdown(f"**HuggingFace API Status:** {hf_status}")
150
+
151
+ api_priority = st.sidebar.radio(
152
+ "Choose API Priority", ["Groq First", "HuggingFace First"], index=0
153
+ )
154
+ model_choice = st.sidebar.selectbox(
155
+ "Choose Model",
156
+ ["llama-3.1-8b-instant", "llama-3.1-70b-versatile", "mixtral-8x7b-32768"],
157
+ )
158
+
159
+ st.sidebar.markdown("### ๐Ÿ”ง Parameters")
160
+ temperature = st.sidebar.slider("Temperature", 0.0, 1.0, 0.4, 0.05)
161
+ max_tokens = st.sidebar.slider("Max Tokens", 100, 2000, 500, 50)
162
+ top_p = st.sidebar.slider("Top P", 0.1, 1.0, 0.9, 0.05)
163
+
164
  st.sidebar.markdown("---")
165
  st.sidebar.markdown("### ๐Ÿ’ฌ Chats")
166
 
 
167
  if "chats" not in st.session_state:
168
  st.session_state.chats = {"Chat 1": {"generate": [], "debug": [], "explain": []}}
169
  if "active_chat" not in st.session_state:
 
171
  if "menu_open" not in st.session_state:
172
  st.session_state.menu_open = {}
173
 
 
174
  if st.sidebar.button("โž• New Chat"):
175
  idx = len(st.session_state.chats) + 1
176
+ new_name = f"Chat {idx}"
177
+ st.session_state.chats[new_name] = {"generate": [], "debug": [], "explain": []}
178
+ st.session_state.active_chat = new_name
179
  st.rerun()
180
 
 
181
  for chat_name in list(st.session_state.chats.keys()):
182
  c1, c2 = st.sidebar.columns([7, 1])
183
  if c1.button(chat_name, key=f"select_{chat_name}"):
184
  st.session_state.active_chat = chat_name
185
  st.rerun()
186
  if c2.button("โ‹ฎ", key=f"menu_{chat_name}"):
187
+ st.session_state.menu_open[chat_name] = not st.session_state.menu_open.get(
188
+ chat_name, False
189
+ )
190
  st.rerun()
191
+
192
  if st.session_state.menu_open.get(chat_name, False):
193
+ action = st.sidebar.radio(
194
+ f"Options for {chat_name}", ["None", "Rename", "Delete"], key=f"opt_{chat_name}"
195
+ )
196
  if action == "Rename":
197
+ new_label = st.sidebar.text_input(
198
+ "New name:", value=chat_name, key=f"rename_{chat_name}"
199
+ )
200
  if st.sidebar.button("Save", key=f"save_{chat_name}"):
201
+ if new_label and new_label.strip():
202
+ st.session_state.chats[new_label] = st.session_state.chats.pop(
203
+ chat_name
204
+ )
205
+ if st.session_state.active_chat == chat_name:
206
+ st.session_state.active_chat = new_label
207
+ st.session_state.menu_open[new_label] = False
208
+ st.rerun()
209
  elif action == "Delete":
210
  if st.sidebar.button("Confirm delete", key=f"del_{chat_name}"):
211
+ st.session_state.chats.pop(chat_name, None)
 
212
  if st.session_state.active_chat == chat_name:
213
+ st.session_state.active_chat = next(iter(st.session_state.chats), None)
 
214
  st.rerun()
215
 
 
 
216
  active_chat = st.session_state.active_chat
217
 
218
+ # -----------------------------
219
  # API helpers
220
+ # -----------------------------
221
  def call_groq(system_prompt, chat_history):
222
  if not groq_client:
223
  return None
224
  try:
225
+ response = groq_client.chat.completions.create(
226
  model=model_choice,
227
  messages=[{"role": "system", "content": system_prompt}]
228
+ + [{"role": role, "content": msg} for role, msg in chat_history],
229
+ temperature=temperature,
230
+ max_tokens=max_tokens,
231
+ top_p=top_p,
232
  )
233
+ return response.choices[0].message.content
234
  except Exception:
235
  return None
236
 
237
+
238
+ def call_huggingface(system_prompt, chat_history):
239
  if not huggingface_api_key:
240
  return None
241
  try:
242
  headers = {"Authorization": f"Bearer {huggingface_api_key}"}
243
  prompt = system_prompt + "\n\n" + "\n".join([f"{r}: {m}" for r, m in chat_history])
244
+ payload = {
245
+ "inputs": prompt,
246
+ "parameters": {"temperature": temperature, "max_new_tokens": max_tokens},
247
+ }
248
+ response = requests.post(
249
+ f"https://api-inference.huggingface.co/models/{model_choice}",
250
+ headers=headers,
251
+ json=payload,
252
+ timeout=60,
253
+ )
254
+ if response.status_code == 200:
255
+ data = response.json()
256
+ if isinstance(data, list) and data and "generated_text" in data[0]:
257
  return data[0]["generated_text"]
258
  if isinstance(data, dict) and "generated_text" in data:
259
  return data["generated_text"]
260
+ return str(data)
261
  return None
262
  except Exception:
263
  return None
264
 
265
+
266
  def get_ai_response(system_prompt, chat_history):
267
+ ai_msg = None
268
  if api_priority == "Groq First":
269
+ ai_msg = call_groq(system_prompt, chat_history) or call_huggingface(
270
+ system_prompt, chat_history
271
+ )
272
  else:
273
+ ai_msg = call_huggingface(system_prompt, chat_history) or call_groq(
274
+ system_prompt, chat_history
275
+ )
276
+ return ai_msg or "โŒ Both APIs failed. Please check your API keys."
277
 
278
+ # -----------------------------
279
  # Render messages
280
+ # -----------------------------
281
  def render_messages_html(messages):
282
  parts = ['<div class="chat-panel">']
283
  for role, msg in messages:
284
  safe = html.escape(msg)
285
  if "```" in msg:
286
+ segments = msg.split("```")
287
  content_html = ""
288
+ for si, seg in enumerate(segments):
289
+ if si % 2 == 1:
290
  lines = seg.split("\n")
291
  code = "\n".join(lines[1:]) if len(lines) > 1 else ""
292
+ content_html += (
293
+ f'<pre class="code-block"><code>{html.escape(code)}</code></pre>'
294
+ )
295
  else:
296
  if seg.strip():
297
  content_html += f"<div>{html.escape(seg)}</div>"
298
  else:
299
  content_html = f"<div>{safe}</div>"
300
+
301
  if role == "user":
302
+ parts.append(
303
+ f'<div class="msg-row msg-user"><div class="bubble bubble-user">{content_html}</div></div>'
304
+ )
305
  else:
306
+ parts.append(
307
+ f'<div class="msg-row msg-assistant"><div class="bubble bubble-assistant">{content_html}</div></div>'
308
+ )
309
  parts.append("</div>")
310
  return "\n".join(parts)
311
 
312
+ # -----------------------------
313
  # Main UI
314
+ # -----------------------------
315
+ st.markdown("<h1 style='margin-bottom:12px'>๐Ÿค– CodeCraft AI - Mini Copilot</h1>", unsafe_allow_html=True)
316
 
317
  tab_labels = ["๐Ÿ’ก Generate Code", "๐Ÿ›  Debug Code", "๐Ÿ“˜ Explain Code"]
318
  tabs = st.tabs(tab_labels)
319
  prompt_map = {
320
+ "generate": "You are a helpful coding assistant. Generate correct code and explain simply.",
321
+ "debug": "You are an expert code debugger. Fix errors, explain changes simply.",
322
+ "explain": "You are a teacher. Explain code step by step in simple words.",
323
  }
324
  tab_keys = ["generate", "debug", "explain"]
325
 
326
  for i, key in enumerate(tab_keys):
327
  with tabs[i]:
328
  messages = st.session_state.chats[active_chat][key]
329
+ html_block = render_messages_html(messages)
330
+ st.markdown(html_block, unsafe_allow_html=True)
331
 
332
  user_input = st.chat_input("Type your message...", key=f"{active_chat}_{key}_input")
333
  if user_input:
 
338
  st.session_state.chats[active_chat][key] = messages
339
  st.rerun()
340
 
341
+ # -----------------------------
342
  # Footer
343
+ # -----------------------------
344
+ st.markdown(
345
+ """
346
+ <div class="cc-footer">โš ๏ธ CodeCraft AI may produce mistakes. Always verify important code.</div>
347
+ """,
348
+ unsafe_allow_html=True,
349
+ )