Humaira81 commited on
Commit
8e2cefb
·
verified ·
1 Parent(s): 28a517b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +134 -28
app.py CHANGED
@@ -4,13 +4,26 @@ from openai import OpenAI
4
 
5
  print("Gradio version:", gr.__version__)
6
 
 
7
  MODEL_HUMANIZER = "gpt-4.1-mini"
8
  MODEL_DETECTOR = "gpt-4.1-mini"
9
  TEMPERATURE_REWRITE = 0.6
10
  MAX_TOKENS_REWRITE = 1200
11
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  def get_client():
13
- api_key = os.environ.get("OPENAI_API_KEY")
14
  base_url = os.environ.get("OPENAI_BASE_URL")
15
  if not api_key:
16
  raise RuntimeError("Missing OPENAI_API_KEY")
@@ -18,41 +31,57 @@ def get_client():
18
  return OpenAI(api_key=api_key, base_url=base_url)
19
  return OpenAI(api_key=api_key)
20
 
21
- SYSTEM_HUMANIZER = (
22
- "Rewrite text into neutral, balanced human English. Preserve meaning; improve clarity; "
23
- "avoid robotic cadence; keep citations."
 
 
 
 
 
 
 
 
24
  )
25
- USER_HUMANIZER_TEMPLATE = "Rewrite this text:\n```text\n{src}\n```"
26
 
27
  SYSTEM_DETECTOR = (
28
- "You are an AI-likeness detector. Return STRICT JSON: "
29
- '{ "ai_likeness_score": float, "verdict": "Likely Human"|"Likely AI"|"Unclear", '
30
- '"rationale": string }.'
31
  )
 
32
  USER_DETECTOR_TEMPLATE = (
33
- "ORIGINAL:\n```text\n{orig}\n```\n"
34
  "COMPARISON:\n```text\n{rew}\n```\n"
35
  "Return JSON only."
36
  )
37
 
38
- def humanize_text(text):
 
39
  try:
 
 
 
40
  client = get_client()
41
  resp = client.chat.completions.create(
42
  model=MODEL_HUMANIZER,
43
  temperature=TEMPERATURE_REWRITE,
44
  max_tokens=MAX_TOKENS_REWRITE,
45
  messages=[
46
- {"role": "system", "content": SYSTEM_HUMANIZER},
47
- {"role": "user", "content": USER_HUMANIZER_TEMPLATE.format(src=text)}
48
  ],
49
  )
50
  return resp.choices[0].message.content.strip()
51
  except Exception as e:
 
 
52
  return f"ERROR: {e}"
53
 
54
- def detect_ai_likeness(original_text, comparison_text):
55
  try:
 
 
56
  client = get_client()
57
  resp = client.chat.completions.create(
58
  model=MODEL_DETECTOR,
@@ -60,26 +89,56 @@ def detect_ai_likeness(original_text, comparison_text):
60
  max_tokens=400,
61
  messages=[
62
  {"role": "system", "content": SYSTEM_DETECTOR},
63
- {"role": "user", "content": USER_DETECTOR_TEMPLATE.format(orig=original_text, rew=comparison_text)}
 
 
64
  ],
65
  )
66
  raw = resp.choices[0].message.content.strip()
67
- data = json.loads(raw)
68
- pct = float(data["ai_likeness_score"])*100
69
- return f"AI Likelihood: {pct:.1f}%\nVerdict: {data['verdict']}\nReason: {data['rationale']}"
 
 
 
 
 
70
  except Exception as e:
 
 
71
  return f"ERROR: {e}"
72
 
 
73
  custom_css = """
74
- #title {text-align:center; font-size:32px; font-weight:800;}
75
- .card {background:white; border:1px solid #eaeaea; border-radius:16px; padding:18px;
76
- box-shadow:0 6px 18px rgba(0,0,0,0.06);}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  """
78
 
79
  theme = gr.themes.Soft(primary_hue="red", neutral_hue="gray")
80
 
81
  with gr.Blocks(theme=theme, css=custom_css) as demo:
82
-
83
  gr.Markdown("""
84
  <div id="title">🕌 Zawiyah AI Collective — <span style='color:#8E0000'>Humanizer AI</span></div>
85
  <p style="text-align:center; font-size:16px; margin-top:-8px">
@@ -87,39 +146,86 @@ with gr.Blocks(theme=theme, css=custom_css) as demo:
87
  </p><hr>
88
  """)
89
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  with gr.Column(elem_classes="card"):
91
- input_text = gr.Textbox(label="✍️ Paste your text", lines=10)
92
  with gr.Row():
93
  btn_humanize = gr.Button("🧠 Humanize Text")
94
  btn_detect = gr.Button("🕵️ AI Likelihood Detector")
95
 
 
96
  with gr.Row():
97
  with gr.Column(elem_classes="card"):
98
- gr.Markdown("### Humanized Output")
99
  output_refined = gr.Textbox(show_label=False, lines=14)
100
  copy_btn = gr.Button("📋 Copy")
101
  with gr.Column(elem_classes="card"):
102
- gr.Markdown("### AI Likelihood Result")
103
- detector_result = gr.Textbox(show_label=False, lines=8)
104
 
105
- btn_humanize.click(humanize_text, input_text, output_refined)
 
106
  btn_detect.click(detect_ai_likeness, [input_text, output_refined], detector_result)
107
 
 
108
  copy_btn.click(
109
  lambda x: x,
110
  inputs=output_refined,
111
  outputs=None,
112
  js="""
113
  function(text){
114
- navigator.clipboard.writeText(text);
115
- alert("Copied ✅");
 
 
116
  }
117
  """
118
  )
119
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  demo.queue().launch()
121
 
122
 
123
 
124
 
125
 
 
 
4
 
5
  print("Gradio version:", gr.__version__)
6
 
7
+ # ===================== CONFIG =====================
8
  MODEL_HUMANIZER = "gpt-4.1-mini"
9
  MODEL_DETECTOR = "gpt-4.1-mini"
10
  TEMPERATURE_REWRITE = 0.6
11
  MAX_TOKENS_REWRITE = 1200
12
 
13
+ STYLE_GUIDANCE = {
14
+ "Neutral":
15
+ "Tone: neutral, balanced, human. Keep meaning. Mix sentence lengths. Avoid robotic cadence & clichés.",
16
+ "Academic (Nature/IEEE)":
17
+ "Tone: formal, precise, journal-like (Nature/IEEE). Use hedging where appropriate; maintain terminology; avoid hype; keep citations intact.",
18
+ "Corporate (Professional Email)":
19
+ "Tone: concise, courteous, professional. Clear requests and actions; avoid slang; keep paragraphs short.",
20
+ "WhatsApp (Casual)":
21
+ "Tone: casual, conversational, natural texting vibe. Use contractions and light emojis sparingly; keep it friendly, not sloppy."
22
+ }
23
+
24
+ # ===================== OPENAI CLIENT =====================
25
  def get_client():
26
+ api_key = os.environ.get("OPENAI_API_KEY")
27
  base_url = os.environ.get("OPENAI_BASE_URL")
28
  if not api_key:
29
  raise RuntimeError("Missing OPENAI_API_KEY")
 
31
  return OpenAI(api_key=api_key, base_url=base_url)
32
  return OpenAI(api_key=api_key)
33
 
34
+ # ===================== PROMPTS =====================
35
+ SYSTEM_HUMANIZER_BASE = (
36
+ "You are Zawiyah AI Humanizer. Rewrite text into clear, human-sounding English. "
37
+ "Preserve meaning, data, names and citations. Improve clarity, reduce redundancy, vary sentence length, "
38
+ "avoid robotic cadence and generic AI phrasing. Do not invent facts."
39
+ )
40
+
41
+ USER_HUMANIZER_TEMPLATE = (
42
+ "Apply this style guidance: {style}\n\n"
43
+ "Rewrite the text naturally while keeping formatting (headings, bullets) tidy:\n"
44
+ "```text\n{src}\n```"
45
  )
 
46
 
47
  SYSTEM_DETECTOR = (
48
+ "You are an AI-likeness detector. Return STRICT JSON only:\n"
49
+ '{ "ai_likeness_score": float, "verdict": "Likely Human"|"Likely AI"|"Unclear", '
50
+ '"rationale": "1–2 concise reasons" }'
51
  )
52
+
53
  USER_DETECTOR_TEMPLATE = (
54
+ "ORIGINAL:\n```text\n{orig}\n```\n\n"
55
  "COMPARISON:\n```text\n{rew}\n```\n"
56
  "Return JSON only."
57
  )
58
 
59
+ # ===================== CORE FUNCS =====================
60
+ def humanize_text(text: str, style_choice: str) -> str:
61
  try:
62
+ if not text or not text.strip():
63
+ return "Please paste some text."
64
+ style_note = STYLE_GUIDANCE.get(style_choice or "Neutral", STYLE_GUIDANCE["Neutral"])
65
  client = get_client()
66
  resp = client.chat.completions.create(
67
  model=MODEL_HUMANIZER,
68
  temperature=TEMPERATURE_REWRITE,
69
  max_tokens=MAX_TOKENS_REWRITE,
70
  messages=[
71
+ {"role": "system", "content": SYSTEM_HUMANIZER_BASE},
72
+ {"role": "user", "content": USER_HUMANIZER_TEMPLATE.format(style=style_note, src=text)}
73
  ],
74
  )
75
  return resp.choices[0].message.content.strip()
76
  except Exception as e:
77
+ print("---- HUMANIZER ERROR ----")
78
+ print(traceback.format_exc())
79
  return f"ERROR: {e}"
80
 
81
+ def detect_ai_likeness(original_text: str, comparison_text: str) -> str:
82
  try:
83
+ if not comparison_text or not comparison_text.strip():
84
+ return "AI Likelihood: N/A\nVerdict: Unclear\nReason: No comparison text provided."
85
  client = get_client()
86
  resp = client.chat.completions.create(
87
  model=MODEL_DETECTOR,
 
89
  max_tokens=400,
90
  messages=[
91
  {"role": "system", "content": SYSTEM_DETECTOR},
92
+ {"role": "user", "content": USER_DETECTOR_TEMPLATE.format(
93
+ orig=original_text or "", rew=comparison_text or ""
94
+ )},
95
  ],
96
  )
97
  raw = resp.choices[0].message.content.strip()
98
+ try:
99
+ data = json.loads(raw)
100
+ pct = float(data.get("ai_likeness_score", 0.5)) * 100
101
+ verdict = data.get("verdict", "Unclear")
102
+ reason = data.get("rationale", "")
103
+ return f"AI Likelihood: {pct:.1f}%\nVerdict: {verdict}\nReason: {reason}"
104
+ except Exception:
105
+ return raw
106
  except Exception as e:
107
+ print("---- DETECTOR ERROR ----")
108
+ print(traceback.format_exc())
109
  return f"ERROR: {e}"
110
 
111
+ # ===================== UI / THEME =====================
112
  custom_css = """
113
+ :root { --brand:#8E0000; }
114
+ #title { text-align:center; font-size:32px; font-weight:800; }
115
+ .gradio-container { max-width: 1000px !important; margin: auto; }
116
+
117
+ /* Cards & toolbars */
118
+ .card { background: #fff; border: 1px solid #eaeaea; border-radius: 16px; padding: 18px;
119
+ box-shadow: 0 6px 18px rgba(0,0,0,0.06); }
120
+ .toolbar { background: #fff; border: 1px solid #eaeaea; border-radius: 12px; padding: 10px 14px;
121
+ box-shadow: 0 4px 14px rgba(0,0,0,0.05); }
122
+
123
+ /* Dark mode via [data-theme="dark"] */
124
+ :root[data-theme="dark"] body,
125
+ :root[data-theme="dark"] .gradio-container { background: #0b0b0f !important; color: #eaeaea; }
126
+ :root[data-theme="dark"] .card { background: #101116; border-color: #222; box-shadow: 0 6px 18px rgba(0,0,0,0.5); }
127
+ :root[data-theme="dark"] .toolbar { background: #101116; border-color: #222; box-shadow: 0 4px 14px rgba(0,0,0,0.4); }
128
+ :root[data-theme="dark"] textarea,
129
+ :root[data-theme="dark"] input,
130
+ :root[data-theme="dark"] .gr-textbox textarea { background: #151723 !important; color: #f0f0f0 !important; border-color: #2a2d3a !important; }
131
+ :root[data-theme="dark"] .gr-button { border-color: #2a2d3a !important; }
132
+
133
+ /* Footer */
134
+ #footer { text-align:center; font-size:12px; color:#666; margin-top:12px; }
135
+ :root[data-theme="dark"] #footer { color:#aaa; }
136
  """
137
 
138
  theme = gr.themes.Soft(primary_hue="red", neutral_hue="gray")
139
 
140
  with gr.Blocks(theme=theme, css=custom_css) as demo:
141
+ # Title
142
  gr.Markdown("""
143
  <div id="title">🕌 Zawiyah AI Collective — <span style='color:#8E0000'>Humanizer AI</span></div>
144
  <p style="text-align:center; font-size:16px; margin-top:-8px">
 
146
  </p><hr>
147
  """)
148
 
149
+ # Far-right small toolbar with Dark Mode toggle (P2)
150
+ with gr.Row():
151
+ gr.Markdown("") # spacer (left)
152
+ with gr.Row(elem_classes="toolbar"):
153
+ dark_btn = gr.Button(value="🌙 Dark mode", elem_id="dark_toggle")
154
+
155
+ # Top toolbar (full width under title) — Writing Style dropdown
156
+ with gr.Row(elem_classes="toolbar"):
157
+ gr.Markdown("**Writing Style**")
158
+ style_dropdown = gr.Dropdown(
159
+ choices=["Neutral", "Academic (Nature/IEEE)", "Corporate (Professional Email)", "WhatsApp (Casual)"],
160
+ value="Neutral",
161
+ interactive=True,
162
+ label=None
163
+ )
164
+
165
+ # Input + actions
166
  with gr.Column(elem_classes="card"):
167
+ input_text = gr.Textbox(label="✍️ Paste Your Text Here", placeholder="Enter text", lines=10)
168
  with gr.Row():
169
  btn_humanize = gr.Button("🧠 Humanize Text")
170
  btn_detect = gr.Button("🕵️ AI Likelihood Detector")
171
 
172
+ # Results
173
  with gr.Row():
174
  with gr.Column(elem_classes="card"):
175
+ gr.Markdown("### Humanized Output")
176
  output_refined = gr.Textbox(show_label=False, lines=14)
177
  copy_btn = gr.Button("📋 Copy")
178
  with gr.Column(elem_classes="card"):
179
+ gr.Markdown("### 📊 AI Likelihood Result")
180
+ detector_result = gr.Textbox(show_label=False, lines=8, interactive=False)
181
 
182
+ # Wiring — core actions
183
+ btn_humanize.click(humanize_text, [input_text, style_dropdown], output_refined)
184
  btn_detect.click(detect_ai_likeness, [input_text, output_refined], detector_result)
185
 
186
+ # Copy to clipboard (Gradio 5 uses js= and a dummy python fn)
187
  copy_btn.click(
188
  lambda x: x,
189
  inputs=output_refined,
190
  outputs=None,
191
  js="""
192
  function(text){
193
+ if(!text){ alert("Nothing to copy"); return; }
194
+ navigator.clipboard.writeText(text)
195
+ .then(()=> alert("Copied ✅"))
196
+ .catch(()=> alert("Copy failed"));
197
  }
198
  """
199
  )
200
 
201
+ # Dark mode toggle (Gradio 5: js= to flip documentElement dataset theme)
202
+ # Also swap button text between 🌙 Dark mode / ☀️ Light mode
203
+ dark_btn.click(
204
+ lambda: None,
205
+ inputs=None,
206
+ outputs=None,
207
+ js="""
208
+ function(){
209
+ const root = document.documentElement;
210
+ const current = root.getAttribute('data-theme');
211
+ const next = current === 'dark' ? '' : 'dark';
212
+ root.setAttribute('data-theme', next);
213
+
214
+ // flip button label
215
+ const btn = document.getElementById('dark_toggle');
216
+ if (btn){
217
+ btn.innerText = (next === 'dark') ? '☀️ Light mode' : '🌙 Dark mode';
218
+ }
219
+ }
220
+ """
221
+ )
222
+
223
+ gr.Markdown("<div id='footer'>Zawiyah AI Collective · Malaysia · v1.0 BETA · Built with Gradio</div>")
224
+
225
  demo.queue().launch()
226
 
227
 
228
 
229
 
230
 
231
+