Diggz10 commited on
Commit
ee17ed9
·
verified ·
1 Parent(s): 456e710

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +88 -117
app.py CHANGED
@@ -1,132 +1,101 @@
1
  import gradio as gr
2
  import graphviz
3
  import os
 
4
  from PIL import Image, ImageDraw, ImageFont
5
 
6
- # --- Setup: Create directories and placeholder image ---
 
 
7
 
8
- # Create a directory for output images if it doesn't exist
9
- if not os.path.exists("outputs"):
10
- os.makedirs("outputs")
11
 
12
- def create_placeholder_image(path="placeholder.png"):
13
- """Creates a placeholder image to display on app startup."""
 
 
 
 
 
 
 
 
14
  try:
15
- img = Image.new('RGB', (600, 800), color=(255, 255, 255))
16
  draw = ImageDraw.Draw(img)
17
  try:
18
- # Use a common font, fallback to default
19
  font = ImageFont.truetype("DejaVuSans.ttf", 24)
20
  except IOError:
21
  font = ImageFont.load_default()
22
- text = "Flowchart will be generated here"
23
- # Get text size using textbbox
24
  bbox = draw.textbbox((0, 0), text, font=font)
25
  text_width = bbox[2] - bbox[0]
26
  text_height = bbox[3] - bbox[1]
27
- position = ((600 - text_width) / 2, (800 - text_height) / 2)
28
  draw.text(position, text, fill=(200, 200, 200), font=font)
29
  img.save(path)
30
  return path
31
  except Exception:
32
  return None
33
 
34
- # --- Core Logic: Flowchart Generation ---
35
-
36
- def generate_flowchart(prompt: str) -> str:
37
  """
38
- Generates a flowchart using Graphviz based on the input prompt.
39
  Returns the file path of the generated PNG image.
40
  """
41
- # A simple keyword-based logic to generate different flowcharts
42
- if "coffee" in prompt.lower():
43
- dot_string = """
44
- digraph G {
45
- graph [pad="0.5", nodesep="0.5", ranksep="0.8", fontname="helvetica"];
46
- node [shape=box, style="rounded,filled", fillcolor="#EAEAFB", fontname="helvetica"];
47
- edge [color="#666666"];
48
- rankdir=TB;
49
-
50
- start [label="Start", shape=ellipse, fillcolor="#D5D6F9"];
51
- have_beans [label="Have coffee beans?", shape=diamond, fillcolor="#F9EED5"];
52
- buy_beans [label="Buy coffee beans"];
53
- grind_beans [label="Grind beans"];
54
- boil_water [label="Boil water"];
55
- add_grounds [label="Add grounds to filter"];
56
- pour_water [label="Pour water over grounds"];
57
- wait [label="Wait for brewing"];
58
- pour_cup [label="Pour coffee into cup"];
59
- add_extras [label="Add milk/sugar?", shape=diamond, fillcolor="#F9EED5"];
60
- add_milk_sugar [label="Add milk and/or sugar"];
61
- drink [label="Drink coffee"];
62
- end_node [label="Enjoy your coffee!", shape=ellipse, fillcolor="#D5D6F9"];
63
-
64
- start -> have_beans;
65
- have_beans -> grind_beans [label=" Yes"];
66
- have_beans -> buy_beans [label="No "];
67
- buy_beans -> grind_beans;
68
- grind_beans -> boil_water;
69
- boil_water -> add_grounds;
70
- add_grounds -> pour_water;
71
- pour_water -> wait;
72
- wait -> pour_cup;
73
- pour_cup -> add_extras;
74
- add_extras -> add_milk_sugar [label=" Yes"];
75
- add_extras -> drink [label="No "];
76
- add_milk_sugar -> drink;
77
- drink -> end_node;
78
- }
79
- """
80
- else:
81
- # A default flowchart for any other prompt
82
- cleaned_prompt = prompt.replace("'", "").replace("\"", "")[:60]
83
- dot_string = f"""
84
- digraph G {{
85
- graph [fontname="helvetica"];
86
- node [shape=box, style="rounded,filled", fillcolor="#EAEAFB", fontname="helvetica"];
87
- rankdir=TB;
88
-
89
- start [label="Start", shape=ellipse, fillcolor="#D5D6F9"];
90
- process [label="Process user request:\\n'{cleaned_prompt}... '"];
91
- end_node [label="End", shape=ellipse, fillcolor="#D5D6F9"];
92
-
93
- start -> process -> end_node;
94
- }}
95
- """
96
 
97
  try:
98
- graph = graphviz.Source(dot_string)
99
- # Save the rendered graph to a file, overwriting previous ones
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
  output_path = graph.render(os.path.join("outputs", "flowchart"), format='png', cleanup=True)
101
- return output_path
102
- except Exception as e:
103
- print(f"Error rendering graphviz: {e}")
104
- return create_placeholder_image("error.png") # Return an error image if something goes wrong
105
-
106
-
107
- def handle_generate_click(prompt: str):
108
- """Function to be called on button click. Updates the UI."""
109
- if not prompt:
110
- # Handle empty prompt case
111
- placeholder_path = create_placeholder_image()
112
- return placeholder_path, gr.update(visible=False)
113
 
114
- image_path = generate_flowchart(prompt)
115
-
116
- # Return the image path to update the gr.Image component
117
- # and a gr.update object for the gr.DownloadButton
118
- return image_path, gr.update(value=image_path, visible=True)
119
 
 
 
 
 
120
 
121
- # --- Gradio UI ---
122
 
123
- # Custom CSS to hide the footer for a cleaner look like the screenshot
124
  css = """
125
  footer {display: none !important}
126
  .gradio-container {background-color: #f8f9fa}
 
127
  """
128
 
129
  with gr.Blocks(theme=gr.themes.Soft(), css=css) as demo:
 
 
 
130
  gr.Markdown("# AI Flowchart Generator")
131
  gr.Markdown(
132
  "Our AI Flowchart Generator allows you to create detailed flowcharts instantly. Whether you need a free "
@@ -135,29 +104,18 @@ with gr.Blocks(theme=gr.themes.Soft(), css=css) as demo:
135
  "AI solution available online."
136
  )
137
 
138
- with gr.Group(): # Using gr.Group to create the white card effect
139
  with gr.Row(equal_height=False):
140
  with gr.Column(scale=1):
141
- lang_dropdown = gr.Dropdown(
142
- label="Language",
143
- choices=["English"],
144
- value="English"
145
- )
146
- chart_type_dropdown = gr.Dropdown(
147
- choices=["Flowchart"],
148
- value="Flowchart",
149
- label=" " # Using space for an empty label like in the screenshot
150
- )
151
  prompt_input = gr.Textbox(
152
  lines=10,
153
- placeholder="Generate a flowchart for making coffee",
154
- value="Generate a flowchart for making coffee",
155
- label=" " # Empty label
156
  )
157
  with gr.Row():
158
- # These buttons are for UI purposes and are not connected to logic
159
- templates_btn = gr.Button("📄 Templates")
160
  generate_btn = gr.Button("✨ Generate", variant="primary")
 
 
161
 
162
  with gr.Column(scale=1):
163
  output_image = gr.Image(
@@ -171,22 +129,35 @@ with gr.Blocks(theme=gr.themes.Soft(), css=css) as demo:
171
  download_btn = gr.DownloadButton(
172
  "⬇️ Download",
173
  variant="primary",
174
- visible=False, # Initially hidden
175
  )
176
 
177
  # --- Event Listeners ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178
  generate_btn.click(
179
- fn=handle_generate_click,
180
- inputs=[prompt_input],
181
- outputs=[output_image, download_btn]
182
- )
183
-
184
- # Pre-load the default example when the app starts
185
- demo.load(
186
- fn=handle_generate_click,
187
  inputs=[prompt_input],
188
- outputs=[output_image, download_btn]
189
  )
190
 
191
  if __name__ == "__main__":
 
 
192
  demo.launch()
 
1
  import gradio as gr
2
  import graphviz
3
  import os
4
+ from huggingface_hub import InferenceClient
5
  from PIL import Image, ImageDraw, ImageFont
6
 
7
+ # --- Constants and Configuration ---
8
+ # Using a powerful open-source instruction-tuned model from Mistral AI
9
+ MODEL_ID = "mistralai/Mistral-7B-Instruct-v0.2"
10
 
11
+ # System prompt to instruct the AI model
12
+ # This is the most crucial part for getting reliable, structured output.
13
+ SYSTEM_PROMPT = """You are an expert at creating flowcharts. A user will provide a text prompt, and your task is to generate the flowchart description in the Graphviz DOT language.
14
 
15
+ Your response MUST be ONLY the Graphviz DOT language source code for a directed graph (digraph).
16
+ - The graph should be top-to-bottom (`rankdir=TB`).
17
+ - Use rounded boxes for process steps (`shape=box, style="rounded,filled", fillcolor="#EAEAFB"`).
18
+ - Use diamonds for decision points (`shape=diamond, fillcolor="#F9EED5"`).
19
+ - Use ellipses for start and end nodes (`shape=ellipse, fillcolor="#D5D6F9"`).
20
+ - Do not include any explanations, comments, or markdown formatting like ```dot ... ```. The entire response must be valid DOT code."""
21
+
22
+ # --- Helper Functions ---
23
+ def create_placeholder_image(text="Flowchart will be generated here", size=(600, 800), path="placeholder.png"):
24
+ """Creates a placeholder or error image with text."""
25
  try:
26
+ img = Image.new('RGB', size, color=(255, 255, 255))
27
  draw = ImageDraw.Draw(img)
28
  try:
 
29
  font = ImageFont.truetype("DejaVuSans.ttf", 24)
30
  except IOError:
31
  font = ImageFont.load_default()
32
+
 
33
  bbox = draw.textbbox((0, 0), text, font=font)
34
  text_width = bbox[2] - bbox[0]
35
  text_height = bbox[3] - bbox[1]
36
+ position = ((size[0] - text_width) / 2, (size[1] - text_height) / 2)
37
  draw.text(position, text, fill=(200, 200, 200), font=font)
38
  img.save(path)
39
  return path
40
  except Exception:
41
  return None
42
 
43
+ # --- Core AI and Rendering Logic ---
44
+ def generate_flowchart(prompt: str, hf_token: str):
 
45
  """
46
+ Calls the Hugging Face Inference API to generate DOT code and then renders it.
47
  Returns the file path of the generated PNG image.
48
  """
49
+ if not hf_token:
50
+ return create_placeholder_image("Error: Hugging Face API Token is not set.\nPlease add it to your Space's secrets."), None
51
+
52
+ if not prompt:
53
+ return create_placeholder_image("Please enter a prompt to generate a flowchart."), None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
 
55
  try:
56
+ # 1. Call the LLM to get the DOT language code
57
+ client = InferenceClient(model=MODEL_ID, token=hf_token)
58
+ response = client.chat_completion(
59
+ messages=[
60
+ {"role": "system", "content": SYSTEM_PROMPT},
61
+ {"role": "user", "content": prompt},
62
+ ],
63
+ max_tokens=1500,
64
+ temperature=0.7,
65
+ )
66
+ dot_code = response.choices[0].message.content.strip()
67
+
68
+ # Sometimes the model still adds markdown, let's strip it just in case
69
+ if dot_code.startswith("```dot"):
70
+ dot_code = dot_code[len("```dot"):].strip()
71
+ if dot_code.startswith("```"):
72
+ dot_code = dot_code[len("```"):].strip()
73
+ if dot_code.endswith("```"):
74
+ dot_code = dot_code[:-len("```")].strip()
75
+
76
+ # 2. Render the DOT code using Graphviz
77
+ graph = graphviz.Source(dot_code)
78
  output_path = graph.render(os.path.join("outputs", "flowchart"), format='png', cleanup=True)
 
 
 
 
 
 
 
 
 
 
 
 
79
 
80
+ return output_path, gr.update(value=output_path, visible=True)
 
 
 
 
81
 
82
+ except Exception as e:
83
+ print(f"An error occurred: {e}")
84
+ error_message = f"An error occurred.\nThis could be due to an invalid API token,\nan issue with the AI model, or invalid generated DOT code.\n\nDetails: {str(e)}"
85
+ return create_placeholder_image(error_message), gr.update(visible=False)
86
 
 
87
 
88
+ # --- Gradio UI ---
89
  css = """
90
  footer {display: none !important}
91
  .gradio-container {background-color: #f8f9fa}
92
+ #status_display {text-align: center; color: #888;}
93
  """
94
 
95
  with gr.Blocks(theme=gr.themes.Soft(), css=css) as demo:
96
+ # Get the Hugging Face token from environment variables
97
+ hf_token = os.environ.get("HF_TOKEN")
98
+
99
  gr.Markdown("# AI Flowchart Generator")
100
  gr.Markdown(
101
  "Our AI Flowchart Generator allows you to create detailed flowcharts instantly. Whether you need a free "
 
104
  "AI solution available online."
105
  )
106
 
107
+ with gr.Group():
108
  with gr.Row(equal_height=False):
109
  with gr.Column(scale=1):
 
 
 
 
 
 
 
 
 
 
110
  prompt_input = gr.Textbox(
111
  lines=10,
112
+ placeholder="e.g., Explain the process of making a cup of tea",
113
+ label="Enter your process description here"
 
114
  )
115
  with gr.Row():
 
 
116
  generate_btn = gr.Button("✨ Generate", variant="primary")
117
+
118
+ status_display = gr.Markdown("", elem_id="status_display")
119
 
120
  with gr.Column(scale=1):
121
  output_image = gr.Image(
 
129
  download_btn = gr.DownloadButton(
130
  "⬇️ Download",
131
  variant="primary",
132
+ visible=False,
133
  )
134
 
135
  # --- Event Listeners ---
136
+ def on_generate_click(prompt):
137
+ # Provide user feedback that generation is in progress
138
+ yield (
139
+ gr.update(interactive=False), # Disable button
140
+ gr.update(visible=False), # Hide download button
141
+ create_placeholder_image("🧠 Generating with AI... Please wait."),
142
+ "Generating... this can take up to 30 seconds."
143
+ )
144
+ # Call the main generation function
145
+ img_path, download_btn_update = generate_flowchart(prompt, hf_token)
146
+ # Update UI with the result
147
+ yield (
148
+ gr.update(interactive=True), # Re-enable button
149
+ download_btn_update, # Show/update download button
150
+ img_path,
151
+ "" # Clear status message
152
+ )
153
+
154
  generate_btn.click(
155
+ fn=on_generate_click,
 
 
 
 
 
 
 
156
  inputs=[prompt_input],
157
+ outputs=[generate_btn, download_btn, output_image, status_display]
158
  )
159
 
160
  if __name__ == "__main__":
161
+ if not os.path.exists("outputs"):
162
+ os.makedirs("outputs")
163
  demo.launch()