TheHickman commited on
Commit
7773cb2
·
verified ·
1 Parent(s): dd9f125

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +63 -60
app.py CHANGED
@@ -4,7 +4,6 @@ import os
4
 
5
  client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
6
 
7
-
8
  # ---- GPT explanation backend ----
9
  def explain_text(selected_text):
10
  if not selected_text or not selected_text.strip():
@@ -13,20 +12,10 @@ def explain_text(selected_text):
13
  response = client.responses.create(
14
  model="gpt-4.1-mini",
15
  input=[
16
- {
17
- "role": "system",
18
- "content": (
19
- "You are an expert machine learning instructor. "
20
- "Explain concepts clearly and intuitively for learners with basic ML knowledge. "
21
- "Keep explanations concise and educational."
22
- ),
23
- },
24
- {
25
- "role": "user",
26
- "content": f'Explain this text from a learning resource:\n\n"""\n{selected_text}\n"""',
27
- },
28
  ],
29
- max_output_tokens=400,
30
  )
31
  return response.output_text
32
  except Exception as e:
@@ -77,52 +66,33 @@ HF_REFERENCE_HTML = """
77
  A story generation model can receive an input like "Once upon a time" and proceed to create a story-like text.
78
  If your generative model training data differs from your use case, you can train a causal language model from scratch.
79
  </p>
80
- <h2>Task Variants</h2>
81
- <h3>Completion Generation Models</h3>
82
- <p>
83
- A popular variant of Text Generation models predicts the next word given a bunch of words.
84
- Common use cases include completing incomplete sentences, continuing a story, or generating code from a description.
85
- The most popular models for this task are GPT-based models, Mistral or Llama series.
86
- </p>
87
- <h3>Text-to-Text Generation Models</h3>
88
- <p>
89
- These models are trained to learn the mapping between a pair of texts, for example translation from one language to another.
90
- The most popular variants are NLLB, FLAN-T5, and BART, which handle summarization, translation, and text classification.
91
- </p>
92
- <h3>Language Model Variants</h3>
93
- <p>When it comes to text generation, the underlying language model can come in several types:</p>
94
- <ul>
95
- <li><strong>Base models:</strong> Plain language models like Mistral 7B and Meta Llama-3-70b. Good for fine-tuning and few-shot prompting.</li>
96
- <li><strong>Instruction-trained models:</strong> Trained to follow a broad range of instructions. Examples include Qwen 2 7B and Meta Llama 70B Instruct.</li>
97
- <li><strong>Human feedback models:</strong> Extend base models using RLHF to align with human preferences for helpfulness, honesty, and harmlessness.</li>
98
- </ul>
99
- <h2>Inference</h2>
100
- <p>
101
- You can use the Transformers library text-generation pipeline to do inference with text generation models.
102
- It takes an input text and generates a continuation of that text.
103
- </p>
104
- <pre style="background: #f5f5f5; padding: 15px; border-radius: 5px; overflow-x: auto;">
105
- from transformers import pipeline
106
- generator = pipeline('text-generation', model='gpt2')
107
- generator("Hello, I'm a language model,", max_length=30, num_return_sequences=3)
108
- </pre>
109
- <h2>Text Generation Inference</h2>
110
- <p>
111
- Text Generation Inference (TGI) is an open-source toolkit for serving LLMs, tackling challenges such as response time.
112
- TGI powers inference solutions like Inference Endpoints and Hugging Chat, as well as multiple community projects.
113
- </p>
114
  </div>
115
  """
116
 
117
-
118
  def switch_content(choice):
119
  return YOUR_WORK_HTML if choice == "My Work" else HF_REFERENCE_HTML
120
 
121
 
122
- # ---- All the magic: floating sticky button + popup tooltip ----
123
  HEAD_HTML = """
124
  <style>
125
- /* Floating FAB style … same as before … */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
  </style>
127
  <script>
128
  (function(){
@@ -131,7 +101,7 @@ HEAD_HTML = """
131
  function buildFAB() {
132
  if(document.getElementById("explain-fab")) return;
133
  const btn=document.createElement("button");
134
- btn.id="explain-fab"; btn.innerHTML="Explain 🧠";
135
  document.body.appendChild(btn);
136
  btn.addEventListener("click", onExplainClick);
137
  }
@@ -157,10 +127,27 @@ HEAD_HTML = """
157
 
158
  async function onExplainClick() {
159
  if(!selectedText) return;
160
- const response=await gradioApp().getElement("hidden-btn").clickAsync(selectedText);
161
- showPopup(response);
162
- selectedText=""; savedRange=null;
163
- hideFAB();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
  }
165
 
166
  function showPopup(text){
@@ -173,6 +160,9 @@ HEAD_HTML = """
173
  popup.style.borderRadius="6px";
174
  popup.style.maxWidth="300px";
175
  popup.style.zIndex=99999;
 
 
 
176
  popup.textContent=text;
177
  document.body.appendChild(popup);
178
  if(savedRange){
@@ -188,13 +178,26 @@ HEAD_HTML = """
188
  </script>
189
  """
190
 
 
191
  with gr.Blocks(head=HEAD_HTML) as demo:
192
- view_toggle = gr.Radio(choices=["My Work","HF Reference"], value="My Work", label="View")
 
 
 
 
 
 
 
 
 
193
  content_display = gr.HTML(YOUR_WORK_HTML)
194
- view_toggle.change(switch_content, view_toggle, content_display)
195
 
196
  # Hidden plumbing
197
- hidden_btn = gr.Button("hidden-btn", visible=False)
198
- hidden_btn.click(explain_text, inputs=gr.Textbox(visible=False), outputs=gr.Textbox(visible=False))
 
 
 
199
 
200
  demo.launch()
 
4
 
5
  client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
6
 
 
7
  # ---- GPT explanation backend ----
8
  def explain_text(selected_text):
9
  if not selected_text or not selected_text.strip():
 
12
  response = client.responses.create(
13
  model="gpt-4.1-mini",
14
  input=[
15
+ {"role": "system", "content": "You are an expert ML instructor. Explain clearly for beginners."},
16
+ {"role": "user", "content": f'Explain this text:\n"""{selected_text}"""'}
 
 
 
 
 
 
 
 
 
 
17
  ],
18
+ max_output_tokens=400
19
  )
20
  return response.output_text
21
  except Exception as e:
 
66
  A story generation model can receive an input like "Once upon a time" and proceed to create a story-like text.
67
  If your generative model training data differs from your use case, you can train a causal language model from scratch.
68
  </p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  </div>
70
  """
71
 
 
72
  def switch_content(choice):
73
  return YOUR_WORK_HTML if choice == "My Work" else HF_REFERENCE_HTML
74
 
75
 
76
+ # ---- Floating FAB + tooltip JS ----
77
  HEAD_HTML = """
78
  <style>
79
+ #explain-fab {
80
+ position: fixed;
81
+ bottom: 36px;
82
+ right: 36px;
83
+ z-index: 99999;
84
+ padding: 12px 22px;
85
+ border-radius: 999px;
86
+ background: #1e1b4b;
87
+ color: #fff;
88
+ font-weight: 600;
89
+ cursor: pointer;
90
+ border: none;
91
+ opacity: 0;
92
+ transform: translateY(12px);
93
+ transition: opacity 0.2s ease, transform 0.2s ease, background 0.15s;
94
+ }
95
+ #explain-fab:hover:not(:disabled){background:#3730a3;}
96
  </style>
97
  <script>
98
  (function(){
 
101
  function buildFAB() {
102
  if(document.getElementById("explain-fab")) return;
103
  const btn=document.createElement("button");
104
+ btn.id="explain-fab"; btn.textContent="Explain 🧠";
105
  document.body.appendChild(btn);
106
  btn.addEventListener("click", onExplainClick);
107
  }
 
127
 
128
  async function onExplainClick() {
129
  if(!selectedText) return;
130
+ // call hidden Gradio button with input
131
+ const hiddenBtn=gradioApp().getElement("hidden-btn");
132
+ if(hiddenBtn){
133
+ hiddenBtn.querySelector("button").click(); // triggers backend
134
+ // assign the selected text to hidden textbox
135
+ const ta=hiddenBtn.querySelector("textarea");
136
+ if(ta){ ta.value=selectedText; ta.dispatchEvent(new Event('input',{bubbles:true})); }
137
+ // wait for response
138
+ const output=await new Promise(resolve=>{
139
+ const obs=new MutationObserver(m=>{
140
+ const outTa=document.querySelector("#hidden-output textarea");
141
+ if(outTa && outTa.value.trim()!==""){
142
+ obs.disconnect();
143
+ resolve(outTa.value.trim());
144
+ }
145
+ });
146
+ obs.observe(document.querySelector("#hidden-output"),{subtree:true,childList:true});
147
+ });
148
+ showPopup(output);
149
+ }
150
+ selectedText=""; savedRange=null; hideFAB();
151
  }
152
 
153
  function showPopup(text){
 
160
  popup.style.borderRadius="6px";
161
  popup.style.maxWidth="300px";
162
  popup.style.zIndex=99999;
163
+ popup.style.fontSize="14px";
164
+ popup.style.lineHeight="1.5";
165
+ popup.style.color="#1c1917";
166
  popup.textContent=text;
167
  document.body.appendChild(popup);
168
  if(savedRange){
 
178
  </script>
179
  """
180
 
181
+
182
  with gr.Blocks(head=HEAD_HTML) as demo:
183
+ gr.Markdown(
184
+ "### 📘 Highlight any text — a floating **Explain 🧠** button will appear. "
185
+ "Click it to show an AI explanation in a popup near your selection."
186
+ )
187
+
188
+ view_toggle = gr.Radio(
189
+ choices=["My Work", "HF Reference"],
190
+ value="My Work",
191
+ label="View",
192
+ )
193
  content_display = gr.HTML(YOUR_WORK_HTML)
194
+ view_toggle.change(fn=switch_content, inputs=view_toggle, outputs=content_display)
195
 
196
  # Hidden plumbing
197
+ hidden_row = gr.Row(visible=False)
198
+ hidden_input = gr.Textbox(label="hidden-input", visible=False)
199
+ hidden_output = gr.Textbox(label="hidden-output", visible=False, elem_id="hidden-output")
200
+ hidden_btn = gr.Button("hidden-btn", elem_id="hidden-btn", visible=False)
201
+ hidden_btn.click(fn=explain_text, inputs=hidden_input, outputs=hidden_output)
202
 
203
  demo.launch()