shaheerawan3's picture
Update app.py
231201c verified
# Required imports - ensure all dependencies are installed
import gradio as gr
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline
try:
import bitsandbytes as bnb
except ImportError:
print("WARNING: bitsandbytes not installed. Required for 4-bit quantization.")
import time
import os
import json
import pandas as pd
import matplotlib.pyplot as plt
import re
from threading import Thread
import numpy as np
from io import StringIO
HF_TOKEN = None
# Global variables to store model, tokenizer and pipe
MODEL = None
TOKENIZER = None
PIPE = None
MODEL_LOADING = False
MODEL_LOADED = False
# Store chat history for different chat sessions
CHATS = {"Main Chat": []}
CURRENT_CHAT = "Main Chat"
# System prompt and generation config
SYSTEM_PROMPT = """You are a helpful AI assistant based on the Mistral-7B-Instruct model.
You specialize in creating structured JSON data for automation workflows like n8n.
When asked to create JSON for n8n workflows:
1. Structure the data in valid JSON format with proper nesting
2. Include all necessary fields and properties for nodes
3. Format with correct indentation and structure
4. Use proper n8n node syntax and follow their data structure requirements
5. Always validate the JSON before returning it
For JSON workflow nodes, be attentive to detail and include all necessary fields."""
GENERATE_CONFIG = {
"max_new_tokens": 1024, # Increased for complex JSON responses
"temperature": 0.5, # Slightly lower for more precise JSON
"top_p": 0.95,
"top_k": 50,
"repetition_penalty": 1.1,
"do_sample": True
}
# File data storage
FILE_DATA = None
ANALYZED_DATA = None
# Function to load the model in background
def load_model_in_background():
global MODEL, TOKENIZER, PIPE, MODEL_LOADING, MODEL_LOADED, HF_TOKEN
try:
MODEL_LOADING = True
print("Starting model loading process...")
# Check if token is provided
if not HF_TOKEN:
MODEL_LOADING = False
return "Error: HuggingFace token is required. Please enter your token and try again."
# Model identifier - using quantized 4-bit version for reduced memory
model_id = "mistralai/Mistral-7B-Instruct-v0.3"
print("Loading tokenizer...")
# Set tokenizer to use legacy format to avoid issues
# Use the token for authentication
TOKENIZER = AutoTokenizer.from_pretrained(
model_id,
legacy_format=True,
token=HF_TOKEN # Add token here
)
print("Loading model with optimized settings for limited memory...")
# Configure model loading with 4-bit quantization for minimum memory usage
MODEL = AutoModelForCausalLM.from_pretrained(
model_id,
torch_dtype=torch.float16, # Use half precision
device_map="auto", # Automatically distribute across available GPUs/CPU
low_cpu_mem_usage=True,
load_in_4bit=True, # Enable 4-bit quantization
max_memory={0: "8GiB"}, # Limit memory usage per GPU
offload_folder="offload_folder", # Use disk offloading if needed
offload_state_dict=True, # Offload state dict to CPU when possible
token=HF_TOKEN # Add token here
)
print("Creating optimized pipeline...")
# Create text generation pipeline with more efficient settings
PIPE = pipeline(
"text-generation",
model=MODEL,
tokenizer=TOKENIZER,
return_full_text=False,
batch_size=1 # Process one batch at a time to reduce memory
)
print("Model loading complete!")
MODEL_LOADING = False
MODEL_LOADED = True
return "Model loaded successfully! Ready to generate responses."
except Exception as e:
MODEL_LOADING = False
error_msg = str(e)
if "401" in error_msg or "authentication" in error_msg.lower():
return f"Authentication error: Please check your HuggingFace token. Error: {error_msg}"
elif "access" in error_msg.lower() or "gated" in error_msg.lower():
return f"Access denied: You may need to request access to this model on HuggingFace. Error: {error_msg}"
else:
return f"Error loading model: {error_msg}"
# Function to generate response using the model
def generate_response(prompt, chat_history, progress=gr.Progress()):
global MODEL, TOKENIZER, PIPE, CHATS, CURRENT_CHAT, SYSTEM_PROMPT, GENERATE_CONFIG, FILE_DATA, ANALYZED_DATA
if not MODEL_LOADED:
if MODEL_LOADING:
return chat_history + [("Your message", "Model is still loading. Please wait a moment before sending messages.")]
else:
return chat_history + [("Your message", "Model not loaded. Please click 'Load Mistral-7B Model' first.")]
try:
# Use the current chat's history
messages = CHATS[CURRENT_CHAT]
# Format conversation history in Mistral's chat format
conversation = []
# Add system prompt if it exists
if SYSTEM_PROMPT:
conversation.append({"role": "system", "content": SYSTEM_PROMPT})
# Add previous messages
for msg in messages:
if msg["role"] != "system": # Skip system messages in the history
conversation.append({"role": msg["role"], "content": msg["content"]})
# Check if JSON formatting is specifically requested
is_json_request = any(keyword in prompt.lower()
for keyword in ["json", "n8n", "workflow", "automation", "format"])
# Handle file-related queries by including context
if ANALYZED_DATA is not None and any(keyword in prompt.lower()
for keyword in ["file", "data", "analyze", "show", "tell me about", "json"]):
file_context = ""
if ANALYZED_DATA["type"] in ["csv", "excel"]:
# For structured data, provide summary info
summary = ANALYZED_DATA["summary"]
file_context = f"""I've analyzed the uploaded {ANALYZED_DATA["type"]} file with {summary["rows"]} rows and {summary["columns"]} columns.
The columns are: {', '.join(summary["column_names"])}.
Here's a sample of the data (first 5 rows): {json.dumps(summary["sample"])}
"""
elif ANALYZED_DATA["type"] == "text":
# For text data, provide the content if not too large
summary = ANALYZED_DATA["summary"]
file_context = f"""I've analyzed the uploaded text file with {summary["word_count"]} words and {summary["line_count"]} lines.
Here's a preview of the content: {summary["preview"]}
"""
elif ANALYZED_DATA["type"] == "json":
# For JSON data
summary = ANALYZED_DATA["summary"]
file_context = f"""I've analyzed the uploaded JSON file which contains a {summary["type"]}.
{"Keys: " + ', '.join(summary["keys"]) if summary["keys"] else ""}
{"Items: " + str(summary["length"]) if summary["length"] else ""}
Here's a preview: {summary["preview"]}
"""
# Enhance the user's query with file context
enhanced_prompt = f"{prompt}\n\nContext about the file: {file_context}"
else:
enhanced_prompt = prompt
# If this is a JSON request, add special instructions
if is_json_request:
enhanced_prompt += "\n\nPlease generate a valid, properly formatted JSON response suitable for n8n workflows. Include all necessary fields and ensure correct formatting. The JSON should be valid and ready to be imported directly into n8n."
# Add current prompt
conversation.append({"role": "user", "content": enhanced_prompt})
# Convert to Mistral's chat format
formatted_prompt = TOKENIZER.apply_chat_template(
conversation,
tokenize=False,
add_generation_prompt=True
)
# Generate response with progress reporting
progress(0, desc="Generating response...")
# Generate response
response = PIPE(
formatted_prompt,
max_new_tokens=GENERATE_CONFIG["max_new_tokens"],
temperature=GENERATE_CONFIG["temperature"],
top_p=GENERATE_CONFIG["top_p"],
top_k=GENERATE_CONFIG["top_k"],
repetition_penalty=GENERATE_CONFIG["repetition_penalty"],
do_sample=GENERATE_CONFIG["do_sample"]
)
progress(1, desc="Response generated!")
# Extract generated text
generated_text = response[0]["generated_text"]
# Add user message to chat history
CHATS[CURRENT_CHAT].append({
"role": "user",
"content": prompt
})
# Add assistant response to chat history
CHATS[CURRENT_CHAT].append({
"role": "assistant",
"content": generated_text
})
# Validate and format JSON if it appears to be a JSON response
if is_json_request and "```json" in generated_text:
try:
# Try to extract JSON from code blocks
json_match = re.search(r'```json\s*([\s\S]*?)\s*```', generated_text)
if json_match:
json_string = json_match.group(1)
# Parse and re-stringify to ensure proper formatting
parsed_json = json.loads(json_string)
formatted_json = json.dumps(parsed_json, indent=2)
# Replace the original JSON with the properly formatted one
generated_text = generated_text.replace(json_match.group(0), f"```json\n{formatted_json}\n```")
except json.JSONDecodeError:
# If JSON parsing fails, we keep the original response
pass
# Update the chat history for the Gradio component (fix the tuple format)
chat_history.append((prompt, generated_text))
return chat_history
except Exception as e:
error_message = f"Error generating response: {str(e)}"
return chat_history + [(prompt, error_message)]
# Function to create a new chat
def create_new_chat(chat_name):
global CHATS, CURRENT_CHAT
if chat_name and chat_name not in CHATS:
CHATS[chat_name] = []
CURRENT_CHAT = chat_name
return f"Created new chat: {chat_name}"
return "Please enter a unique chat name"
# MODIFICATION 3: Add function to set HuggingFace token
def set_hf_token(token):
global HF_TOKEN
if token and token.strip():
HF_TOKEN = token.strip()
return "HuggingFace token saved successfully!"
else:
return "Please enter a valid HuggingFace token."
# Function to handle file upload and analysis
def analyze_uploaded_file(file):
global FILE_DATA, ANALYZED_DATA, CHATS, CURRENT_CHAT
if file is None:
return "No file uploaded."
try:
file_extension = file.name.split('.')[-1].lower()
if file_extension == 'csv':
data = pd.read_csv(file.name)
FILE_DATA = data
ANALYZED_DATA = {
"type": "csv",
"data": data,
"summary": {
"rows": len(data),
"columns": len(data.columns),
"column_names": list(data.columns),
"data_types": {col: str(dtype) for col, dtype in data.dtypes.items()},
"sample": data.head(5).to_dict(orient='records')
}
}
elif file_extension in ['txt', 'md']:
with open(file.name, 'r', encoding='utf-8') as f:
content = f.read()
FILE_DATA = content
ANALYZED_DATA = {
"type": "text",
"data": content,
"summary": {
"length": len(content),
"word_count": len(content.split()),
"line_count": len(content.splitlines()),
"preview": content[:500] + ("..." if len(content) > 500 else "")
}
}
elif file_extension == 'json':
with open(file.name, 'r', encoding='utf-8') as f:
content = f.read()
data = json.loads(content)
FILE_DATA = data
ANALYZED_DATA = {
"type": "json",
"data": data,
"summary": {
"type": "object" if isinstance(data, dict) else "array",
"keys": list(data.keys()) if isinstance(data, dict) else None,
"length": len(data) if isinstance(data, list) else None,
"preview": str(data)[:500] + ("..." if len(str(data)) > 500 else "")
}
}
elif file_extension in ['xls', 'xlsx']:
data = pd.read_excel(file.name)
FILE_DATA = data
ANALYZED_DATA = {
"type": "excel",
"data": data,
"summary": {
"rows": len(data),
"columns": len(data.columns),
"column_names": list(data.columns),
"data_types": {col: str(dtype) for col, dtype in data.dtypes.items()},
"sample": data.head(5).to_dict(orient='records')
}
}
else:
return f"File type .{file_extension} is not supported."
# Add file summary to current chat as system message
file_summary = f"File analyzed: {file.name}\n"
if ANALYZED_DATA['type'] == 'csv' or ANALYZED_DATA['type'] == 'excel':
file_summary += f"- {ANALYZED_DATA['summary']['rows']} rows, {ANALYZED_DATA['summary']['columns']} columns\n"
file_summary += f"- Columns: {', '.join(ANALYZED_DATA['summary']['column_names'])}"
elif ANALYZED_DATA['type'] == 'text':
file_summary += f"- {ANALYZED_DATA['summary']['word_count']} words, {ANALYZED_DATA['summary']['line_count']} lines"
elif ANALYZED_DATA['type'] == 'json':
file_summary += f"- Type: {ANALYZED_DATA['summary']['type']}"
if ANALYZED_DATA['summary']['keys']:
file_summary += f"\n- Keys: {', '.join(ANALYZED_DATA['summary']['keys'])}"
# Add system message to current chat
CHATS[CURRENT_CHAT].append({
"role": "system",
"content": file_summary
})
return f"Successfully analyzed {ANALYZED_DATA['type']} file: {file.name}"
except Exception as e:
return f"Error analyzing file: {str(e)}"
# Function to convert data to n8n JSON format
def convert_to_n8n_json():
global ANALYZED_DATA
if ANALYZED_DATA is None:
return "No file has been analyzed yet. Please upload a file first."
try:
if ANALYZED_DATA['type'] in ['csv', 'excel']:
# Convert DataFrame to n8n compatible JSON
data = ANALYZED_DATA['data']
records = data.to_dict(orient='records')
# Generate n8n workflow JSON template
n8n_json = {
"name": "Generated Data Workflow",
"nodes": [
{
"parameters": {
"jsCode": f"return {json.dumps(records, indent=2)};"
},
"id": "1",
"name": "Code",
"type": "n8n-nodes-base.code",
"typeVersion": 1,
"position": [
250,
300
]
}
],
"connections": {},
"active": False,
"settings": {},
"version": 1,
"meta": {
"instanceId": "GENERATED"
}
}
return json.dumps(n8n_json, indent=2)
elif ANALYZED_DATA['type'] == 'json':
# The data is already in JSON format, just need to wrap it in n8n structure
data = ANALYZED_DATA['data']
n8n_json = {
"name": "JSON Workflow",
"nodes": [
{
"parameters": {
"jsCode": f"return {json.dumps(data, indent=2)};"
},
"id": "1",
"name": "Code",
"type": "n8n-nodes-base.code",
"typeVersion": 1,
"position": [
250,
300
]
}
],
"connections": {},
"active": False,
"settings": {},
"version": 1,
"meta": {
"instanceId": "GENERATED"
}
}
return json.dumps(n8n_json, indent=2)
elif ANALYZED_DATA['type'] == 'text':
# Convert text to a simple n8n workflow
text_data = ANALYZED_DATA['data']
n8n_json = {
"name": "Text Processing Workflow",
"nodes": [
{
"parameters": {
"jsCode": f"return {{ text: {json.dumps(text_data)} }};"
},
"id": "1",
"name": "Code",
"type": "n8n-nodes-base.code",
"typeVersion": 1,
"position": [
250,
300
]
}
],
"connections": {},
"active": False,
"settings": {},
"version": 1,
"meta": {
"instanceId": "GENERATED"
}
}
return json.dumps(n8n_json, indent=2)
else:
return "Cannot convert this file type to n8n JSON format."
except Exception as e:
return f"Error generating n8n JSON: {str(e)}"
# Function to update system prompt
def update_system_prompt(new_prompt):
global SYSTEM_PROMPT
SYSTEM_PROMPT = new_prompt
return f"System prompt updated!"
# Function to update generation parameters
def update_generation_params(temp, max_tokens, top_p, rep_penalty):
global GENERATE_CONFIG
GENERATE_CONFIG["temperature"] = temp
GENERATE_CONFIG["max_new_tokens"] = max_tokens
GENERATE_CONFIG["top_p"] = top_p
GENERATE_CONFIG["repetition_penalty"] = rep_penalty
return f"Generation parameters updated!"
# Function to display file data information
def display_file_info():
global ANALYZED_DATA
if ANALYZED_DATA is None:
return "No file has been analyzed yet."
file_info = f"## File Analysis Results\n\n"
file_info += f"**File Type:** {ANALYZED_DATA['type']}\n\n"
if ANALYZED_DATA['type'] in ['csv', 'excel']:
summary = ANALYZED_DATA['summary']
file_info += f"**Rows:** {summary['rows']}\n"
file_info += f"**Columns:** {summary['columns']}\n"
file_info += f"**Column Names:** {', '.join(summary['column_names'])}\n\n"
# Sample data preview
file_info += "**Sample Data (First 5 rows):**\n"
sample_df = pd.DataFrame(summary['sample'])
file_info += sample_df.to_markdown()
elif ANALYZED_DATA['type'] == 'text':
summary = ANALYZED_DATA['summary']
file_info += f"**Length:** {summary['length']} characters\n"
file_info += f"**Word Count:** {summary['word_count']}\n"
file_info += f"**Line Count:** {summary['line_count']}\n\n"
file_info += "**Preview:**\n```\n" + summary['preview'] + "\n```"
elif ANALYZED_DATA['type'] == 'json':
summary = ANALYZED_DATA['summary']
file_info += f"**Type:** {summary['type']}\n"
if summary['keys']:
file_info += f"**Keys:** {', '.join(summary['keys'])}\n"
if summary['length'] is not None:
file_info += f"**Length:** {summary['length']} items\n"
file_info += "\n**Preview:**\n```json\n" + summary['preview'] + "\n```"
return file_info
# Function to select current chat
def select_chat(chat_name):
global CURRENT_CHAT
CURRENT_CHAT = chat_name
return f"Switched to chat: {chat_name}"
# Function to clear current chat
def clear_current_chat():
global CHATS, CURRENT_CHAT
CHATS[CURRENT_CHAT] = []
return f"Cleared chat: {CURRENT_CHAT}"
# Function to load model and return status
def load_model_button():
global HF_TOKEN
if not HF_TOKEN:
return "Please enter your HuggingFace token first before loading the model."
if MODEL_LOADED:
return "Model is already loaded and ready!"
elif MODEL_LOADING:
return "Model is currently loading... Please wait."
else:
thread = Thread(target=load_model_in_background)
thread.start()
return "Started loading the model. This may take a few minutes..."
# Function to get available chats
def get_available_chats():
global CHATS
return list(CHATS.keys())
# Main Gradio app
def create_gradio_interface():
# CSS for better styling
css = """
.gradio-container {max-width: 100% !important; padding: 0}
.chat-message-user {background-color: #e0f7fa; padding: 12px; border-radius: 8px; margin-bottom: 8px}
.chat-message-bot {background-color: #f1f8e9; padding: 12px; border-radius: 8px; margin-bottom: 8px}
.file-info {border: 1px solid #ddd; padding: 15px; border-radius: 5px; margin-top: 10px}
.json-output {font-family: monospace; white-space: pre; overflow-x: auto; background-color: #f5f5f5; padding: 15px; border-radius: 5px;}
"""
# Setup tabs for different functionalities
with gr.Blocks(css=css) as app:
gr.Markdown("# 🤖 Advanced Mistral-7B-Instruct Chatbot for n8n JSON Generation")
# Add fallback mode when model loading fails
fallback_mode = gr.State(False)
with gr.Tab("Chat"):
with gr.Row():
with gr.Column(scale=3):
# Initialize with empty list to fix the tuple format error
chatbot = gr.Chatbot(
[],
elem_id="chatbot",
height=500,
bubble_full_width=False,
avatar_images=(None, None),
)
with gr.Row():
msg = gr.Textbox(
placeholder="Type your message here...",
container=False,
scale=8,
autofocus=True
)
send_btn = gr.Button("Send", scale=1, variant="primary")
# Fallback response mode when model fails to load
def simple_fallback_response(message, history):
# Sample n8n JSON structure for common requests
if any(keyword in message.lower() for keyword in ['json', 'n8n', 'workflow']):
response = """Here's a basic n8n workflow JSON structure you can use:
```json
{
"name": "Simple Workflow",
"nodes": [
{
"parameters": {
"values": {
"string": [
{
"name": "data",
"value": "Your data here"
}
]
}
},
"id": "1",
"name": "Set",
"type": "n8n-nodes-base.set",
"typeVersion": 1,
"position": [250, 300]
}
],
"connections": {},
"active": false,
"settings": {},
"version": 1
}
```
You can customize this template with your specific data. If you need a more complex structure or specific node types, please let me know."""
elif 'file' in message.lower() or 'data' in message.lower():
response = "To analyze files or data, please upload your file in the 'File Analysis & JSON Conversion' tab. I'll be able to help you convert it to n8n compatible JSON format."
else:
response = "I'm currently operating in fallback mode because the Mistral-7B model couldn't be loaded. I can still help with basic n8n JSON structures. Try asking for a specific workflow type or JSON structure you need for n8n."
return history + [(message, response)]
with gr.Row():
chat_selector = gr.Dropdown(
choices=get_available_chats(),
value=CURRENT_CHAT,
label="Select Chat",
interactive=True
)
with gr.Column(scale=1):
new_chat_name = gr.Textbox(
placeholder="New chat name",
label="Create New Chat",
container=True
)
with gr.Row():
create_chat_btn = gr.Button("Create", variant="secondary")
clear_chat_btn = gr.Button("Clear Current Chat", variant="secondary")
with gr.Column(scale=1):
# HuggingFace Token Input
gr.Markdown("### HuggingFace Authentication")
hf_token_input = gr.Textbox(
label="HuggingFace Access Token",
placeholder="Enter your HF token (hf_xxx...)",
type="password",
info="Required to download the Mistral-7B model"
)
set_token_btn = gr.Button("Set Token", variant="secondary")
token_status = gr.Textbox(
label="Token Status",
value="No token set",
interactive=False,
lines=1
)
# Model Loading and Settings
gr.Markdown("### Model Loading")
with gr.Row():
load_model_btn = gr.Button("Load Mistral-7B Model", variant="primary")
use_fallback_btn = gr.Button("Use Simple JSON Mode", variant="secondary")
model_status = gr.Textbox(label="Model Status", value="Not loaded", interactive=False)
# Function to toggle fallback mode
def toggle_fallback_mode(state):
global MODEL_LOADED
if MODEL_LOADED:
return state, "Model is already loaded. No need for fallback mode."
else:
return not state, "Using simple JSON generation mode. Limited functionality but no model loading required."
# System Prompt
system_prompt_input = gr.Textbox(
label="System Prompt",
value=SYSTEM_PROMPT,
lines=4,
placeholder="Enter system prompt to guide the AI's behavior..."
)
update_prompt_btn = gr.Button("Update System Prompt", variant="secondary")
# Model Parameters
gr.Markdown("### Generation Parameters")
temperature = gr.Slider(
minimum=0.1,
maximum=2.0,
value=GENERATE_CONFIG["temperature"],
step=0.1,
label="Temperature"
)
max_tokens = gr.Slider(
minimum=64,
maximum=2048,
value=GENERATE_CONFIG["max_new_tokens"],
step=64,
label="Max Tokens"
)
top_p = gr.Slider(
minimum=0.1,
maximum=1.0,
value=GENERATE_CONFIG["top_p"],
step=0.05,
label="Top P"
)
rep_penalty = gr.Slider(
minimum=1.0,
maximum=2.0,
value=GENERATE_CONFIG["repetition_penalty"],
step=0.1,
label="Repetition Penalty"
)
update_params_btn = gr.Button("Update Parameters", variant="secondary")
with gr.Tab("File Analysis & JSON Conversion"):
with gr.Row():
with gr.Column(scale=1):
file_upload = gr.File(label="Upload a file to analyze")
analyze_btn = gr.Button("Analyze File", variant="primary")
convert_json_btn = gr.Button("Convert to n8n JSON", variant="primary")
with gr.Column(scale=2):
with gr.Tabs():
with gr.TabItem("File Analysis"):
file_analysis_output = gr.Markdown(label="File Analysis Results")
with gr.TabItem("n8n JSON Output"):
n8n_json_output = gr.Code(
language="json",
label="n8n Compatible JSON",
lines=20
)
with gr.Tab("JSON Formatting Guide"):
gr.Markdown("""
# n8n JSON Formatting Guide
This tab provides guidance on creating well-structured JSON for n8n workflows.
## Basic n8n Workflow Structure
```json
{
"name": "My Workflow",
"nodes": [
{
"parameters": { /* Node-specific parameters */ },
"id": "1",
"name": "Start Node",
"type": "n8n-nodes-base.some-node-type",
"typeVersion": 1,
"position": [250, 300]
}
// Additional nodes...
],
"connections": {
"Start Node": {
"main": [
[
{
"node": "Second Node",
"type": "main",
"index": 0
}
]
]
}
// Additional connections...
}
}
```
## Common n8n Node Types
### HTTP Request Node
```json
{
"parameters": {
"url": "https://api.example.com/data",
"method": "GET",
"authentication": "none",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
}
},
"name": "HTTP Request",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 1,
"position": [250, 300],
"id": "1"
}
```
### Function Node (JavaScript)
```json
{
"parameters": {
"functionCode": "// Code here\nreturn items;"
},
"name": "Function",
"type": "n8n-nodes-base.function",
"typeVersion": 1,
"position": [450, 300],
"id": "2"
}
```
### Set Node (Manual Data)
```json
{
"parameters": {
"values": {
"string": [
{
"name": "fieldName",
"value": "value"
}
],
"number": [
{
"name": "count",
"value": 42
}
]
}
},
"name": "Set",
"type": "n8n-nodes-base.set",
"typeVersion": 1,
"position": [650, 300],
"id": "3"
}
```
""")
gr.Markdown("""
## Tips for Creating n8n-Compatible JSON
1. Ensure all JSON keys and values are properly quoted
2. Use proper nesting for workflow components
3. Define unique IDs for each node
4. Properly define connections between nodes
5. Include all required parameters for each node type
Use the chat interface to ask for specific n8n node configurations or workflow patterns.
""")
# Set up event handlers
# Modify to handle fallback mode
def handle_message(message, chat_history, is_fallback):
if is_fallback:
return simple_fallback_response(message, chat_history)
else:
return generate_response(message, chat_history)
send_btn.click(
handle_message,
inputs=[msg, chatbot, fallback_mode],
outputs=chatbot,
api_name="chat"
)
msg.submit(
handle_message,
inputs=[msg, chatbot, fallback_mode],
outputs=chatbot,
api_name=False
)
load_model_btn.click(
load_model_button,
outputs=model_status,
api_name="load_model"
)
use_fallback_btn.click(
toggle_fallback_mode,
inputs=[fallback_mode],
outputs=[fallback_mode, model_status],
api_name="fallback_mode"
)
update_prompt_btn.click(
update_system_prompt,
inputs=system_prompt_input,
outputs=model_status,
api_name="update_prompt"
)
update_params_btn.click(
update_generation_params,
inputs=[temperature, max_tokens, top_p, rep_penalty],
outputs=model_status,
api_name="update_params"
)
analyze_btn.click(
analyze_uploaded_file,
inputs=file_upload,
outputs=model_status,
api_name="analyze_file"
).then(
display_file_info,
outputs=file_analysis_output,
api_name=False
)
convert_json_btn.click(
convert_to_n8n_json,
outputs=n8n_json_output,
api_name="convert_to_n8n"
)
chat_selector.change(
select_chat,
inputs=chat_selector,
outputs=model_status,
api_name="select_chat"
)
create_chat_btn.click(
create_new_chat,
inputs=new_chat_name,
outputs=model_status,
api_name="create_chat"
).then(
get_available_chats,
outputs=chat_selector,
api_name=False
)
clear_chat_btn.click(
clear_current_chat,
outputs=model_status,
api_name="clear_chat"
)
set_token_btn.click(
set_hf_token,
inputs=hf_token_input,
outputs=token_status,
api_name="set_token"
)
# Initialize empty chatbot
chatbot.value = []
return app
# Launch the app
demo = create_gradio_interface()
if __name__ == "__main__":
demo.launch()