Download app.py from drshabbirhassan/CSS_WITH_LEXISCAN_ASPIRE: direct link, hf CLI and curl.
- Browser
- Download file 4.75 kB
-
https://huggingface.co/spaces/drshabbirhassan/CSS_WITH_LEXISCAN_ASPIRE/resolve/main/app.py
- Command line
-
hf download hf://spaces/drshabbirhassan/CSS_WITH_LEXISCAN_ASPIRE/app.py
-
curl -L -o app.py https://huggingface.co/spaces/drshabbirhassan/CSS_WITH_LEXISCAN_ASPIRE/resolve/main/app.py
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 | |