File size: 10,573 Bytes
77ad748
 
 
 
69fdfa8
15cb681
123bfc8
69fdfa8
15cb681
dd08002
15cb681
 
 
ed79b7f
123bfc8
69fdfa8
15cb681
123bfc8
 
69fdfa8
123bfc8
 
 
15cb681
 
f02ad06
15cb681
d601d5b
123bfc8
d601d5b
 
 
123bfc8
d601d5b
 
 
69fdfa8
123bfc8
d601d5b
69fdfa8
 
 
 
d601d5b
 
 
 
 
15cb681
 
123bfc8
f02ad06
123bfc8
15cb681
69fdfa8
15cb681
123bfc8
69fdfa8
 
 
 
 
d601d5b
69fdfa8
 
 
 
d601d5b
69fdfa8
123bfc8
77ad748
123bfc8
15cb681
 
123bfc8
ea342d7
123bfc8
6b704ca
ea342d7
6b704ca
d601d5b
 
 
6b704ca
 
 
dd08002
f02ad06
 
6b704ca
 
ea342d7
f02ad06
69fdfa8
 
ea342d7
 
d601d5b
6b704ca
 
d601d5b
ea342d7
 
 
 
 
 
 
f02ad06
ea342d7
 
 
 
 
f02ad06
ea342d7
dd08002
 
f02ad06
ea342d7
 
 
 
 
 
 
dd08002
6b704ca
f2f28b2
 
d601d5b
f2f28b2
d601d5b
 
f2f28b2
123bfc8
 
6b704ca
123bfc8
 
0631415
69fdfa8
 
 
6b704ca
 
69fdfa8
d601d5b
 
69fdfa8
d601d5b
 
69fdfa8
d601d5b
69fdfa8
 
 
 
 
6b704ca
d601d5b
6b704ca
 
69fdfa8
d601d5b
 
 
123bfc8
 
6b704ca
 
 
15cb681
 
77ad748
123bfc8
77ad748
dd08002
15cb681
 
da2ccac
15cb681
123bfc8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
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)