drshabbirhassan's picture
Update app.py
0034db2 verified
Raw History Blame Contribute Delete
4.75 kB
# app.py — CSS LexiScan for Hugging Face Spaces
# Uses HF Secret 'SCAN' for Groq API key
# Fully self-contained: précis + vocabulary extraction + Gradio UI
import os
import json
from typing import Dict
import gradio as gr
import pandas as pd
from groq import Groq
# === Prompt Templates ===
SYSTEM_PROMPT = (
"You are a helpful, concise assistant specialized in creating high-quality précis "
"and teaching vocabulary for CSS aspirants. Always output valid JSON with keys 'precis' and 'difficult_words'."
)
USER_PROMPT_TEMPLATE = (
"Here is a passage delimited by triple backticks.\n"
"Task:\n"
"1) Produce a concise précis (≤30% of original length).\n"
"2) Identify up to 7 difficult/uncommon words, each with word, part_of_speech, meaning (1–2 sentences), example sentence.\n"
"Rules:\n"
"- Return ONLY valid JSON.\n"
"- Avoid repetition.\n"
"Passage:\n```{passage}```"
)
FEW_SHOT = (
"Example input: 'The rapid expansion of renewable energy sources has altered global energy markets.'\n"
"Example output (JSON):\n"
"{\n"
" \"precis\": \"Renewable energy growth is reshaping global markets.\",\n"
" \"difficult_words\": [\n"
" {\"word\": \"renewable\", \"part_of_speech\": \"adjective\", \"meaning\": \"Able to be replenished naturally without being exhausted.\", \"example\": \"Wind and sunlight are renewable sources of power.\"}\n"
" ]\n"
"}"
)
# === Helper Functions ===
def get_groq_api_key(secret_name: str = "SCAN") -> str:
key = os.environ.get(secret_name)
if not key:
raise ValueError(f"No Groq API key found. Set it in HF Secrets as '{secret_name}'.")
return key
def make_groq_client(api_key: str):
return Groq(api_key=api_key)
def truncate(text: str, max_len: int) -> str:
text = text.strip()
return text if len(text) <= max_len else text[:max_len-1] + "…"
def extract_json(text: str) -> str:
start = text.find("{")
end = text.rfind("}")
if start == -1 or end == -1 or end <= start:
raise ValueError("No JSON found in model response.")
return text[start:end+1]
def post_process(parsed: Dict) -> Dict:
precis = parsed.get("precis", "").strip()
difficult = parsed.get("difficult_words", [])
seen = set()
cleaned = []
for item in difficult:
word = item.get("word", "").strip()
if not word or word.lower() in seen:
continue
seen.add(word.lower())
cleaned.append({
"word": word,
"part_of_speech": item.get("part_of_speech", "").strip(),
"meaning": truncate(item.get("meaning", ""), 200),
"example": truncate(item.get("example", ""), 200)
})
return {"precis": truncate(precis, 2000), "difficult_words": cleaned}
def generate_precis_and_vocab(client: Groq, passage: str, model: str = "llama-3.3-70b-versatile") -> Dict:
passage = passage.strip()
chat_completion = client.chat.completions.create(
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": FEW_SHOT},
{"role": "user", "content": USER_PROMPT_TEMPLATE.format(passage=passage)}
],
model=model,
temperature=0.2,
max_tokens=800
)
raw_output = chat_completion.choices[0].message.content
json_text = extract_json(raw_output)
parsed = json.loads(json_text)
return post_process(parsed)
# === Gradio UI ===
def build_app(client: Groq):
def process_text(passage: str):
if not passage.strip():
return "Please enter a passage.", None
try:
parsed = generate_precis_and_vocab(client, passage)
except Exception as e:
return f"Error: {e}", None
precis = parsed.get("precis", "")
df = pd.DataFrame(parsed.get("difficult_words", []))
return precis, df
with gr.Blocks() as demo:
gr.Markdown("# 📝 CSS LexiScan — Précis & Vocabulary Assistant")
passage_input = gr.Textbox(lines=10, label="Paste your passage here:")
generate_btn = gr.Button("Generate Précis & Vocabulary")
precis_output = gr.Textbox(lines=5, label="Generated Précis")
vocab_output = gr.Dataframe(
headers=["word", "part_of_speech", "meaning", "example"],
label="Difficult Words"
)
generate_btn.click(fn=process_text, inputs=passage_input, outputs=[precis_output, vocab_output])
return demo
# === Main ===
if __name__ == "__main__":
api_key = get_groq_api_key("SCAN") # <-- Uses HF secret named 'SCAN'
client = make_groq_client(api_key)
app = build_app(client)
app.launch() # HF Spaces will automatically host this