ciaochris commited on
Commit
123bfc8
·
verified ·
1 Parent(s): d134a65

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +205 -177
app.py CHANGED
@@ -1,217 +1,245 @@
1
- # Copyright 2024 Christopher Woodyard
2
- # Licensed under the Apache License, Version 2.0
3
- # [License details remain unchanged]
4
-
5
  import os
6
  import logging
7
  import gradio as gr
8
  from groq import Groq
9
- import requests
10
  from datetime import datetime
11
  import json
12
- from typing import Tuple, Optional
13
 
14
- # Configure logging with file output
 
15
  logging.basicConfig(
16
  level=logging.INFO,
17
  format='%(asctime)s - %(levelname)s - %(message)s',
18
- handlers=[
19
- logging.FileHandler(f'humantouch_{datetime.now().strftime("%Y%m%d")}.log'),
20
- logging.StreamHandler()
21
- ]
22
  )
23
 
 
24
  class HumanTouchApp:
25
  def __init__(self):
 
26
  self.client = self._initialize_groq_client()
27
- self.model = "llama-3.3-70b-versatile"
28
- self.system_prompt = self._load_system_prompt()
29
- self.history_file = "processing_history.json"
30
 
31
  def _initialize_groq_client(self) -> Groq:
32
- """Initialize Groq client with error handling"""
33
- try:
34
- client = Groq(api_key=os.environ.get("GROQ_API_KEY"))
35
- logging.info("Groq client initialized successfully")
36
- return client
37
- except KeyError:
38
- logging.error("GROQ_API_KEY not found in environment variables")
39
- raise EnvironmentError("Please set the GROQ_API_KEY environment variable")
40
- except Exception as e:
41
- logging.error(f"Error initializing Groq client: {e}")
42
- raise
43
 
44
  def _load_system_prompt(self) -> str:
45
- """Load and return the system prompt"""
 
 
 
 
46
  return """
47
- [Your existing SYSTEM_PROMPT remains unchanged]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
 
50
- def humanize_text(self, ai_text: str, creativity_level: float) -> str:
51
- """Process text through Groq API for humanization"""
52
  try:
53
- logging.info(f"Humanizing text with creativity level: {creativity_level}")
 
 
 
 
 
 
 
 
54
  response = self.client.chat.completions.create(
55
  model=self.model,
56
- temperature=min(1.0, 0.4 + (creativity_level * 0.1)),
57
- max_tokens=4000, # Increased for longer texts
58
- messages=[
59
- {"role": "system", "content": self.system_prompt},
60
- {"role": "user", "content": f"""
61
- Please humanize the following text, applying the guidelines provided:
62
- Original text:
63
- {ai_text}
64
- Humanized version:
65
- """}
66
- ]
67
  )
68
- result = response.choices[0].message.content.strip()
69
- self._save_to_history(ai_text, result)
70
- logging.info("Text humanization completed")
71
- return result
72
- except requests.exceptions.RequestException as e:
73
- logging.error(f"Network error: {e}")
74
- return f"Network error: {str(e)}. Please try again."
75
- except Exception as e:
76
- logging.error(f"Processing error: {e}")
77
- return f"Error: {str(e)}"
78
-
79
- def _save_to_history(self, input_text: str, output_text: str) -> None:
80
- """Save processing history to JSON file"""
81
- history_entry = {
82
- "timestamp": datetime.now().isoformat(),
83
- "input": input_text[:100], # Truncate for storage efficiency
84
- "output": output_text[:100],
85
- "input_length": len(input_text.split())
86
- }
87
-
88
- try:
89
- history = []
90
- if os.path.exists(self.history_file):
91
- with open(self.history_file, 'r') as f:
92
- history = json.load(f)
93
- history.append(history_entry)
94
- with open(self.history_file, 'w') as f:
95
- json.dump(history[-100:], f) # Keep last 100 entries
96
  except Exception as e:
97
- logging.warning(f"Failed to save history: {e}")
 
 
98
 
99
- def process_text(self, ai_text: str, creativity_level: float) -> Tuple[str, str]:
100
- """Main processing function with validation"""
101
- if not ai_text.strip():
102
- return "Please provide text to humanize.", "Input word count: 0"
103
-
104
- humanized = self.humanize_text(ai_text, creativity_level)
105
- input_count = len(ai_text.split())
106
- output_count = len(humanized.split())
107
-
108
- stats = (f"Input words: {input_count} | Output words: {output_count} | "
109
- f"Change: {((output_count - input_count) / input_count * 100):.1f}%")
110
- return humanized, stats
111
-
112
- # Enhanced CSS with better responsiveness
113
- custom_css = """
114
- body {
115
- background: linear-gradient(135deg, #6DD5FA, #FF758C);
116
- font-family: 'Arial', sans-serif;
117
- min-height: 100vh;
118
- }
119
- .container {
120
- max-width: 900px;
121
- margin: 2rem auto;
122
- padding: 2rem;
123
- background: rgba(255, 255, 255, 0.9);
124
- border-radius: 20px;
125
- box-shadow: 0 8px 32px rgba(31, 38, 135, 0.37);
126
- }
127
- .title { font-size: 2.5rem; color: #2D3748; }
128
- .description { color: #4A5568; }
129
- .input-box, .output-box {
130
- border: 2px solid #63B3ED;
131
- border-radius: 12px;
132
- padding: 1rem;
133
- background: white;
134
- transition: border-color 0.3s ease;
135
- }
136
- .input-box:focus, .output-box:focus {
137
- border-color: #3182CE;
138
- box-shadow: 0 0 8px rgba(49, 130, 206, 0.3);
139
- }
140
- @media (max-width: 768px) {
141
- .container { margin: 1rem; padding: 1rem; }
142
- .title { font-size: 2rem; }
143
- }
144
- button.primary {
145
- background: linear-gradient(45deg, #ED64A6, #4299E1);
146
- padding: 12px 24px;
147
- border-radius: 9999px;
148
- }
149
- button.primary:hover {
150
- background: linear-gradient(45deg, #F687B3, #5A67D8);
151
- }
152
- .stats { color: #718096; font-size: 0.9rem; }
153
- """
154
 
 
 
155
  def create_interface():
156
  app = HumanTouchApp()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
 
158
- with gr.Blocks(css=custom_css, title="HumanTouch") as interface:
159
- gr.Markdown("""
160
- <div class="container">
161
- <h1 class="title">🧙‍♂️ HumanTouch</h1>
162
- <p class="description">Breathe life into AI text with human-like finesse! Powered by Vers3Dynamics</p>
163
- </div>
164
- """)
165
-
166
- with gr.Row(equal_height=False):
167
- with gr.Column(scale=1):
168
- input_text = gr.Textbox(
169
- label="AI-Generated Text",
170
- lines=12,
171
- placeholder="Paste your AI text here...",
172
- elem_classes="input-box"
173
- )
174
- creativity = gr.Slider(
175
- 0, 6, 3, step=1,
176
- label="Creativity Level",
177
- info="Higher values increase creative liberty (0-6)"
178
- )
179
- btn = gr.Button("Start ✨", variant="primary")
180
-
181
- with gr.Column(scale=1):
182
- output_text = gr.Textbox(
183
- label="Humanized Result",
184
- lines=12,
185
- interactive=False,
186
- elem_classes="output-box"
187
- )
188
- stats = gr.Markdown(elem_classes="stats")
189
-
190
- gr.Examples(
191
- examples=[
192
- ["The system analyzed the dataset and determined optimal parameters.", 3],
193
- ["The AI assistant completed its task sequence efficiently.", 4]
194
- ],
195
- inputs=[input_text, creativity]
196
- )
197
-
198
- btn.click(app.process_text, [input_text, creativity], [output_text, stats])
199
- input_text.change(
200
- lambda x: f"Input words: {len(x.split())}",
201
- inputs=[input_text],
202
- outputs=[stats]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
203
  )
204
 
205
  return interface
206
 
 
207
  if __name__ == "__main__":
208
- logging.info("Launching HumanTouch App")
209
  try:
210
  interface = create_interface()
211
- interface.launch(
212
- debug=True,
213
- server_name="0.0.0.0",
214
- share=True # Enable public sharing option
215
- )
216
  except Exception as e:
217
- logging.error(f"Application launch failed: {e}")
 
 
 
 
 
1
  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
+ # Configure logging for better debugging in Hugging Face logs
11
  logging.basicConfig(
12
  level=logging.INFO,
13
  format='%(asctime)s - %(levelname)s - %(message)s',
14
+ handlers=[logging.StreamHandler()]
 
 
 
15
  )
16
 
17
+ # --- The Core Application Logic ---
18
  class HumanTouchApp:
19
  def __init__(self):
20
+ # Securely initialize Groq client using Hugging Face Secrets
21
  self.client = self._initialize_groq_client()
22
+ self.model = "llama-3.1-70b-versatile" # Using the latest powerful model
23
+ self.system_prompt_template = self._load_system_prompt()
 
24
 
25
  def _initialize_groq_client(self) -> Groq:
26
+ """Initialize Groq client, pulling the API key from HF Secrets."""
27
+ api_key = os.environ.get("GROQ_API_KEY")
28
+ if not api_key:
29
+ logging.error("FATAL: GROQ_API_KEY secret not found in Hugging Face Space settings.")
30
+ # In a real app, this should raise an error or display a persistent message.
31
+ # For this demo, we'll allow it to fail gracefully in the API call.
32
+ return None
33
+ logging.info("Groq client initialized successfully.")
34
+ return Groq(api_key=api_key)
 
 
35
 
36
  def _load_system_prompt(self) -> str:
37
+ """
38
+ Loads the foundational system prompt template.
39
+ This prompt is now dynamic and will be formatted with user controls.
40
+ """
41
+ # ⬇️ PASTE YOUR ORIGINAL SYSTEM PROMPT INSIDE THE TRIPLE QUOTES ⬇️
42
  return """
43
+ You are HumanTouch, an AI specializing in transforming text into emotionally resonant communication.
44
+ Your persona is determined by the chosen 'Ink Resonance'.
45
+ Your output style is guided by two scores:
46
+ 1. **Style Score (0-100):** 0 is purely logical and precise. 100 is highly poetic, abstract, and metaphorical.
47
+ 2. **Tone Score (0-100):** 0 is formal and stoic. 100 is casual, emotional, and passionate.
48
+
49
+ 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.
50
+
51
+ Here are the Ink Resonance personalities:
52
+ - **Cosmic (Default):** Wise, expansive, slightly mysterious.
53
+ - **Ember (Premium):** Passionate, fiery, bold, and direct.
54
+ - **Crystal (Premium):** Sharp, analytical, precise, and elegant.
55
+ - **Verdant (Premium):** Natural, organic, growing, and holistic.
56
+ """
57
+
58
+ 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]:
59
+ """
60
+ Main function to generate the AI's co-creative response.
61
+ This is the new "heart" of the application.
62
  """
63
+ if not self.client:
64
+ # Display error in chat if the API key is missing
65
+ chat_history.append([user_text, "Error: The GROQ_API_KEY is not configured on the server. Please contact the administrator."])
66
+ return chat_history, ""
67
+
68
+ if not user_text.strip():
69
+ # Don't respond to empty input
70
+ return chat_history, ""
71
+
72
+ # Check for premium features
73
+ if ink_resonance in ["Ember", "Crystal", "Verdant"]:
74
+ # In a real app, you'd have user authentication. Here, we simulate the paywall.
75
+ chat_history.append([user_text, f"The '{ink_resonance}' Ink Resonance is a premium feature. To unlock new AI personalities and support our work, please upgrade! For now, I'll use the default Cosmic ink."])
76
+ ink_resonance = "Cosmic"
77
+
78
+ # Format the dynamic system prompt
79
+ dynamic_system_prompt = self.system_prompt_template.format(
80
+ ink_personality=ink_resonance,
81
+ style_score=style_level,
82
+ tone_score=tone_level
83
+ )
84
 
 
 
85
  try:
86
+ logging.info(f"Generating response for '{user_text[:30]}...' with Style: {style_level}, Tone: {tone_level}, Ink: {ink_resonance}")
87
+
88
+ messages = [{"role": "system", "content": dynamic_system_prompt}]
89
+ # Optional: include some history for context, but for this tool, it's often better to be stateless.
90
+ # for human, ai in chat_history[-2:]: # last 2 turns
91
+ # messages.append({"role": "user", "content": human})
92
+ # messages.append({"role": "assistant", "content": ai})
93
+ messages.append({"role": "user", "content": user_text})
94
+
95
  response = self.client.chat.completions.create(
96
  model=self.model,
97
+ messages=messages,
98
+ temperature=0.5 + (style_level / 200) + (tone_level / 200), # Map 0-100 sliders to a sensible temp range
99
+ max_tokens=4096,
 
 
 
 
 
 
 
 
100
  )
101
+ ai_response = response.choices[0].message.content.strip()
102
+
103
+ chat_history.append([user_text, ai_response])
104
+ logging.info("Successfully generated response.")
105
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
  except Exception as e:
107
+ logging.error(f"Error during Groq API call: {e}")
108
+ ai_response = f"An error occurred while connecting to the AI. Details: {str(e)}"
109
+ chat_history.append([user_text, ai_response])
110
 
111
+ # Return updated history and clear the input box
112
+ return chat_history, ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
 
114
+
115
+ # --- The Gradio User Interface ---
116
  def create_interface():
117
  app = HumanTouchApp()
118
+
119
+ # The new CSS for our "Symbiotic Canvas" vision
120
+ custom_css = """
121
+ /* --- Main Layout & Background --- */
122
+ #main_container { background: #111827; }
123
+ #header { text-align: center; margin: 20px auto; color: #E5E7EB; }
124
+ #header h1 { font-size: 2.5rem; font-weight: 600; }
125
+ #header p { font-size: 1.1rem; color: #9CA3AF; }
126
+
127
+ /* --- The Unified Canvas (achieved with gr.Chatbot) --- */
128
+ #symbiotic_canvas {
129
+ background: #1F2937;
130
+ border-radius: 20px;
131
+ box-shadow: inset 0 2px 4px 0 rgba(0,0,0,0.5);
132
+ height: 60vh !important;
133
+ border: 1px solid #374151;
134
+ }
135
+ /* Style the user's message (Seed Text) */
136
+ #symbiotic_canvas .user { background-color: transparent !important; color: #F9FAFB; }
137
+ /* Style the AI's message (Bloomed Text) and add the animation */
138
+ #symbiotic_canvas .bot { background-color: transparent !important; color: #A7F3D0; animation: bloom 0.7s ease-in-out; }
139
+ @keyframes bloom {
140
+ 0% { opacity: 0; transform: translateY(10px) scale(0.98); }
141
+ 100% { opacity: 1; transform: translateY(0) scale(1); }
142
+ }
143
+
144
+ /* --- The Control Deck --- */
145
+ #control_deck {
146
+ background: #1F2937;
147
+ padding: 20px;
148
+ border-radius: 20px;
149
+ border: 1px solid #374151;
150
+ }
151
+ #control_deck .gradio-slider label span { color: #D1D5DB; } /* Slider labels */
152
 
153
+ /* --- Ink Resonances (Radio Buttons styled as icons) --- */
154
+ #ink_selector { gap: 1rem; }
155
+ #ink_selector .gradio-radio label {
156
+ background: #374151 !important; color: #E5E7EB !important;
157
+ padding: 10px 15px !important; border-radius: 12px !important;
158
+ border: 2px solid transparent !important; transition: all 0.2s ease-in-out;
159
+ }
160
+ #ink_selector .gradio-radio input:checked + label {
161
+ border-color: #34D399 !important; background: #10B981 !important;
162
+ box-shadow: 0 0 15px rgba(16, 185, 129, 0.5);
163
+ }
164
+ /* Style for premium/locked inks */
165
+ #ink_selector .gradio-radio:nth-child(n+2) label:after {
166
+ content: '🔒'; /* lock emoji */
167
+ margin-left: 8px; font-size: 0.8em;
168
+ }
169
+ #ink_selector .gradio-radio:nth-child(1) label:after {
170
+ content: '✨'; /* default emoji */
171
+ margin-left: 8px; font-size: 0.8em;
172
+ }
173
+
174
+ /* --- The Input Bar --- */
175
+ #chat_input textarea {
176
+ background-color: #374151; color: #F9FAFB;
177
+ border: 1px solid #4B5563; border-radius: 15px !important;
178
+ }
179
+ """
180
+
181
+ with gr.Blocks(css=custom_css, theme=gr.themes.Base(), title="HumanTouch") as interface:
182
+ with gr.Column(elem_id="main_container"):
183
+ # Header
184
+ with gr.Row(elem_id="header"):
185
+ gr.Markdown("""
186
+ # ✨ HumanTouch
187
+ <p>A Symbiotic Canvas for Co-Creative Writing</p>
188
+ """)
189
+
190
+ # The main UI: Canvas on the left, Controls on the right
191
+ with gr.Row(equal_height=False):
192
+ with gr.Column(scale=3):
193
+ chatbot = gr.Chatbot(
194
+ [],
195
+ label="Symbiotic Canvas",
196
+ elem_id="symbiotic_canvas",
197
+ bubble_full_width=True,
198
+ avatar_images=(None, "https://i.imgur.com/Q6Zz3Jz.png") # User has none, Bot has a simple avatar
199
+ )
200
+ chat_input = gr.Textbox(
201
+ placeholder="Start your thought here... (Press Enter to submit)",
202
+ elem_id="chat_input",
203
+ show_label=False,
204
+ container=False
205
+ )
206
+
207
+ with gr.Column(scale=1, elem_id="control_deck"):
208
+ gr.Markdown("### Resonance Controls")
209
+ style_slider = gr.Slider(
210
+ 0, 100, 50, step=1,
211
+ label="Style",
212
+ info="Logical (0) <-> Poetic (100)"
213
+ )
214
+ tone_slider = gr.Slider(
215
+ 0, 100, 50, step=1,
216
+ label="Tone",
217
+ info="Formal (0) <-> Passionate (100)"
218
+ )
219
+
220
+ gr.Markdown("### Ink Resonance")
221
+ ink_choice = gr.Radio(
222
+ ["Cosmic", "Ember", "Crystal", "Verdant"],
223
+ value="Cosmic",
224
+ label="Select AI Personality",
225
+ show_label=False,
226
+ elem_id="ink_selector"
227
+ )
228
+
229
+ # Event Handling Logic
230
+ chat_input.submit(
231
+ app.generate_response,
232
+ [chat_input, chatbot, style_slider, tone_slider, ink_choice],
233
+ [chatbot, chat_input] # Update chatbot and clear input
234
  )
235
 
236
  return interface
237
 
238
+
239
  if __name__ == "__main__":
240
+ logging.info("Launching HumanTouch App with new Symbiotic UI...")
241
  try:
242
  interface = create_interface()
243
+ interface.launch(debug=True) # Share=True is not recommended for local dev with secrets
 
 
 
 
244
  except Exception as e:
245
+ logging.critical(f"Application launch failed: {e}", exc_info=True)