new(all): Clean up.
This commit is contained in:
parent
99d68b5cb5
commit
66ec78e670
2 changed files with 0 additions and 349 deletions
12
cexp.sh
12
cexp.sh
|
|
@ -1,12 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Remove output.txt if it exists to start fresh
|
||||
rm -f output.txt
|
||||
|
||||
# Find all .ts and .tsx files excluding node_modules, and concatenate filename and contents into output.txt
|
||||
find . -type f \( -name "*.ts" -o -name "*.tsx" \) -not -path "*/node_modules/*" | while read -r file; do
|
||||
echo -e "\n// File: $file\n" >> output.txt
|
||||
cat "$file" >> output.txt
|
||||
done
|
||||
|
||||
echo "All TypeScript (.ts and .tsx) code has been combined into output.txt with filenames as headers, excluding node_modules"
|
||||
337
cimp.sh
337
cimp.sh
|
|
@ -1,337 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Create project directories
|
||||
mkdir -p ./src/preload
|
||||
mkdir -p ./src/renderer
|
||||
mkdir -p ./src/services
|
||||
|
||||
# Create preload.ts file
|
||||
cat <<EOL > ./src/preload/preload.ts
|
||||
// File: ./src/preload/preload.ts
|
||||
|
||||
const { ipcRenderer } = require('electron');
|
||||
|
||||
//@ts-nocheck
|
||||
(window as any).myApi = {
|
||||
//@ts-nocheck
|
||||
sendMessage: (message: any) => {
|
||||
console.log('preload.sendMessage', { message });
|
||||
ipcRenderer.send('message-from-renderer', message);
|
||||
},
|
||||
//@ts-nocheck
|
||||
receiveMessage: (callback: any) => {
|
||||
console.log('preload.receiveMessage', { callback });
|
||||
ipcRenderer.on('message-from-main', (event, arg) => callback(arg));
|
||||
},
|
||||
};
|
||||
EOL
|
||||
|
||||
# Create index.tsx file
|
||||
cat <<EOL > ./src/renderer/index.tsx
|
||||
// File: ./src/renderer/index.tsx
|
||||
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import App from '../components/App';
|
||||
|
||||
ReactDOM.createRoot(
|
||||
document.getElementById('root') as HTMLElement
|
||||
).render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>
|
||||
);
|
||||
EOL
|
||||
|
||||
# Create player.service.ts file
|
||||
cat <<EOL > ./src/services/player.service.ts
|
||||
// File: ./src/services/player.service.ts
|
||||
|
||||
import { ipcMain } from 'electron';
|
||||
import { AutomationEvent, ScreenAnalysis } from './types';
|
||||
import { OpenAIService } from './openai.service';
|
||||
|
||||
export class PlayerService {
|
||||
private openAIService: OpenAIService;
|
||||
|
||||
constructor() {
|
||||
console.log('PlayerService.constructor', {});
|
||||
this.openAIService = new OpenAIService();
|
||||
}
|
||||
|
||||
async executeBasicCode(code: string) {
|
||||
console.log('PlayerService.executeBasicCode', { code });
|
||||
const lines = code.split('\\n');
|
||||
|
||||
for (const line of lines) {
|
||||
if (line.trim().startsWith('REM') || line.trim() === '') continue;
|
||||
|
||||
const match = line.match(/^\\d+\\s+(\\w+)\\s+"([^"]+)"(?:\\s+"([^"]+)")?/);
|
||||
if (!match) continue;
|
||||
|
||||
const [_, command, identifier, value] = match;
|
||||
await this.executeCommand(command, identifier, value);
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
}
|
||||
}
|
||||
|
||||
private async executeCommand(command: string, identifier: string, value?: string) {
|
||||
console.log('PlayerService.executeCommand', { command, identifier, value });
|
||||
const screenshotPath = await this.captureScreen();
|
||||
|
||||
const analysis = await this.openAIService.analyzeScreen(screenshotPath);
|
||||
const element = analysis.elements.find(e => e.identifier === identifier);
|
||||
|
||||
if (!element) throw new Error(\`Element not found: \${identifier}\`);
|
||||
|
||||
const centerX = element.bounds.x + element.bounds.width / 2;
|
||||
const centerY = element.bounds.y + element.bounds.height / 2;
|
||||
|
||||
switch (command) {
|
||||
case 'CLICK':
|
||||
await this.simulateClick(centerX, centerY);
|
||||
break;
|
||||
case 'TYPE':
|
||||
await this.simulateClick(centerX, centerY);
|
||||
await this.simulateTyping(value || '');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private async captureScreen(): Promise<string> {
|
||||
console.log('PlayerService.captureScreen', {});
|
||||
return new Promise((resolve, reject) => {
|
||||
ipcMain.once('screen-captured', (_, screenshotPath) => {
|
||||
resolve(screenshotPath);
|
||||
});
|
||||
|
||||
ipcMain.emit('capture-screen');
|
||||
});
|
||||
}
|
||||
|
||||
private async simulateClick(x: number, y: number): Promise<void> {
|
||||
console.log('PlayerService.simulateClick', { x, y });
|
||||
return new Promise((resolve) => {
|
||||
ipcMain.once('click-completed', () => {
|
||||
resolve();
|
||||
});
|
||||
|
||||
ipcMain.emit('simulate-click', { x, y });
|
||||
});
|
||||
}
|
||||
|
||||
private async simulateTyping(text: string): Promise<void> {
|
||||
console.log('PlayerService.simulateTyping', { text });
|
||||
return new Promise((resolve) => {
|
||||
ipcMain.once('typing-completed', () => {
|
||||
resolve();
|
||||
});
|
||||
|
||||
ipcMain.emit('simulate-typing', { text });
|
||||
});
|
||||
}
|
||||
}
|
||||
EOL
|
||||
|
||||
# Create types.ts file
|
||||
cat <<EOL > ./src/services/types.ts
|
||||
// File: ./src/services/types.ts
|
||||
|
||||
export interface AutomationAction {
|
||||
type: 'click' | 'type' | 'move';
|
||||
identifier: string;
|
||||
value?: string;
|
||||
confidence: number;
|
||||
bounds: {
|
||||
x: number;
|
||||
y: number;
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface AutomationEvent {
|
||||
type: 'click' | 'type' | 'move';
|
||||
identifier: string;
|
||||
value?: string;
|
||||
timestamp: number;
|
||||
narration: string;
|
||||
}
|
||||
|
||||
export interface WhisperResponse {
|
||||
text: string;
|
||||
segments: any;
|
||||
}
|
||||
|
||||
export interface ScreenContext {
|
||||
screenshot: string;
|
||||
transcription: string;
|
||||
cursorPosition: { x: number, y: number };
|
||||
}
|
||||
|
||||
export interface ScreenAnalysis {
|
||||
timestamp: number,
|
||||
elements: {
|
||||
identifier: string;
|
||||
type: string;
|
||||
bounds: { x: number; y: number; width: number; height: number };
|
||||
value?: string;
|
||||
}[];
|
||||
}
|
||||
EOL
|
||||
|
||||
# Create recorder.service.ts file
|
||||
cat <<EOL > ./src/services/recorder.service.ts
|
||||
// File: ./src/services/recorder.service.ts
|
||||
|
||||
const { ipcRenderer } = require('electron'); // Require ipcRender
|
||||
import { AutomationEvent, ScreenAnalysis, WhisperResponse } from '../services/types';
|
||||
import { OpenAIService } from '../services/openai.service';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
|
||||
export class RecorderService {
|
||||
private events: AutomationEvent[] = [];
|
||||
private recording: boolean = false;
|
||||
private openAIService: OpenAIService;
|
||||
private currentScreenshot: string = '';
|
||||
private lastTranscription: string = '';
|
||||
private recordingProcess: any = null;
|
||||
private tempDir: string;
|
||||
private currentAudioFile: string = '';
|
||||
private silenceTimer: NodeJS.Timeout | null = null;
|
||||
private isProcessingAudio: boolean = false;
|
||||
|
||||
constructor() {
|
||||
console.log('RecorderService.constructor', {});
|
||||
this.openAIService = new OpenAIService();
|
||||
this.tempDir = path.join(process.cwd(), 'temp_recordings');
|
||||
if (!fs.existsSync(this.tempDir)) {
|
||||
fs.mkdirSync(this.tempDir, { recursive: true });
|
||||
}
|
||||
}
|
||||
|
||||
public async startRecording() {
|
||||
console.log('RecorderService.startRecording', {});
|
||||
try {
|
||||
this.recording = true;
|
||||
this.events = [];
|
||||
await this.setupAudioRecording();
|
||||
await this.requestScreenshot();
|
||||
ipcRenderer.on('keyboard-event', this.keyboardHandleEvent);
|
||||
} catch (error) {
|
||||
console.error('Failed to start recording:', error);
|
||||
this.recording = false;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
private async setupAudioRecording() {
|
||||
console.log('RecorderService.setupAudioRecording', {});
|
||||
try {
|
||||
ipcRenderer.on('audio-level', this.handleAudioLevel);
|
||||
ipcRenderer.on('audio-chunk', this.handleAudioChunk);
|
||||
} catch (error) {
|
||||
console.error('Error setting up audio recording:', error);
|
||||
throw new Error(\`Failed to setup audio recording: \${error.message}\`);
|
||||
}
|
||||
}
|
||||
|
||||
private handleAudioLevel = async (_: any, level: number) => {
|
||||
console.log('RecorderService.handleAudioLevel', { level });
|
||||
if (!this.recording) return;
|
||||
|
||||
const SILENCE_THRESHOLD = 0.01;
|
||||
const SILENCE_DURATION = 1000;
|
||||
|
||||
if (level < SILENCE_THRESHOLD) {
|
||||
if (!this.silenceTimer && !this.isProcessingAudio) {
|
||||
this.silenceTimer = setTimeout(async () => {
|
||||
if (this.recording) {
|
||||
await this.processSilence();
|
||||
}
|
||||
}, SILENCE_DURATION);
|
||||
}
|
||||
} else {
|
||||
if (this.silenceTimer) {
|
||||
clearTimeout(this.silenceTimer);
|
||||
this.silenceTimer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private handleAudioChunk = async (_: any, chunk: Buffer) => {
|
||||
console.log('RecorderService.handleAudioChunk', { chunk });
|
||||
if (!this.recording) return;
|
||||
|
||||
try {
|
||||
const audioFilePath = path.join(this.tempDir, \`audio-\${Date.now()}.wav\`);
|
||||
fs.writeFileSync(audioFilePath, chunk);
|
||||
|
||||
if (this.silenceTimer) {
|
||||
clearTimeout(this.silenceTimer);
|
||||
this.silenceTimer = null;
|
||||
await this.processAudioFile(audioFilePath);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error handling audio chunk:', error);
|
||||
}
|
||||
};
|
||||
|
||||
private async processSilence() {
|
||||
console.log('RecorderService.processSilence', {});
|
||||
if (this.isProcessingAudio) return;
|
||||
|
||||
this.isProcessingAudio = true;
|
||||
try {
|
||||
const audioFilePath = await ipcRenderer.invoke('save-audio-chunk');
|
||||
if (audioFilePath) {
|
||||
this.currentAudioFile = audioFilePath;
|
||||
await this.processAudioFile(audioFilePath);
|
||||
await this.requestScreenshot();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error processing silence:', error);
|
||||
} finally {
|
||||
this.isProcessingAudio = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async processAudioFile(audioFilePath: string) {
|
||||
console.log('RecorderService.processAudioFile', { audioFilePath });
|
||||
const transcription = await this.openAIService.transcribeAudio(audioFilePath);
|
||||
this.lastTranscription = transcription;
|
||||
await this.requestScreenshot();
|
||||
}
|
||||
|
||||
private async requestScreenshot() {
|
||||
console.log('RecorderService.requestScreenshot', {});
|
||||
await ipcRenderer.invoke('request-screenshot');
|
||||
}
|
||||
|
||||
private keyboardHandleEvent = async (_: any, event: any) => {
|
||||
console.log('RecorderService.keyboardHandleEvent', { event });
|
||||
if (!this.recording) return;
|
||||
|
||||
const automationEvent: AutomationEvent = {
|
||||
type: 'keyboard',
|
||||
identifier: event.key,
|
||||
timestamp: Date.now(),
|
||||
narration: this.lastTranscription,
|
||||
};
|
||||
|
||||
this.events.push(automationEvent);
|
||||
};
|
||||
|
||||
public async stopRecording() {
|
||||
console.log('RecorderService.stopRecording', {});
|
||||
try {
|
||||
this.recording = false;
|
||||
ipcRenderer.removeListener('keyboard-event', this.keyboardHandleEvent);
|
||||
await ipcRenderer.invoke('stop-audio-recording');
|
||||
} catch (error) {
|
||||
console.error('Failed to stop recording:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
EOL
|
||||
Loading…
Add table
Reference in a new issue