icebear0828 Claude Opus 4.6 commited on
Commit
debd0e1
·
1 Parent(s): 35ed5a4

ui: two-level tabs — protocol (OpenAI/Anthropic/Gemini) → language (Python/cURL/Node.js)

Browse files

Restructure Integration Examples into a 3x3 grid with protocol as the
top-level tab and language as the sub-level tab. Each combination gets
its own idiomatic code example using the native SDK for that protocol.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Files changed (1) hide show
  1. public/dashboard.html +144 -75
public/dashboard.html CHANGED
@@ -475,8 +475,32 @@
475
  transition: background 0.2s;
476
  }
477
  .code-block .copy-code-btn:hover { background: rgba(255,255,255,0.2); }
478
- .tab-content { display: none; }
479
- .tab-content.active { display: block; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
480
 
481
  /* Footer */
482
  .footer {
@@ -581,33 +605,28 @@
581
  <!-- Integration Examples -->
582
  <div class="examples-card">
583
  <h2 class="section-title">Integration Examples</h2>
584
- <div class="tabs">
585
- <button class="tab active" onclick="switchTab('python', this)">Python</button>
586
- <button class="tab" onclick="switchTab('curl', this)">cURL</button>
587
- <button class="tab" onclick="switchTab('node', this)">Node.js</button>
588
- <button class="tab" onclick="switchTab('anthropic', this)">Anthropic</button>
589
- <button class="tab" onclick="switchTab('gemini', this)">Gemini</button>
590
- </div>
591
- <div class="tab-content active" id="tab-python">
592
- <div class="code-block" id="code-python">Loading...
593
- <button class="copy-code-btn" onclick="copyCode('code-python')">&#9112; Copy</button></div>
594
- </div>
595
- <div class="tab-content" id="tab-curl">
596
- <div class="code-block" id="code-curl">Loading...
597
- <button class="copy-code-btn" onclick="copyCode('code-curl')">&#9112; Copy</button></div>
598
  </div>
599
- <div class="tab-content" id="tab-node">
600
- <div class="code-block" id="code-node">Loading...
601
- <button class="copy-code-btn" onclick="copyCode('code-node')">&#9112; Copy</button></div>
602
- </div>
603
- <div class="tab-content" id="tab-anthropic">
604
- <div class="code-block" id="code-anthropic">Loading...
605
- <button class="copy-code-btn" onclick="copyCode('code-anthropic')">&#9112; Copy</button></div>
606
- </div>
607
- <div class="tab-content" id="tab-gemini">
608
- <div class="code-block" id="code-gemini">Loading...
609
- <button class="copy-code-btn" onclick="copyCode('code-gemini')">&#9112; Copy</button></div>
610
  </div>
 
 
 
 
 
 
 
 
 
 
611
  </div>
612
  </div>
613
 
@@ -812,12 +831,19 @@
812
  }
813
  }
814
 
 
 
 
 
 
815
  function updateCodeExamples() {
816
  const baseUrl = escapeHtml(document.getElementById('baseUrl').value);
817
  const apiKey = escapeHtml(document.getElementById('apiKey').value || 'any-string');
818
  const model = escapeHtml(document.getElementById('defaultModel').value);
 
819
 
820
- document.getElementById('code-python').innerHTML =
 
821
  `from openai import OpenAI
822
 
823
  client = OpenAI(
@@ -827,27 +853,20 @@ client = OpenAI(
827
 
828
  response = client.chat.completions.create(
829
  model="${model}",
830
- messages=[
831
- {"role": "user", "content": "Explain quantum computing in simple terms"}
832
- ],
833
  )
 
834
 
835
- print(response.choices[0].message.content)
836
- <button class="copy-code-btn" onclick="copyCode('code-python')">&#9112; Copy Code</button>`;
837
-
838
- document.getElementById('code-curl').innerHTML =
839
  `curl ${baseUrl}/chat/completions \\
840
  -H "Content-Type: application/json" \\
841
  -H "Authorization: Bearer ${apiKey}" \\
842
  -d '{
843
  "model": "${model}",
844
- "messages": [
845
- {"role": "user", "content": "Explain quantum computing in simple terms"}
846
- ]
847
- }'
848
- <button class="copy-code-btn" onclick="copyCode('code-curl')">&#9112; Copy Code</button>`;
849
 
850
- document.getElementById('code-node').innerHTML =
851
  `import OpenAI from "openai";
852
 
853
  const client = new OpenAI({
@@ -857,56 +876,90 @@ const client = new OpenAI({
857
 
858
  const stream = await client.chat.completions.create({
859
  model: "${model}",
860
- messages: [
861
- { role: "user", content: "Explain quantum computing in simple terms" },
862
- ],
863
  stream: true,
864
  });
865
-
866
  for await (const chunk of stream) {
867
  process.stdout.write(chunk.choices[0]?.delta?.content || "");
868
- }
869
- <button class="copy-code-btn" onclick="copyCode('code-node')">&#9112; Copy</button>`;
 
 
 
870
 
871
- const messagesUrl = escapeHtml(window.location.origin + '/v1/messages');
872
- document.getElementById('code-anthropic').innerHTML =
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
873
  `import Anthropic from "@anthropic-ai/sdk";
874
 
875
  const client = new Anthropic({
876
- baseURL: "${messagesUrl.replace('/v1/messages', '/v1')}",
877
  apiKey: "${apiKey}",
878
  });
879
 
880
  const message = await client.messages.create({
881
  model: "claude-sonnet-4-20250514",
882
  max_tokens: 1024,
883
- messages: [
884
- { role: "user", content: "Explain quantum computing in simple terms" },
885
- ],
886
  });
 
887
 
888
- console.log(message.content[0].text);
889
- <button class="copy-code-btn" onclick="copyCode('code-anthropic')">&#9112; Copy</button>`;
 
890
 
891
- const geminiBase = escapeHtml(window.location.origin);
892
- document.getElementById('code-gemini').innerHTML =
893
- `curl ${geminiBase}/v1beta/models/gemini-2.5-pro:generateContent?key=${apiKey} \\
894
- -H "Content-Type: application/json" \\
895
- -d '{
896
- "contents": [
897
- {"role": "user", "parts": [{"text": "Explain quantum computing"}]}
898
- ]
899
- }'
 
900
 
901
- # Streaming
902
- curl ${geminiBase}/v1beta/models/gemini-2.5-pro:streamGenerateContent?alt=sse&key=${apiKey} \\
903
  -H "Content-Type: application/json" \\
904
  -d '{
905
- "contents": [
906
- {"role": "user", "parts": [{"text": "Explain quantum computing"}]}
907
- ]
908
- }'
909
- <button class="copy-code-btn" onclick="copyCode('code-gemini')">&#9112; Copy</button>`;
 
 
 
 
 
 
 
 
 
 
 
910
  }
911
 
912
  function saveOverrides() {
@@ -954,11 +1007,27 @@ curl ${geminiBase}/v1beta/models/gemini-2.5-pro:streamGenerateContent?alt=sse&ke
954
  document.getElementById('defaultModel').addEventListener('change', () => { updateCodeExamples(); saveOverrides(); });
955
  }
956
 
957
- function switchTab(tab, el) {
958
- document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
959
- document.querySelectorAll('.tab-content').forEach(t => t.classList.remove('active'));
 
 
 
 
 
 
 
 
 
 
960
  el.classList.add('active');
961
- document.getElementById('tab-' + tab).classList.add('active');
 
 
 
 
 
 
962
  }
963
 
964
  function copyField(id, btn) {
 
475
  transition: background 0.2s;
476
  }
477
  .code-block .copy-code-btn:hover { background: rgba(255,255,255,0.2); }
478
+ .tabs-protocol {
479
+ margin-bottom: 0;
480
+ border-bottom: none;
481
+ }
482
+ .tabs-protocol .tab {
483
+ font-weight: 600;
484
+ font-size: 0.82rem;
485
+ }
486
+ .tabs-protocol .tab.active {
487
+ border-bottom-color: #10a37f;
488
+ }
489
+ .tabs-lang {
490
+ border-bottom: 1px solid #e5e7eb;
491
+ margin-bottom: 0.75rem;
492
+ }
493
+ .tabs-lang .tab {
494
+ font-size: 0.75rem;
495
+ padding: 5px 12px;
496
+ color: #9ca3af;
497
+ }
498
+ .tabs-lang .tab.active {
499
+ color: #111827;
500
+ border-bottom-color: #6b7280;
501
+ }
502
+ .code-panel { display: none; }
503
+ .code-panel.active { display: block; }
504
 
505
  /* Footer */
506
  .footer {
 
605
  <!-- Integration Examples -->
606
  <div class="examples-card">
607
  <h2 class="section-title">Integration Examples</h2>
608
+ <!-- Protocol tabs (top level) -->
609
+ <div class="tabs tabs-protocol">
610
+ <button class="tab active" onclick="switchProtocol('openai', this)">OpenAI</button>
611
+ <button class="tab" onclick="switchProtocol('anthropic', this)">Anthropic</button>
612
+ <button class="tab" onclick="switchProtocol('gemini', this)">Gemini</button>
 
 
 
 
 
 
 
 
 
613
  </div>
614
+ <!-- Language tabs (sub level) -->
615
+ <div class="tabs tabs-lang">
616
+ <button class="tab active" data-lang="python" onclick="switchLang('python', this)">Python</button>
617
+ <button class="tab" data-lang="curl" onclick="switchLang('curl', this)">cURL</button>
618
+ <button class="tab" data-lang="node" onclick="switchLang('node', this)">Node.js</button>
 
 
 
 
 
 
619
  </div>
620
+ <!-- Code panels: {protocol}-{lang} -->
621
+ <div class="code-panel active" id="panel-openai-python"><div class="code-block" id="code-openai-python">Loading...<button class="copy-code-btn" onclick="copyCode('code-openai-python')">&#9112; Copy</button></div></div>
622
+ <div class="code-panel" id="panel-openai-curl"><div class="code-block" id="code-openai-curl">Loading...<button class="copy-code-btn" onclick="copyCode('code-openai-curl')">&#9112; Copy</button></div></div>
623
+ <div class="code-panel" id="panel-openai-node"><div class="code-block" id="code-openai-node">Loading...<button class="copy-code-btn" onclick="copyCode('code-openai-node')">&#9112; Copy</button></div></div>
624
+ <div class="code-panel" id="panel-anthropic-python"><div class="code-block" id="code-anthropic-python">Loading...<button class="copy-code-btn" onclick="copyCode('code-anthropic-python')">&#9112; Copy</button></div></div>
625
+ <div class="code-panel" id="panel-anthropic-curl"><div class="code-block" id="code-anthropic-curl">Loading...<button class="copy-code-btn" onclick="copyCode('code-anthropic-curl')">&#9112; Copy</button></div></div>
626
+ <div class="code-panel" id="panel-anthropic-node"><div class="code-block" id="code-anthropic-node">Loading...<button class="copy-code-btn" onclick="copyCode('code-anthropic-node')">&#9112; Copy</button></div></div>
627
+ <div class="code-panel" id="panel-gemini-python"><div class="code-block" id="code-gemini-python">Loading...<button class="copy-code-btn" onclick="copyCode('code-gemini-python')">&#9112; Copy</button></div></div>
628
+ <div class="code-panel" id="panel-gemini-curl"><div class="code-block" id="code-gemini-curl">Loading...<button class="copy-code-btn" onclick="copyCode('code-gemini-curl')">&#9112; Copy</button></div></div>
629
+ <div class="code-panel" id="panel-gemini-node"><div class="code-block" id="code-gemini-node">Loading...<button class="copy-code-btn" onclick="copyCode('code-gemini-node')">&#9112; Copy</button></div></div>
630
  </div>
631
  </div>
632
 
 
831
  }
832
  }
833
 
834
+ function setCode(id, code) {
835
+ const el = document.getElementById(id);
836
+ if (el) el.innerHTML = code + `\n<button class="copy-code-btn" onclick="copyCode('${id}')">&#9112; Copy</button>`;
837
+ }
838
+
839
  function updateCodeExamples() {
840
  const baseUrl = escapeHtml(document.getElementById('baseUrl').value);
841
  const apiKey = escapeHtml(document.getElementById('apiKey').value || 'any-string');
842
  const model = escapeHtml(document.getElementById('defaultModel').value);
843
+ const origin = escapeHtml(window.location.origin);
844
 
845
+ // ── OpenAI ──
846
+ setCode('code-openai-python',
847
  `from openai import OpenAI
848
 
849
  client = OpenAI(
 
853
 
854
  response = client.chat.completions.create(
855
  model="${model}",
856
+ messages=[{"role": "user", "content": "Hello"}],
 
 
857
  )
858
+ print(response.choices[0].message.content)`);
859
 
860
+ setCode('code-openai-curl',
 
 
 
861
  `curl ${baseUrl}/chat/completions \\
862
  -H "Content-Type: application/json" \\
863
  -H "Authorization: Bearer ${apiKey}" \\
864
  -d '{
865
  "model": "${model}",
866
+ "messages": [{"role": "user", "content": "Hello"}]
867
+ }'`);
 
 
 
868
 
869
+ setCode('code-openai-node',
870
  `import OpenAI from "openai";
871
 
872
  const client = new OpenAI({
 
876
 
877
  const stream = await client.chat.completions.create({
878
  model: "${model}",
879
+ messages: [{ role: "user", content: "Hello" }],
 
 
880
  stream: true,
881
  });
 
882
  for await (const chunk of stream) {
883
  process.stdout.write(chunk.choices[0]?.delta?.content || "");
884
+ }`);
885
+
886
+ // ── Anthropic ──
887
+ setCode('code-anthropic-python',
888
+ `import anthropic
889
 
890
+ client = anthropic.Anthropic(
891
+ base_url="${origin}/v1",
892
+ api_key="${apiKey}",
893
+ )
894
+
895
+ message = client.messages.create(
896
+ model="claude-sonnet-4-20250514",
897
+ max_tokens=1024,
898
+ messages=[{"role": "user", "content": "Hello"}],
899
+ )
900
+ print(message.content[0].text)`);
901
+
902
+ setCode('code-anthropic-curl',
903
+ `curl ${origin}/v1/messages \\
904
+ -H "Content-Type: application/json" \\
905
+ -H "x-api-key: ${apiKey}" \\
906
+ -H "anthropic-version: 2023-06-01" \\
907
+ -d '{
908
+ "model": "claude-sonnet-4-20250514",
909
+ "max_tokens": 1024,
910
+ "messages": [{"role": "user", "content": "Hello"}]
911
+ }'`);
912
+
913
+ setCode('code-anthropic-node',
914
  `import Anthropic from "@anthropic-ai/sdk";
915
 
916
  const client = new Anthropic({
917
+ baseURL: "${origin}/v1",
918
  apiKey: "${apiKey}",
919
  });
920
 
921
  const message = await client.messages.create({
922
  model: "claude-sonnet-4-20250514",
923
  max_tokens: 1024,
924
+ messages: [{ role: "user", content: "Hello" }],
 
 
925
  });
926
+ console.log(message.content[0].text);`);
927
 
928
+ // ── Gemini ──
929
+ setCode('code-gemini-python',
930
+ `from google import genai
931
 
932
+ client = genai.Client(
933
+ api_key="${apiKey}",
934
+ http_options={"base_url": "${origin}/v1beta"},
935
+ )
936
+
937
+ response = client.models.generate_content(
938
+ model="gemini-2.5-pro",
939
+ contents="Hello",
940
+ )
941
+ print(response.text)`);
942
 
943
+ setCode('code-gemini-curl',
944
+ `curl "${origin}/v1beta/models/gemini-2.5-pro:generateContent?key=${apiKey}" \\
945
  -H "Content-Type: application/json" \\
946
  -d '{
947
+ "contents": [{"role": "user", "parts": [{"text": "Hello"}]}]
948
+ }'`);
949
+
950
+ setCode('code-gemini-node',
951
+ `import { GoogleGenAI } from "@google/genai";
952
+
953
+ const ai = new GoogleGenAI({
954
+ apiKey: "${apiKey}",
955
+ httpOptions: { baseUrl: "${origin}/v1beta" },
956
+ });
957
+
958
+ const response = await ai.models.generateContent({
959
+ model: "gemini-2.5-pro",
960
+ contents: "Hello",
961
+ });
962
+ console.log(response.text);`);
963
  }
964
 
965
  function saveOverrides() {
 
1007
  document.getElementById('defaultModel').addEventListener('change', () => { updateCodeExamples(); saveOverrides(); });
1008
  }
1009
 
1010
+ let currentProtocol = 'openai';
1011
+ let currentLang = 'python';
1012
+
1013
+ function switchProtocol(proto, el) {
1014
+ currentProtocol = proto;
1015
+ document.querySelectorAll('.tabs-protocol .tab').forEach(t => t.classList.remove('active'));
1016
+ el.classList.add('active');
1017
+ showActivePanel();
1018
+ }
1019
+
1020
+ function switchLang(lang, el) {
1021
+ currentLang = lang;
1022
+ document.querySelectorAll('.tabs-lang .tab').forEach(t => t.classList.remove('active'));
1023
  el.classList.add('active');
1024
+ showActivePanel();
1025
+ }
1026
+
1027
+ function showActivePanel() {
1028
+ document.querySelectorAll('.code-panel').forEach(p => p.classList.remove('active'));
1029
+ const panel = document.getElementById('panel-' + currentProtocol + '-' + currentLang);
1030
+ if (panel) panel.classList.add('active');
1031
  }
1032
 
1033
  function copyField(id, btn) {