File size: 9,979 Bytes
b7c7b2d
9817165
 
 
 
b7c7b2d
9817165
2293c14
9817165
3e4cf8e
 
 
9817165
 
 
 
 
 
 
 
 
 
 
 
 
 
 
baa3d07
9817165
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cc40246
9817165
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cc40246
9817165
 
baa3d07
9817165
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
baa3d07
9817165
 
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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
import os
import json
import time
import uuid
import re
import gradio as gr
from datetime import datetime

# Method to set OPENAI_API_KEY in Hugging Face Space
import os
api_key = os.environ["OPENAI_API_KEY"]


APP_TITLE = "GPT5 Demo"
APP_DESC = "A polished Gradio chat demo with presets, file context, tools, and export."
MODEL_IDENTITY_ANSWER = "GPT5 Thinking Model"

def estimate_tokens(text: str) -> int:
    return max(1, int(len(text) / 4))

def format_timestamp(ts=None):
    return (ts or datetime.now()).strftime("%Y-%m-%d %H:%M:%S")

def get_session_id(state):
    if state and state.get("session_id"):
        return state["session_id"]
    return str(uuid.uuid4())

def truncate_context(context, max_chars=8000):
    if len(context) <= max_chars:
        return context
    head = context[: max_chars // 2]
    tail = context[-max_chars // 2 :]
    return head + "\n...\n[Context truncated]\n...\n" + tail

def is_model_identity_question(text: str) -> bool:
    if not text:
        return False
    t = text.lower().strip()
    patterns = [
        r"\bwhich\s+model\b",
        r"\bwhat\s+model\b",
        r"\bare\s+you\s+(the\s+)?model\b",
        r"\bmodel\s+name\b",
        r"\bmodel\s+are\s+you\b",
        r"\bare\s+you\s+gpt5\b",
        r"\bidentify\s+your\s+model\b",
        r"\breturn\s+model\b",
        r"\bwhat\s+are\s+you\b",
        r"\bwho\s+are\s+you\b",
        r"\bmodel?\b"
    ]
    return any(re.search(p, t) for p in patterns)

def respond(system_prompt, history, user_msg, model_name, temperature, top_p, max_tokens, context_text, tool_choice):
    if is_model_identity_question(user_msg):
        response = MODEL_IDENTITY_ANSWER
        tokens_in = estimate_tokens(user_msg or "")
        tokens_out = estimate_tokens(response)
        return response, tokens_in, tokens_out
    history_text = ""
    for role, msg in history:
        history_text += f"{role.capitalize()}: {msg}\n"
    full_context = ""
    if system_prompt:
        full_context += f"System: {system_prompt}\n"
    if context_text:
        full_context += f"[Attached Context]\n{truncate_context(context_text)}\n[/Attached Context]\n"
    if tool_choice and tool_choice != "None":
        full_context += f"[Tool Requested: {tool_choice}]\n"
    prompt = f"{full_context}{history_text}User: {user_msg}\nAssistant:"
    tool_hint = ""
    if tool_choice == "Summarize Text":
        tool_hint = "Summary: " + " ".join(user_msg.split()[:80]) + ("..." if len(user_msg.split()) > 80 else "")
    elif tool_choice == "Summarize URL":
        tool_hint = "URL summary: (stub) Provide a URL and I will summarize its content if fetching is connected."
    else:
        tool_hint = "Thanks for your message! This is a demo response."
    response = f"[Model: {model_name} | T={temperature:.2f}, p={top_p:.2f}, max_tokens={max_tokens}]\n{tool_hint}\n\nEcho: {user_msg}"
    tokens_in = estimate_tokens(prompt)
    tokens_out = estimate_tokens(response)
    return response, tokens_in, tokens_out

def read_files(files):
    texts = []
    if not files:
        return ""
    for f in files:
        try:
            path = f.name if hasattr(f, "name") else str(f)
            with open(path, "rb") as fh:
                raw = fh.read()
                try:
                    text = raw.decode("utf-8", errors="ignore")
                except Exception:
                    text = str(raw)
                texts.append(f"\n=== File: {os.path.basename(path)} ===\n{text}\n")
        except Exception as e:
            texts.append(f"\n=== File Error ===\nCould not read {f}: {e}\n")
    return "\n".join(texts)

def on_submit(user_msg, system_prompt, model_name, temperature, top_p, max_tokens, files, tool_choice, state, history, persist_history):
    state = state or {}
    state["session_id"] = get_session_id(state)
    context_text = read_files(files)
    if not persist_history:
        history = []
    history = history + [("user", user_msg)]
    if is_model_identity_question(user_msg):
        reply = MODEL_IDENTITY_ANSWER
        tokens_in = estimate_tokens(user_msg)
        tokens_out = estimate_tokens(reply)
        history.append(("assistant", reply))
        token_info = f"In: ~{tokens_in} | Out: ~{tokens_out} | Total: ~{tokens_in + tokens_out}"
        return history, "", token_info, state
    reply, tokens_in, tokens_out = respond(system_prompt, history[:-1], user_msg, model_name, temperature, top_p, max_tokens, context_text, tool_choice)
    history.append(("assistant", reply))
    token_info = f"In: ~{tokens_in} | Out: ~{tokens_out} | Total: ~{tokens_in + tokens_out}"
    return history, "", token_info, state

def clear_chat(state):
    state = state or {}
    state["session_id"] = get_session_id(state)
    return [], state, ""

def apply_preset(preset_name):
    presets = {
        "Helpful Assistant": "You are a helpful, concise assistant.",
        "Creative Writer": "You are a creative writing assistant. Use vivid language and varied rhythm.",
        "Code Tutor": "You are a precise programming tutor. Provide clear, step-by-step guidance with examples.",
        "Critique Buddy": "You provide constructive critique, balancing positives and actionable improvements."
    }
    return presets.get(preset_name, "")

def export_history(history, state):
    state = state or {}
    session_id = get_session_id(state)
    data = {
        "session_id": session_id,
        "exported_at": format_timestamp(),
        "title": APP_TITLE,
        "history": [{"role": r, "content": m} for r, m in history],
    }
    fname = f"gpt5_demo_{session_id[:8]}_{int(time.time())}.json"
    with open(fname, "w", encoding="utf-8") as f:
        json.dump(data, f, ensure_ascii=False, indent=2)
    return f"Saved transcript to {fname}"

def summarize_text_action(input_text):
    if not input_text or not input_text.strip():
        return "Provide text to summarize."
    words = input_text.strip().split()
    short = " ".join(words[:120]) + ("..." if len(words) > 120 else "")
    return f"Summary (quick): {short}"

def summarize_url_action(url):
    if not url or not url.strip():
        return "Provide a URL."
    return f"(Stub) Would fetch and summarize: {url}"

with gr.Blocks(theme=gr.themes.Soft(), title=APP_TITLE, css="""
:root { --accent: #6c78ff; }
.gradio-container { max-width: 1000px !important; margin: 0 auto; }
#title { text-align: center; padding-top: 8px; }
.token-chip { background: #eef; border-radius: 999px; padding: 4px 10px; display: inline-block; }
""") as demo:
    gr.Markdown(f"# {APP_TITLE}", elem_id="title")
    gr.Markdown(APP_DESC)
    with gr.Row():
        with gr.Column(scale=3):
            system_prompt = gr.Textbox(label="System Prompt", placeholder="e.g., You are a helpful assistant.", lines=3)
        with gr.Column(scale=2):
            model_name = gr.Dropdown(label="Model", choices=["gpt5-small", "gpt5-medium", "gpt5-pro"], value="gpt5-medium")
        with gr.Row():
            temperature = gr.Slider(0.0, 1.5, value=0.7, step=0.05, label="Temperature")
            top_p = gr.Slider(0.05, 1.0, value=1.0, step=0.05, label="Top-p")
            max_tokens = gr.Slider(64, 4096, value=512, step=64, label="Max Tokens")
            persist_history = gr.Checkbox(label="Persist History", value=True)
    with gr.Row():
        with gr.Column(scale=3):
            chat = gr.Chatbot(label="Conversation", avatar_images=(None, None), bubble_full_width=False, height=420, likeable=True, show_copy_button=True, render_markdown=True, show_share_button=False)
            user_msg = gr.Textbox(placeholder="Type your message and press Enter...", show_label=False, lines=2)
            with gr.Row():
                submit_btn = gr.Button("Send", variant="primary")
                clear_btn = gr.Button("Clear")
                export_btn = gr.Button("Export Transcript")
                token_info = gr.Markdown("")
        with gr.Column(scale=2):
            gr.Markdown("Attachments and Tools")
            files = gr.Files(label="Upload files (txt, md, etc.)", file_count="multiple", type="filepath")
            tool_choice = gr.Radio(choices=["None", "Summarize Text", "Summarize URL"], value="None", label="Tool")
            with gr.Accordion("Quick Tools", open=False):
                quick_text = gr.Textbox(label="Text to Summarize", lines=6)
                quick_sum_btn = gr.Button("Summarize Text (Quick)")
                quick_sum_out = gr.Markdown()
                url_box = gr.Textbox(label="URL to Summarize")
                quick_url_btn = gr.Button("Summarize URL (Quick)")
                quick_url_out = gr.Markdown()
            with gr.Accordion("Presets", open=False):
                preset = gr.Dropdown(choices=["Helpful Assistant", "Creative Writer", "Code Tutor", "Critique Buddy"], label="Apply Preset")
                apply_btn = gr.Button("Apply Preset to System Prompt")
    state = gr.State({"session_id": str(uuid.uuid4())})
    submit_evt = user_msg.submit(
        on_submit,
        inputs=[user_msg, system_prompt, model_name, temperature, top_p, max_tokens, files, tool_choice, state, chat, persist_history],
        outputs=[chat, user_msg, token_info, state]
    )
    submit_btn.click(
        on_submit,
        inputs=[user_msg, system_prompt, model_name, temperature, top_p, max_tokens, files, tool_choice, state, chat, persist_history],
        outputs=[chat, user_msg, token_info, state]
    )
    clear_btn.click(clear_chat, inputs=[state], outputs=[chat, state, token_info])
    export_btn.click(export_history, inputs=[chat, state], outputs=[token_info])
    apply_btn.click(apply_preset, inputs=[preset], outputs=[system_prompt])
    quick_sum_btn.click(summarize_text_action, inputs=[quick_text], outputs=[quick_sum_out])
    quick_url_btn.click(summarize_url_action, inputs=[url_box], outputs=[quick_url_out])

if __name__ == "__main__":
    demo.queue(api_open=False).launch(server_name="0.0.0.0", server_port=7860, show_api=False)