Add user defined system message
This commit is contained in:
@@ -12,7 +12,7 @@ llm:
|
||||
url: "http://localhost:8081/v1"
|
||||
key: ${ODIDERE_LLM_KEY}
|
||||
model: "default"
|
||||
system_prompt: "You are a helpful voice assistant. Be concise."
|
||||
system_message: "You are a helpful voice assistant. Be concise."
|
||||
timeout: "5m"
|
||||
|
||||
tts:
|
||||
|
||||
@@ -22,8 +22,8 @@ type Config struct {
|
||||
Key string `yaml:"key"`
|
||||
// Model is the model identifier.
|
||||
Model string `yaml:"model"`
|
||||
// SystemPrompt is prepended to all conversations.
|
||||
SystemPrompt string `yaml:"system_prompt"`
|
||||
// SystemMessage is prepended to all conversations.
|
||||
SystemMessage string `yaml:"system_message"`
|
||||
// Timeout is the maximum duration for a query (e.g., "5m").
|
||||
// Defaults to 5 minutes if empty.
|
||||
Timeout string `yaml:"timeout"`
|
||||
@@ -49,13 +49,13 @@ func (cfg Config) Validate() error {
|
||||
|
||||
// Client wraps an OpenAI-compatible client with tool execution support.
|
||||
type Client struct {
|
||||
client *openai.Client
|
||||
log *slog.Logger
|
||||
model string
|
||||
registry *tool.Registry
|
||||
systemPrompt string
|
||||
timeout time.Duration
|
||||
tools []openai.Tool
|
||||
client *openai.Client
|
||||
log *slog.Logger
|
||||
model string
|
||||
registry *tool.Registry
|
||||
systemMessage string
|
||||
timeout time.Duration
|
||||
tools []openai.Tool
|
||||
}
|
||||
|
||||
// NewClient creates a new LLM client with the provided configuration.
|
||||
@@ -70,10 +70,10 @@ func NewClient(
|
||||
}
|
||||
|
||||
llm := &Client{
|
||||
log: log,
|
||||
model: cfg.Model,
|
||||
systemPrompt: cfg.SystemPrompt,
|
||||
registry: registry,
|
||||
log: log,
|
||||
model: cfg.Model,
|
||||
systemMessage: cfg.SystemMessage,
|
||||
registry: registry,
|
||||
}
|
||||
|
||||
if cfg.Timeout == "" {
|
||||
@@ -122,12 +122,14 @@ func (c *Client) DefaultModel() string {
|
||||
|
||||
// Query sends messages to the LLM using the specified model.
|
||||
// If model is empty, uses the default configured model.
|
||||
// If systemMessage is non-empty, it overrides the configured system message.
|
||||
// Returns all messages generated during the query, including tool calls
|
||||
// and tool results. The final message is the last element in the slice.
|
||||
func (c *Client) Query(
|
||||
ctx context.Context,
|
||||
messages []openai.ChatCompletionMessage,
|
||||
model string,
|
||||
systemMessage string,
|
||||
) ([]openai.ChatCompletionMessage, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, c.timeout)
|
||||
defer cancel()
|
||||
@@ -137,13 +139,19 @@ func (c *Client) Query(
|
||||
model = c.model
|
||||
}
|
||||
|
||||
// Prepend system prompt, if configured and not already present.
|
||||
if c.systemPrompt != "" && (len(messages) == 0 ||
|
||||
// Use per-request system message if provided, otherwise fall back to config.
|
||||
effectiveMessage := c.systemMessage
|
||||
if systemMessage != "" {
|
||||
effectiveMessage = systemMessage
|
||||
}
|
||||
|
||||
// Prepend system message, if configured and not already present.
|
||||
if effectiveMessage != "" && (len(messages) == 0 ||
|
||||
messages[0].Role != openai.ChatMessageRoleSystem) {
|
||||
messages = append(
|
||||
[]openai.ChatCompletionMessage{{
|
||||
Role: openai.ChatMessageRoleSystem,
|
||||
Content: c.systemPrompt,
|
||||
Content: effectiveMessage,
|
||||
}},
|
||||
messages...,
|
||||
)
|
||||
@@ -239,11 +247,13 @@ type StreamEvent struct {
|
||||
// streams results. Each complete message (assistant reply, tool call,
|
||||
// tool result) is sent to the events channel as it becomes available.
|
||||
// The channel is closed before returning.
|
||||
// If systemMessage is non-empty, it overrides the configured system message.
|
||||
// Returns all messages generated during the query.
|
||||
func (c *Client) QueryStream(
|
||||
ctx context.Context,
|
||||
messages []openai.ChatCompletionMessage,
|
||||
model string,
|
||||
systemMessage string,
|
||||
events chan<- StreamEvent,
|
||||
) error {
|
||||
defer close(events)
|
||||
@@ -256,13 +266,19 @@ func (c *Client) QueryStream(
|
||||
model = c.model
|
||||
}
|
||||
|
||||
// Prepend system prompt, if configured and not already present.
|
||||
if c.systemPrompt != "" && (len(messages) == 0 ||
|
||||
// Use per-request system message if provided, otherwise fall back to config.
|
||||
effectiveMessage := c.systemMessage
|
||||
if systemMessage != "" {
|
||||
effectiveMessage = systemMessage
|
||||
}
|
||||
|
||||
// Prepend system message, if configured and not already present.
|
||||
if effectiveMessage != "" && (len(messages) == 0 ||
|
||||
messages[0].Role != openai.ChatMessageRoleSystem) {
|
||||
messages = append(
|
||||
[]openai.ChatCompletionMessage{{
|
||||
Role: openai.ChatMessageRoleSystem,
|
||||
Content: c.systemPrompt,
|
||||
Content: effectiveMessage,
|
||||
}},
|
||||
messages...,
|
||||
)
|
||||
|
||||
@@ -67,11 +67,11 @@ func TestConfigValidate(t *testing.T) {
|
||||
{
|
||||
name: "valid full config",
|
||||
cfg: Config{
|
||||
Key: "sk-test-key",
|
||||
Model: "test-model",
|
||||
SystemPrompt: "You are a helpful assistant.",
|
||||
Timeout: "30m",
|
||||
URL: "http://localhost:8080",
|
||||
Key: "sk-test-key",
|
||||
Model: "test-model",
|
||||
SystemMessage: "You are a helpful assistant.",
|
||||
Timeout: "30m",
|
||||
URL: "http://localhost:8080",
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
@@ -121,11 +121,11 @@ func TestNewClient(t *testing.T) {
|
||||
{
|
||||
name: "valid config with all fields",
|
||||
cfg: Config{
|
||||
Key: "test-key",
|
||||
Model: "test-model",
|
||||
SystemPrompt: "Test prompt",
|
||||
Timeout: "5m",
|
||||
URL: "http://localhost:8080",
|
||||
Key: "test-key",
|
||||
Model: "test-model",
|
||||
SystemMessage: "Test message",
|
||||
Timeout: "5m",
|
||||
URL: "http://localhost:8080",
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
|
||||
@@ -311,6 +311,8 @@ type Request struct {
|
||||
Messages []openai.ChatCompletionMessage `json:"messages"`
|
||||
// Model is the LLM model ID. If empty, the default model is used.
|
||||
Model string `json:"model,omitempty"`
|
||||
// SystemMessage overrides the configured system message for this request.
|
||||
SystemMessage string `json:"system_message,omitempty"`
|
||||
// Voice is the voice ID for TTS.
|
||||
Voice string `json:"voice,omitempty"`
|
||||
}
|
||||
@@ -455,7 +457,7 @@ func (svc *Service) voice(w http.ResponseWriter, r *http.Request) {
|
||||
if model == "" {
|
||||
model = svc.llm.DefaultModel()
|
||||
}
|
||||
msgs, err := svc.llm.Query(ctx, messages, model)
|
||||
msgs, err := svc.llm.Query(ctx, messages, model, req.SystemMessage)
|
||||
if err != nil {
|
||||
log.ErrorContext(
|
||||
ctx,
|
||||
@@ -731,7 +733,7 @@ func (svc *Service) voiceStream(w http.ResponseWriter, r *http.Request) {
|
||||
llmErr error
|
||||
)
|
||||
go func() {
|
||||
llmErr = svc.llm.QueryStream(ctx, messages, model, events)
|
||||
llmErr = svc.llm.QueryStream(ctx, messages, model, req.SystemMessage, events)
|
||||
}()
|
||||
|
||||
// Consume events and send as SSE.
|
||||
|
||||
@@ -90,4 +90,9 @@
|
||||
<path d="m15 9-6 6"/>
|
||||
<path d="m9 9 6 6"/>
|
||||
</symbol>
|
||||
|
||||
<symbol id="settings" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z"/>
|
||||
<circle cx="12" cy="12" r="3"/>
|
||||
</symbol>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.9 KiB |
@@ -593,6 +593,201 @@ body {
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
/* ==================== */
|
||||
/* Settings Modal */
|
||||
/* ==================== */
|
||||
|
||||
.settings-overlay {
|
||||
display: none;
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 1000;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: var(--s1);
|
||||
}
|
||||
|
||||
.settings-overlay.open {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.settings-panel {
|
||||
background: var(--color-surface);
|
||||
border: 1px solid var(--color-border-light);
|
||||
border-radius: var(--radius);
|
||||
width: 100%;
|
||||
max-width: 480px;
|
||||
max-height: 90vh;
|
||||
overflow-y: auto;
|
||||
padding: var(--s1);
|
||||
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.settings-panel__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: var(--s1);
|
||||
}
|
||||
|
||||
.settings-panel__title {
|
||||
font-size: var(--s1);
|
||||
font-weight: 600;
|
||||
color: var(--color-text);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Close button: remove toolbar border, darken the X. */
|
||||
#settings-close {
|
||||
border: none;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
#settings-close:hover {
|
||||
border-color: transparent;
|
||||
color: var(--color-text);
|
||||
}
|
||||
}
|
||||
|
||||
/* Tabs */
|
||||
.settings-tabs {
|
||||
display: flex;
|
||||
border-bottom: 2px solid var(--color-border-light);
|
||||
margin-bottom: var(--s1);
|
||||
}
|
||||
|
||||
.settings-tab {
|
||||
padding: var(--s-2) var(--s-1);
|
||||
background: transparent;
|
||||
border: none;
|
||||
border-bottom: 2px solid transparent;
|
||||
margin-bottom: -2px;
|
||||
font-family: inherit;
|
||||
font-size: var(--s-1);
|
||||
color: var(--color-text-muted);
|
||||
cursor: pointer;
|
||||
transition: all 0.15s ease;
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
.settings-tab:hover {
|
||||
color: var(--color-text);
|
||||
}
|
||||
}
|
||||
|
||||
.settings-tab:focus-visible {
|
||||
outline: 2px solid var(--color-primary);
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
.settings-tab.active {
|
||||
color: var(--color-text);
|
||||
border-bottom-color: var(--color-primary);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* Tab panels */
|
||||
.settings-tab-panel {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.settings-tab-panel.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.settings-label {
|
||||
display: block;
|
||||
font-size: var(--s-1);
|
||||
font-weight: 500;
|
||||
color: var(--color-text);
|
||||
margin-bottom: var(--s-2);
|
||||
}
|
||||
|
||||
.settings-select {
|
||||
width: 100%;
|
||||
height: var(--s2);
|
||||
padding: 0 var(--s-1);
|
||||
font-family: inherit;
|
||||
font-size: var(--s-1);
|
||||
line-height: var(--s2);
|
||||
color: var(--color-text);
|
||||
background: var(--color-surface);
|
||||
border: 1px solid var(--color-border-light);
|
||||
border-radius: var(--radius);
|
||||
cursor: pointer;
|
||||
margin-bottom: var(--s1);
|
||||
}
|
||||
|
||||
.settings-select:focus-visible {
|
||||
outline: 2px solid var(--color-primary);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.settings-textarea {
|
||||
display: block;
|
||||
width: 100%;
|
||||
min-height: calc(var(--s2) * 6);
|
||||
padding: var(--s-1);
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--s-1);
|
||||
line-height: 1.5;
|
||||
color: var(--color-text);
|
||||
background: var(--color-bg);
|
||||
border: 1px solid var(--color-border-light);
|
||||
border-radius: var(--radius);
|
||||
resize: vertical;
|
||||
margin-bottom: var(--s-1);
|
||||
}
|
||||
|
||||
.settings-textarea:focus {
|
||||
outline: 2px solid var(--color-primary);
|
||||
outline-offset: 1px;
|
||||
}
|
||||
|
||||
.settings-save-row {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.settings-save-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: var(--s-2) var(--s-1);
|
||||
font-family: inherit;
|
||||
font-size: var(--s-1);
|
||||
font-weight: 500;
|
||||
color: white;
|
||||
background: var(--color-primary);
|
||||
border: none;
|
||||
border-radius: var(--radius);
|
||||
cursor: pointer;
|
||||
transition: background-color 0.15s ease;
|
||||
min-width: var(--s2);
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
.settings-save-btn:hover {
|
||||
background: var(--color-primary-hover);
|
||||
}
|
||||
}
|
||||
|
||||
.settings-save-btn:focus-visible {
|
||||
outline: 2px solid var(--color-primary);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.settings-save-btn--success {
|
||||
background: var(--color-green);
|
||||
}
|
||||
|
||||
.settings-save-btn .icon {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
}
|
||||
|
||||
/* ==================== */
|
||||
/* Animations */
|
||||
/* ==================== */
|
||||
@@ -668,4 +863,16 @@ body {
|
||||
max-width: 128px;
|
||||
font-size: var(--s-1);
|
||||
}
|
||||
|
||||
.settings-overlay {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.settings-panel {
|
||||
max-width: 100%;
|
||||
max-height: 100dvh;
|
||||
height: 100dvh;
|
||||
border-radius: 0;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ const ICONS_URL = '/static/icons.svg';
|
||||
const MODELS_ENDPOINT = '/v1/models';
|
||||
const MODEL_KEY = 'odidere_model';
|
||||
const STORAGE_KEY = 'odidere_history';
|
||||
const SYSTEM_MESSAGE_KEY = 'odidere_system_message';
|
||||
const VOICES_ENDPOINT = '/v1/voices';
|
||||
const VOICE_KEY = 'odidere_voice';
|
||||
|
||||
@@ -42,6 +43,15 @@ class Odidere {
|
||||
this.$voice = document.getElementById('voice');
|
||||
this.$mute = document.getElementById('mute');
|
||||
|
||||
// Settings modal
|
||||
this.$settings = document.getElementById('settings');
|
||||
this.$settingsOverlay = document.getElementById('settings-overlay');
|
||||
this.$settingsClose = document.getElementById('settings-close');
|
||||
this.$settingsTabs = document.querySelectorAll('.settings-tab');
|
||||
this.$settingsPanels = document.querySelectorAll('.settings-tab-panel');
|
||||
this.$systemMessageInput = document.getElementById('system-message-input');
|
||||
this.$saveSystemMessage = document.getElementById('save-system-message');
|
||||
|
||||
// Templates
|
||||
this.$tplAssistantMessage = document.getElementById(
|
||||
'tpl-assistant-message',
|
||||
@@ -151,6 +161,28 @@ class Odidere {
|
||||
});
|
||||
// Mute button
|
||||
this.$mute.addEventListener('click', () => this.#toggleMute());
|
||||
|
||||
// Settings modal
|
||||
this.$settings.addEventListener('click', () => this.openSettings());
|
||||
this.$settingsClose.addEventListener('click', () => this.closeSettings());
|
||||
this.$settingsOverlay.addEventListener('click', (e) => {
|
||||
if (e.target === this.$settingsOverlay) this.closeSettings();
|
||||
});
|
||||
this.document.addEventListener('keydown', (e) => {
|
||||
if (
|
||||
e.key === 'Escape' &&
|
||||
this.$settingsOverlay.classList.contains('open')
|
||||
) {
|
||||
e.preventDefault();
|
||||
this.closeSettings();
|
||||
}
|
||||
});
|
||||
this.$settingsTabs.forEach(($tab) => {
|
||||
$tab.addEventListener('click', () => this.#switchTab($tab.dataset.tab));
|
||||
});
|
||||
this.$saveSystemMessage.addEventListener('click', () =>
|
||||
this.#saveSystemMessage(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -557,6 +589,10 @@ class Odidere {
|
||||
voice: this.$voice.value,
|
||||
model: this.$model.value,
|
||||
};
|
||||
const systemMessage = localStorage.getItem(SYSTEM_MESSAGE_KEY);
|
||||
if (systemMessage) {
|
||||
payload.system_message = systemMessage;
|
||||
}
|
||||
if (audio) {
|
||||
payload.audio = await this.#toBase64(audio);
|
||||
}
|
||||
@@ -674,7 +710,11 @@ class Odidere {
|
||||
}
|
||||
|
||||
// Collect tool results and render once all have arrived.
|
||||
if (message.role === 'tool' && pendingTools && pendingTools.assistant) {
|
||||
if (
|
||||
message.role === 'tool' &&
|
||||
pendingTools &&
|
||||
pendingTools.assistant
|
||||
) {
|
||||
pendingTools.results.push(message);
|
||||
// Add to history (server needs it) but don't render yet.
|
||||
this.#appendHistory([message]);
|
||||
@@ -849,6 +889,67 @@ class Odidere {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* openSettings opens the settings modal and loads current values.
|
||||
*/
|
||||
openSettings() {
|
||||
this.$settingsOverlay.classList.add('open');
|
||||
this.#loadSystemMessage();
|
||||
this.#switchTab('model-voice');
|
||||
// Focus the close button for accessibility.
|
||||
this.$settingsClose.focus();
|
||||
}
|
||||
|
||||
/**
|
||||
* closeSettings closes the settings modal and restores focus.
|
||||
*/
|
||||
closeSettings() {
|
||||
this.$settingsOverlay.classList.remove('open');
|
||||
this.$settings.focus();
|
||||
}
|
||||
|
||||
/**
|
||||
* #switchTab switches the active tab in the settings modal.
|
||||
* @param {string} tabName
|
||||
*/
|
||||
#switchTab(tabName) {
|
||||
this.$settingsTabs.forEach(($tab) => {
|
||||
const isActive = $tab.dataset.tab === tabName;
|
||||
$tab.classList.toggle('active', isActive);
|
||||
$tab.setAttribute('aria-selected', String(isActive));
|
||||
});
|
||||
this.$settingsPanels.forEach(($panel) => {
|
||||
const isActive = $panel.dataset.tabPanel === tabName;
|
||||
$panel.classList.toggle('active', isActive);
|
||||
$panel.hidden = !isActive;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* #saveSystemMessage saves the textarea value to localStorage.
|
||||
*/
|
||||
#saveSystemMessage() {
|
||||
const value = this.$systemMessageInput.value;
|
||||
localStorage.setItem(SYSTEM_MESSAGE_KEY, value);
|
||||
|
||||
// Brief visual feedback on the save button.
|
||||
this.$saveSystemMessage.replaceChildren(this.#icon('check'));
|
||||
this.$saveSystemMessage.classList.add('settings-save-btn--success');
|
||||
|
||||
setTimeout(() => {
|
||||
this.$saveSystemMessage.textContent = 'Save';
|
||||
this.$saveSystemMessage.classList.remove('settings-save-btn--success');
|
||||
}, 1500);
|
||||
}
|
||||
|
||||
/**
|
||||
* #loadSystemMessage reads from localStorage and populates the textarea.
|
||||
*/
|
||||
#loadSystemMessage() {
|
||||
const stored = localStorage.getItem(SYSTEM_MESSAGE_KEY);
|
||||
this.$systemMessageInput.value = stored || '';
|
||||
}
|
||||
|
||||
// ====================
|
||||
// RENDER: SELECTS
|
||||
// ====================
|
||||
|
||||
@@ -2,5 +2,6 @@
|
||||
<body>
|
||||
{{ template "main" . }}
|
||||
{{ template "templates" . }}
|
||||
{{ template "modal/settings" . }}
|
||||
</body>
|
||||
{{ end }}
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
{{ define "footer/toolbar" }}
|
||||
<div class="footer__toolbar">
|
||||
<button
|
||||
type="button"
|
||||
class="footer__toolbar-btn"
|
||||
id="settings"
|
||||
aria-label="Settings"
|
||||
>
|
||||
<svg class="icon"><use href="/static/icons.svg#settings"></use></svg>
|
||||
</button>
|
||||
<div class="footer__toolbar-spacer"></div>
|
||||
<button
|
||||
type="button"
|
||||
class="footer__toolbar-btn"
|
||||
@@ -8,17 +17,6 @@
|
||||
>
|
||||
<svg class="icon"><use href="/static/icons.svg#reset"></use></svg>
|
||||
</button>
|
||||
<div class="footer__toolbar-spacer"></div>
|
||||
<select id="model" class="footer__select" aria-label="Model">
|
||||
<option value="" disabled selected>
|
||||
Loading...
|
||||
</option>
|
||||
</select>
|
||||
<select id="voice" class="footer__select" aria-label="Voice">
|
||||
<option value="" disabled selected>
|
||||
Loading...
|
||||
</option>
|
||||
</select>
|
||||
<button
|
||||
type="button"
|
||||
class="footer__toolbar-btn"
|
||||
|
||||
83
internal/service/templates/static/modal/settings.gohtml
Normal file
83
internal/service/templates/static/modal/settings.gohtml
Normal file
@@ -0,0 +1,83 @@
|
||||
{{ define "modal/settings" }}
|
||||
<div class="settings-overlay" id="settings-overlay">
|
||||
<div class="settings-panel" role="dialog" aria-modal="true"
|
||||
aria-labelledby="settings-title">
|
||||
<div class="settings-panel__header">
|
||||
<h2 class="settings-panel__title" id="settings-title">Settings</h2>
|
||||
<button
|
||||
type="button"
|
||||
class="footer__toolbar-btn"
|
||||
id="settings-close"
|
||||
aria-label="Close settings"
|
||||
>
|
||||
<svg class="icon"><use href="/static/icons.svg#close"></use></svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="settings-tabs" role="tablist">
|
||||
<button
|
||||
type="button"
|
||||
class="settings-tab active"
|
||||
role="tab"
|
||||
data-tab="model-voice"
|
||||
aria-selected="true"
|
||||
aria-controls="panel-model-voice"
|
||||
>Model & Voice</button>
|
||||
<button
|
||||
type="button"
|
||||
class="settings-tab"
|
||||
role="tab"
|
||||
data-tab="system-message"
|
||||
aria-selected="false"
|
||||
aria-controls="panel-system-message"
|
||||
>System Message</button>
|
||||
</div>
|
||||
|
||||
<div class="settings-tab-panels">
|
||||
<div
|
||||
class="settings-tab-panel active"
|
||||
role="tabpanel"
|
||||
data-tab-panel="model-voice"
|
||||
id="panel-model-voice"
|
||||
aria-labelledby="tab-model-voice"
|
||||
>
|
||||
<label class="settings-label" for="model">Model</label>
|
||||
<select id="model" class="settings-select" aria-label="Model">
|
||||
<option value="" disabled selected>Loading...</option>
|
||||
</select>
|
||||
|
||||
<label class="settings-label" for="voice">Voice</label>
|
||||
<select id="voice" class="settings-select" aria-label="Voice">
|
||||
<option value="" disabled selected>Loading...</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="settings-tab-panel"
|
||||
role="tabpanel"
|
||||
data-tab-panel="system-message"
|
||||
id="panel-system-message"
|
||||
aria-labelledby="tab-system-message"
|
||||
hidden
|
||||
>
|
||||
<label class="settings-label" for="system-message-input">
|
||||
System Message
|
||||
</label>
|
||||
<textarea
|
||||
id="system-message-input"
|
||||
class="settings-textarea"
|
||||
rows="8"
|
||||
placeholder="Enter system message..."
|
||||
></textarea>
|
||||
<div class="settings-save-row">
|
||||
<button
|
||||
type="button"
|
||||
class="settings-save-btn"
|
||||
id="save-system-message"
|
||||
>Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
4
vendor/github.com/google/uuid/dce.go
generated
vendored
4
vendor/github.com/google/uuid/dce.go
generated
vendored
@@ -42,7 +42,7 @@ func NewDCESecurity(domain Domain, id uint32) (UUID, error) {
|
||||
// NewDCEPerson returns a DCE Security (Version 2) UUID in the person
|
||||
// domain with the id returned by os.Getuid.
|
||||
//
|
||||
// NewDCESecurity(Person, uint32(os.Getuid()))
|
||||
// NewDCESecurity(Person, uint32(os.Getuid()))
|
||||
func NewDCEPerson() (UUID, error) {
|
||||
return NewDCESecurity(Person, uint32(os.Getuid()))
|
||||
}
|
||||
@@ -50,7 +50,7 @@ func NewDCEPerson() (UUID, error) {
|
||||
// NewDCEGroup returns a DCE Security (Version 2) UUID in the group
|
||||
// domain with the id returned by os.Getgid.
|
||||
//
|
||||
// NewDCESecurity(Group, uint32(os.Getgid()))
|
||||
// NewDCESecurity(Group, uint32(os.Getgid()))
|
||||
func NewDCEGroup() (UUID, error) {
|
||||
return NewDCESecurity(Group, uint32(os.Getgid()))
|
||||
}
|
||||
|
||||
4
vendor/github.com/google/uuid/hash.go
generated
vendored
4
vendor/github.com/google/uuid/hash.go
generated
vendored
@@ -45,7 +45,7 @@ func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID {
|
||||
// NewMD5 returns a new MD5 (Version 3) UUID based on the
|
||||
// supplied name space and data. It is the same as calling:
|
||||
//
|
||||
// NewHash(md5.New(), space, data, 3)
|
||||
// NewHash(md5.New(), space, data, 3)
|
||||
func NewMD5(space UUID, data []byte) UUID {
|
||||
return NewHash(md5.New(), space, data, 3)
|
||||
}
|
||||
@@ -53,7 +53,7 @@ func NewMD5(space UUID, data []byte) UUID {
|
||||
// NewSHA1 returns a new SHA1 (Version 5) UUID based on the
|
||||
// supplied name space and data. It is the same as calling:
|
||||
//
|
||||
// NewHash(sha1.New(), space, data, 5)
|
||||
// NewHash(sha1.New(), space, data, 5)
|
||||
func NewSHA1(space UUID, data []byte) UUID {
|
||||
return NewHash(sha1.New(), space, data, 5)
|
||||
}
|
||||
|
||||
1
vendor/github.com/google/uuid/node_js.go
generated
vendored
1
vendor/github.com/google/uuid/node_js.go
generated
vendored
@@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build js
|
||||
// +build js
|
||||
|
||||
package uuid
|
||||
|
||||
1
vendor/github.com/google/uuid/node_net.go
generated
vendored
1
vendor/github.com/google/uuid/node_net.go
generated
vendored
@@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !js
|
||||
// +build !js
|
||||
|
||||
package uuid
|
||||
|
||||
17
vendor/github.com/google/uuid/null.go
generated
vendored
17
vendor/github.com/google/uuid/null.go
generated
vendored
@@ -17,15 +17,14 @@ var jsonNull = []byte("null")
|
||||
// NullUUID implements the SQL driver.Scanner interface so
|
||||
// it can be used as a scan destination:
|
||||
//
|
||||
// var u uuid.NullUUID
|
||||
// err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&u)
|
||||
// ...
|
||||
// if u.Valid {
|
||||
// // use u.UUID
|
||||
// } else {
|
||||
// // NULL value
|
||||
// }
|
||||
//
|
||||
// var u uuid.NullUUID
|
||||
// err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&u)
|
||||
// ...
|
||||
// if u.Valid {
|
||||
// // use u.UUID
|
||||
// } else {
|
||||
// // NULL value
|
||||
// }
|
||||
type NullUUID struct {
|
||||
UUID UUID
|
||||
Valid bool // Valid is true if UUID is not NULL
|
||||
|
||||
10
vendor/github.com/google/uuid/uuid.go
generated
vendored
10
vendor/github.com/google/uuid/uuid.go
generated
vendored
@@ -187,10 +187,12 @@ func Must(uuid UUID, err error) UUID {
|
||||
}
|
||||
|
||||
// Validate returns an error if s is not a properly formatted UUID in one of the following formats:
|
||||
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
|
||||
//
|
||||
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
|
||||
//
|
||||
// It returns an error if the format is invalid, otherwise nil.
|
||||
func Validate(s string) error {
|
||||
switch len(s) {
|
||||
|
||||
14
vendor/github.com/google/uuid/version4.go
generated
vendored
14
vendor/github.com/google/uuid/version4.go
generated
vendored
@@ -9,7 +9,7 @@ import "io"
|
||||
// New creates a new random UUID or panics. New is equivalent to
|
||||
// the expression
|
||||
//
|
||||
// uuid.Must(uuid.NewRandom())
|
||||
// uuid.Must(uuid.NewRandom())
|
||||
func New() UUID {
|
||||
return Must(NewRandom())
|
||||
}
|
||||
@@ -17,7 +17,7 @@ func New() UUID {
|
||||
// NewString creates a new random UUID and returns it as a string or panics.
|
||||
// NewString is equivalent to the expression
|
||||
//
|
||||
// uuid.New().String()
|
||||
// uuid.New().String()
|
||||
func NewString() string {
|
||||
return Must(NewRandom()).String()
|
||||
}
|
||||
@@ -31,11 +31,11 @@ func NewString() string {
|
||||
//
|
||||
// A note about uniqueness derived from the UUID Wikipedia entry:
|
||||
//
|
||||
// Randomly generated UUIDs have 122 random bits. One's annual risk of being
|
||||
// hit by a meteorite is estimated to be one chance in 17 billion, that
|
||||
// means the probability is about 0.00000000006 (6 × 10−11),
|
||||
// equivalent to the odds of creating a few tens of trillions of UUIDs in a
|
||||
// year and having one duplicate.
|
||||
// Randomly generated UUIDs have 122 random bits. One's annual risk of being
|
||||
// hit by a meteorite is estimated to be one chance in 17 billion, that
|
||||
// means the probability is about 0.00000000006 (6 × 10−11),
|
||||
// equivalent to the odds of creating a few tens of trillions of UUIDs in a
|
||||
// year and having one duplicate.
|
||||
func NewRandom() (UUID, error) {
|
||||
if !poolEnabled {
|
||||
return NewRandomFromReader(rander)
|
||||
|
||||
8
vendor/gopkg.in/yaml.v3/apic.go
generated
vendored
8
vendor/gopkg.in/yaml.v3/apic.go
generated
vendored
@@ -1,17 +1,17 @@
|
||||
//
|
||||
//
|
||||
// Copyright (c) 2011-2019 Canonical Ltd
|
||||
// Copyright (c) 2006-2010 Kirill Simonov
|
||||
//
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
// of the Software, and to permit persons to whom the Software is furnished to do
|
||||
// so, subject to the following conditions:
|
||||
//
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
|
||||
9
vendor/gopkg.in/yaml.v3/emitterc.go
generated
vendored
9
vendor/gopkg.in/yaml.v3/emitterc.go
generated
vendored
@@ -162,10 +162,9 @@ func yaml_emitter_emit(emitter *yaml_emitter_t, event *yaml_event_t) bool {
|
||||
// Check if we need to accumulate more events before emitting.
|
||||
//
|
||||
// We accumulate extra
|
||||
// - 1 event for DOCUMENT-START
|
||||
// - 2 events for SEQUENCE-START
|
||||
// - 3 events for MAPPING-START
|
||||
//
|
||||
// - 1 event for DOCUMENT-START
|
||||
// - 2 events for SEQUENCE-START
|
||||
// - 3 events for MAPPING-START
|
||||
func yaml_emitter_need_more_events(emitter *yaml_emitter_t) bool {
|
||||
if emitter.events_head == len(emitter.events) {
|
||||
return true
|
||||
@@ -241,7 +240,7 @@ func yaml_emitter_increase_indent(emitter *yaml_emitter_t, flow, indentless bool
|
||||
emitter.indent += 2
|
||||
} else {
|
||||
// Everything else aligns to the chosen indentation.
|
||||
emitter.indent = emitter.best_indent*((emitter.indent+emitter.best_indent)/emitter.best_indent)
|
||||
emitter.indent = emitter.best_indent * ((emitter.indent + emitter.best_indent) / emitter.best_indent)
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
||||
142
vendor/gopkg.in/yaml.v3/parserc.go
generated
vendored
142
vendor/gopkg.in/yaml.v3/parserc.go
generated
vendored
@@ -227,7 +227,8 @@ func yaml_parser_state_machine(parser *yaml_parser_t, event *yaml_event_t) bool
|
||||
|
||||
// Parse the production:
|
||||
// stream ::= STREAM-START implicit_document? explicit_document* STREAM-END
|
||||
// ************
|
||||
//
|
||||
// ************
|
||||
func yaml_parser_parse_stream_start(parser *yaml_parser_t, event *yaml_event_t) bool {
|
||||
token := peek_token(parser)
|
||||
if token == nil {
|
||||
@@ -249,9 +250,12 @@ func yaml_parser_parse_stream_start(parser *yaml_parser_t, event *yaml_event_t)
|
||||
|
||||
// Parse the productions:
|
||||
// implicit_document ::= block_node DOCUMENT-END*
|
||||
// *
|
||||
//
|
||||
// *
|
||||
//
|
||||
// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
|
||||
// *************************
|
||||
//
|
||||
// *************************
|
||||
func yaml_parser_parse_document_start(parser *yaml_parser_t, event *yaml_event_t, implicit bool) bool {
|
||||
|
||||
token := peek_token(parser)
|
||||
@@ -356,8 +360,8 @@ func yaml_parser_parse_document_start(parser *yaml_parser_t, event *yaml_event_t
|
||||
|
||||
// Parse the productions:
|
||||
// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
|
||||
// ***********
|
||||
//
|
||||
// ***********
|
||||
func yaml_parser_parse_document_content(parser *yaml_parser_t, event *yaml_event_t) bool {
|
||||
token := peek_token(parser)
|
||||
if token == nil {
|
||||
@@ -379,9 +383,10 @@ func yaml_parser_parse_document_content(parser *yaml_parser_t, event *yaml_event
|
||||
|
||||
// Parse the productions:
|
||||
// implicit_document ::= block_node DOCUMENT-END*
|
||||
// *************
|
||||
// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
|
||||
//
|
||||
// *************
|
||||
//
|
||||
// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
|
||||
func yaml_parser_parse_document_end(parser *yaml_parser_t, event *yaml_event_t) bool {
|
||||
token := peek_token(parser)
|
||||
if token == nil {
|
||||
@@ -428,30 +433,41 @@ func yaml_parser_set_event_comments(parser *yaml_parser_t, event *yaml_event_t)
|
||||
|
||||
// Parse the productions:
|
||||
// block_node_or_indentless_sequence ::=
|
||||
// ALIAS
|
||||
// *****
|
||||
// | properties (block_content | indentless_block_sequence)?
|
||||
// ********** *
|
||||
// | block_content | indentless_block_sequence
|
||||
// *
|
||||
//
|
||||
// ALIAS
|
||||
// *****
|
||||
// | properties (block_content | indentless_block_sequence)?
|
||||
// ********** *
|
||||
// | block_content | indentless_block_sequence
|
||||
// *
|
||||
//
|
||||
// block_node ::= ALIAS
|
||||
// *****
|
||||
// | properties block_content?
|
||||
// ********** *
|
||||
// | block_content
|
||||
// *
|
||||
//
|
||||
// *****
|
||||
// | properties block_content?
|
||||
// ********** *
|
||||
// | block_content
|
||||
// *
|
||||
//
|
||||
// flow_node ::= ALIAS
|
||||
// *****
|
||||
// | properties flow_content?
|
||||
// ********** *
|
||||
// | flow_content
|
||||
// *
|
||||
//
|
||||
// *****
|
||||
// | properties flow_content?
|
||||
// ********** *
|
||||
// | flow_content
|
||||
// *
|
||||
//
|
||||
// properties ::= TAG ANCHOR? | ANCHOR TAG?
|
||||
// *************************
|
||||
//
|
||||
// *************************
|
||||
//
|
||||
// block_content ::= block_collection | flow_collection | SCALAR
|
||||
// ******
|
||||
//
|
||||
// ******
|
||||
//
|
||||
// flow_content ::= flow_collection | SCALAR
|
||||
// ******
|
||||
//
|
||||
// ******
|
||||
func yaml_parser_parse_node(parser *yaml_parser_t, event *yaml_event_t, block, indentless_sequence bool) bool {
|
||||
//defer trace("yaml_parser_parse_node", "block:", block, "indentless_sequence:", indentless_sequence)()
|
||||
|
||||
@@ -682,8 +698,8 @@ func yaml_parser_parse_node(parser *yaml_parser_t, event *yaml_event_t, block, i
|
||||
|
||||
// Parse the productions:
|
||||
// block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END
|
||||
// ******************** *********** * *********
|
||||
//
|
||||
// ******************** *********** * *********
|
||||
func yaml_parser_parse_block_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
|
||||
if first {
|
||||
token := peek_token(parser)
|
||||
@@ -740,7 +756,8 @@ func yaml_parser_parse_block_sequence_entry(parser *yaml_parser_t, event *yaml_e
|
||||
|
||||
// Parse the productions:
|
||||
// indentless_sequence ::= (BLOCK-ENTRY block_node?)+
|
||||
// *********** *
|
||||
//
|
||||
// *********** *
|
||||
func yaml_parser_parse_indentless_sequence_entry(parser *yaml_parser_t, event *yaml_event_t) bool {
|
||||
token := peek_token(parser)
|
||||
if token == nil {
|
||||
@@ -805,14 +822,14 @@ func yaml_parser_split_stem_comment(parser *yaml_parser_t, stem_len int) {
|
||||
|
||||
// Parse the productions:
|
||||
// block_mapping ::= BLOCK-MAPPING_START
|
||||
// *******************
|
||||
// ((KEY block_node_or_indentless_sequence?)?
|
||||
// *** *
|
||||
// (VALUE block_node_or_indentless_sequence?)?)*
|
||||
//
|
||||
// BLOCK-END
|
||||
// *********
|
||||
// *******************
|
||||
// ((KEY block_node_or_indentless_sequence?)?
|
||||
// *** *
|
||||
// (VALUE block_node_or_indentless_sequence?)?)*
|
||||
//
|
||||
// BLOCK-END
|
||||
// *********
|
||||
func yaml_parser_parse_block_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
|
||||
if first {
|
||||
token := peek_token(parser)
|
||||
@@ -881,13 +898,11 @@ func yaml_parser_parse_block_mapping_key(parser *yaml_parser_t, event *yaml_even
|
||||
// Parse the productions:
|
||||
// block_mapping ::= BLOCK-MAPPING_START
|
||||
//
|
||||
// ((KEY block_node_or_indentless_sequence?)?
|
||||
//
|
||||
// (VALUE block_node_or_indentless_sequence?)?)*
|
||||
// ***** *
|
||||
// BLOCK-END
|
||||
//
|
||||
// ((KEY block_node_or_indentless_sequence?)?
|
||||
//
|
||||
// (VALUE block_node_or_indentless_sequence?)?)*
|
||||
// ***** *
|
||||
// BLOCK-END
|
||||
func yaml_parser_parse_block_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool {
|
||||
token := peek_token(parser)
|
||||
if token == nil {
|
||||
@@ -915,16 +930,18 @@ func yaml_parser_parse_block_mapping_value(parser *yaml_parser_t, event *yaml_ev
|
||||
|
||||
// Parse the productions:
|
||||
// flow_sequence ::= FLOW-SEQUENCE-START
|
||||
// *******************
|
||||
// (flow_sequence_entry FLOW-ENTRY)*
|
||||
// * **********
|
||||
// flow_sequence_entry?
|
||||
// *
|
||||
// FLOW-SEQUENCE-END
|
||||
// *****************
|
||||
// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
|
||||
// *
|
||||
//
|
||||
// *******************
|
||||
// (flow_sequence_entry FLOW-ENTRY)*
|
||||
// * **********
|
||||
// flow_sequence_entry?
|
||||
// *
|
||||
// FLOW-SEQUENCE-END
|
||||
// *****************
|
||||
//
|
||||
// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
|
||||
//
|
||||
// *
|
||||
func yaml_parser_parse_flow_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
|
||||
if first {
|
||||
token := peek_token(parser)
|
||||
@@ -987,11 +1004,10 @@ func yaml_parser_parse_flow_sequence_entry(parser *yaml_parser_t, event *yaml_ev
|
||||
return true
|
||||
}
|
||||
|
||||
//
|
||||
// Parse the productions:
|
||||
// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
|
||||
// *** *
|
||||
//
|
||||
// *** *
|
||||
func yaml_parser_parse_flow_sequence_entry_mapping_key(parser *yaml_parser_t, event *yaml_event_t) bool {
|
||||
token := peek_token(parser)
|
||||
if token == nil {
|
||||
@@ -1011,8 +1027,8 @@ func yaml_parser_parse_flow_sequence_entry_mapping_key(parser *yaml_parser_t, ev
|
||||
|
||||
// Parse the productions:
|
||||
// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
|
||||
// ***** *
|
||||
//
|
||||
// ***** *
|
||||
func yaml_parser_parse_flow_sequence_entry_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool {
|
||||
token := peek_token(parser)
|
||||
if token == nil {
|
||||
@@ -1035,8 +1051,8 @@ func yaml_parser_parse_flow_sequence_entry_mapping_value(parser *yaml_parser_t,
|
||||
|
||||
// Parse the productions:
|
||||
// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
|
||||
// *
|
||||
//
|
||||
// *
|
||||
func yaml_parser_parse_flow_sequence_entry_mapping_end(parser *yaml_parser_t, event *yaml_event_t) bool {
|
||||
token := peek_token(parser)
|
||||
if token == nil {
|
||||
@@ -1053,16 +1069,17 @@ func yaml_parser_parse_flow_sequence_entry_mapping_end(parser *yaml_parser_t, ev
|
||||
|
||||
// Parse the productions:
|
||||
// flow_mapping ::= FLOW-MAPPING-START
|
||||
// ******************
|
||||
// (flow_mapping_entry FLOW-ENTRY)*
|
||||
// * **********
|
||||
// flow_mapping_entry?
|
||||
// ******************
|
||||
// FLOW-MAPPING-END
|
||||
// ****************
|
||||
// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
|
||||
// * *** *
|
||||
//
|
||||
// ******************
|
||||
// (flow_mapping_entry FLOW-ENTRY)*
|
||||
// * **********
|
||||
// flow_mapping_entry?
|
||||
// ******************
|
||||
// FLOW-MAPPING-END
|
||||
// ****************
|
||||
//
|
||||
// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
|
||||
// - *** *
|
||||
func yaml_parser_parse_flow_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
|
||||
if first {
|
||||
token := peek_token(parser)
|
||||
@@ -1128,8 +1145,7 @@ func yaml_parser_parse_flow_mapping_key(parser *yaml_parser_t, event *yaml_event
|
||||
|
||||
// Parse the productions:
|
||||
// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
|
||||
// * ***** *
|
||||
//
|
||||
// - ***** *
|
||||
func yaml_parser_parse_flow_mapping_value(parser *yaml_parser_t, event *yaml_event_t, empty bool) bool {
|
||||
token := peek_token(parser)
|
||||
if token == nil {
|
||||
|
||||
8
vendor/gopkg.in/yaml.v3/readerc.go
generated
vendored
8
vendor/gopkg.in/yaml.v3/readerc.go
generated
vendored
@@ -1,17 +1,17 @@
|
||||
//
|
||||
//
|
||||
// Copyright (c) 2011-2019 Canonical Ltd
|
||||
// Copyright (c) 2006-2010 Kirill Simonov
|
||||
//
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
// of the Software, and to permit persons to whom the Software is furnished to do
|
||||
// so, subject to the following conditions:
|
||||
//
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
|
||||
42
vendor/gopkg.in/yaml.v3/scannerc.go
generated
vendored
42
vendor/gopkg.in/yaml.v3/scannerc.go
generated
vendored
@@ -1614,11 +1614,11 @@ func yaml_parser_scan_to_next_token(parser *yaml_parser_t) bool {
|
||||
// Scan a YAML-DIRECTIVE or TAG-DIRECTIVE token.
|
||||
//
|
||||
// Scope:
|
||||
// %YAML 1.1 # a comment \n
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
// %TAG !yaml! tag:yaml.org,2002: \n
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
//
|
||||
// %YAML 1.1 # a comment \n
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
// %TAG !yaml! tag:yaml.org,2002: \n
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
func yaml_parser_scan_directive(parser *yaml_parser_t, token *yaml_token_t) bool {
|
||||
// Eat '%'.
|
||||
start_mark := parser.mark
|
||||
@@ -1719,11 +1719,11 @@ func yaml_parser_scan_directive(parser *yaml_parser_t, token *yaml_token_t) bool
|
||||
// Scan the directive name.
|
||||
//
|
||||
// Scope:
|
||||
// %YAML 1.1 # a comment \n
|
||||
// ^^^^
|
||||
// %TAG !yaml! tag:yaml.org,2002: \n
|
||||
// ^^^
|
||||
//
|
||||
// %YAML 1.1 # a comment \n
|
||||
// ^^^^
|
||||
// %TAG !yaml! tag:yaml.org,2002: \n
|
||||
// ^^^
|
||||
func yaml_parser_scan_directive_name(parser *yaml_parser_t, start_mark yaml_mark_t, name *[]byte) bool {
|
||||
// Consume the directive name.
|
||||
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
||||
@@ -1758,8 +1758,9 @@ func yaml_parser_scan_directive_name(parser *yaml_parser_t, start_mark yaml_mark
|
||||
// Scan the value of VERSION-DIRECTIVE.
|
||||
//
|
||||
// Scope:
|
||||
// %YAML 1.1 # a comment \n
|
||||
// ^^^^^^
|
||||
//
|
||||
// %YAML 1.1 # a comment \n
|
||||
// ^^^^^^
|
||||
func yaml_parser_scan_version_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, major, minor *int8) bool {
|
||||
// Eat whitespaces.
|
||||
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
||||
@@ -1797,10 +1798,11 @@ const max_number_length = 2
|
||||
// Scan the version number of VERSION-DIRECTIVE.
|
||||
//
|
||||
// Scope:
|
||||
// %YAML 1.1 # a comment \n
|
||||
// ^
|
||||
// %YAML 1.1 # a comment \n
|
||||
// ^
|
||||
//
|
||||
// %YAML 1.1 # a comment \n
|
||||
// ^
|
||||
// %YAML 1.1 # a comment \n
|
||||
// ^
|
||||
func yaml_parser_scan_version_directive_number(parser *yaml_parser_t, start_mark yaml_mark_t, number *int8) bool {
|
||||
|
||||
// Repeat while the next character is digit.
|
||||
@@ -1834,9 +1836,9 @@ func yaml_parser_scan_version_directive_number(parser *yaml_parser_t, start_mark
|
||||
// Scan the value of a TAG-DIRECTIVE token.
|
||||
//
|
||||
// Scope:
|
||||
// %TAG !yaml! tag:yaml.org,2002: \n
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
//
|
||||
// %TAG !yaml! tag:yaml.org,2002: \n
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
func yaml_parser_scan_tag_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, handle, prefix *[]byte) bool {
|
||||
var handle_value, prefix_value []byte
|
||||
|
||||
@@ -2847,7 +2849,7 @@ func yaml_parser_scan_line_comment(parser *yaml_parser_t, token_mark yaml_mark_t
|
||||
continue
|
||||
}
|
||||
if parser.buffer[parser.buffer_pos+peek] == '#' {
|
||||
seen := parser.mark.index+peek
|
||||
seen := parser.mark.index + peek
|
||||
for {
|
||||
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
||||
return false
|
||||
@@ -2876,7 +2878,7 @@ func yaml_parser_scan_line_comment(parser *yaml_parser_t, token_mark yaml_mark_t
|
||||
parser.comments = append(parser.comments, yaml_comment_t{
|
||||
token_mark: token_mark,
|
||||
start_mark: start_mark,
|
||||
line: text,
|
||||
line: text,
|
||||
})
|
||||
}
|
||||
return true
|
||||
@@ -2910,7 +2912,7 @@ func yaml_parser_scan_comments(parser *yaml_parser_t, scan_mark yaml_mark_t) boo
|
||||
// the foot is the line below it.
|
||||
var foot_line = -1
|
||||
if scan_mark.line > 0 {
|
||||
foot_line = parser.mark.line-parser.newlines+1
|
||||
foot_line = parser.mark.line - parser.newlines + 1
|
||||
if parser.newlines == 0 && parser.mark.column > 1 {
|
||||
foot_line++
|
||||
}
|
||||
@@ -2996,7 +2998,7 @@ func yaml_parser_scan_comments(parser *yaml_parser_t, scan_mark yaml_mark_t) boo
|
||||
recent_empty = false
|
||||
|
||||
// Consume until after the consumed comment line.
|
||||
seen := parser.mark.index+peek
|
||||
seen := parser.mark.index + peek
|
||||
for {
|
||||
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
||||
return false
|
||||
|
||||
8
vendor/gopkg.in/yaml.v3/writerc.go
generated
vendored
8
vendor/gopkg.in/yaml.v3/writerc.go
generated
vendored
@@ -1,17 +1,17 @@
|
||||
//
|
||||
//
|
||||
// Copyright (c) 2011-2019 Canonical Ltd
|
||||
// Copyright (c) 2006-2010 Kirill Simonov
|
||||
//
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
// of the Software, and to permit persons to whom the Software is furnished to do
|
||||
// so, subject to the following conditions:
|
||||
//
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
|
||||
75
vendor/gopkg.in/yaml.v3/yaml.go
generated
vendored
75
vendor/gopkg.in/yaml.v3/yaml.go
generated
vendored
@@ -17,8 +17,7 @@
|
||||
//
|
||||
// Source code and other details for the project are available at GitHub:
|
||||
//
|
||||
// https://github.com/go-yaml/yaml
|
||||
//
|
||||
// https://github.com/go-yaml/yaml
|
||||
package yaml
|
||||
|
||||
import (
|
||||
@@ -75,16 +74,15 @@ type Marshaler interface {
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// type T struct {
|
||||
// F int `yaml:"a,omitempty"`
|
||||
// B int
|
||||
// }
|
||||
// var t T
|
||||
// yaml.Unmarshal([]byte("a: 1\nb: 2"), &t)
|
||||
// type T struct {
|
||||
// F int `yaml:"a,omitempty"`
|
||||
// B int
|
||||
// }
|
||||
// var t T
|
||||
// yaml.Unmarshal([]byte("a: 1\nb: 2"), &t)
|
||||
//
|
||||
// See the documentation of Marshal for the format of tags and a list of
|
||||
// supported tag options.
|
||||
//
|
||||
func Unmarshal(in []byte, out interface{}) (err error) {
|
||||
return unmarshal(in, out, false)
|
||||
}
|
||||
@@ -185,36 +183,35 @@ func unmarshal(in []byte, out interface{}, strict bool) (err error) {
|
||||
//
|
||||
// The field tag format accepted is:
|
||||
//
|
||||
// `(...) yaml:"[<key>][,<flag1>[,<flag2>]]" (...)`
|
||||
// `(...) yaml:"[<key>][,<flag1>[,<flag2>]]" (...)`
|
||||
//
|
||||
// The following flags are currently supported:
|
||||
//
|
||||
// omitempty Only include the field if it's not set to the zero
|
||||
// value for the type or to empty slices or maps.
|
||||
// Zero valued structs will be omitted if all their public
|
||||
// fields are zero, unless they implement an IsZero
|
||||
// method (see the IsZeroer interface type), in which
|
||||
// case the field will be excluded if IsZero returns true.
|
||||
// omitempty Only include the field if it's not set to the zero
|
||||
// value for the type or to empty slices or maps.
|
||||
// Zero valued structs will be omitted if all their public
|
||||
// fields are zero, unless they implement an IsZero
|
||||
// method (see the IsZeroer interface type), in which
|
||||
// case the field will be excluded if IsZero returns true.
|
||||
//
|
||||
// flow Marshal using a flow style (useful for structs,
|
||||
// sequences and maps).
|
||||
// flow Marshal using a flow style (useful for structs,
|
||||
// sequences and maps).
|
||||
//
|
||||
// inline Inline the field, which must be a struct or a map,
|
||||
// causing all of its fields or keys to be processed as if
|
||||
// they were part of the outer struct. For maps, keys must
|
||||
// not conflict with the yaml keys of other struct fields.
|
||||
// inline Inline the field, which must be a struct or a map,
|
||||
// causing all of its fields or keys to be processed as if
|
||||
// they were part of the outer struct. For maps, keys must
|
||||
// not conflict with the yaml keys of other struct fields.
|
||||
//
|
||||
// In addition, if the key is "-", the field is ignored.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// type T struct {
|
||||
// F int `yaml:"a,omitempty"`
|
||||
// B int
|
||||
// }
|
||||
// yaml.Marshal(&T{B: 2}) // Returns "b: 2\n"
|
||||
// yaml.Marshal(&T{F: 1}} // Returns "a: 1\nb: 0\n"
|
||||
//
|
||||
// type T struct {
|
||||
// F int `yaml:"a,omitempty"`
|
||||
// B int
|
||||
// }
|
||||
// yaml.Marshal(&T{B: 2}) // Returns "b: 2\n"
|
||||
// yaml.Marshal(&T{F: 1}} // Returns "a: 1\nb: 0\n"
|
||||
func Marshal(in interface{}) (out []byte, err error) {
|
||||
defer handleErr(&err)
|
||||
e := newEncoder()
|
||||
@@ -358,22 +355,21 @@ const (
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// var person struct {
|
||||
// Name string
|
||||
// Address yaml.Node
|
||||
// }
|
||||
// err := yaml.Unmarshal(data, &person)
|
||||
//
|
||||
// var person struct {
|
||||
// Name string
|
||||
// Address yaml.Node
|
||||
// }
|
||||
// err := yaml.Unmarshal(data, &person)
|
||||
//
|
||||
// Or by itself:
|
||||
//
|
||||
// var person Node
|
||||
// err := yaml.Unmarshal(data, &person)
|
||||
//
|
||||
// var person Node
|
||||
// err := yaml.Unmarshal(data, &person)
|
||||
type Node struct {
|
||||
// Kind defines whether the node is a document, a mapping, a sequence,
|
||||
// a scalar value, or an alias to another node. The specific data type of
|
||||
// scalar nodes may be obtained via the ShortTag and LongTag methods.
|
||||
Kind Kind
|
||||
Kind Kind
|
||||
|
||||
// Style allows customizing the apperance of the node in the tree.
|
||||
Style Style
|
||||
@@ -421,7 +417,6 @@ func (n *Node) IsZero() bool {
|
||||
n.HeadComment == "" && n.LineComment == "" && n.FootComment == "" && n.Line == 0 && n.Column == 0
|
||||
}
|
||||
|
||||
|
||||
// LongTag returns the long form of the tag that indicates the data type for
|
||||
// the node. If the Tag field isn't explicitly defined, one will be computed
|
||||
// based on the node properties.
|
||||
|
||||
10
vendor/gopkg.in/yaml.v3/yamlh.go
generated
vendored
10
vendor/gopkg.in/yaml.v3/yamlh.go
generated
vendored
@@ -438,7 +438,9 @@ type yaml_document_t struct {
|
||||
// The number of written bytes should be set to the size_read variable.
|
||||
//
|
||||
// [in,out] data A pointer to an application data specified by
|
||||
// yaml_parser_set_input().
|
||||
//
|
||||
// yaml_parser_set_input().
|
||||
//
|
||||
// [out] buffer The buffer to write the data from the source.
|
||||
// [in] size The size of the buffer.
|
||||
// [out] size_read The actual number of bytes read from the source.
|
||||
@@ -639,7 +641,6 @@ type yaml_parser_t struct {
|
||||
}
|
||||
|
||||
type yaml_comment_t struct {
|
||||
|
||||
scan_mark yaml_mark_t // Position where scanning for comments started
|
||||
token_mark yaml_mark_t // Position after which tokens will be associated with this comment
|
||||
start_mark yaml_mark_t // Position of '#' comment mark
|
||||
@@ -659,13 +660,14 @@ type yaml_comment_t struct {
|
||||
// @a buffer to the output.
|
||||
//
|
||||
// @param[in,out] data A pointer to an application data specified by
|
||||
// yaml_emitter_set_output().
|
||||
//
|
||||
// yaml_emitter_set_output().
|
||||
//
|
||||
// @param[in] buffer The buffer with bytes to be written.
|
||||
// @param[in] size The size of the buffer.
|
||||
//
|
||||
// @returns On success, the handler should return @c 1. If the handler failed,
|
||||
// the returned value should be @c 0.
|
||||
//
|
||||
type yaml_write_handler_t func(emitter *yaml_emitter_t, buffer []byte) error
|
||||
|
||||
type yaml_emitter_state_t int
|
||||
|
||||
20
vendor/gopkg.in/yaml.v3/yamlprivateh.go
generated
vendored
20
vendor/gopkg.in/yaml.v3/yamlprivateh.go
generated
vendored
@@ -1,17 +1,17 @@
|
||||
//
|
||||
//
|
||||
// Copyright (c) 2011-2019 Canonical Ltd
|
||||
// Copyright (c) 2006-2010 Kirill Simonov
|
||||
//
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
// of the Software, and to permit persons to whom the Software is furnished to do
|
||||
// so, subject to the following conditions:
|
||||
//
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
@@ -137,8 +137,8 @@ func is_crlf(b []byte, i int) bool {
|
||||
func is_breakz(b []byte, i int) bool {
|
||||
//return is_break(b, i) || is_z(b, i)
|
||||
return (
|
||||
// is_break:
|
||||
b[i] == '\r' || // CR (#xD)
|
||||
// is_break:
|
||||
b[i] == '\r' || // CR (#xD)
|
||||
b[i] == '\n' || // LF (#xA)
|
||||
b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85)
|
||||
b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028)
|
||||
@@ -151,8 +151,8 @@ func is_breakz(b []byte, i int) bool {
|
||||
func is_spacez(b []byte, i int) bool {
|
||||
//return is_space(b, i) || is_breakz(b, i)
|
||||
return (
|
||||
// is_space:
|
||||
b[i] == ' ' ||
|
||||
// is_space:
|
||||
b[i] == ' ' ||
|
||||
// is_breakz:
|
||||
b[i] == '\r' || // CR (#xD)
|
||||
b[i] == '\n' || // LF (#xA)
|
||||
@@ -166,8 +166,8 @@ func is_spacez(b []byte, i int) bool {
|
||||
func is_blankz(b []byte, i int) bool {
|
||||
//return is_blank(b, i) || is_breakz(b, i)
|
||||
return (
|
||||
// is_blank:
|
||||
b[i] == ' ' || b[i] == '\t' ||
|
||||
// is_blank:
|
||||
b[i] == ' ' || b[i] == '\t' ||
|
||||
// is_breakz:
|
||||
b[i] == '\r' || // CR (#xD)
|
||||
b[i] == '\n' || // LF (#xA)
|
||||
|
||||
Reference in New Issue
Block a user