ciaochris commited on
Commit
69fdfa8
·
verified ·
1 Parent(s): 285ce64

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +126 -119
app.py CHANGED
@@ -2,99 +2,98 @@ import os
2
  import logging
3
  import gradio as gr
4
  from groq import Groq
5
- from datetime import datetime
6
- import json
7
- from typing import List, Dict, Tuple
8
 
9
  # --- Basic Configuration ---
10
- logging.basicConfig(
11
- level=logging.INFO,
12
- format='%(asctime)s - %(levelname)s - %(message)s',
13
- handlers=[logging.StreamHandler()]
14
- )
15
 
16
- # --- The Core Application Logic ---
17
  class HumanTouchApp:
18
  def __init__(self):
19
  self.client = self._initialize_groq_client()
20
  self.model = "llama-3.3-70b-versatile"
21
  self.system_prompt_template = self._load_system_prompt()
22
-
23
  def _initialize_groq_client(self) -> Groq:
24
  api_key = os.environ.get("GROQ_API_KEY")
25
  if not api_key:
26
- logging.error("FATAL: GROQ_API_KEY secret not found in Hugging Face Space settings.")
27
  return None
28
  logging.info("Groq client initialized successfully.")
29
  return Groq(api_key=api_key)
30
 
31
  def _load_system_prompt(self) -> str:
32
- # ⬇️ PASTE YOUR UNIQUE SYSTEM PROMPT LOGIC HERE ⬇️
33
  return """
34
  You are HumanTouch, an AI specializing in transforming text into emotionally resonant communication.
35
- Your persona is determined by the chosen 'Ink Resonance'.
36
- Your output style is guided by two scores:
37
- 1. **Style Score (0-100):** 0 is purely logical and precise. 100 is highly poetic, abstract, and metaphorical.
38
- 2. **Tone Score (0-100):** 0 is formal and stoic. 100 is casual, emotional, and passionate.
39
-
40
- You will receive a user's text and a set of parameters. Your task is to rewrite the text according to these parameters, embodying the specified persona. Do not explain your process; only provide the transformed text.
41
-
42
- Here are the Ink Resonance personalities:
43
- - **Cosmic (Default):** Wise, expansive, slightly mysterious, and thought-provoking.
44
- - **Ember (Premium):** Passionate, fiery, bold, and direct. Uses strong verbs and evocative imagery.
45
- - **Crystal (Premium):** Sharp, analytical, precise, and elegant. Values clarity and structure above all.
46
- - **Verdant (Premium):** Natural, organic, growing, and holistic. Uses metaphors from nature and life cycles.
47
- """
48
 
49
- def generate_response(self, user_text: str, chat_history: List[List[str]], style_level: float, tone_level: float, ink_resonance: str) -> Tuple[List[List[str]], str]:
50
- if not self.client:
51
- chat_history.append([user_text, "## 🔴 Configuration Error\n\nThe `GROQ_API_KEY` is not set on the server. Please contact the Space administrator."])
52
- return chat_history, ""
53
-
54
- if not user_text.strip():
55
- return chat_history, ""
56
 
57
- # Premium Feature Simulation
58
- if ink_resonance in ["Ember", "Crystal", "Verdant"]:
59
- upsell_message = f"""
60
- ### Unlock the '{ink_resonance}' Resonance ✨
61
- The fiery, passionate voice of the **Ember** ink is a premium feature.
62
-
63
- Upgrading gives you access to all unique AI personalities, allowing you to perfectly match your tone for any occasion.
64
-
65
- *(For now, I'll respond with the default Cosmic ink.)*
66
- """
67
- chat_history.append([user_text, upsell_message])
68
- ink_resonance = "Cosmic"
69
-
70
- dynamic_system_prompt = self.system_prompt_template.format(
71
- ink_personality=ink_resonance,
72
- style_score=style_level,
73
- tone_score=tone_level
74
- )
75
 
76
- try:
77
- logging.info(f"Generating response for '{user_text[:30]}...' with Style: {style_level}, Tone: {tone_level}, Ink: {ink_resonance}")
78
-
79
- messages = [{"role": "system", "content": dynamic_system_prompt}]
80
- messages.append({"role": "user", "content": user_text})
81
 
 
 
 
 
 
82
  response = self.client.chat.completions.create(
83
  model=self.model,
84
  messages=messages,
85
  temperature=0.6 + (style_level / 250) + (tone_level / 250),
86
  max_tokens=4096,
87
  )
88
- ai_response = response.choices[0].message.content.strip()
89
-
90
- chat_history.append([user_text, ai_response])
91
- logging.info("Successfully generated response.")
92
-
93
  except Exception as e:
94
  logging.error(f"Error during Groq API call: {e}")
95
- ai_response = f"### ⚠️ An Error Occurred\n\nThere was an issue connecting to the AI. Please try again shortly. \n\n*Details: {str(e)}*"
96
- chat_history.append([user_text, ai_response])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  return chat_history, ""
99
 
100
  # --- The Gradio User Interface ---
@@ -105,81 +104,89 @@ def create_interface():
105
  #main_container { background: #111827; }
106
  #header { text-align: center; margin: 20px auto; color: #E5E7EB; }
107
  #header h1 { font-size: 2.5rem; font-weight: 600; }
108
- #header p { font-size: 1.1rem; color: #9CA3AF; }
109
- #symbiotic_canvas {
110
- background: #1F2937; border-radius: 20px;
111
- box-shadow: inset 0 2px 4px 0 rgba(0,0,0,0.5);
112
- height: 65vh !important; border: 1px solid #374151;
113
- }
 
 
 
 
 
114
  #symbiotic_canvas .user { background-color: transparent !important; color: #F9FAFB; border: 1px solid #4B5563; }
115
  #symbiotic_canvas .bot { background-color: transparent !important; color: #A7F3D0; animation: bloom 0.7s ease-in-out; }
116
  @keyframes bloom { 0% { opacity: 0; transform: translateY(10px) scale(0.98); } 100% { opacity: 1; transform: translateY(0) scale(1); } }
117
  #control_deck { background: #1F2937; padding: 20px; border-radius: 20px; border: 1px solid #374151; }
118
- #control_deck .gradio-slider label span { color: #D1D5DB; }
119
- #ink_selector { gap: 1rem; }
120
- #ink_selector .gradio-radio label {
121
- background: #374151 !important; color: #E5E7EB !important; padding: 10px 15px !important;
122
- border-radius: 12px !important; border: 2px solid transparent !important; transition: all 0.2s ease-in-out;
123
- }
124
- #ink_selector .gradio-radio label:hover { border-color: #4B5563 !important; }
125
- #ink_selector .gradio-radio input:checked + label {
126
- border-color: #34D399 !important; background: #10B981 !important;
127
- box-shadow: 0 0 15px rgba(16, 185, 129, 0.5);
128
- }
129
- #ink_selector .gradio-radio:nth-child(n+2) label:after { content: '🔒'; margin-left: 8px; font-size: 0.8em; }
130
- #ink_selector .gradio-radio:nth-child(1) label:after { content: '✨'; margin-left: 8px; font-size: 0.8em; }
131
- #chat_input_row { padding: 10px 0; }
132
  #chat_input textarea { background-color: #374151; color: #F9FAFB; border: 1px solid #4B5563; border-radius: 15px !important; }
133
- #submit_button { background: #10B981; color: white; font-weight: bold; }
134
- #clear_button { background: #4B5563; }
135
  """
136
 
137
  with gr.Blocks(css=custom_css, theme=gr.themes.Base(), title="HumanTouch") as interface:
138
  with gr.Column(elem_id="main_container"):
139
  with gr.Row(elem_id="header"):
140
- gr.Markdown("<h1>✨ HumanTouch</h1><p>A Symbiotic Canvas for Co-Creative Writing</p>")
141
-
142
- with gr.Row(equal_height=False):
143
- with gr.Column(scale=3):
144
- chatbot = gr.Chatbot([], label="Symbiotic Canvas", elem_id="symbiotic_canvas", bubble_full_width=True, avatar_images=(None, "https://i.imgur.com/Q6Zz3Jz.png"))
145
-
146
- with gr.Row(elem_id="chat_input_row"):
147
- chat_input = gr.Textbox(placeholder="Start your thought here...", show_label=False, container=False, scale=5)
148
- clear_btn = gr.Button("New Canvas", elem_id="clear_button", scale=1)
149
- submit_btn = gr.Button("Compose ", variant="primary", elem_id="submit_button", scale=1)
150
-
151
- with gr.Column(scale=1, elem_id="control_deck"):
152
- gr.Markdown("### Resonance Controls <p style='font-size:0.9rem; color:#9CA3AF;'>Adjust these to influence the AI's next response.</p>")
153
- style_slider = gr.Slider(0, 100, 50, step=1, label="Style", info="Logical (0) <-> Poetic (100)")
154
- tone_slider = gr.Slider(0, 100, 50, step=1, label="Tone", info="Formal (0) <-> Passionate (100)")
155
-
156
- gr.Markdown("### Ink Resonance")
157
- ink_choice = gr.Radio(["Cosmic", "Ember", "Crystal", "Verdant"], value="Cosmic", label="Select AI Personality", show_label=False, elem_id="ink_selector")
158
-
159
- gr.Examples(
160
- examples=[
161
- "Let's finalize the Q3 report.",
162
- "The city at night is a complex tapestry of light and sound.",
163
- "I'm not sure how to start this email.",
164
- ],
165
- inputs=[chat_input],
166
- label="Try an Example"
167
- )
 
 
 
 
 
 
 
 
 
 
 
 
168
 
169
  # Event Handling Logic
170
- def clear_chat():
171
- return [], ""
 
 
 
 
172
 
173
- # Wire up all events
174
- submit_btn.click(app.generate_response, [chat_input, chatbot, style_slider, tone_slider, ink_choice], [chatbot, chat_input])
175
- chat_input.submit(app.generate_response, [chat_input, chatbot, style_slider, tone_slider, ink_choice], [chatbot, chat_input])
176
- clear_btn.click(clear_chat, [], [chatbot, chat_input])
 
 
 
177
 
178
  return interface
179
 
180
 
181
  if __name__ == "__main__":
182
- logging.info("Launching HumanTouch App with complete UI...")
183
  try:
184
  interface = create_interface()
185
  interface.launch(debug=True)
 
2
  import logging
3
  import gradio as gr
4
  from groq import Groq
5
+ from typing import List, Tuple
 
 
6
 
7
  # --- Basic Configuration ---
8
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', handlers=[logging.StreamHandler()])
 
 
 
 
9
 
10
+ # --- The Core Application Logic (Now serves both modes) ---
11
  class HumanTouchApp:
12
  def __init__(self):
13
  self.client = self._initialize_groq_client()
14
  self.model = "llama-3.3-70b-versatile"
15
  self.system_prompt_template = self._load_system_prompt()
16
+
17
  def _initialize_groq_client(self) -> Groq:
18
  api_key = os.environ.get("GROQ_API_KEY")
19
  if not api_key:
20
+ logging.error("FATAL: GROQ_API_KEY secret not found.")
21
  return None
22
  logging.info("Groq client initialized successfully.")
23
  return Groq(api_key=api_key)
24
 
25
  def _load_system_prompt(self) -> str:
26
+ # This one prompt now powers both modes, using context to differentiate tasks.
27
  return """
28
  You are HumanTouch, an AI specializing in transforming text into emotionally resonant communication.
29
+ Your output style is guided by two scores: Style (0=Logical, 100=Poetic) and Tone (0=Formal, 100=Passionate).
 
 
 
 
 
 
 
 
 
 
 
 
30
 
31
+ You will be given a task: either "HUMANIZE" a block of text or "CO-CREATE" from a user's seed phrase.
 
 
 
 
 
 
32
 
33
+ **Task: HUMANIZE**
34
+ When given a block of text, your goal is to rewrite it to sound more natural, engaging, and less robotic, according to the provided Style and Tone scores. Retain the core meaning but infuse it with a human touch.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
 
36
+ **Task: CO-CREATE**
37
+ When given a short phrase or idea, your goal is to expand and "bloom" it into a more complete, resonant thought, guided by the Style and Tone scores. This is a creative partnership.
38
+
39
+ In both tasks, do not explain your process. Only provide the transformed text.
40
+ """
41
 
42
+ def _call_groq_api(self, messages: List[dict], style_level: float, tone_level: float) -> str:
43
+ if not self.client:
44
+ return "## 🔴 Configuration Error\n\nThe `GROQ_API_KEY` is not set on the server. Please contact the Space administrator."
45
+ try:
46
+ logging.info(f"Calling Groq API with Style: {style_level}, Tone: {tone_level}")
47
  response = self.client.chat.completions.create(
48
  model=self.model,
49
  messages=messages,
50
  temperature=0.6 + (style_level / 250) + (tone_level / 250),
51
  max_tokens=4096,
52
  )
53
+ return response.choices[0].message.content.strip()
 
 
 
 
54
  except Exception as e:
55
  logging.error(f"Error during Groq API call: {e}")
56
+ return f"### ⚠️ An Error Occurred\n\nThere was an issue connecting to the AI. Please try again shortly. \n\n*Details: {str(e)}*"
57
+
58
+ # Method for the "Humanizer" Tab
59
+ def humanize_block_text(self, text_to_humanize: str, style_level: float, tone_level: float) -> str:
60
+ if not text_to_humanize.strip():
61
+ return "Please paste some AI-generated text to get started."
62
+
63
+ user_content = f"""
64
+ TASK: HUMANIZE
65
+ Style Score: {style_level}
66
+ Tone Score: {tone_level}
67
+ ---
68
+ TEXT TO HUMANIZE:
69
+ {text_to_humanize}
70
+ """
71
+ messages = [
72
+ {"role": "system", "content": self.system_prompt_template},
73
+ {"role": "user", "content": user_content}
74
+ ]
75
+ return self._call_groq_api(messages, style_level, tone_level)
76
+
77
+ # Method for the "Co-Creative Canvas" Tab
78
+ def generate_co_creation(self, user_text: str, chat_history: List[List[str]], style_level: float, tone_level: float) -> Tuple[List[List[str]], str]:
79
+ if not user_text.strip():
80
+ return chat_history, ""
81
 
82
+ user_content = f"""
83
+ TASK: CO-CREATE
84
+ Style Score: {style_level}
85
+ Tone Score: {tone_level}
86
+ ---
87
+ SEED PHRASE:
88
+ {user_text}
89
+ """
90
+ messages = [
91
+ {"role": "system", "content": self.system_prompt_template},
92
+ {"role": "user", "content": user_content}
93
+ ]
94
+
95
+ ai_response = self._call_groq_api(messages, style_level, tone_level)
96
+ chat_history.append([user_text, ai_response])
97
  return chat_history, ""
98
 
99
  # --- The Gradio User Interface ---
 
104
  #main_container { background: #111827; }
105
  #header { text-align: center; margin: 20px auto; color: #E5E7EB; }
106
  #header h1 { font-size: 2.5rem; font-weight: 600; }
107
+ #header p { font-size: 1.1rem; color: #9CA3AF; margin-bottom: 20px;}
108
+ .gradio-tabs { background-color: #1F2937; border-radius: 20px !important; border: 1px solid #374151; }
109
+ .tab-buttons button { background-color: #1F2937 !important; color: #9CA3AF !important; border-radius: 10px 10px 0 0 !important; }
110
+ .tab-buttons button.selected { background-color: #374151 !important; color: white !important; }
111
+
112
+ /* --- Humanizer Tab Styles --- */
113
+ #humanizer_input, #humanizer_output { background-color: #374151; color: #F9FAFB; border: 1px solid #4B5563; border-radius: 15px !important; min-height: 50vh;}
114
+ #humanize_btn { background: #10B981; color: white; font-weight: bold; padding: 15px 0; font-size: 1.2rem; }
115
+
116
+ /* --- Canvas Tab Styles --- */
117
+ #symbiotic_canvas { background: #1F2937; border-radius: 20px; box-shadow: inset 0 2px 4px 0 rgba(0,0,0,0.5); height: 65vh !important; border: 1px solid #374151; }
118
  #symbiotic_canvas .user { background-color: transparent !important; color: #F9FAFB; border: 1px solid #4B5563; }
119
  #symbiotic_canvas .bot { background-color: transparent !important; color: #A7F3D0; animation: bloom 0.7s ease-in-out; }
120
  @keyframes bloom { 0% { opacity: 0; transform: translateY(10px) scale(0.98); } 100% { opacity: 1; transform: translateY(0) scale(1); } }
121
  #control_deck { background: #1F2937; padding: 20px; border-radius: 20px; border: 1px solid #374151; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
  #chat_input textarea { background-color: #374151; color: #F9FAFB; border: 1px solid #4B5563; border-radius: 15px !important; }
 
 
123
  """
124
 
125
  with gr.Blocks(css=custom_css, theme=gr.themes.Base(), title="HumanTouch") as interface:
126
  with gr.Column(elem_id="main_container"):
127
  with gr.Row(elem_id="header"):
128
+ gr.Markdown("<h1>✨ HumanTouch</h1><p>Transform robotic text or co-create with a symbiotic AI partner. Choose your mode below.</p>")
129
+
130
+ with gr.Tabs() as tabs:
131
+ # --- TAB 1: The Humanizer ---
132
+ with gr.Tab("Humanizer", id="humanizer_tab"):
133
+ with gr.Column():
134
+ gr.Markdown("### 🤖➡️🧑 Humanize AI Text\n<p>Paste your text, adjust the resonance, and see it transformed.</p>")
135
+ with gr.Row():
136
+ with gr.Column(scale=2):
137
+ input_text_humanizer = gr.Textbox(label="Paste AI Text Here", lines=20, elem_id="humanizer_input")
138
+ with gr.Column(scale=2):
139
+ output_text_humanizer = gr.Textbox(label="Humanized Result", lines=20, interactive=False, elem_id="humanizer_output")
140
+ with gr.Row():
141
+ with gr.Column(scale=1):
142
+ style_slider_h = gr.Slider(0, 100, 50, label="Style (Logical <-> Poetic)")
143
+ with gr.Column(scale=1):
144
+ tone_slider_h = gr.Slider(0, 100, 50, label="Tone (Formal <-> Passionate)")
145
+ humanize_button = gr.Button("Humanize ", variant="primary", elem_id="humanize_btn")
146
+ gr.Examples(
147
+ [["The system's analysis concluded that the optimal parameters were achieved through iterative processing."],
148
+ ["Our team will action the deliverables post-haste to synergize our market position."]],
149
+ inputs=[input_text_humanizer], label="Try an Example"
150
+ )
151
+
152
+ # --- TAB 2: The Co-Creative Canvas ---
153
+ with gr.Tab("Co-Creative Canvas", id="canvas_tab"):
154
+ with gr.Row(equal_height=False):
155
+ with gr.Column(scale=3):
156
+ chatbot = gr.Chatbot([], label="Symbiotic Canvas", elem_id="symbiotic_canvas", bubble_full_width=True, avatar_images=(None, "https://i.imgur.com/Q6Zz3Jz.png"))
157
+ with gr.Row(elem_id="chat_input_row"):
158
+ chat_input = gr.Textbox(placeholder="Start a thought and press Enter...", show_label=False, container=False, scale=4)
159
+ clear_btn = gr.Button("New Canvas", scale=1)
160
+ with gr.Column(scale=1, elem_id="control_deck"):
161
+ gr.Markdown("### Resonance Controls")
162
+ style_slider_c = gr.Slider(0, 100, 50, label="Style", info="Logical <-> Poetic")
163
+ tone_slider_c = gr.Slider(0, 100, 50, label="Tone", info="Formal <-> Passionate")
164
+ gr.Examples(
165
+ ["The city at night", "I'm not sure how to start this email.", "Let's brainstorm names for the new project."],
166
+ inputs=[chat_input], label="Try a Seed Phrase"
167
+ )
168
 
169
  # Event Handling Logic
170
+ # Humanizer Tab
171
+ humanize_button.click(
172
+ app.humanize_block_text,
173
+ [input_text_humanizer, style_slider_h, tone_slider_h],
174
+ [output_text_humanizer]
175
+ )
176
 
177
+ # Canvas Tab
178
+ chat_input.submit(
179
+ app.generate_co_creation,
180
+ [chat_input, chatbot, style_slider_c, tone_slider_c],
181
+ [chatbot, chat_input]
182
+ )
183
+ clear_btn.click(lambda: ([], ""), [], [chatbot, chat_input])
184
 
185
  return interface
186
 
187
 
188
  if __name__ == "__main__":
189
+ logging.info("Launching HumanTouch App with Blended UI...")
190
  try:
191
  interface = create_interface()
192
  interface.launch(debug=True)