style: run prettier
This commit is contained in:
@ -9,7 +9,10 @@
|
|||||||
} from "svelte-maplibre-gl";
|
} from "svelte-maplibre-gl";
|
||||||
import { view } from "./sidebar.svelte";
|
import { view } from "./sidebar.svelte";
|
||||||
import { map, pin } from "./map.svelte";
|
import { map, pin } from "./map.svelte";
|
||||||
import { decodePolyline, routing } from "$lib/services/navigation/routing.svelte";
|
import {
|
||||||
|
decodePolyline,
|
||||||
|
routing,
|
||||||
|
} from "$lib/services/navigation/routing.svelte";
|
||||||
import { location } from "./location.svelte";
|
import { location } from "./location.svelte";
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
@ -84,18 +87,26 @@
|
|||||||
{/each} -->
|
{/each} -->
|
||||||
<Marker
|
<Marker
|
||||||
lnglat={{
|
lnglat={{
|
||||||
lat: decodePolyline(routing.currentTrip!.legs[0].shape)[routing.currentTripInfo.currentManeuver!.begin_shape_index].lat,
|
lat: decodePolyline(routing.currentTrip!.legs[0].shape)[
|
||||||
lng: decodePolyline(routing.currentTrip!.legs[0].shape)[routing.currentTripInfo.currentManeuver!.begin_shape_index].lon
|
routing.currentTripInfo.currentManeuver!.begin_shape_index
|
||||||
|
].lat,
|
||||||
|
lng: decodePolyline(routing.currentTrip!.legs[0].shape)[
|
||||||
|
routing.currentTripInfo.currentManeuver!.begin_shape_index
|
||||||
|
].lon,
|
||||||
}}
|
}}
|
||||||
color="lime"
|
color="lime"
|
||||||
/>
|
/>
|
||||||
<Marker
|
<Marker
|
||||||
lnglat={{
|
lnglat={{
|
||||||
lat: decodePolyline(routing.currentTrip!.legs[0].shape)[routing.currentTripInfo.currentManeuver!.end_shape_index].lat,
|
lat: decodePolyline(routing.currentTrip!.legs[0].shape)[
|
||||||
lng: decodePolyline(routing.currentTrip!.legs[0].shape)[routing.currentTripInfo.currentManeuver!.end_shape_index].lon
|
routing.currentTripInfo.currentManeuver!.end_shape_index
|
||||||
|
].lat,
|
||||||
|
lng: decodePolyline(routing.currentTrip!.legs[0].shape)[
|
||||||
|
routing.currentTripInfo.currentManeuver!.end_shape_index
|
||||||
|
].lon,
|
||||||
}}
|
}}
|
||||||
color="red"
|
color="red"
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
<!-- <Hash /> -->
|
<!-- <Hash /> -->
|
||||||
<!-- <GeolocateControl
|
<!-- <GeolocateControl
|
||||||
|
|||||||
@ -108,10 +108,15 @@
|
|||||||
>
|
>
|
||||||
<div class="p-2 flex gap-2">
|
<div class="p-2 flex gap-2">
|
||||||
{#if routing.currentTripInfo.currentManeuver?.type === 26 || routing.currentTripInfo.currentManeuver?.type === 27}
|
{#if routing.currentTripInfo.currentManeuver?.type === 26 || routing.currentTripInfo.currentManeuver?.type === 27}
|
||||||
{@const exit = routing.currentTripInfo.currentManeuver?.type === 26
|
{@const exit =
|
||||||
? routing.currentTripInfo.currentManeuver?.roundabout_exit_count
|
routing.currentTripInfo.currentManeuver?.type === 26
|
||||||
: routing.currentTrip?.legs[0].maneuvers[routing.currentTripInfo.maneuverIdx - 1].roundabout_exit_count}
|
? routing.currentTripInfo.currentManeuver?.roundabout_exit_count
|
||||||
<span class="border-white border-4 rounded-full text-3xl flex items-center justify-center w-12 h-12">
|
: routing.currentTrip?.legs[0].maneuvers[
|
||||||
|
routing.currentTripInfo.maneuverIdx - 1
|
||||||
|
].roundabout_exit_count}
|
||||||
|
<span
|
||||||
|
class="border-white border-4 rounded-full text-3xl flex items-center justify-center w-12 h-12"
|
||||||
|
>
|
||||||
{exit}
|
{exit}
|
||||||
</span>
|
</span>
|
||||||
{:else}
|
{:else}
|
||||||
|
|||||||
@ -65,7 +65,9 @@
|
|||||||
<Input bind:value={toLocation} />
|
<Input bind:value={toLocation} />
|
||||||
</div>
|
</div>
|
||||||
<span>
|
<span>
|
||||||
You can use <strong>current</strong> for your current location, <strong>home</strong> or <strong>work</strong> for saved locations.
|
You can use <strong>current</strong> for your current location,
|
||||||
|
<strong>home</strong>
|
||||||
|
or <strong>work</strong> for saved locations.
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
@ -98,7 +100,7 @@
|
|||||||
]);
|
]);
|
||||||
const res = await fetchRoute(ROUTING_SERVER, req);
|
const res = await fetchRoute(ROUTING_SERVER, req);
|
||||||
routes = [res.trip];
|
routes = [res.trip];
|
||||||
if(res.alternates) {
|
if (res.alternates) {
|
||||||
for (const alternate of res.alternates) {
|
for (const alternate of res.alternates) {
|
||||||
if (alternate.trip) {
|
if (alternate.trip) {
|
||||||
routes.push(alternate.trip);
|
routes.push(alternate.trip);
|
||||||
@ -122,7 +124,9 @@
|
|||||||
{#if i == 0}
|
{#if i == 0}
|
||||||
<StarIcon />
|
<StarIcon />
|
||||||
{/if}
|
{/if}
|
||||||
{Math.round(route.summary.length)}km - {formatTime(Math.round(route.summary.time))}
|
{Math.round(route.summary.length)}km - {formatTime(
|
||||||
|
Math.round(route.summary.time),
|
||||||
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -13,7 +13,7 @@ class DuckWeb extends WebPlugin implements DuckPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Duck = registerPlugin<DuckPlugin>("Duck", {
|
const Duck = registerPlugin<DuckPlugin>("Duck", {
|
||||||
web: new DuckWeb()
|
web: new DuckWeb(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default Duck;
|
export default Duck;
|
||||||
@ -1,12 +1,14 @@
|
|||||||
import * as tts from '@diffusionstudio/vits-web';
|
import * as tts from "@diffusionstudio/vits-web";
|
||||||
import TTSWorker from './TTSWorker.ts?worker';
|
import TTSWorker from "./TTSWorker.ts?worker";
|
||||||
|
|
||||||
// const VOICE = "en_US-hfc_female-medium";
|
// const VOICE = "en_US-hfc_female-medium";
|
||||||
const VOICE = "de_DE-thorsten-medium";
|
const VOICE = "de_DE-thorsten-medium";
|
||||||
|
|
||||||
export async function downloadVoice(): Promise<void> {
|
export async function downloadVoice(): Promise<void> {
|
||||||
await tts.download(VOICE, (progress) => {
|
await tts.download(VOICE, (progress) => {
|
||||||
console.log(`Downloading ${progress.url} - ${Math.round(progress.loaded * 100 / progress.total)}%`);
|
console.log(
|
||||||
|
`Downloading ${progress.url} - ${Math.round((progress.loaded * 100) / progress.total)}%`,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -21,22 +23,25 @@ let playing = false;
|
|||||||
let generating = 0;
|
let generating = 0;
|
||||||
const worker = new TTSWorker();
|
const worker = new TTSWorker();
|
||||||
|
|
||||||
worker.addEventListener('message', (event: MessageEvent<{ type: 'result', audio: Blob, text: string }>) => {
|
worker.addEventListener(
|
||||||
if (event.data.type != 'result') return;
|
"message",
|
||||||
|
(event: MessageEvent<{ type: "result"; audio: Blob; text: string }>) => {
|
||||||
|
if (event.data.type != "result") return;
|
||||||
|
|
||||||
// const audio = new Audio();
|
// const audio = new Audio();
|
||||||
// audio.src = URL.createObjectURL(event.data.audio);
|
// audio.src = URL.createObjectURL(event.data.audio);
|
||||||
// audio.play();
|
// audio.play();
|
||||||
// console.log("Audio playing");
|
// console.log("Audio playing");
|
||||||
// audio.onended = () => {
|
// audio.onended = () => {
|
||||||
// playing = false;
|
// playing = false;
|
||||||
// };
|
// };
|
||||||
const item = queue.find(item => item.text === event.data.text);
|
const item = queue.find((item) => item.text === event.data.text);
|
||||||
if (item) {
|
if (item) {
|
||||||
item.audio = event.data.audio; // Set the audio blob for the item
|
item.audio = event.data.audio; // Set the audio blob for the item
|
||||||
generating--;
|
generating--;
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
// if(playing) return;
|
// if(playing) return;
|
||||||
@ -73,9 +78,9 @@ setInterval(() => {
|
|||||||
generating++;
|
generating++;
|
||||||
console.log("Generating audio for:", item.text);
|
console.log("Generating audio for:", item.text);
|
||||||
worker.postMessage({
|
worker.postMessage({
|
||||||
type: 'init',
|
type: "init",
|
||||||
text: item.text,
|
text: item.text,
|
||||||
voiceId: VOICE
|
voiceId: VOICE,
|
||||||
});
|
});
|
||||||
item.audio = undefined; // Reset audio to undefined until generated
|
item.audio = undefined; // Reset audio to undefined until generated
|
||||||
}
|
}
|
||||||
@ -110,26 +115,28 @@ export function queueSpeech(text: string) {
|
|||||||
// const audio = new Audio();
|
// const audio = new Audio();
|
||||||
// audio.src = URL.createObjectURL(wav);
|
// audio.src = URL.createObjectURL(wav);
|
||||||
// audio.play();
|
// audio.play();
|
||||||
if (queue.some(item => item.text === text)) {
|
if (queue.some((item) => item.text === text)) {
|
||||||
// console.warn("Text already in queue, not adding again:", text);
|
// console.warn("Text already in queue, not adding again:", text);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log("Queuing text for speech:", text);
|
console.log("Queuing text for speech:", text);
|
||||||
queue.push({
|
queue.push({
|
||||||
text,
|
text,
|
||||||
shouldPlay: false
|
shouldPlay: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function speak(text: string) {
|
export function speak(text: string) {
|
||||||
const existingItem = queue.find(item => item.text === text);
|
const existingItem = queue.find((item) => item.text === text);
|
||||||
if (existingItem) {
|
if (existingItem) {
|
||||||
existingItem.shouldPlay = true;
|
existingItem.shouldPlay = true;
|
||||||
} else {
|
} else {
|
||||||
console.warn("Adding new item to play immediately. Consider queuing instead!");
|
console.warn(
|
||||||
|
"Adding new item to play immediately. Consider queuing instead!",
|
||||||
|
);
|
||||||
queue.push({
|
queue.push({
|
||||||
text,
|
text,
|
||||||
shouldPlay: true
|
shouldPlay: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import Duck from "../DuckPlugin";
|
|||||||
export let tts: TextToSpeechPlugin | "web" | null = null;
|
export let tts: TextToSpeechPlugin | "web" | null = null;
|
||||||
|
|
||||||
export async function initTTS() {
|
export async function initTTS() {
|
||||||
if(Capacitor.isNativePlatform()) {
|
if (Capacitor.isNativePlatform()) {
|
||||||
console.log("Using Capacitor TTS");
|
console.log("Using Capacitor TTS");
|
||||||
tts = (await import("@capacitor-community/text-to-speech")).TextToSpeech;
|
tts = (await import("@capacitor-community/text-to-speech")).TextToSpeech;
|
||||||
} else {
|
} else {
|
||||||
@ -15,14 +15,14 @@ export async function initTTS() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default async function say(text: string) {
|
export default async function say(text: string) {
|
||||||
if(!tts) {
|
if (!tts) {
|
||||||
// alert("TTS not initialized");
|
// alert("TTS not initialized");
|
||||||
// console.error("TTS not initialized");
|
// console.error("TTS not initialized");
|
||||||
await initTTS();
|
await initTTS();
|
||||||
// return;
|
// return;
|
||||||
}
|
}
|
||||||
Duck.duck();
|
Duck.duck();
|
||||||
if(tts !== "web") {
|
if (tts !== "web") {
|
||||||
try {
|
try {
|
||||||
await tts?.speak({
|
await tts?.speak({
|
||||||
text: text,
|
text: text,
|
||||||
|
|||||||
@ -1,16 +1,18 @@
|
|||||||
import * as tts from '@diffusionstudio/vits-web';
|
import * as tts from "@diffusionstudio/vits-web";
|
||||||
|
|
||||||
async function main(event: MessageEvent<tts.InferenceConfg & { type: 'init' }>) {
|
async function main(
|
||||||
if (event.data?.type != 'init') return;
|
event: MessageEvent<tts.InferenceConfg & { type: "init" }>,
|
||||||
|
) {
|
||||||
|
if (event.data?.type != "init") return;
|
||||||
|
|
||||||
const start = performance.now();
|
const start = performance.now();
|
||||||
const blob = await tts.predict({
|
const blob = await tts.predict({
|
||||||
text: event.data.text,
|
text: event.data.text,
|
||||||
voiceId: event.data.voiceId,
|
voiceId: event.data.voiceId,
|
||||||
});
|
});
|
||||||
console.log('Time taken:', performance.now() - start + ' ms');
|
console.log("Time taken:", performance.now() - start + " ms");
|
||||||
|
|
||||||
self.postMessage({ type: 'result', audio: blob, text: event.data.text });
|
self.postMessage({ type: "result", audio: blob, text: event.data.text });
|
||||||
}
|
}
|
||||||
|
|
||||||
self.addEventListener('message', main);
|
self.addEventListener("message", main);
|
||||||
|
|||||||
@ -1,20 +1,28 @@
|
|||||||
import { OVERPASS_SERVER } from "../hosts";
|
import { OVERPASS_SERVER } from "../hosts";
|
||||||
import type { OverpassResult } from "../Overpass";
|
import type { OverpassResult } from "../Overpass";
|
||||||
|
|
||||||
export async function generateVoiceGuidance(maneuver: Maneuver, shape: WorldLocation[]): Promise<string> {
|
export async function generateVoiceGuidance(
|
||||||
if(maneuver.begin_shape_index == 0) {
|
maneuver: Maneuver,
|
||||||
|
shape: WorldLocation[],
|
||||||
|
): Promise<string> {
|
||||||
|
if (maneuver.begin_shape_index == 0) {
|
||||||
return maneuver.verbal_pre_transition_instruction;
|
return maneuver.verbal_pre_transition_instruction;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(maneuver.type === 26 || maneuver.type === 27) {
|
if (maneuver.type === 26 || maneuver.type === 27) {
|
||||||
return `Im Kreisverkehr die ${maneuver.roundabout_exit_count}te Ausfahrt nehmen${(maneuver.street_names ?? []).length == 0 ? "." : ` auf ${(maneuver.street_names || []).join(", ")}.`}`;
|
return `Im Kreisverkehr die ${maneuver.roundabout_exit_count}te Ausfahrt nehmen${(maneuver.street_names ?? []).length == 0 ? "." : ` auf ${(maneuver.street_names || []).join(", ")}.`}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const landmarks = await findNearbyLandmarks(shape[maneuver.begin_shape_index]);
|
const landmarks = await findNearbyLandmarks(
|
||||||
if(landmarks.length == 0) {
|
shape[maneuver.begin_shape_index],
|
||||||
|
);
|
||||||
|
if (landmarks.length == 0) {
|
||||||
return maneuver.verbal_pre_transition_instruction;
|
return maneuver.verbal_pre_transition_instruction;
|
||||||
}
|
}
|
||||||
console.log("Original instruction:", maneuver.verbal_pre_transition_instruction);
|
console.log(
|
||||||
|
"Original instruction:",
|
||||||
|
maneuver.verbal_pre_transition_instruction,
|
||||||
|
);
|
||||||
return `Hinter ${landmarks[0].tags.name}, ${typeToName(maneuver.type)}${(maneuver.street_names ?? []).length == 0 ? "." : ` auf ${(maneuver.street_names || []).join(", ")}.`}`;
|
return `Hinter ${landmarks[0].tags.name}, ${typeToName(maneuver.type)}${(maneuver.street_names ?? []).length == 0 ? "." : ` auf ${(maneuver.street_names || []).join(", ")}.`}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,8 +80,8 @@ export async function findNearbyLandmarks(location: WorldLocation) {
|
|||||||
const lat = location.lat;
|
const lat = location.lat;
|
||||||
const lon = location.lon;
|
const lon = location.lon;
|
||||||
const res = await fetch(OVERPASS_SERVER, {
|
const res = await fetch(OVERPASS_SERVER, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: `[out:json];
|
body: `[out:json];
|
||||||
(
|
(
|
||||||
node(around:${radius}, ${lat}, ${lon})["amenity"="fuel"]["name"];
|
node(around:${radius}, ${lat}, ${lon})["amenity"="fuel"]["name"];
|
||||||
way(around:${radius}, ${lat}, ${lon})["amenity"="fuel"]["name"];
|
way(around:${radius}, ${lat}, ${lon})["amenity"="fuel"]["name"];
|
||||||
@ -83,11 +91,15 @@ export async function findNearbyLandmarks(location: WorldLocation) {
|
|||||||
way(around:${radius}, ${lat}, ${lon})["shop"]["name"];
|
way(around:${radius}, ${lat}, ${lon})["shop"]["name"];
|
||||||
);
|
);
|
||||||
out center tags;`,
|
out center tags;`,
|
||||||
}).then((res) => res.json() as Promise<OverpassResult>);
|
}).then((res) => res.json() as Promise<OverpassResult>);
|
||||||
// Sort by distance to the location
|
// Sort by distance to the location
|
||||||
return res.elements.sort((a, b) => {
|
return res.elements.sort((a, b) => {
|
||||||
const distA = Math.sqrt(Math.pow(a.lat! - lat, 2) + Math.pow(a.lon! - lon, 2));
|
const distA = Math.sqrt(
|
||||||
const distB = Math.sqrt(Math.pow(b.lat! - lat, 2) + Math.pow(b.lon! - lon, 2));
|
Math.pow(a.lat! - lat, 2) + Math.pow(a.lon! - lon, 2),
|
||||||
|
);
|
||||||
|
const distB = Math.sqrt(
|
||||||
|
Math.pow(b.lat! - lat, 2) + Math.pow(b.lon! - lon, 2),
|
||||||
|
);
|
||||||
return distA - distB;
|
return distA - distB;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -194,11 +194,13 @@ async function tickRoute() {
|
|||||||
);
|
);
|
||||||
if (distanceToEnd <= verbalDistance) {
|
if (distanceToEnd <= verbalDistance) {
|
||||||
hasAnnouncedPreInstruction = true;
|
hasAnnouncedPreInstruction = true;
|
||||||
const instruction = USE_LANDMARK_INSTRUCTIONS ? await generateVoiceGuidance(currentManeuver, polyline) : currentManeuver.verbal_pre_transition_instruction;
|
const instruction = USE_LANDMARK_INSTRUCTIONS
|
||||||
|
? await generateVoiceGuidance(currentManeuver, polyline)
|
||||||
|
: currentManeuver.verbal_pre_transition_instruction;
|
||||||
console.log(
|
console.log(
|
||||||
"[Verbal instruction] ",
|
"[Verbal instruction] ",
|
||||||
// currentManeuver.verbal_pre_transition_instruction,
|
// currentManeuver.verbal_pre_transition_instruction,
|
||||||
instruction
|
instruction,
|
||||||
);
|
);
|
||||||
say(instruction);
|
say(instruction);
|
||||||
}
|
}
|
||||||
@ -253,7 +255,7 @@ async function tickRoute() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function verbalPreInstructionDistance(speed: number): number {
|
function verbalPreInstructionDistance(speed: number): number {
|
||||||
return (speed * 2.222) + 37.144;
|
return speed * 2.222 + 37.144;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function stopNavigation() {
|
export function stopNavigation() {
|
||||||
|
|||||||
Reference in New Issue
Block a user