ritik26esh commited on
Commit
5b4e64e
·
verified ·
1 Parent(s): 2e2fc6f

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +221 -0
  2. requirements.txt +7 -0
app.py ADDED
@@ -0,0 +1,221 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import gradio as gr
3
+ import torch
4
+ from transformers import AutoTokenizer, AutoModelForCausalLM
5
+
6
+ MODEL_ID = os.getenv("MODEL_ID", "LiquidAI/LFM2.5-1.2B-Instruct")
7
+ HF_TOKEN = os.getenv("HF_TOKEN", None)
8
+
9
+ # Cache model/tokenizer so Space loads once
10
+ _tokenizer = None
11
+ _model = None
12
+
13
+ def load_llm():
14
+ global _tokenizer, _model
15
+ if _tokenizer is None or _model is None:
16
+ _tokenizer = AutoTokenizer.from_pretrained(MODEL_ID, token=HF_TOKEN)
17
+
18
+ # device_map="auto" uses GPU if available, else CPU
19
+ _model = AutoModelForCausalLM.from_pretrained(
20
+ MODEL_ID,
21
+ token=HF_TOKEN,
22
+ torch_dtype="auto",
23
+ device_map="auto",
24
+ )
25
+ _model.eval()
26
+ return _tokenizer, _model
27
+
28
+
29
+ def build_messages(
30
+ negotiation_type: str,
31
+ your_role: str,
32
+ counterpart_role: str,
33
+ relationship: str,
34
+ goal: str,
35
+ context: str,
36
+ constraints: str,
37
+ concessions: str,
38
+ deadline: str,
39
+ tone: str,
40
+ include_subject: bool,
41
+ signature_name: str,
42
+ email_thread: str,
43
+ ):
44
+ # Negotiation-focused system prompt
45
+ system = f"""
46
+ You are an email drafting assistant specialized in negotiation emails.
47
+
48
+ Rules:
49
+ - Keep the tone: {tone}.
50
+ - Be respectful and professional. No threats, no insults, no pressure tactics.
51
+ - Use principled negotiation: be clear on interests, propose options, ask focused questions.
52
+ - Do not invent facts, dates, prices, legal terms, or policy. Use only what the user provides.
53
+ - Keep paragraphs short.
54
+
55
+ Output format:
56
+ {"- First line must be a subject line like: Subject: <...>\\n\\nThen the email body." if include_subject else "- Output ONLY the email body (no subject line)."}
57
+ End with a sign-off using the provided name if given.
58
+ """.strip()
59
+
60
+ user = f"""
61
+ Create a negotiation email draft.
62
+
63
+ Negotiation type: {negotiation_type}
64
+ Your role: {your_role}
65
+ Counterpart role: {counterpart_role}
66
+ Relationship/context: {relationship}
67
+
68
+ Goal / Ask:
69
+ {goal}
70
+
71
+ Background details (facts only):
72
+ {context}
73
+
74
+ Constraints / non-negotiables:
75
+ {constraints}
76
+
77
+ Possible concessions / flexibility:
78
+ {concessions}
79
+
80
+ Deadline / timing:
81
+ {deadline}
82
+
83
+ Existing email thread (if any):
84
+ {email_thread}
85
+
86
+ Signature name:
87
+ {signature_name}
88
+ """.strip()
89
+
90
+ return [
91
+ {"role": "system", "content": system},
92
+ {"role": "user", "content": user},
93
+ ]
94
+
95
+
96
+ def generate_draft(
97
+ negotiation_type,
98
+ your_role,
99
+ counterpart_role,
100
+ relationship,
101
+ goal,
102
+ context,
103
+ constraints,
104
+ concessions,
105
+ deadline,
106
+ tone,
107
+ include_subject,
108
+ signature_name,
109
+ email_thread,
110
+ max_new_tokens,
111
+ temperature,
112
+ top_p,
113
+ top_k,
114
+ repetition_penalty,
115
+ ):
116
+ tokenizer, model = load_llm()
117
+
118
+ messages = build_messages(
119
+ negotiation_type=negotiation_type,
120
+ your_role=your_role,
121
+ counterpart_role=counterpart_role,
122
+ relationship=relationship,
123
+ goal=goal,
124
+ context=context,
125
+ constraints=constraints,
126
+ concessions=concessions,
127
+ deadline=deadline,
128
+ tone=tone,
129
+ include_subject=include_subject,
130
+ signature_name=signature_name,
131
+ email_thread=email_thread,
132
+ )
133
+
134
+ prompt = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
135
+
136
+ inputs = tokenizer(prompt, return_tensors="pt")
137
+ inputs = {k: v.to(model.device) for k, v in inputs.items()}
138
+
139
+ with torch.no_grad():
140
+ out = model.generate(
141
+ **inputs,
142
+ max_new_tokens=int(max_new_tokens),
143
+ do_sample=True,
144
+ temperature=float(temperature),
145
+ top_p=float(top_p),
146
+ top_k=int(top_k),
147
+ repetition_penalty=float(repetition_penalty),
148
+ )
149
+
150
+ text = tokenizer.decode(out[0][inputs["input_ids"].shape[1]:], skip_special_tokens=True).strip()
151
+
152
+ # Ensure sign-off if user provided a name and model forgot it
153
+ if signature_name and signature_name.strip() and signature_name.strip() not in text[-150:]:
154
+ text = text.rstrip() + f"\n\nRegards,\n{signature_name.strip()}"
155
+
156
+ return text
157
+
158
+
159
+ with gr.Blocks(title="Negotiation Email Draft Tool (LFM2)") as demo:
160
+ gr.Markdown(
161
+ "# Negotiation Email Draft Tool (Powered by LFM2)\n"
162
+ "Fill the fields, then generate a negotiation-ready email draft.\n"
163
+ "Note: Output is a draft. Verify details before sending."
164
+ )
165
+
166
+ with gr.Row():
167
+ negotiation_type = gr.Dropdown(
168
+ ["Salary/Offer", "Vendor Pricing", "Contract Terms", "Rent/Lease", "Timeline/Delivery", "Refund/Resolution", "Other"],
169
+ value="Vendor Pricing",
170
+ label="Negotiation Type",
171
+ )
172
+ tone = gr.Dropdown(
173
+ ["Warm and collaborative", "Firm but polite", "Direct and concise", "Formal and cautious"],
174
+ value="Firm but polite",
175
+ label="Tone",
176
+ )
177
+
178
+ with gr.Row():
179
+ your_role = gr.Dropdown(
180
+ ["Buyer/Client", "Seller/Vendor", "Candidate/Employee", "Employer", "Tenant", "Landlord", "Other"],
181
+ value="Buyer/Client",
182
+ label="Your Role",
183
+ )
184
+ counterpart_role = gr.Dropdown(
185
+ ["Buyer/Client", "Seller/Vendor", "Recruiter/Employer", "Candidate/Employee", "Tenant", "Landlord", "Other"],
186
+ value="Seller/Vendor",
187
+ label="Counterpart Role",
188
+ )
189
+
190
+ relationship = gr.Textbox(label="Relationship Context (1–2 lines)", placeholder="Existing vendor relationship, new negotiation, prior discussions, etc.")
191
+ goal = gr.Textbox(label="Goal / Ask (be specific)", lines=3, placeholder="Example: Request 12% price reduction or extended payment terms (Net 45).")
192
+ context = gr.Textbox(label="Background Facts", lines=4, placeholder="Facts you want included (numbers, dates, scope, current offer, etc).")
193
+ constraints = gr.Textbox(label="Constraints / Non-Negotiables", lines=3, placeholder="Example: Budget cap, delivery deadline, must-have clause.")
194
+ concessions = gr.Textbox(label="Possible Concessions", lines=3, placeholder="Example: Longer contract term, faster payment, higher volume.")
195
+ deadline = gr.Textbox(label="Deadline / Timing", placeholder="Example: Need confirmation by Friday EOD.")
196
+ email_thread = gr.Textbox(label="Existing Email Thread (optional)", lines=6, placeholder="Paste prior messages here if this is a reply.")
197
+ signature_name = gr.Textbox(label="Signature Name (optional)", placeholder="Your name")
198
+
199
+ include_subject = gr.Checkbox(value=True, label="Include subject line")
200
+ with gr.Accordion("Generation settings (advanced)", open=False):
201
+ max_new_tokens = gr.Slider(120, 600, value=280, step=10, label="Max new tokens")
202
+ # Model card recommends low temperature/top_p for controlled output :contentReference[oaicite:3]{index=3}
203
+ temperature = gr.Slider(0.0, 1.0, value=0.1, step=0.05, label="Temperature")
204
+ top_p = gr.Slider(0.05, 1.0, value=0.1, step=0.05, label="Top-p")
205
+ top_k = gr.Slider(0, 200, value=50, step=5, label="Top-k")
206
+ repetition_penalty = gr.Slider(1.0, 1.3, value=1.05, step=0.01, label="Repetition penalty")
207
+
208
+ btn = gr.Button("Generate Draft")
209
+ output = gr.Textbox(label="Draft Email", lines=14)
210
+
211
+ btn.click(
212
+ fn=generate_draft,
213
+ inputs=[
214
+ negotiation_type, your_role, counterpart_role, relationship, goal, context,
215
+ constraints, concessions, deadline, tone, include_subject, signature_name,
216
+ email_thread, max_new_tokens, temperature, top_p, top_k, repetition_penalty
217
+ ],
218
+ outputs=[output],
219
+ )
220
+
221
+ demo.queue().launch()
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ gradio>=4.44.0
2
+ torch
3
+ transformers>=4.57.0
4
+ accelerate>=0.33.0
5
+ safetensors>=0.4.3
6
+ sentencepiece>=0.2.0
7
+ huggingface_hub>=0.24.0