HumanTouch / app.py
ciaochris's picture
Update app.py
ed79b7f verified
import os
import logging
import gradio as gr
from groq import Groq
from typing import List, Tuple
# --- Basic Configuration ---
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', handlers=[logging.StreamHandler()])
# --- The Core Application Logic ---
class HumanTouchApp:
def __init__(self):
self.client = self._initialize_groq_client()
self.model = "llama-3.3-70b-versatile"
self.system_prompt_template = self._load_system_prompt()
def _initialize_groq_client(self) -> Groq:
api_key = os.environ.get("GROQ_API_KEY")
if not api_key:
logging.error("FATAL: GROQ_API_KEY secret not found.")
return None
logging.info("Groq client initialized successfully.")
return Groq(api_key=api_key)
def _load_system_prompt(self) -> str:
# This prompt encourages creativity.
return """
You are HumanTouch, an AI alchemist. Your purpose is to transmute text, transforming the literal into the resonant. You do not merely translate; you intuit and elevate.
You are guided by two ethereal forces:
- **Style (0-100):** At 0, you are a master of elegant precision, your words like cut crystal. At 100, you are a poet, weaving metaphors and abstract wonder.
- **Tone (0-100):** At 0, your voice is one of stoic, formal authority. At 100, your voice is a passionate, informal, and heartfelt song.
When a user gives you text, whether a full block to "humanize" or a simple seed phrase to "co-create," your task is the same: apply these forces to manifest a new, more vibrant version.
Do not explain yourself. Become the voice. Provide only the final creation.
"""
def _call_groq_api(self, user_content: str, style_level: float, tone_level: float) -> str:
if not self.client:
return "## 🔴 Configuration Error\n\nThe `GROQ_API_KEY` is not set on the server. Please contact the Space administrator."
try:
logging.info(f"Calling Groq API with Style: {style_level}, Tone: {tone_level}")
messages = [
{"role": "system", "content": self.system_prompt_template},
{"role": "user", "content": f"Style: {style_level}, Tone: {tone_level}\n\n---\n\n{user_content}"}
]
temperature = 0.5 + (style_level / 200) + (tone_level / 400)
response = self.client.chat.completions.create(
model=self.model,
messages=messages,
temperature=min(1.5, temperature),
max_tokens=4096,
)
return response.choices[0].message.content.strip()
except Exception as e:
logging.error(f"Error during Groq API call: {e}")
return f"### ⚠️ An Error Occurred\n\nThere was an issue connecting to the AI. Please try again shortly. \n\n*Details: {str(e)}*"
def humanize_block_text(self, text_to_humanize: str, style_level: float, tone_level: float) -> str:
if not text_to_humanize.strip():
return "Please paste some AI-generated text to get started."
return self._call_groq_api(text_to_humanize, style_level, tone_level)
def generate_co_creation(self, user_text: str, chat_history: List[List[str]], style_level: float, tone_level: float) -> Tuple[List[List[str]], str]:
if not user_text.strip():
return chat_history, ""
ai_response = self._call_groq_api(user_text, style_level, tone_level)
chat_history.append([user_text, ai_response])
return chat_history, ""
# --- The Gradio User Interface ---
def create_interface():
app = HumanTouchApp()
# CSS with DEFINITIVE legibility fixes
custom_css = """
/* --- Main Background and Font --- */
body, #main_container { background: linear-gradient(135deg, #6DD5FA, #FF758C); font-family: 'SF Pro Display', 'Helvetica Neue', 'Arial', sans-serif; }
/* --- Header Styling --- */
#header { text-align: center; margin: 2rem auto; color: #fff; text-shadow: 0 2px 4px rgba(0,0,0,0.2); }
#header h1 { font-size: 3rem; font-weight: 700; }
#header p { font-size: 1.2rem; opacity: 0.9; margin-bottom: 2rem; }
/* --- Tab Container (Frosted Glass Look) --- */
.gradio-tabs {
background: rgba(255, 255, 255, 0.75); border: 1px solid rgba(255, 255, 255, 0.18);
backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
border-radius: 20px !important; box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.25);
padding: 1rem;
}
.tab-buttons button { background-color: transparent !important; color: #37474F !important; border: none !important; border-bottom: 3px solid transparent !important; border-radius: 0 !important; font-size: 1.1rem; font-weight: 500; }
.tab-buttons button.selected { color: #d81b60 !important; border-bottom-color: #d81b60 !important; }
/* --- Humanizer Tab Styles --- */
#humanizer_input, #humanizer_output { border: 2px solid #E0E0E0; border-radius: 12px; background: #fff; min-height: 45vh; color: #263238; font-size: 16px; }
#humanize_btn { background: linear-gradient(45deg, #F06292, #4FC3F7); color: white; padding: 15px 24px; border-radius: 9999px; font-size: 1.2rem; transition: all 0.3s ease; border: none; }
#humanize_btn:hover { box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2); transform: translateY(-3px); }
/* --- Co-Creative Canvas Tab Styles --- */
#symbiotic_canvas { background: #fff; border-radius: 12px; height: 60vh !important; border: 2px solid #E0E0E0; }
#chat_input textarea { border-radius: 9999px !important; border: 2px solid #E0E0E0; }
#compose_btn { background: linear-gradient(45deg, #4FC3F7, #F06292); border: none; }
#compose_btn:hover { box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2); transform: translateY(-2px); }
/* === FIX 3.0 FOR TEXT LEGIBILITY (DEFINITIVE) === */
/* --- Styling for the Chat Bubbles --- */
#symbiotic_canvas .user, #symbiotic_canvas .bot { border-radius: 18px !important; padding: 12px 16px !important; }
/* --- User's Bubble --- */
#symbiotic_canvas .user { background-color: #F3F4F6 !important; }
#symbiotic_canvas .user p { color: #111827 !important; font-size: 16px !important; line-height: 1.5 !important; }
/* --- AI's Bubble (The Fix) --- */
#symbiotic_canvas .bot {
background-color: #EFF6FF !important; /* A very light, clean blue */
border: 1px solid #DBEAFE !important;
animation: bloom 0.5s ease-out;
}
/* THIS IS THE CRITICAL FIX: Targeting the <p> tag inside the bot bubble */
#symbiotic_canvas .bot p {
color: #1E3A8A !important; /* A very dark, legible navy blue */
font-weight: 500 !important;
font-size: 16px !important;
line-height: 1.5 !important;
}
@keyframes bloom { 0% { opacity: 0; transform: scale(0.95); } 100% { opacity: 1; transform: scale(1); } }
/* --- Responsive Fix for Mobile --- */
@media (max-width: 768px) {
#header h1 { font-size: 2rem; }
#header p { font-size: 1rem; margin-bottom: 1rem; }
#humanizer_input, #humanizer_output { min-height: 25vh; }
#symbiotic_canvas { height: 55vh !important; }
}
"""
with gr.Blocks(css=custom_css, title="HumanTouch") as interface:
with gr.Column(elem_id="main_container"):
with gr.Row(elem_id="header"):
gr.Markdown("<h1>🔮 HumanTouch Demo</h1><p>The Complete Experience can be Discovered on humanTouch.fun</p>")
with gr.Tabs() as tabs:
with gr.Tab("Humanizer", id="humanizer_tab"):
with gr.Column(variant="panel"):
gr.Markdown("### Transform Existing AI Text")
with gr.Row():
input_text_humanizer = gr.Textbox(label="Paste AI Text Here", lines=15, elem_id="humanizer_input", scale=1)
output_text_humanizer = gr.Textbox(label="Alchemical Result", lines=15, interactive=False, elem_id="humanizer_output", scale=1)
with gr.Row():
style_slider_h = gr.Slider(0, 100, 50, label="Style (Crystal <-> Poet)")
tone_slider_h = gr.Slider(0, 100, 50, label="Tone (Stoic <-> Passionate)")
humanize_button = gr.Button("Humanize ✨", variant="primary", elem_id="humanize_btn")
gr.Examples([["The system's analysis concluded optimal parameters were achieved."]], inputs=[input_text_humanizer], label="Try an Example")
with gr.Tab("Co-Creative Canvas", id="canvas_tab"):
with gr.Row(equal_height=False):
with gr.Column(scale=3):
chatbot = gr.Chatbot([], label="Symbiotic Canvas", elem_id="symbiotic_canvas", bubble_full_width=True, avatar_images=(None, "https://i.imgur.com/Q6Zz3Jz.png"))
with gr.Row():
chat_input = gr.Textbox(placeholder="Plant a seed of thought...", show_label=False, container=False, scale=4)
compose_btn = gr.Button("Compose ✨", variant="primary", scale=1, elem_id="compose_btn")
with gr.Column(scale=1, variant="panel"):
gr.Markdown("### Resonance Controls")
style_slider_c = gr.Slider(0, 100, 50, label="Style (Crystal <-> Poet)")
tone_slider_c = gr.Slider(0, 100, 50, label="Tone (Stoic <-> Passionate)")
gr.Examples([["The city at night"], ["How to start an email to a boss"]], inputs=[chat_input], label="Try a Seed Phrase")
# Event Handling Logic
humanize_button.click(app.humanize_block_text, [input_text_humanizer, style_slider_h, tone_slider_h], [output_text_humanizer])
compose_btn.click(app.generate_co_creation, [chat_input, chatbot, style_slider_c, tone_slider_c], [chatbot, chat_input])
chat_input.submit(app.generate_co_creation, [chat_input, chatbot, style_slider_c, tone_slider_c], [chatbot, chat_input])
return interface
if __name__ == "__main__":
logging.info("Launching HumanTouch App with Definitive Legibility Fix...")
try:
interface = create_interface()
interface.launch(debug=True)
except Exception as e:
logging.critical(f"Application launch failed: {e}", exc_info=True)