drshabbirhassan commited on
Commit
ca293bb
·
verified ·
1 Parent(s): 45a2f6e

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +123 -0
app.py ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app.py — CSS LexiScan for Hugging Face Spaces
2
+ # Fully self-contained: précis + vocabulary extraction + Gradio UI
3
+
4
+ import os
5
+ import json
6
+ from typing import Dict
7
+
8
+ import gradio as gr
9
+ import pandas as pd
10
+ from groq import Groq
11
+
12
+ # === Prompt Templates ===
13
+ SYSTEM_PROMPT = (
14
+ "You are a helpful, concise assistant specialized in creating high-quality précis "
15
+ "and teaching vocabulary for CSS aspirants. Always output valid JSON with keys 'precis' and 'difficult_words'."
16
+ )
17
+
18
+ USER_PROMPT_TEMPLATE = (
19
+ "Here is a passage delimited by triple backticks.\n"
20
+ "Task:\n"
21
+ "1) Produce a concise précis (≤30% of original length).\n"
22
+ "2) Identify up to 7 difficult/uncommon words, each with word, part_of_speech, meaning (1–2 sentences), example sentence.\n"
23
+ "Rules:\n"
24
+ "- Return ONLY valid JSON.\n"
25
+ "- Avoid repetition.\n"
26
+ "Passage:\n```{passage}```"
27
+ )
28
+
29
+ FEW_SHOT = (
30
+ "Example input: 'The rapid expansion of renewable energy sources has altered global energy markets.'\n"
31
+ "Example output (JSON):\n"
32
+ "{\n"
33
+ " \"precis\": \"Renewable energy growth is reshaping global markets.\",\n"
34
+ " \"difficult_words\": [\n"
35
+ " {\"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"
36
+ " ]\n"
37
+ "}"
38
+ )
39
+
40
+ # === Helper Functions ===
41
+ def get_groq_api_key(secret_name: str = "GROQ_API_KEY") -> str:
42
+ key = os.environ.get(secret_name)
43
+ if not key:
44
+ raise ValueError(f"No Groq API key found. Set it in HF Secrets as '{secret_name}'.")
45
+ return key
46
+
47
+ def make_groq_client(api_key: str):
48
+ return Groq(api_key=api_key)
49
+
50
+ def truncate(text: str, max_len: int) -> str:
51
+ text = text.strip()
52
+ return text if len(text) <= max_len else text[:max_len-1] + "…"
53
+
54
+ def extract_json(text: str) -> str:
55
+ start = text.find("{")
56
+ end = text.rfind("}")
57
+ if start == -1 or end == -1 or end <= start:
58
+ raise ValueError("No JSON found in model response.")
59
+ return text[start:end+1]
60
+
61
+ def post_process(parsed: Dict) -> Dict:
62
+ precis = parsed.get("precis", "").strip()
63
+ difficult = parsed.get("difficult_words", [])
64
+ seen = set()
65
+ cleaned = []
66
+ for item in difficult:
67
+ word = item.get("word", "").strip()
68
+ if not word or word.lower() in seen:
69
+ continue
70
+ seen.add(word.lower())
71
+ cleaned.append({
72
+ "word": word,
73
+ "part_of_speech": item.get("part_of_speech", "").strip(),
74
+ "meaning": truncate(item.get("meaning", ""), 200),
75
+ "example": truncate(item.get("example", ""), 200)
76
+ })
77
+ return {"precis": truncate(precis, 2000), "difficult_words": cleaned}
78
+
79
+ def generate_precis_and_vocab(client: Groq, passage: str, model: str = "llama-3.3-70b-versatile") -> Dict:
80
+ passage = passage.strip()
81
+ chat_completion = client.chat.completions.create(
82
+ messages=[
83
+ {"role": "system", "content": SYSTEM_PROMPT},
84
+ {"role": "user", "content": FEW_SHOT},
85
+ {"role": "user", "content": USER_PROMPT_TEMPLATE.format(passage=passage)}
86
+ ],
87
+ model=model,
88
+ temperature=0.2,
89
+ max_tokens=800
90
+ )
91
+ raw_output = chat_completion.choices[0].message.content
92
+ json_text = extract_json(raw_output)
93
+ parsed = json.loads(json_text)
94
+ return post_process(parsed)
95
+
96
+ # === Gradio UI ===
97
+ def build_app(client: Groq):
98
+ def process_text(passage: str):
99
+ if not passage.strip():
100
+ return "Please enter a passage.", None
101
+ try:
102
+ parsed = generate_precis_and_vocab(client, passage)
103
+ except Exception as e:
104
+ return f"Error: {e}", None
105
+ precis = parsed.get("precis", "")
106
+ df = pd.DataFrame(parsed.get("difficult_words", []))
107
+ return precis, df
108
+
109
+ with gr.Blocks() as demo:
110
+ gr.Markdown("# 📝 CSS LexiScan — Précis & Vocabulary Assistant")
111
+ passage_input = gr.Textbox(lines=10, label="Paste your passage here:")
112
+ generate_btn = gr.Button("Generate Précis & Vocabulary")
113
+ precis_output = gr.Textbox(lines=5, label="Generated Précis")
114
+ vocab_output = gr.Dataframe(headers=["word", "part_of_speech", "meaning", "example"], label="Difficult Words")
115
+ generate_btn.click(fn=process_text, inputs=passage_input, outputs=[precis_output, vocab_output])
116
+ return demo
117
+
118
+ # === Main ===
119
+ if __name__ == "__main__":
120
+ api_key = get_groq_api_key()
121
+ client = make_groq_client(api_key)
122
+ app = build_app(client)
123
+ app.launch() # HF Spaces will automatically host this