Kezovic commited on
Commit
16a72df
·
verified ·
1 Parent(s): fdb5f98

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +127 -49
app.py CHANGED
@@ -8,27 +8,44 @@ MODEL_REPO = "Kezovic/iris-q4gguf-nitrallora"
8
  MODEL_FILE = "Llama-3.2-1B-Instruct.Q4_K_M.gguf"
9
  CONTEXT_WINDOW = 2048
10
  MAX_NEW_TOKENS = 400
11
- TEMPERATURE = 1.5 # Note: min_p = 0.1 is kept as requested in the configuration from the previous prompt
12
 
13
  # --- Model Loading ---
 
 
 
14
  def load_llm():
 
15
  llm = None
16
  print("Downloading model...")
17
  try:
18
  model_path = hf_hub_download(repo_id=MODEL_REPO, filename=MODEL_FILE)
19
- llm = Llama(
20
- model_path=model_path,
21
- n_ctx=CONTEXT_WINDOW,
22
- n_threads=2,
23
- verbose=False,
24
- min_p = 0.1
25
- )
26
- print("Model loaded successfully!")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  except Exception as e:
28
  print(f"Error loading model: {e}")
29
- return llm
30
- llm_generator = load_llm()
31
- llm_analyst = load_llm()
32
 
33
  # --- Persona and Format Maps (Hardened Constraints) ---
34
  persona_map = {
@@ -38,7 +55,6 @@ persona_map = {
38
  "Shakespearean Actor": "You are a dramatic Shakespearean actor. Use Early Modern English (thee, thou), dramatic flair, and iambic rhythm."
39
  }
40
 
41
- # CONSTRAINTS ARE HARDENED: Clear rules to help adherence.
42
  format_map = {
43
  "Limerick": "The poem MUST have exactly 5 lines (A-A-B-B-A rhyme scheme) and be HUMOROUS.",
44
  "Sonnet": "The poem MUST have exactly 14 lines and express a complete thought or feeling.",
@@ -47,10 +63,20 @@ format_map = {
47
  "Ballad": "The poem MUST tell a narrative story using four-line stanzas (quatrains) and a simple rhyme scheme like A-B-C-B. It should be 4-6 stanzas long."
48
  }
49
 
 
 
 
 
 
 
 
 
 
 
 
50
  # --- Prompt Construction Helper Function (Simplified) ---
51
  def build_poem_prompt(voice_instruction, constraint_instruction, format_type, topic):
52
  """Constructs a simple, direct prompt for initial poem generation."""
53
- # Combined, prioritized instruction block for maximum clarity
54
  full_instruction = (
55
  f"Instruction:\n"
56
  f"{voice_instruction}\n"
@@ -61,68 +87,100 @@ def build_poem_prompt(voice_instruction, constraint_instruction, format_type, to
61
 
62
  # --- LLM Function: Step 1 (Generate Poem) ---
63
  def generate_poem(format_type, persona, topic, progress=gr.Progress()):
64
- # 1. VISUAL FEEDBACK & Error Checks
 
 
 
 
65
  progress(0, desc="Consulting the Muse...")
66
  time.sleep(0.2)
67
-
68
- # --- POEM GENERATION ---
69
  progress(0.2, desc=f"Summoning {persona} and drafting poem...")
70
  selected_voice = persona_map.get(persona, "You are a helpful assistant.")
71
  selected_constraint = format_map.get(format_type, "Write a poem.")
72
-
73
  full_poem_prompt = build_poem_prompt(selected_voice, selected_constraint, format_type, topic)
74
  output = llm_generator(
75
  prompt=full_poem_prompt,
76
  max_tokens=MAX_NEW_TOKENS,
77
  temperature=TEMPERATURE,
78
- # Minimal stop sequences to prevent cutting off the poem prematurely
79
  stop=["STRICT FORMAT RULE:", "\n\n\n"],
80
  echo=False
81
  )
82
-
83
- # Clean up output
84
  poem_text = output['choices'][0]['text'].strip()
85
-
86
- # Simple post-processing to clean up any residual instruction text if the model echoes it
87
- # We are trusting the instruction "Your output must contain ONLY the poem, nothing else."
88
-
89
  progress(1.0, desc="Poem draft complete!")
90
- # NOTE: Only returns the poem output
91
  return poem_text
92
 
93
  # --- LLM Function: Step 2 (Analyze Poem - SIMPLIFIED) ---
94
  def analyze_poem(poem_text, progress=gr.Progress()):
95
-
 
 
 
 
96
  progress(0, desc="Analyzing style for literary match...")
97
  time.sleep(0.2)
98
-
99
- # Secondary prompt for the analysis task - MINIMALIST QUESTION
100
- # The prompt is simplified to remove conversational fluff and simply present the poem for analysis.
101
  poet_prompt = (
102
- f"Give a 5 sentence analysis of the poem below. Do not write a poem yourself, only provide the 5 sentence analysis"
103
  f"POEM:\n{poem_text}\n"
104
  )
105
-
106
  output_poet = llm_analyst(
107
  prompt=poet_prompt,
108
- max_tokens=200, # Keep this response short
109
- temperature=1.5,
110
- # Minimal stop sequences for clean output
111
  echo=False
112
  )
113
-
114
- # Clean up the output using simple string manipulation
115
  poet_suggestion = output_poet['choices'][0]['text'].strip()
116
-
117
  progress(1.0, desc="Analysis complete!")
118
-
119
  return poet_suggestion
120
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
  # --- UI Layout ---
122
  with gr.Blocks(title="The Poetry Workshop", theme=gr.themes.Soft()) as demo:
123
  gr.Markdown("# 🖋️ The Poetry Workshop - Collaborative Analyst")
124
- gr.Markdown("Generate a poem based on a topic and persona, then use the separate button to analyze the output.")
125
 
 
126
  with gr.Group():
127
  with gr.Row(equal_height=True):
128
  gr.Markdown("### I want to write a ")
@@ -152,10 +210,10 @@ with gr.Blocks(title="The Poetry Workshop", theme=gr.themes.Soft()) as demo:
152
  scale=5
153
  )
154
  generate_btn = gr.Button("✨ Create Poem Draft", variant="primary", scale=1)
155
-
156
- gr.Markdown("---")
157
-
158
- # Added Analyze Button
159
  analyze_btn = gr.Button("🔍 Analyze This Poem", variant="secondary")
160
 
161
  with gr.Row():
@@ -166,29 +224,49 @@ with gr.Blocks(title="The Poetry Workshop", theme=gr.themes.Soft()) as demo:
166
  placeholder="Your masterpiece will appear here..."
167
  )
168
 
169
- # New Textbox for the Poet Suggestion
170
  poet_suggestion_display = gr.Textbox(
171
  label="Literary Analysis: Suggested Poet",
172
  lines=12,
173
  interactive=False,
174
  placeholder="Click 'Analyze This Poem' to run the LLM analysis."
175
  )
176
-
 
 
 
 
 
 
 
 
 
 
 
 
177
  # --- Event Handling ---
178
-
179
- # 1. Initial Generation: Outputs only the poem text
180
  generate_btn.click(
181
  fn=generate_poem,
182
  inputs=[format_dropdown, persona_dropdown, topic_input],
183
  outputs=[output_display]
184
  )
185
 
186
- # 2. Analysis (New Step): Inputs only the poem text
187
  analyze_btn.click(
188
  fn=analyze_poem,
189
  inputs=[output_display],
190
  outputs=poet_suggestion_display
191
  )
192
 
 
 
 
 
 
 
 
 
 
193
  if __name__ == "__main__":
194
  demo.launch()
 
8
  MODEL_FILE = "Llama-3.2-1B-Instruct.Q4_K_M.gguf"
9
  CONTEXT_WINDOW = 2048
10
  MAX_NEW_TOKENS = 400
11
+ TEMPERATURE = 1.5
12
 
13
  # --- Model Loading ---
14
+ llm_generator = None
15
+ llm_analyst = None
16
+
17
  def load_llm():
18
+ global llm_generator, llm_analyst
19
  llm = None
20
  print("Downloading model...")
21
  try:
22
  model_path = hf_hub_download(repo_id=MODEL_REPO, filename=MODEL_FILE)
23
+
24
+ # Function to create a Llama instance
25
+ def create_llama_instance():
26
+ return Llama(
27
+ model_path=model_path,
28
+ n_ctx=CONTEXT_WINDOW,
29
+ n_threads=2,
30
+ verbose=False,
31
+ min_p = 0.1
32
+ )
33
+
34
+ # 1. Load Generator LLM
35
+ print("Loading LLM Generator instance...")
36
+ llm_generator = create_llama_instance()
37
+ print("LLM Generator loaded.")
38
+
39
+ # 2. Load Analyst LLM
40
+ print("Loading LLM Analyst instance...")
41
+ llm_analyst = create_llama_instance()
42
+ print("LLM Analyst loaded.")
43
+
44
+ print("Both models loaded successfully!")
45
  except Exception as e:
46
  print(f"Error loading model: {e}")
47
+
48
+ load_llm()
 
49
 
50
  # --- Persona and Format Maps (Hardened Constraints) ---
51
  persona_map = {
 
55
  "Shakespearean Actor": "You are a dramatic Shakespearean actor. Use Early Modern English (thee, thou), dramatic flair, and iambic rhythm."
56
  }
57
 
 
58
  format_map = {
59
  "Limerick": "The poem MUST have exactly 5 lines (A-A-B-B-A rhyme scheme) and be HUMOROUS.",
60
  "Sonnet": "The poem MUST have exactly 14 lines and express a complete thought or feeling.",
 
63
  "Ballad": "The poem MUST tell a narrative story using four-line stanzas (quatrains) and a simple rhyme scheme like A-B-C-B. It should be 4-6 stanzas long."
64
  }
65
 
66
+ # --- Refinement Instruction Map (New) ---
67
+ # Maps the button label to the strict instruction given to the model
68
+ REFINEMENT_INSTRUCTIONS = {
69
+ "Make it Shorter": "Rewrite the poem to be significantly shorter, reducing the line count by at least 3 lines, while keeping the core meaning.",
70
+ "Use Flowery Language": "Rewrite the poem using highly elaborate, decorative, and verbose language with many adjectives and metaphors.",
71
+ "Make it More Intense": "Rewrite the poem with greater emotional intensity. Use stronger, more dramatic vocabulary and imagery.",
72
+ "Add a Title": "Rewrite the poem and include an original, appropriate title at the very beginning, followed by the poem text.",
73
+ "Be More Humorous": "Rewrite the poem to be more light-hearted and humorous. Add a punchline or witty observation."
74
+ }
75
+
76
+
77
  # --- Prompt Construction Helper Function (Simplified) ---
78
  def build_poem_prompt(voice_instruction, constraint_instruction, format_type, topic):
79
  """Constructs a simple, direct prompt for initial poem generation."""
 
80
  full_instruction = (
81
  f"Instruction:\n"
82
  f"{voice_instruction}\n"
 
87
 
88
  # --- LLM Function: Step 1 (Generate Poem) ---
89
  def generate_poem(format_type, persona, topic, progress=gr.Progress()):
90
+ if not llm_generator:
91
+ return "Error: Generator model not loaded."
92
+ if not topic:
93
+ return "Please enter a topic!"
94
+
95
  progress(0, desc="Consulting the Muse...")
96
  time.sleep(0.2)
97
+
 
98
  progress(0.2, desc=f"Summoning {persona} and drafting poem...")
99
  selected_voice = persona_map.get(persona, "You are a helpful assistant.")
100
  selected_constraint = format_map.get(format_type, "Write a poem.")
101
+
102
  full_poem_prompt = build_poem_prompt(selected_voice, selected_constraint, format_type, topic)
103
  output = llm_generator(
104
  prompt=full_poem_prompt,
105
  max_tokens=MAX_NEW_TOKENS,
106
  temperature=TEMPERATURE,
 
107
  stop=["STRICT FORMAT RULE:", "\n\n\n"],
108
  echo=False
109
  )
110
+
 
111
  poem_text = output['choices'][0]['text'].strip()
 
 
 
 
112
  progress(1.0, desc="Poem draft complete!")
 
113
  return poem_text
114
 
115
  # --- LLM Function: Step 2 (Analyze Poem - SIMPLIFIED) ---
116
  def analyze_poem(poem_text, progress=gr.Progress()):
117
+ if not llm_analyst:
118
+ return "Error: Analyst model not loaded."
119
+ if not poem_text or poem_text.startswith("Error:"):
120
+ return "Please generate a valid poem first!"
121
+
122
  progress(0, desc="Analyzing style for literary match...")
123
  time.sleep(0.2)
124
+
 
 
125
  poet_prompt = (
126
+ f"Give a 5 sentence analysis of the poem below. Do not write a poem yourself, only provide the 5 sentence analysis."
127
  f"POEM:\n{poem_text}\n"
128
  )
129
+
130
  output_poet = llm_analyst(
131
  prompt=poet_prompt,
132
+ max_tokens=200,
133
+ temperature=0.4, # Lowered temperature for more stable analysis
 
134
  echo=False
135
  )
136
+
 
137
  poet_suggestion = output_poet['choices'][0]['text'].strip()
 
138
  progress(1.0, desc="Analysis complete!")
 
139
  return poet_suggestion
140
 
141
+ # --- LLM Function: Step 3 (Refine Poem - NEW) ---
142
+ def refine_poem(poem_text, refinement_instruction, progress=gr.Progress()):
143
+ if not llm_generator:
144
+ return "Error: Generator model not loaded."
145
+ if not poem_text or poem_text.startswith("Error:"):
146
+ return "Please generate a valid poem first before refining it!"
147
+
148
+ progress(0, desc=f"Applying refinement: {refinement_instruction}...")
149
+ time.sleep(0.2)
150
+
151
+ # Combined instruction for refinement
152
+ refinement_prompt = (
153
+ f"You are a highly disciplined creative writer. Your task is to revise the following poem based ONLY on the REVISION INSTRUCTION.\n"
154
+ f"REVISION INSTRUCTION: {refinement_instruction}\n"
155
+ f"Your output must contain ONLY the revised poem text, nothing else.\n\n"
156
+ f"ORIGINAL POEM:\n{poem_text}\n\n"
157
+ f"REVISED POEM: "
158
+ )
159
+
160
+ output = llm_generator(
161
+ prompt=refinement_prompt,
162
+ max_tokens=MAX_NEW_TOKENS,
163
+ temperature=TEMPERATURE,
164
+ stop=["ORIGINAL POEM:", "\n\n\n"],
165
+ echo=False
166
+ )
167
+
168
+ # Clean up output
169
+ revised_poem_text = output['choices'][0]['text'].strip()
170
+
171
+ # Simple check to remove the REVISED POEM: marker if the model echoes it
172
+ if revised_poem_text.startswith("REVISED POEM:"):
173
+ revised_poem_text = revised_poem_text[len("REVISED POEM:"):].strip()
174
+
175
+ progress(1.0, desc="Refinement complete!")
176
+ return revised_poem_text
177
+
178
  # --- UI Layout ---
179
  with gr.Blocks(title="The Poetry Workshop", theme=gr.themes.Soft()) as demo:
180
  gr.Markdown("# 🖋️ The Poetry Workshop - Collaborative Analyst")
181
+ gr.Markdown("Generate a poem based on a topic and persona, then use the separate buttons to analyze or refine the output.")
182
 
183
+ ## 📝 Poem Generation Controls
184
  with gr.Group():
185
  with gr.Row(equal_height=True):
186
  gr.Markdown("### I want to write a ")
 
210
  scale=5
211
  )
212
  generate_btn = gr.Button("✨ Create Poem Draft", variant="primary", scale=1)
213
+
214
+ gr.Markdown("---")
215
+
216
+ ## 🔍 Analysis Section
217
  analyze_btn = gr.Button("🔍 Analyze This Poem", variant="secondary")
218
 
219
  with gr.Row():
 
224
  placeholder="Your masterpiece will appear here..."
225
  )
226
 
 
227
  poet_suggestion_display = gr.Textbox(
228
  label="Literary Analysis: Suggested Poet",
229
  lines=12,
230
  interactive=False,
231
  placeholder="Click 'Analyze This Poem' to run the LLM analysis."
232
  )
233
+
234
+ gr.Markdown("---")
235
+
236
+ ## ⚙️ Poem Refinement Section (New)
237
+ with gr.Group():
238
+ gr.Markdown("### Refine Poem")
239
+ gr.Markdown("Click a button below to automatically revise the current poem in the **'Your Poem'** box.")
240
+ with gr.Row():
241
+ # Dynamically create buttons based on the map
242
+ buttons = []
243
+ for label in REFINEMENT_INSTRUCTIONS.keys():
244
+ buttons.append(gr.Button(label, scale=1, variant="light"))
245
+
246
  # --- Event Handling ---
247
+
248
+ # 1. Initial Generation
249
  generate_btn.click(
250
  fn=generate_poem,
251
  inputs=[format_dropdown, persona_dropdown, topic_input],
252
  outputs=[output_display]
253
  )
254
 
255
+ # 2. Analysis
256
  analyze_btn.click(
257
  fn=analyze_poem,
258
  inputs=[output_display],
259
  outputs=poet_suggestion_display
260
  )
261
 
262
+ # 3. Refinement Events (Wired to the refinement buttons)
263
+ # Iterate through the buttons and assign a click event to each one
264
+ for i, (label, instruction) in enumerate(REFINEMENT_INSTRUCTIONS.items()):
265
+ buttons[i].click(
266
+ fn=lambda p, i=instruction: refine_poem(p, i), # Use a lambda to capture the specific instruction
267
+ inputs=[output_display],
268
+ outputs=[output_display]
269
+ )
270
+
271
  if __name__ == "__main__":
272
  demo.launch()