File size: 5,383 Bytes
682ffcf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
from typing import List, Tuple, Dict
import re

# History/message helpers
History = List[Tuple[str, str]]
Messages = List[Dict[str, str]]

def history_to_messages(history: History, system: str) -> Messages:
    messages = [{'role': 'system', 'content': system}]
    for h in history:
        user_content = h[0]
        if isinstance(user_content, list):
            text_content = ""
            for item in user_content:
                if isinstance(item, dict) and item.get("type") == "text":
                    text_content += item.get("text", "")
            user_content = text_content if text_content else str(user_content)
        
        messages.append({'role': 'user', 'content': user_content})
        messages.append({'role': 'assistant', 'content': h[1]})
    return messages

def messages_to_history(messages: Messages) -> Tuple[str, History]:
    assert messages[0]['role'] == 'system'
    history = []
    for q, r in zip(messages[1::2], messages[2::2]):
        user_content = q['content']
        if isinstance(user_content, list):
            text_content = ""
            for item in user_content:
                if isinstance(item, dict) and item.get("type") == "text":
                    text_content += item.get("text", "")
            user_content = text_content if text_content else str(user_content)
        
        history.append([user_content, r['content']])
    return history

def history_render(history: History):
    return gr.update(visible=True), history

def clear_history():
    return [], [], None, ""

def update_image_input_visibility(model):
    is_ernie_vl = model.get("id") == "baidu/ERNIE-4.5-VL-424B-A47B-Base-PT"
    is_glm_vl = model.get("id") == "THUDM/GLM-4.1V-9B-Thinking"
    return gr.update(visible=is_ernie_vl or is_glm_vl)

def process_image_for_model(image):
    import io, base64
    import numpy as np
    from PIL import Image
    
    if image is None:
        return None
    
    if isinstance(image, np.ndarray):
        image = Image.fromarray(image)
    
    buffer = io.BytesIO()
    image.save(buffer, format='PNG')
    img_str = base64.b64encode(buffer.getvalue()).decode()
    return f"data:image/png;base64,{img_str}"

def create_multimodal_message(text, image=None):
    if image is None:
        return {"role": "user", "content": text}
    
    content = [
        {"type": "text", "text": text},
        {"type": "image_url", "image_url": {"url": process_image_for_model(image)}}
    ]
    return {"role": "user", "content": content}

# Code–block parsing
def remove_code_block(text):
    patterns = [
        r'```(?:html|HTML)\n([\s\S]+?)\n```',
        r'```\n([\s\S]+?)\n```',
        r'```([\s\S]+?)```'
    ]
    for pattern in patterns:
        match = re.search(pattern, text, re.DOTALL)
        if match:
            extracted = match.group(1).strip()
            if extracted.split('\n', 1)[0].strip().lower() in ['python','html','css','javascript','json','c','cpp','markdown','latex','jinja2','typescript','yaml','dockerfile','shell','r','sql','sql-mssql','sql-mysql','sql-mariadb','sql-sqlite','sql-cassandra','sql-plsql','sql-hive','sql-pgsql','sql-gql','sql-gpsql','sql-sparksql','sql-esper']:
                return extracted.split('\n',1)[1] if '\n' in extracted else ''
            return extracted
    if text.strip().startswith('<!DOCTYPE') or text.strip().startswith('<html'):
        return text.strip()
    if text.strip().startswith('```python'):
        return text.strip()[9:-3].strip()
    lines = text.strip().split('\n',1)
    if lines[0].strip().lower() in ['python','html','css','javascript','json','c','cpp','markdown','latex','jinja2','typescript','yaml','dockerfile','shell','r','sql','sql-mssql','sql-mysql','sql-mariadb','sql-sqlite','sql-cassandra','sql-plsql','sql-hive','sql-pgsql','sql-gql','sql-gpsql','sql-sparksql','sql-esper']:
        return lines[1] if len(lines)>1 else ''
    return text.strip()

def parse_transformers_js_output(text):
    files={'index.html':'','index.js':'','style.css':''}
    html_match=re.search(r'```html\s*\n([\s\S]+?)\n```',text,re.IGNORECASE)
    if html_match: files['index.html']=html_match.group(1).strip()
    js_match=re.search(r'```javascript\s*\n([\s\S]+?)\n```',text,re.IGNORECASE)
    if js_match: files['index.js']=js_match.group(1).strip()
    css_match=re.search(r'```css\s*\n([\s\S]+?)\n```',text,re.IGNORECASE)
    if css_match: files['style.css']=css_match.group(1).strip()
    if not(files['index.html'] and files['index.js'] and files['style.css']):
        html_fallback=re.search(r'===\s*index\.html\s*===\n([\s\S]+?)(?=\n===|$)',text,re.IGNORECASE)
        js_fallback=re.search(r'===\s*index\.js\s*===\n([\s\S]+?)(?=\n===|$)',text,re.IGNORECASE)
        css_fallback=re.search(r'===\s*style\.css\s*===\n([\s\S]+?)(?=\n===|$)',text,re.IGNORECASE)
        if html_fallback: files['index.html']=html_fallback.group(1).strip()
        if js_fallback: files['index.js']=js_fallback.group(1).strip()
        if css_fallback: files['style.css']=css_fallback.group(1).strip()
    return files

def format_transformers_js_output(files):
    output=[]
    output.append("=== index.html ===")
    output.append(files['index.html'])
    output.append("\n=== index.js ===")
    output.append(files['index.js'])
    output.append("\n=== style.css ===")
    output.append(files['style.css'])
    return '\n'.join(output)