Ars135 commited on
Commit
3bdcf00
·
verified ·
1 Parent(s): 8471f5a

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +43 -0
  2. summarizer.py +94 -0
app.py ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from summarizer import TextSummarizer
3
+
4
+ # Initialize the summarizer globally to load the model once
5
+ print("Initializing Summarizer...")
6
+ global_summarizer = TextSummarizer()
7
+
8
+ def summarize_text(text, target_words):
9
+ try:
10
+ # Ensure summarizer is initialized
11
+ if global_summarizer.llm is None:
12
+ return "Error: Model not loaded.", ""
13
+
14
+ summary, stats = global_summarizer.summarize(text, int(target_words))
15
+ return summary, stats
16
+ except Exception as e:
17
+ return f"An error occurred: {str(e)}", ""
18
+
19
+ # Create the Gradio interface
20
+ with gr.Blocks() as iface:
21
+ gr.Markdown("# AI Text Summarizer (Local Mistral-7B)")
22
+ gr.Markdown("Enter a long text to get a concise summary using the **Mistral-7B** model (running locally).")
23
+ gr.Markdown("> **Note:** The first run might take a moment to load the model. Subsequent runs will be faster.")
24
+
25
+ with gr.Row():
26
+ with gr.Column():
27
+ text_input = gr.Textbox(lines=10, label="Input Text", placeholder="Enter text to summarize here...")
28
+ # Changed from Max Tokens to Target Words
29
+ length_slider = gr.Slider(minimum=10, maximum=500, value=100, step=10, label="Target Summary Length (Words)")
30
+ submit_btn = gr.Button("Summarize", variant="primary")
31
+
32
+ with gr.Column():
33
+ output_text = gr.Textbox(label="Summary", lines=10)
34
+ stats_output = gr.Textbox(label="Statistics", lines=2)
35
+
36
+ submit_btn.click(
37
+ fn=summarize_text,
38
+ inputs=[text_input, length_slider],
39
+ outputs=[output_text, stats_output]
40
+ )
41
+
42
+ if __name__ == "__main__":
43
+ iface.launch()
summarizer.py ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from ctransformers import AutoModelForCausalLM
2
+ import os
3
+ from huggingface_hub import hf_hub_download
4
+
5
+ class TextSummarizer:
6
+ _model_instance = None
7
+
8
+ def __init__(self, model_path="mistral-7b-instruct-v0.1.Q4_K_M.gguf"):
9
+ """
10
+ Initialize the local LLM summarizer.
11
+ Loads the model only once (Singleton pattern).
12
+ """
13
+ if TextSummarizer._model_instance is None:
14
+ print("Loading model...")
15
+ if not os.path.exists(model_path):
16
+ print(f"Model file {model_path} not found. Downloading...")
17
+ try:
18
+ # Download specific file from the repo
19
+ model_path = hf_hub_download(
20
+ repo_id="TheBloke/Mistral-7B-Instruct-v0.1-GGUF",
21
+ filename="mistral-7b-instruct-v0.1.Q4_K_M.gguf",
22
+ local_dir=".",
23
+ local_dir_use_symlinks=False
24
+ )
25
+ print("Download complete.")
26
+ except Exception as e:
27
+ raise RuntimeError(f"Failed to download model: {e}")
28
+
29
+ # Load the model
30
+ # threads=2 is safer for free HF Spaces (usually 2 vCPU)
31
+ TextSummarizer._model_instance = AutoModelForCausalLM.from_pretrained(
32
+ model_path,
33
+ model_type="mistral",
34
+ context_length=4096,
35
+ threads=2
36
+ )
37
+ print("Model loaded successfully.")
38
+
39
+ self.llm = TextSummarizer._model_instance
40
+
41
+ def summarize(self, text, target_words=100):
42
+ """
43
+ Summarize the given text using Mistral-7B with a target word count.
44
+ """
45
+ if not text or not text.strip():
46
+ return "Error: Input text cannot be empty.", ""
47
+
48
+ # Estimate max tokens needed (1 word ~= 1.3 tokens, plus buffer)
49
+ # We set a hard limit to prevent infinite generation, but give enough room.
50
+ max_new_tokens = int(target_words * 2.5)
51
+
52
+ # Construct prompt for Mistral Instruct
53
+ # Format: <s>[INST] {prompt} [/INST]
54
+ prompt = f"<s>[INST] Please summarize the following text in approximately {target_words} words:\n\n{text} [/INST]"
55
+
56
+ try:
57
+ # Generate summary
58
+ response = self.llm(prompt, max_new_tokens=max_new_tokens, temperature=0.2, repetition_penalty=1.1)
59
+
60
+ summary_text = response.strip()
61
+
62
+ # Stats
63
+ input_words = len(text.split())
64
+ summary_words = len(summary_text.split())
65
+ # Approximate token count (simple whitespace split is a rough proxy, but for display it's okay)
66
+ # For more accuracy we could use self.llm.tokenize(text) if available, but split is fast/sufficient for UI.
67
+ summary_tokens = int(summary_words * 1.3)
68
+
69
+ stats = f"Input Words: {input_words}. Summary Words: {summary_words} (~{summary_tokens} tokens)."
70
+
71
+ return summary_text, stats
72
+ except Exception as e:
73
+ return f"Error during summarization: {e}", ""
74
+
75
+ if __name__ == "__main__":
76
+ # Simple test
77
+ try:
78
+ summarizer = TextSummarizer()
79
+ text = """
80
+ The Transformer is a deep learning model introduced in 2017 by Google researchers.
81
+ It is primarily used in the field of natural language processing (NLP).
82
+ Like recurrent neural networks (RNNs), Transformers are designed to handle sequential data,
83
+ such as natural language, for tasks such as translation and text summarization.
84
+ However, unlike RNNs, Transformers do not require that the sequential data be processed in order.
85
+ For example, if the input data is a natural language sentence, the Transformer does not need to
86
+ process the beginning of it before the end. Due to this feature, the Transformer allows for
87
+ much more parallelization than RNNs and therefore reduced training times.
88
+ """
89
+ print("Original Text:\n", text)
90
+ summary, stats = summarizer.summarize(text)
91
+ print("\nSummary:\n", summary)
92
+ print("\nStats:", stats)
93
+ except Exception as e:
94
+ print(e)