DrishtiSharma commited on
Commit
e92ff41
·
verified ·
1 Parent(s): 7b514ad

Create multilingual_word_limit_issue_v3.py

Browse files
lab/multilingual_word_limit_issue_v3.py ADDED
@@ -0,0 +1,331 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from graph import EssayWriter, RouteQuery, GraphState
3
+ from language_options import language_options
4
+ from crew import *
5
+ import os
6
+ import re
7
+ import traceback
8
+ import base64
9
+
10
+ # Install Graphviz if not found
11
+ if os.system("which dot") != 0:
12
+ os.system("apt-get update && apt-get install -y graphviz")
13
+
14
+ st.markdown(
15
+ """
16
+ <h1 style="text-align: center; white-space: nowrap; font-size: 2.5em;">
17
+ Multi-Agent Essay Writing Assistant
18
+ </h1>
19
+ """,
20
+ unsafe_allow_html=True
21
+ )
22
+
23
+ # Ensure session state variables are initialized properly
24
+ if "messages" not in st.session_state:
25
+ st.session_state["messages"] = [{"role": "assistant", "content": "Hello! How can I assist you today?"}]
26
+
27
+ if "app" not in st.session_state:
28
+ st.session_state["app"] = None
29
+
30
+ if "chat_active" not in st.session_state:
31
+ st.session_state["chat_active"] = True
32
+
33
+ # Sidebar with essay settings and user-defined length
34
+ # Sidebar with essay settings and user-defined length
35
+ with st.sidebar:
36
+ st.subheader("📝 Note:")
37
+ st.info(
38
+ "\n\n 1. This app uses the 'gpt-4o-mini-2024-07-18' model."
39
+ "\n\n 2. Writing essays may take some time, approximately 1-2 minutes."
40
+ )
41
+
42
+ # API Key Retrieval
43
+ openai_key = st.secrets.get("OPENAI_API_KEY", "")
44
+
45
+ st.divider()
46
+
47
+ # User-defined essay length selection
48
+ st.subheader("⚙️🛠️ Configure Essay Settings:")
49
+ essay_length = st.number_input(
50
+ "Select Essay Length (words):",
51
+ min_value=150,
52
+ max_value=500,
53
+ value=250,
54
+ step=50
55
+ )
56
+
57
+ #st.divider()
58
+
59
+ #Language Selection
60
+ #st.subheader("🌍 Select Language:")
61
+ selected_language = st.selectbox("Choose Language:", sorted(language_options.keys()), index=list(language_options.keys()).index("English"))
62
+
63
+ st.divider()
64
+
65
+ # Reference section
66
+ st.subheader("📖 References:")
67
+ st.markdown(
68
+ "[1. Multi-Agent System with CrewAI and LangChain](https://discuss.streamlit.io/t/new-project-i-have-build-a-multi-agent-system-with-crewai-and-langchain/84002)",
69
+ unsafe_allow_html=True
70
+ )
71
+
72
+
73
+ # Initialize agents function
74
+ def initialize_agents():
75
+ if not openai_key:
76
+ st.error("⚠️ OpenAI API key is missing! Please provide a valid key through Hugging Face Secrets.")
77
+ st.session_state["chat_active"] = True
78
+ return None
79
+
80
+ os.environ["OPENAI_API_KEY"] = openai_key
81
+ try:
82
+ # Prevent re-initialization
83
+ if "app" in st.session_state and st.session_state["app"] is not None:
84
+ return st.session_state["app"]
85
+
86
+ # Initialize the full EssayWriter instance
87
+ essay_writer = EssayWriter() # Store the full instance
88
+ st.session_state["app"] = essay_writer # Now contains `graph`
89
+ st.session_state["chat_active"] = False # Enable chat after successful initialization
90
+
91
+ return essay_writer
92
+ except Exception as e:
93
+ st.error(f"❌ Error initializing agents: {e}")
94
+ st.session_state["chat_active"] = True
95
+ return None
96
+
97
+
98
+ # Automatically initialize agents on app load
99
+ if st.session_state["app"] is None:
100
+ st.session_state["app"] = initialize_agents()
101
+
102
+ if st.session_state["app"] is None:
103
+ st.error("⚠️ Failed to initialize agents. Please check your API key and restart the app.")
104
+
105
+ app = st.session_state["app"]
106
+
107
+ # Function to invoke the agent and generate a response
108
+ def enforce_word_limit(text, limit):
109
+ """Enforces strict word limit by truncating extra words."""
110
+ words = re.findall(r'\b\w+\b', text)
111
+ return ' '.join(words[:limit]) if len(words) > limit else text
112
+
113
+ def detect_unexpected_english(text, selected_language):
114
+ """Detects unintended English words when another language is selected."""
115
+ if selected_language != "English":
116
+ english_words = re.findall(r'\b(?:is|the|and|or|in|on|at|to|with|for|of|by|it|that|this|was|he|she|they|we|you|I)\b', text)
117
+ return len(english_words) > 5 # Allow a small tolerance
118
+
119
+ def generate_response(topic, length, selected_language):
120
+ if not app or not hasattr(app, "graph"):
121
+ st.error("Agents are not initialized. Please check the system or restart the app.")
122
+ return {"response": "Error: Agents not initialized."}
123
+
124
+ # Dynamically adjust structure based on length
125
+ if length <= 250:
126
+ intro_limit, body_limit, conclusion_limit = length // 5, length // 2, length // 5
127
+ num_sections = 2 # Shorter essays should have fewer sections
128
+ elif length <= 350:
129
+ intro_limit, body_limit, conclusion_limit = length // 6, length // 1.8, length // 6
130
+ num_sections = 3
131
+ else:
132
+ intro_limit, body_limit, conclusion_limit = length // 7, length // 1.7, length // 7
133
+ num_sections = 4
134
+
135
+ # Optimized Structured Prompt
136
+ refined_prompt = f"""
137
+ Write a **well-structured, informative, and engaging** essay on "{topic}" **strictly in {selected_language}.**
138
+
139
+ **Word Limit:** Exactly {length} words. **Do not exceed or fall short of this limit.**
140
+ **Language Rules:** Use natural linguistic style from {selected_language}. **Do not use English** unless explicitly requested.
141
+
142
+ **Essay Structure:**
143
+ - **Title**: Max 10 words.
144
+ - **Introduction ({intro_limit} words max)**:
145
+ - Clearly define the topic and its significance.
146
+ - Provide a strong thesis statement.
147
+ - Preview the key points covered in the essay.
148
+ - **Main Body ({body_limit} words max, {num_sections} sections)**:
149
+ - Each section must have:
150
+ - A **clear subheading**.
151
+ - A concise topic sentence with supporting details.
152
+ - Relevant **examples, statistics, or historical references**.
153
+ - Maintain natural **flow** between sections.
154
+ - **Conclusion ({conclusion_limit} words max)**:
155
+ - Summarize key insights **without repetition**.
156
+ - Reinforce the thesis **based on discussion**.
157
+ - End with a strong **closing statement** (reflection or call to action).
158
+
159
+ **Hard Rules:**
160
+ - **Use only {selected_language}**. No English unless explicitly requested.
161
+ - **Do not exceed {length} words.** Absolute limit.
162
+ - **Write concisely and avoid fluff**. No redundancy.
163
+ - **Merge similar ideas** to maintain smooth readability.
164
+ - **Ensure strict adherence to section word limits**.
165
+ """
166
+
167
+ # Invoke AI model with enforced word limit
168
+ response = app.graph.invoke(input={
169
+ "topic": topic,
170
+ "length": length,
171
+ "prompt": refined_prompt,
172
+ "language": selected_language,
173
+ "max_tokens": length + 10 # Small buffer for better trimming
174
+ })
175
+
176
+ # Strict word limit enforcement
177
+ essay_text = enforce_word_limit(response.get("essay", ""), length)
178
+
179
+ # Detect unintended English words in non-English essays
180
+ if detect_unexpected_english(essay_text, selected_language):
181
+ return {"response": f"⚠️ Warning: Some English words were detected in the {selected_language} essay. Try regenerating."}
182
+
183
+ return {"essay": essay_text}
184
+
185
+
186
+
187
+ # Define Tabs
188
+ tab1, tab2 = st.tabs(["📜 Essay Generation", "📊 Workflow Viz"])
189
+
190
+ # 📜 Tab 1: Essay Generation
191
+ with tab1:
192
+ # Display chat messages from the session
193
+ if "messages" not in st.session_state:
194
+ st.session_state["messages"] = [{"role": "assistant", "content": "Hello! How can I assist you today?"}]
195
+
196
+ for message in st.session_state["messages"]:
197
+ with st.chat_message(message["role"]):
198
+ st.markdown(message["content"], unsafe_allow_html=True)
199
+
200
+ # Input
201
+ topic = st.text_input("📝 Provide an essay topic:", value="Write an essay on the cultural diversity of India")
202
+
203
+ # Add spacing
204
+ st.write("")
205
+
206
+ # Generate button
207
+ if st.button("🚀 Generate Essay"):
208
+ if topic and topic.strip(): # Ensure it's not empty
209
+ # Store user message only if it's not already stored
210
+ if not any(msg["content"] == topic for msg in st.session_state["messages"]):
211
+ st.session_state["messages"].append({"role": "user", "content": topic})
212
+
213
+ with st.spinner("⏳ Generating your essay..."):
214
+ response = None
215
+ if app:
216
+ response = app.write_essay({"topic": topic})
217
+ else:
218
+ st.error("⚠️ Agents are not initialized. Please check the system or restart the app.")
219
+
220
+ # Store and display assistant response
221
+ if response and "essay" in response:
222
+ essay = response["essay"]
223
+
224
+ assistant_response = f"Here is your {essay_length}-word essay preview and the download link."
225
+ st.session_state["messages"].append({"role": "assistant", "content": assistant_response})
226
+
227
+ st.chat_message("assistant").markdown(assistant_response)
228
+
229
+ # Create Two-Column Layout
230
+ col1, col2 = st.columns(2)
231
+
232
+ with col1:
233
+ st.markdown(f"### 📝 Essay Preview ({essay_length} words)")
234
+ st.markdown(f"#### {essay['header']}")
235
+ st.markdown(essay["entry"])
236
+
237
+ for para in essay["paragraphs"]:
238
+ st.markdown(f"**{para['sub_header']}**")
239
+ st.markdown(para["paragraph"])
240
+
241
+ st.markdown("**🖊️ Conclusion:**")
242
+ st.markdown(essay["conclusion"])
243
+
244
+ with col2:
245
+ st.markdown("### ✍️ Edit Your Essay:")
246
+
247
+ # Combine all parts of the essay into one editable text field
248
+ full_essay_text = f"## {essay['header']}\n\n{essay['entry']}\n\n"
249
+ for para in essay["paragraphs"]:
250
+ full_essay_text += f"### {para['sub_header']}\n{para['paragraph']}\n\n"
251
+ full_essay_text += f"**Conclusion:**\n{essay['conclusion']}"
252
+
253
+ # Editable text area for the user
254
+ edited_essay = st.text_area("Edit Here:", value=full_essay_text, height=300)
255
+
256
+ # Save and Download buttons
257
+ save_col1, save_col2 = st.columns(2)
258
+
259
+ with save_col1:
260
+ if st.button("💾 Save as TXT"):
261
+ with open("edited_essay.txt", "w", encoding="utf-8") as file:
262
+ file.write(edited_essay)
263
+ with open("edited_essay.txt", "rb") as file:
264
+ st.download_button(label="⬇️ Download TXT", data=file, file_name="edited_essay.txt", mime="text/plain")
265
+
266
+ with save_col2:
267
+ if st.button("📄 Save as PDF"):
268
+ from fpdf import FPDF
269
+
270
+ pdf = FPDF()
271
+ pdf.set_auto_page_break(auto=True, margin=15)
272
+ pdf.add_page()
273
+ pdf.set_font("Arial", size=12)
274
+
275
+ for line in edited_essay.split("\n"):
276
+ pdf.cell(200, 10, txt=line, ln=True, align='L')
277
+
278
+ pdf.output("edited_essay.pdf")
279
+
280
+ with open("edited_essay.pdf", "rb") as file:
281
+ st.download_button(label="⬇️ Download PDF", data=file, file_name="edited_essay.pdf", mime="application/pdf")
282
+
283
+ # Provide download link for the original PDF
284
+ pdf_name = response.get("pdf_name")
285
+ if pdf_name and os.path.exists(pdf_name):
286
+ with open(pdf_name, "rb") as pdf_file:
287
+ b64 = base64.b64encode(pdf_file.read()).decode()
288
+ href = f"<a href='data:application/octet-stream;base64,{b64}' download='{pdf_name}'>📄 Click here to download the original PDF</a>"
289
+ st.markdown(href, unsafe_allow_html=True)
290
+
291
+ # Save response in session state
292
+ st.session_state["messages"].append(
293
+ {"role": "assistant", "content": f"Here is your {essay_length}-word essay preview and the download link."}
294
+ )
295
+ elif response:
296
+ st.markdown(response["response"])
297
+ st.session_state["messages"].append({"role": "assistant", "content": response["response"]})
298
+ else:
299
+ st.error("⚠️ No response received. Please try again.")
300
+
301
+
302
+
303
+ # 📊 Tab 2: Workflow Visualization
304
+ with tab2:
305
+ #st.subheader("📊 Multi-Agent Essay Writer Workflow Viz")
306
+
307
+ try:
308
+ graph_path = "/tmp/graph.png"
309
+ if os.path.exists(graph_path):
310
+ st.image(graph_path, caption="Multi-Agent Essay Writer Workflow Visualization", use_container_width=True)
311
+ else:
312
+ st.warning("⚠️ Workflow graph not found. Please run `graph.py` to regenerate `graph.png`.")
313
+
314
+ except Exception as e:
315
+ st.error("❌ An error occurred while generating the workflow visualization.")
316
+ st.text_area("Error Details:", traceback.format_exc(), height=500)
317
+
318
+
319
+ # Acknowledgement Section
320
+ st.markdown(
321
+ """
322
+ <div style="text-align: center; font-size: 14px; color: #555; padding-top: 200px; margin-top: 200px;">
323
+ <strong>Acknowledgement:</strong> This app is based on Mesut Duman's work:
324
+ <a href="https://github.com/mesutdmn/Autonomous-Multi-Agent-Systems-with-CrewAI-Essay-Writer/tree/main"
325
+ target="_blank" style="color: #007BFF; text-decoration: none;">
326
+ CrewAI Essay Writer
327
+ </a>
328
+ </div>
329
+ """,
330
+ unsafe_allow_html=True,
331
+ )