Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions docs/dev/backends-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -283,12 +283,13 @@ the generator instead. Prose outside the markers is preserved. -->
| `Bert-Phishing-ONNX` | 1.34 | classification |
| `Phishing-Email-Detection-ONNX` | 0.27 | classification |

#### `openmoss` — OpenMOSS TTS (2 models)
#### `openmoss` — OpenMOSS TTS (3 models)

| Model | Size (GB) | Labels |
|-------|-----------|--------|
| `MOSS-VoiceGen` | 7.3 | tts, voice-design |
| `OpenMOSS-TTS` | 12.5 | tts |
| `MOSS-SoundEffect` | 6.6 | audio-generation |
| `MOSS-TTS-Local` | 15.8 | tts |
| `OpenMOSS-TTS` | 19.8 | tts |

#### `ryzenai-llm` — Ryzen AI LLM (79 models)

Expand Down
13 changes: 13 additions & 0 deletions src/app/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { AccountSession, currentSession, subscribeAccountSessionChanges } from '
import { setPresetStorageScope } from './presetStore';
import { customModelToModelInfo, loadCustomModels } from './features/customModels/customModelStore';
import { findModelInfoByName, isCollectionFullyLoaded, isCollectionModel, withVirtualLoadedCollections } from './features/collections/collectionModels';
import { isModelSelectionLocked, onModelSelectionUnlocked } from './features/modelSettings/modelSelectionLock';
import ChatView from './components/ChatView';
import ModelManager from './components/ModelManager';
import ConnectView from './components/ConnectView';
Expand Down Expand Up @@ -314,10 +315,16 @@ const App: React.FC = () => {
};
setLoadedModels(enriched);
setCurrentModel(current => {
if (current && isModelSelectionLocked()) return current;
if (current && enriched.some(m => m.model_name === current && (canSelectInComposer(m) || customSelectable(m.model_name) || infoSelectable(m.model_name)))) return current;
if (current) {
const info = findModelInfoByName(knownInfos, current);
if (info && isCollectionModel(info) && isCollectionFullyLoaded(info, loaded)) return current;
// A downloaded model the user picked stays picked while it is still
// being prepared. Loading a backend can take minutes (install, then
// weights), and eviction is a resource decision, not a user one —
// neither should silently retarget the composer.
if (info && (info as any).downloaded) return current;
}
const virtualOmni = enriched.find(model => {
const info = findModelInfoByName(knownInfos, model.model_name);
Expand All @@ -330,6 +337,12 @@ const App: React.FC = () => {
});
}, [accountSession.storageScope]);

useEffect(() => onModelSelectionUnlocked(() => {
api.refresh()
.then(result => { if (result) applyLoadedModels(result.health.all_models_loaded); })
.catch(() => { });
}), [applyLoadedModels]);

const navigateToRoute = useCallback((nextRoute: AppRoute) => {
if (nextRoute.view === 'dashboard') lastWorkspaceSectionsRef.current.dashboard = nextRoute.section;
if (nextRoute.view === 'connect') lastWorkspaceSectionsRef.current.connect = nextRoute.section;
Expand Down
277 changes: 150 additions & 127 deletions src/app/src/components/ChatView.tsx

Large diffs are not rendered by default.

27 changes: 27 additions & 0 deletions src/app/src/features/modelSettings/modelSelectionLock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
type Listener = () => void;

let depth = 0;
const listeners = new Set<Listener>();

export function isModelSelectionLocked(): boolean {
return depth > 0;
}

export function onModelSelectionUnlocked(listener: Listener): () => void {
listeners.add(listener);
return () => { listeners.delete(listener); };
}

export async function withModelSelectionLock<T>(run: () => Promise<T>): Promise<T> {
depth += 1;
try {
return await run();
} finally {
depth = Math.max(0, depth - 1);
if (depth === 0) {
listeners.forEach(listener => {
try { listener(); } catch { }
});
}
}
}
28 changes: 28 additions & 0 deletions src/app/src/styles/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -11215,6 +11215,34 @@ button.detail-presets__explanation-step {
cursor: not-allowed;
}

.composer__openmoss-params {
min-width: 0;
flex-basis: 100%;
}

.composer__openmoss-params > summary {
cursor: pointer;
font-size: var(--type-overline-size);
line-height: 1;
letter-spacing: 0.08em;
text-transform: uppercase;
font-weight: var(--weight-semibold);
color: var(--text-tertiary);
padding: var(--space-1) 0;
user-select: none;
}

.composer__openmoss-params > summary:hover {
color: var(--text-secondary);
}

.composer__openmoss-params-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
gap: var(--space-2) var(--space-3);
padding-top: var(--space-2);
}

.composer__openmoss-status {
grid-column: 1 / -1;
min-height: 18px;
Expand Down
28 changes: 27 additions & 1 deletion src/cpp/include/lemon/backends/openmoss/openmoss_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,18 @@
#include "lemon/wrapped_server.h"
#include "lemon/server_capabilities.h"
#include "lemon/backends/backend_utils.h"
#include <map>
#include <mutex>
#include <string>
#include <utility>
#include <vector>

namespace lemon {
namespace backends {

class OpenMossServer : public WrappedServer, public ITextToSpeechServer {
class OpenMossServer : public WrappedServer,
public ITextToSpeechServer,
public IAudioGenerationServer {
public:
static InstallParams get_install_params(const std::string& backend, const std::string& version);

Expand All @@ -26,10 +32,30 @@ class OpenMossServer : public WrappedServer, public ITextToSpeechServer {
void unload() override;

void audio_speech(const json& request, httplib::DataSink& sink) override;
void audio_generations(const json& request, httplib::DataSink& sink) override;
std::vector<std::string> supported_audio_formats() const override { return {"wav"}; }

private:
struct Subprocess {
ProcessHandle handle;
int port = 0;
};

std::string resolve_binary_path(const std::string& backend);
Subprocess spawn(const std::string& model_path);

// The voice-design model is a component of the speech model, but
// moss-tts-server hosts exactly one --model per process. It is spawned only
// to render a reference sample and torn down immediately, so steady-state
// residency stays at the speech model alone.
std::string design_reference_sample(const std::string& voice_description);
json apply_voice_design(const json& request);

std::string exe_path_;
std::string voicegen_path_;
std::map<std::string, std::string> reference_cache_;
std::vector<std::pair<std::string, std::string>> env_vars_;
std::mutex design_mutex_;
};

namespace openmoss {
Expand Down
14 changes: 11 additions & 3 deletions src/cpp/resources/backend_versions.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@
"moss-tts-rocm-windows-x64.zip": "sha256:c9178dfad4ddf51fc8d8df8d1412e65237ff364ca9ca8fc997c9c71f55d60827",
"moss-tts-cuda-linux-x64.tar.gz": "sha256:8662251a854bda4993a5f99e90ba02c176797bf22b1c5b3e89a0061b0a4b102a",
"moss-tts-cuda-windows-x64.zip": "sha256:2b2f5f4b6757d99acf621b43426483ab0bc4a70f1f13904c17deed09cac70969"
},
"v0.2.0": {
"moss-tts-vulkan-linux-x64.tar.gz": "sha256:26f67337940cffaa26efd233764888c1e571ff438b16a8c432ca090e31e3d372",
"moss-tts-vulkan-windows-x64.zip": "sha256:d35ff25c39b0f9fb75191a8d267e4350fdb9bad8ed68f23f2925272a4d27354c",
"moss-tts-rocm-linux-x64.tar.gz": "sha256:32b94cc4b3c7fd6856ed6f73f281ac2099eacc07dfd3344ae34ee4145e0a88d0",
"moss-tts-rocm-windows-x64.zip": "sha256:17e782acafed4865a40ed2f8330c46dbdec15cff5d6cb66c243feeaa5d3e5ad0",
"moss-tts-cuda-linux-x64.tar.gz": "sha256:f4b7ab3fc308c66c984ee42fa0b038b483dde2d20dbfed11fa7f94d78205365c",
"moss-tts-cuda-windows-x64.zip": "sha256:8229a74e51f111db3214b3e3c3fd2d9e6dad34443448693023519c4bb7da688d"
}
},
"pwilkin/acestep.cpp": {
Expand Down Expand Up @@ -182,9 +190,9 @@
"cuda": "v0.4.3"
},
"openmoss": {
"vulkan": "v0.1.3",
"rocm-stable": "v0.1.3",
"cuda": "v0.1.3"
"vulkan": "v0.2.0",
"rocm-stable": "v0.2.0",
"cuda": "v0.2.0"
},
"clear_bin_if_lemonade_below": "9.4.0"
}
61 changes: 54 additions & 7 deletions src/cpp/resources/server_models.json
Original file line number Diff line number Diff line change
Expand Up @@ -1657,23 +1657,70 @@
"size": 15.4
},
"OpenMOSS-TTS": {
"checkpoint": "ilintar/moss-tts-gguf:moss-tts-1.5-q8_0.gguf",
"checkpoints": {
"main": "ilintar/moss-tts-gguf:moss-tts-1.5-q8_0.gguf",
"main_extras": "ilintar/moss-tts-gguf:moss-tts-1.5-q8_0.extras.gguf",
"voicegen": "ilintar/moss-voicegen-gguf:moss-voicegen.gguf",
"voicegen_extras": "ilintar/moss-voicegen-gguf:moss-voicegen.extras.gguf"
},
"recipe": "openmoss",
"suggested": true,
"labels": [
"tts"
],
"size": 19.8,
"speech_defaults": {
"audio_temperature": 1.7,
"audio_top_p": 0.8,
"audio_top_k": 25,
"audio_repetition_penalty": 1.0,
"text_temperature": 1.5,
"text_top_p": 1.0,
"text_top_k": 50,
"speed": 1.0
}
},
"MOSS-TTS-Local": {
"checkpoints": {
"main": "ilintar/moss-tts-local-gguf:moss-tts-local-1.5-q8_0.gguf",
"main_extras": "ilintar/moss-tts-local-gguf:moss-tts-local-1.5-q8_0.extras.gguf",
"voicegen": "ilintar/moss-voicegen-gguf:moss-voicegen.gguf",
"voicegen_extras": "ilintar/moss-voicegen-gguf:moss-voicegen.extras.gguf"
},
"recipe": "openmoss",
"suggested": true,
"labels": [
"tts"
],
"size": 12.5
"size": 15.8,
"speech_defaults": {
"audio_temperature": 1.5,
"audio_top_p": 0.6,
"audio_top_k": 50,
"audio_repetition_penalty": 1.1,
"text_temperature": 1.5,
"text_top_p": 1.0,
"text_top_k": 50,
"speed": 1.0
}
},
"MOSS-VoiceGen": {
"checkpoint": "ilintar/moss-voicegen-gguf:moss-voicegen.gguf",
"MOSS-SoundEffect": {
"checkpoints": {
"main": "ilintar/moss-soundeffect-gguf:moss-soundeffect-2.0.gguf",
"main_extras": "ilintar/moss-soundeffect-gguf:moss-soundeffect-2.0.extras.gguf"
},
"recipe": "openmoss",
"suggested": true,
"labels": [
"tts",
"voice-design"
"audio-generation"
],
"size": 7.3
"size": 6.6,
"audio_defaults": {
"seconds": 10,
"steps": 100,
"cfg_scale": 4.0,
"sigma_shift": 5.0
}
},
"RealESRGAN-x4plus": {
"checkpoint": "amd/realesrgan-x4plus:RealESRGAN_x4plus.pth",
Expand Down
Loading
Loading