@@ -25,7 +25,8 @@ const C = {
2525 successGlow : "rgba(52, 211, 153, 0.20)" ,
2626} ;
2727
28- export const LAYLA_SIGNALLING_URL = "https://layla-signalling-production.up.railway.app" ;
28+ const LAYLA_SIGNALLING_URL =
29+ "https://layla-signalling-production.up.railway.app" ;
2930const WEBRTC_DATA_CHANNEL_LABEL = "layla-datachannel" ;
3031const CHUNK_SIZE = 16_000 ;
3132const MAX_SERVER_LOGS_TO_DISPLAY = 500 ;
@@ -46,27 +47,6 @@ interface LogEntry {
4647 msg : string ;
4748}
4849
49- // ─── IPC Bridge (Electron main process) ─────────────────────────────────────────
50- // This assumes you expose these via contextBridge/preload.
51- // Adjust to match your actual preload API.
52-
53- interface ElectronBridge {
54- startServer : (
55- serverPath : string ,
56- modelPath : string ,
57- visionModelPath : string ,
58- additionalArgs : string ,
59- ) => Promise < void > ;
60- stopServer : ( ) => Promise < void > ;
61- getDeviceName : ( ) => Promise < string > ;
62- onServerLog : ( callback : ( log : string ) => void ) => ( ) => void ;
63- }
64-
65- function getElectronBridge ( ) : ElectronBridge {
66- // eslint-disable-next-line @typescript-eslint/no-explicit-any
67- return ( window as any ) . electronBridge as ElectronBridge ;
68- }
69-
7050// ─── Helpers ────────────────────────────────────────────────────────────────────
7151
7252const generateTimestamp = ( offsetMs = 0 ) : string => {
@@ -249,12 +229,18 @@ const LogViewer: React.FC<{ logs: LogEntry[] }> = ({ logs }) => {
249229
250230 useEffect ( ( ) => {
251231 if ( expanded && scrollRef . current ) {
252- setTimeout ( ( ) => {
253- scrollRef . current ?. scrollTo ( {
254- top : scrollRef . current . scrollHeight ,
255- behavior : "smooth" ,
256- } ) ;
257- } , 100 ) ;
232+ const el = scrollRef . current ;
233+ const isNearBottom =
234+ el . scrollHeight - el . scrollTop - el . clientHeight < 100 ;
235+
236+ if ( isNearBottom ) {
237+ setTimeout ( ( ) => {
238+ scrollRef . current ?. scrollTo ( {
239+ top : scrollRef . current . scrollHeight ,
240+ behavior : "smooth" ,
241+ } ) ;
242+ } , 100 ) ;
243+ }
258244 }
259245 } , [ logs , expanded ] ) ;
260246
@@ -329,9 +315,10 @@ const QrModal: React.FC<{
329315
330316// ─── Main Component ─────────────────────────────────────────────────────────────
331317
332- const LlmServerPanel : React . FC < { goToSettings : ( ) => void } > = ( {
333- goToSettings,
334- } ) => {
318+ const LlmServerPanel : React . FC < {
319+ goToSettings : ( ) => void ;
320+ settingsRefreshCounter : number ; // used to trigger settings reload when coming back from settings page
321+ } > = ( { goToSettings, settingsRefreshCounter } ) => {
335322 // ── State ──
336323 const [ running , setRunning ] = useState ( false ) ;
337324 const [ status , setStatus ] = useState ( "Idle" ) ;
@@ -379,7 +366,10 @@ const LlmServerPanel: React.FC<{ goToSettings: () => void }> = ({
379366
380367 const addLog = ( level : LogType , msg : string ) => {
381368 const ts = generateTimestamp ( ) ;
382- setLogs ( ( prev ) => [ ...prev . slice ( - ( MAX_SERVER_LOGS_TO_DISPLAY - 1 ) ) , { ts, type : level , msg } ] ) ;
369+ setLogs ( ( prev ) => [
370+ ...prev . slice ( - ( MAX_SERVER_LOGS_TO_DISPLAY - 1 ) ) ,
371+ { ts, type : level , msg } ,
372+ ] ) ;
383373 } ;
384374
385375 // ── WebRTC (browser native) ──
@@ -711,34 +701,29 @@ const LlmServerPanel: React.FC<{ goToSettings: () => void }> = ({
711701 // it is important to update the running state immediately to avoid async function calls trying to use the old RTC connection after we've initiated shutdown
712702 runningRef . current = false ;
713703
714- await getElectronBridge ( ) . stopServer ( ) ;
704+ await window . electronBridge . stopServer ( ) ;
715705 } ;
716706
717707 const startServer = async ( ) => {
718- if ( ! modelPathRef . current ) {
719- throw new Error (
720- "Model path is not set. Please set the model path in settings." ,
708+ if ( modelPathRef . current && localServerPathRef . current ) {
709+ setStatus ( "Starting llama.cpp server..." ) ;
710+ addLog ( "INFO" , "Starting llama.cpp server…" ) ;
711+
712+ await window . electronBridge . startServer (
713+ localServerPathRef . current ,
714+ modelPathRef . current ,
715+ visionModelPathRef . current || "" ,
716+ additionalArgsRef . current || "" ,
721717 ) ;
722- }
723- if ( ! localServerPathRef . current ) {
724- throw new Error (
725- "Local server path is not set. Please set it in settings ." ,
718+ } else {
719+ addLog (
720+ "WARN" ,
721+ "Model or server path is not set. Skipping LLM server start (assume another server is running) ." ,
726722 ) ;
727723 }
728724
729- setStatus ( "Starting llama.cpp server..." ) ;
730- addLog ( "INFO" , "Starting llama.cpp server…" ) ;
731-
732- await getElectronBridge ( ) . startServer (
733- localServerPathRef . current ,
734- modelPathRef . current ,
735- visionModelPathRef . current || "" ,
736- additionalArgsRef . current || "" ,
737- ) ;
738-
739725 runningRef . current = true ;
740726
741- // give it a second for the animation to finish to feel more polished
742727 setTimeout ( ( ) => {
743728 setShowQrCode ( true ) ;
744729 } , 1000 ) ;
@@ -769,8 +754,7 @@ const LlmServerPanel: React.FC<{ goToSettings: () => void }> = ({
769754 // ── Load settings ──
770755
771756 const loadSettings = async ( ) => {
772- const bridge = getElectronBridge ( ) ;
773- const computerName = await bridge . getDeviceName ( ) ;
757+ const computerName = await window . electronBridge . getDeviceName ( ) ;
774758
775759 const settings = await UserSettingsService . getMultipleSettings ( [
776760 UserSettingKey . MODEL_PATH ,
@@ -827,6 +811,21 @@ const LlmServerPanel: React.FC<{ goToSettings: () => void }> = ({
827811 } ;
828812 } , [ ] ) ;
829813
814+ useEffect ( ( ) => {
815+ // this logic skips the initial load when app starts
816+ if ( settingsRefreshCounter > 0 ) {
817+ // reload settings (they won't be applied if the server is already running, but will be picked up on restart)
818+ loadSettings ( )
819+ . then ( ( ) => {
820+ window . electronBridge . showAlert (
821+ "Settings updated" ,
822+ "Your changes have been saved. If the server is currently running, please restart it to apply the new settings." ,
823+ ) ;
824+ } )
825+ . catch ( ( e ) => addLog ( "ERROR" , `Failed to load settings: ${ e . message } ` ) ) ;
826+ }
827+ } , [ settingsRefreshCounter ] ) ;
828+
830829 // ── Init ──
831830
832831 useEffect ( ( ) => {
0 commit comments