Skip to content

Commit

Permalink
add confirmation, parse server, local db to music app (#126)
Browse files Browse the repository at this point in the history
  • Loading branch information
steveluc authored Oct 2, 2023
1 parent ec3a37c commit 0dabc70
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 68 deletions.
2 changes: 1 addition & 1 deletion examples/calendar/src/calendarActionsSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export type EventTimeRange = {
};

export type Event = {
// date (example: March 22, 2024) or relative date (example: after EventReference)
// date (example: March 22, 2024) or relative date (example: after EventReference)
day: string;
timeRange: EventTimeRange;
description: string;
Expand Down
11 changes: 10 additions & 1 deletion examples/music/src/dbInterface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ function executeQuery(query: string, params: any[] = []): Row[] | void {
console.log(`Error executing query: ${query} against ${dbPath}`);
return;
}

db.all(query, params, (error: Error, rows: Row[]) => {
db.close();

Expand All @@ -24,6 +24,15 @@ function executeQuery(query: string, params: any[] = []): Row[] | void {
});
}

export function insertTracks(tracks: SpotifyApi.TrackObjectFull[]) {
let insertQuery = 'INSERT INTO tracks (id, title, artist_id, album_id, duration, release_data, genre)\nVALUES\n';
for (const track of tracks) {
// TODO: genre
insertQuery += ` (${track.id},${track.name},${track.artists[0].id},${track.album.id},${track.duration_ms},${track.album.release_date})`;
}


}
export function getArtists() {
const query = "SELECT * FROM artists";
const artists = executeQuery(query);
Expand Down
77 changes: 31 additions & 46 deletions examples/music/src/endpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,31 +109,20 @@ export async function getArtist(service: SpotifyService, id: string) {
return undefined;
}

export async function getHistory(
service: SpotifyService,
limit = limitMax,
offset = 0
) {
export async function getHistoryURL(service: SpotifyService, url: string) {
const config = {
headers: {
Authorization: `Bearer ${service.retrieveUser().token}`,
},
};

const recentlyPlayedUrl = getUrlWithParams(
"https://api.spotify.com/v1/me/player/recently-played",
{
limit,
offset,
}
);
console.log(recentlyPlayedUrl);
// params += `&after=${Date.parse('2023-01-01T00:00:00.000Z')}`;
// params += `&before=${Date.now()}`;
console.log(url);
try {
const spotifyResult = await axios.get(recentlyPlayedUrl, config);
const spotifyResult = await axios.get(url, config);

return spotifyResult.data as SpotifyApi.UsersRecentlyPlayedTracksResponse;
const spotData =
spotifyResult.data as SpotifyApi.UsersRecentlyPlayedTracksResponse;
return spotData;
} catch (e) {
if (e instanceof axios.AxiosError) {
console.log(e.message);
Expand All @@ -144,30 +133,30 @@ export async function getHistory(
return undefined;
}

export async function getKRecent(service: SpotifyService, k = 100) {
if (k > limitMax) {
const playHistory = [] as SpotifyApi.PlayHistoryObject[];
let offset = 0;
while (k > 0) {
let count = limitMax;
if (k < count) {
count = k;
}
const hist = await getHistory(service, count, offset);
if (hist && hist.items) {
playHistory.push(...hist.items);
}
k -= limitMax;
offset += limitMax;
}
return playHistory;
} else {
const hist = await getHistory(service, k);
export async function getRecent(
service: SpotifyService,
after = Date.parse("2023-01-01T00:00:00.000Z")
) {
const playHistory = [] as SpotifyApi.PlayHistoryObject[];
console.log(new Date(after).toLocaleString());
const params = {
limit: 50,
after,
};
let nextURL: string | null | undefined = getUrlWithParams(
"https://api.spotify.com/v1/me/player/recently-played",
params
);
while (nextURL) {
const hist = await getHistoryURL(service, nextURL);
if (hist && hist.items) {
return hist.items;
console.log(hist.items.length);
playHistory.push(...hist.items);
}
nextURL = hist?.next;
console.log(nextURL);
}
return undefined;
return playHistory;
}

export async function getUserProfile(service: SpotifyService) {
Expand Down Expand Up @@ -261,13 +250,12 @@ export async function play(
if (contextUri) {
smallTrack.context_uri = contextUri;
if (trackNumber) {
smallTrack.offset = { position: trackNumber};
smallTrack.offset = { position: trackNumber };
if (seekms) {
smallTrack.position_ms = seekms;
}
}
}
else if (uris) {
} else if (uris) {
smallTrack.uris = uris;
}
const playUrl = getUrlWithParams(
Expand Down Expand Up @@ -344,7 +332,7 @@ export async function getQueue(service: SpotifyService) {
};
try {
const spotifyResult = await axios.get(
`https://api.spotify.com/v1/me/player/queue`,
`https://api.spotify.com/v1/me/player/queue?limit=50`,
config
);

Expand Down Expand Up @@ -456,10 +444,7 @@ export async function getPlaylists(service: SpotifyService) {
return undefined;
}

export async function getAlbumTracks(
service: SpotifyService,
albumId: string
) {
export async function getAlbumTracks(service: SpotifyService, albumId: string) {
const config = {
headers: {
Authorization: `Bearer ${service.retrieveUser().token}`,
Expand Down
30 changes: 26 additions & 4 deletions examples/music/src/localParser.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,31 @@
import chalk from "chalk";
import axios from "axios";
import path from "path";
import dotenv from "dotenv";

dotenv.config({ path: path.join(__dirname, "../../../.env") });

export async function parseOut(request: string, surl: string) {
try {
const result = await axios.post(surl, {
Text: request,
});
console.log(result.data);
} catch (e) {
if (e instanceof axios.AxiosError) {
console.log(e.message);
} else {
throw e;
}
}
}

export function localParser(userPrompt: string) {
userPrompt = userPrompt.trim();
const surl = process.env.PARSER_SERVICE_ENDPOINT;
if (surl) {
parseOut(userPrompt, surl);
}
if (
userPrompt === "play" ||
userPrompt === "resume" ||
Expand Down Expand Up @@ -45,10 +69,9 @@ export function localParser(userPrompt: string) {
if (matchedShuffleSet) {
const shuffleArg = matchedShuffleSet[1];
let shuffleFunc = "";
if (["on","true","yes"].includes(shuffleArg)) {
if (["on", "true", "yes"].includes(shuffleArg)) {
shuffleFunc = "shuffleOn";
}
else if (["off","false","no"].includes(shuffleArg)) {
} else if (["off", "false", "no"].includes(shuffleArg)) {
shuffleFunc = "shuffleOff";
}
if (shuffleFunc.length > 0) {
Expand All @@ -60,7 +83,6 @@ export function localParser(userPrompt: string) {
},
],
});

}
}
}
Expand Down
82 changes: 66 additions & 16 deletions examples/music/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import fs from "fs";
import path from "path";
import readline from "readline/promises";
import { Authzor } from "./authz";
import chalk from "chalk";
import dotenv from "dotenv";
import * as Filter from "./trackFilter";
import {
createLanguageModel,
createProgramTranslator,
processRequests,
Program,
createModuleTextFromProgram,
evaluateJsonProgram,
Expand Down Expand Up @@ -39,6 +39,7 @@ import {
shuffle,
getAlbumTracks,
getQueue,
getRecent,
} from "./endpoints";
import { listAvailableDevices, printStatus, selectDevice } from "./playback";
import { SpotifyService, User } from "./service";
Expand Down Expand Up @@ -75,7 +76,7 @@ async function printTrackNames(
let count = 1;
for (const track of tracks) {
let prefix = "";
if (context && (tracks.length > 1)) {
if (context && tracks.length > 1) {
prefix = `T${count}: `;
}
console.log(chalk.cyanBright(`${prefix}${track.name}`));
Expand Down Expand Up @@ -236,14 +237,20 @@ async function handleCall(
const currentQueue = await getQueue(clientContext.service);
if (currentQueue) {
// not yet supporting episidoes
const filtered = currentQueue.queue.filter((item) => item.type === "track") as SpotifyApi.TrackObjectFull[];
const filtered = currentQueue.queue.filter(
(item) => item.type === "track"
) as SpotifyApi.TrackObjectFull[];
console.log(chalk.magentaBright("Current Queue:"));
console.log(
chalk.cyanBright(`--------------------------------------------`)
chalk.cyanBright(
`--------------------------------------------`
)
);
await printTrackNames(filtered, clientContext);
console.log(
chalk.cyanBright(`--------------------------------------------`)
chalk.cyanBright(
`--------------------------------------------`
)
);
await printStatus(clientContext);
}
Expand Down Expand Up @@ -311,7 +318,10 @@ async function handleCall(
break;
}
case "setVolume": {
const newVolumeLevel = args[0] as number;
let newVolumeLevel = args[0] as number;
if (newVolumeLevel > 50) {
newVolumeLevel = 50;
}
console.log(
chalk.yellowBright(`setting volume to ${newVolumeLevel} ...`)
);
Expand All @@ -326,8 +336,8 @@ async function handleCall(
let nv = Math.floor(
(1.0 + volumeChangeAmount / 100.0) * volpct
);
if (nv > 100) {
nv = 100;
if (nv > 50) {
nv = 50;
}
console.log(chalk.yellowBright(`setting volume to ${nv} ...`));
await setVolume(clientContext.service, nv);
Expand Down Expand Up @@ -495,10 +505,7 @@ async function handleCall(
const playlistCollection = args[0] as PlaylistTrackCollection;
if (playlistCollection) {
const playlist = playlistCollection.getPlaylist();
await deletePlaylist(
clientContext.service,
playlist.id
);
await deletePlaylist(clientContext.service, playlist.id);
console.log(
chalk.magentaBright(`playlist ${playlist.name} deleted`)
);
Expand Down Expand Up @@ -527,7 +534,34 @@ async function handleCall(
// set this to false to just look at llm generation without Spotify connection
const spotifyConnect = true;

// Process requests interactively or from the input file specified on the command line
export async function index(context: IClientContext) {
let playHistory = await getRecent(
context.service,
Date.parse("2018-01-01T00:00:00.00Z")
);
if (playHistory) {
console.log(playHistory?.length);
let trackNames = '';
playHistory.map((item) => {
trackNames += item.track.name + '\n';
});
fs.writeFileSync("bigFetch.txt", trackNames);
}
}

function checkAck(input: string, program: Program): Program | undefined {
const linput = input.toLocaleLowerCase();
if (["y","yes","ok"].includes(linput)) {
return program;
} else {
return undefined;
}
}

// whether to confirm each action with the user
const confirmMode = true;

// Process requests interactively (no batch mode for now)
async function musicApp() {
const authz = new Authzor();
authz.authorize(spotifyConnect, async (token) => {
Expand All @@ -541,7 +575,15 @@ async function musicApp() {
)
);
}
processRequests("🎵> ", process.argv[2], async (request) => {
const musicPrompt = "🎵> ";
const confirmPrompt = "👍👎 (answer y/n)> ";
const stdio = readline.createInterface({ input: process.stdin, output: process.stdout });
while (true) {
const request = await stdio.question(musicPrompt);
if (request.toLowerCase() === "quit" || request.toLowerCase() === "exit") {
stdio.close();
return;
}
const localResult = localParser(request);
let program: Program | undefined = undefined;
if (localResult) {
Expand All @@ -550,13 +592,21 @@ async function musicApp() {
const response = await translator.translate(request);
if (!response.success) {
console.log(response.message);
return;
continue;
}
program = response.data;
}
if (program !== undefined) {
chalkPlan(program);
console.log(getData(createModuleTextFromProgram(program)));
if (confirmMode && (!localResult)) {
const input = await stdio.question(confirmPrompt);
program = checkAck(input, program);
if (program === undefined) {
console.log("Thanks for the feedback. Canceling execution...")
continue;
}
}
if (context !== undefined) {
const result = await evaluateJsonProgram(
program,
Expand All @@ -576,7 +626,7 @@ async function musicApp() {
}
}
}
});
}
});
}

Expand Down

0 comments on commit 0dabc70

Please sign in to comment.