alihmaou commited on
Commit
8a7669a
·
1 Parent(s): 6994f46

Added a diagram generator (based on my drawittome tool)

Browse files
Files changed (4) hide show
  1. .gitignore +1 -0
  2. app.py +5 -3
  3. requirements.txt +5 -1
  4. tools/diagrams.py +93 -0
.gitignore CHANGED
@@ -1,4 +1,5 @@
1
  .env
 
2
  # Byte-compiled / optimized / DLL files
3
  __pycache__/
4
  *.py[cod]
 
1
  .env
2
+ tests/
3
  # Byte-compiled / optimized / DLL files
4
  __pycache__/
5
  *.py[cod]
app.py CHANGED
@@ -1,17 +1,19 @@
1
  import gradio as gr
2
- from tools import jokes, weather, datasetananalysis
3
 
4
 
5
  demo = gr.TabbedInterface(
6
  [
7
  gr.Interface(fn=jokes.smalljoke,inputs=["text"],outputs="text", title="Small joke teller", description="Tells a small joke in french"),
8
  gr.Interface(fn=jokes.longjoke,inputs=["text","text","text","text" ],outputs="text", title="Long joke teller", description="Tells a longer joke in french"),
9
- gr.Interface(fn=datasetananalysis.describedataset,inputs=["text" ],outputs="text", title="Dataset descriptor", description="Provides a usefull description of a dataset to allow content and structure awareness before SQL requesting on it.")
 
10
  ],
11
  [
12
  "Histoire courte",
13
  "Histoire longue",
14
- "Description d'un dataset"
 
15
  ]
16
  )
17
 
 
1
  import gradio as gr
2
+ from tools import jokes, weather, datasetananalysis, diagrams
3
 
4
 
5
  demo = gr.TabbedInterface(
6
  [
7
  gr.Interface(fn=jokes.smalljoke,inputs=["text"],outputs="text", title="Small joke teller", description="Tells a small joke in french"),
8
  gr.Interface(fn=jokes.longjoke,inputs=["text","text","text","text" ],outputs="text", title="Long joke teller", description="Tells a longer joke in french"),
9
+ gr.Interface(fn=datasetananalysis.describedataset,inputs=["text" ],outputs="text", title="Dataset descriptor", description="Provides a usefull description of a dataset to allow content and structure awareness before SQL requesting on it."),
10
+ gr.Interface(fn=diagrams.generateDiagram, inputs=["text","text"], outputs=["html","html","text","text"], title="Diagrams generator", description="Generates a mermaid diagram to explain a submited text. The diagram is returned in different formats(svg and raw code)")
11
  ],
12
  [
13
  "Histoire courte",
14
  "Histoire longue",
15
+ "Description d'un dataset",
16
+ "Générateur de diagrammes"
17
  ]
18
  )
19
 
requirements.txt CHANGED
@@ -1,3 +1,7 @@
1
  python-dotenv
2
  gradio[mcp]
3
- openai
 
 
 
 
 
1
  python-dotenv
2
  gradio[mcp]
3
+ openai
4
+ huggingface_hub
5
+ zlib
6
+ base64
7
+ huggingface_hub
tools/diagrams.py ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import zlib
2
+ import base64
3
+ import os
4
+ from dotenv import load_dotenv
5
+ from huggingface_hub import InferenceClient
6
+
7
+ load_dotenv()
8
+ os.environ["SAMBANOVA_API_KEY"]
9
+
10
+ PROMPT="""
11
+ ###PERSONA : Tu es un analyste métier sénior, expert en vulgarisation et en diagrammes formels.
12
+ ###INSTRUCTION : En fonction d’un sujet donné, sélectionne le type de diagramme le plus adapté parmi ceux listés, puis génère un diagramme complet, lisible, et détaillé. Syntaxe Mermaid uniquement, sans explication hors-code.
13
+ Génère le code mermaid, et rien que le code mermaid expliquant le mieux la description qui suit.
14
+ ### Sélection du type de diagramme (`mermaid_diag_type`) :
15
+ - `Graph TB` : **choix par défaut**. Regroupe les éléments par blocs. Applique des couleurs si possible.
16
+ - `flowchart TD` : pour les **processus** et **arbres de décision**.
17
+ - `sequenceDiagram` : pour les **enchaînements complexes** entre **acteurs ou systèmes**.
18
+ - `classDiagram` : si **demande explicite** ou si **entrants techniques** (ex. schéma SQL).
19
+ - `stateDiagram-v2` : si **demande explicite** ou **entrants techniques** comme une user story.
20
+ - `erDiagram` : autre **choix par défaut** pour exposer les relations entités-attributs. Regroupe et colore les blocs.
21
+ - `gantt` : si **thématique projet ou travaux**, avec des **tâches identifiables**.
22
+ - `timeline` : pour toute **chronologie**, **biographie**, ou **historique**. Regroupe les événements par **décennie**, ou **siècle** si nécessaire. Exemple de syntaxe :
23
+ timeline
24
+ title History of Social Media Platform
25
+ 2002 : LinkedIn
26
+ 2004 : Facebook
27
+ : Google
28
+ 2005 : YouTube
29
+ 2006 : Twitter
30
+
31
+ ### Règles de syntaxe :
32
+ - Les noms d’entités doivent être **concis**.
33
+ - Ne pas utiliser de **parenthèses** sauf si **sens sémantique clair** : elles perturbent le parsing Mermaid.
34
+ - Évite aussi les caractères spéciaux non compatibles Mermaid (`@`, `{}`, `[]`, etc.).
35
+ - Utilise des noms explicites pour les nœuds (ex. `AgentDemandeur` plutôt que `A`)
36
+ - Utilise `%%` pour commenter ou annoter hors rendu visuel.
37
+ - Segmente clairement, évite les diagrammes illisibles ou trop denses.
38
+ - Rédige dans la **langue du demandeur** ou celle du **texte d’origine**.
39
+
40
+ Objectif : produire un diagramme Mermaid clair, fidèle, et directement exploitable dans un contexte explicatif, technique ou décisionnel.
41
+ """
42
+ import os
43
+
44
+
45
+
46
+ def getModelResponseFromContent(content, provider_name="sambanova", provider_env_key="SAMBANOVA_API_KEY", model="meta-llama/Llama-4-Scout-17B-16E-Instruct"):
47
+ client = InferenceClient(
48
+ provider=provider_name,
49
+ api_key=os.environ[provider_env_key],
50
+ )
51
+
52
+ completion = client.chat.completions.create(
53
+ model=model,
54
+ messages=[
55
+ {
56
+ "role": "user",
57
+ f"content": content
58
+ }
59
+ ],
60
+ )
61
+
62
+ raw_response = completion.choices[0].message.content
63
+ mermaid_code_cleaned = raw_response.replace("```mermaid", "").replace("```", "").strip()
64
+ mermaid_diagram_type = mermaid_code_cleaned.split('\n', 1)[0].strip()
65
+
66
+ return mermaid_code_cleaned, mermaid_diagram_type
67
+
68
+ def kroki_img_from_mermaid(mermaid_code: str, output_format: str = "svg") -> str:
69
+ compressed = zlib.compress(mermaid_code.encode('utf-8'))
70
+ b64 = base64.urlsafe_b64encode(compressed).decode('utf-8')
71
+ image_url = f"https://kroki.io/mermaid/{output_format}/{b64}"
72
+ html_img = f"""<a href="{image_url}" target="_blank"> <img src="{image_url}" alt="Diagramme Mermaid via Kroki" > </a>"""
73
+ return html_img
74
+
75
+
76
+ def generateDiagram(input_text="I broke my car yesterday, and the mechanics will give it back to me after insurance payment.", input_precisions="Choose the best diagram paradigm"):
77
+ """Generates a mermaid diagram to explain a submited text. The diagram is returned in different formats(html and raw code)
78
+
79
+ Args:
80
+ input_text: the text to explain with a diagram.
81
+ input_precisions: diagram settings, by default the tool has the ability to choose the best type of diagram.
82
+
83
+ Returns:
84
+ kroki_html_img: svg image in an img html tag.
85
+ kroki_html_link: full kroki link with image and link to kroki page.
86
+ mermaid_diag_type: type of diagram selected by the tool
87
+ mermaid_code: mermaid code
88
+ """
89
+ full_content_prompt = f"{PROMPT}. ###INPUT : {input_text}. ###PRECISIONS {input_precisions}"
90
+ mermaid_code, mermaid_diag_type = getModelResponseFromContent(content=full_content_prompt )
91
+ kroki_html_link = kroki_img_from_mermaid(mermaid_code)
92
+ kroki_html_img = kroki_html_link[kroki_html_link.find('<img '):kroki_html_link.find('>', kroki_html_link.find('<img ')) + 1]
93
+ return kroki_html_img, kroki_html_link, mermaid_diag_type, mermaid_code