Fixed settings for prompts
This commit is contained in:
parent
3f874e5b0c
commit
f1610c06a8
3 changed files with 148 additions and 48 deletions
|
|
@ -53,6 +53,8 @@ pub struct TranscriptionArgs {
|
|||
pub subtitle_path: String,
|
||||
pub selected_frames: Vec<SelectedFrame>,
|
||||
pub api_key: String,
|
||||
pub visual_prompt: String,
|
||||
pub subtitle_prompt: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
|
|
@ -259,15 +261,9 @@ pub async fn process_transcription_impl(args: TranscriptionArgs) -> Result<Trans
|
|||
fs::write(&frame_path, image_data)
|
||||
.map_err(|e| Error::IoError(e))?;
|
||||
|
||||
let visual_prompt = format!("Analyze this video frame from timestamp {} and provide a visual description focusing on:
|
||||
1. The visual setup and environment
|
||||
2. The people present, their appearance, and positioning
|
||||
3. Any relevant visual context or background details
|
||||
4. Do not include details about the individuals' hands
|
||||
let frame_prompt = format!("{}\n\nTimestamp: {}", args.visual_prompt, frame.time);
|
||||
|
||||
Format the description in clear, concise paragraphs that would be helpful for DeafBlind readers to understand the visual context. Focus on spatial relationships and important visual details that contribute to understanding the scene. Use maximum of 200 words and do not include your own thoughts-- just provide the visual description alone.", frame.time);
|
||||
|
||||
let description = query_gemini(&args.api_key, &visual_prompt, Some(frame_path.to_str().unwrap())).await?;
|
||||
let description = query_gemini(&args.api_key, &frame_prompt, Some(frame_path.to_str().unwrap())).await?;
|
||||
frame_descriptions.push((frame.time, description));
|
||||
}
|
||||
|
||||
|
|
@ -345,34 +341,11 @@ Format the description in clear, concise paragraphs that would be helpful for De
|
|||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
|
||||
let subtitle_prompt = format!(r#"I will provide you with timestamped scene descriptions and subtitle content. Create a chronological narrative that combines these elements with these strict rules:
|
||||
|
||||
Scene Descriptions:
|
||||
{}
|
||||
|
||||
Subtitle Content with Timestamps:
|
||||
{}
|
||||
|
||||
Required Format Rules:
|
||||
1. Use ONLY the exact dialogue lines from the subtitle content - do not add, modify, or create new dialogue but feel free to turn them into paragraphs provided that content of exact words are not modified.
|
||||
2. For the first scene description, MOVE it to the beginning of the narration. For the rest of the scenes, ensure that they are located according to their exact timestamps when they occur in the dialogue flow.
|
||||
3. Keep all dialogue in strict chronological order and to be quoted verbatim
|
||||
4. For multiple speakers, add speaker identification before their lines until the next speaker's dialogue lines. If there is only one speaker, do not add a speaker identifier.
|
||||
5. Include speaking manner (e.g., "warmly", "firmly") only when clearly implied by the subtitle text
|
||||
6. Use paragraph breaks to separate different scenes if there is more than one scene
|
||||
7. Ensure that there are no timestamps in the output including for the scenes
|
||||
|
||||
Critical Requirements:
|
||||
- Do not invent or modify any dialogue
|
||||
- Only use the provided subtitle text verbatim
|
||||
- Scene descriptions should be inserted exactly where their timestamps occur except for the first scene which is to start at the beginning of the narration
|
||||
- Maintain precise chronological order of all elements
|
||||
- Keep your thoughts and ideas to yourself
|
||||
|
||||
Format the output as a flowing narrative that preserves all original dialogue while weaving in the visual context at the appropriate moments as like it's a novel."#,
|
||||
scene_descriptions,
|
||||
formatted_subtitles
|
||||
);
|
||||
let subtitle_prompt = format!("{}\n\nScene Descriptions:\n{}\n\nSubtitle Content with Timestamps:\n{}",
|
||||
args.subtitle_prompt,
|
||||
scene_descriptions,
|
||||
formatted_subtitles
|
||||
);
|
||||
|
||||
// Process the subtitle content with scene descriptions
|
||||
let subtitle_narrative = query_gemini(&args.api_key, &subtitle_prompt, None).await?;
|
||||
|
|
|
|||
37
src/App.tsx
37
src/App.tsx
|
|
@ -2,7 +2,7 @@ import { useState, useEffect } from 'react';
|
|||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { FileSelector } from './components/FileSelector';
|
||||
import { GeminiSettings } from './components/GeminiSettings';
|
||||
import { Settings } from './components/Settings';
|
||||
import { Settings, DEFAULT_VISUAL_PROMPT, DEFAULT_SUBTITLE_PROMPT } from './components/Settings';
|
||||
import { VideoTimeline } from './components/VideoTimeline';
|
||||
import './styles/index.css';
|
||||
|
||||
|
|
@ -32,6 +32,14 @@ function App() {
|
|||
const [resizeTo720p, setResizeTo720p] = useState(true);
|
||||
const [geminiEnabled, setGeminiEnabled] = useState(false);
|
||||
const [apiKey, setApiKey] = useState('AIzaSyAF825tPTh77oL0knsGFEyvsN0iPUO_bXc');
|
||||
const [visualPrompt, setVisualPrompt] = useState(() => {
|
||||
const saved = localStorage.getItem('visualPrompt');
|
||||
return saved || DEFAULT_VISUAL_PROMPT;
|
||||
});
|
||||
const [subtitlePrompt, setSubtitlePrompt] = useState(() => {
|
||||
const saved = localStorage.getItem('subtitlePrompt');
|
||||
return saved || DEFAULT_SUBTITLE_PROMPT;
|
||||
});
|
||||
const [selectedFrames, setSelectedFrames] = useState<SelectedFrame[]>([]);
|
||||
const [transcription, setTranscription] = useState<TranscriptionState | null>(null);
|
||||
const [thumbnails, setThumbnails] = useState<Thumbnail[]>([]);
|
||||
|
|
@ -44,6 +52,15 @@ function App() {
|
|||
}
|
||||
const [isSettingsOpen, setIsSettingsOpen] = useState(false);
|
||||
|
||||
// Persist prompts to localStorage when they change
|
||||
useEffect(() => {
|
||||
localStorage.setItem('visualPrompt', visualPrompt);
|
||||
}, [visualPrompt]);
|
||||
|
||||
useEffect(() => {
|
||||
localStorage.setItem('subtitlePrompt', subtitlePrompt);
|
||||
}, [subtitlePrompt]);
|
||||
|
||||
useEffect(() => {
|
||||
invoke('check_dependencies')
|
||||
.catch(err => {
|
||||
|
|
@ -104,7 +121,7 @@ function App() {
|
|||
addBlackBar,
|
||||
resizeTo720p,
|
||||
geminiEnabled,
|
||||
selectedFrames: selectedFrames
|
||||
selectedFrames: selectedFrames
|
||||
});
|
||||
|
||||
// Process transcription first if Gemini is enabled
|
||||
|
|
@ -116,11 +133,13 @@ function App() {
|
|||
video_path: videoFile.path,
|
||||
subtitle_path: subtitleFile.path,
|
||||
selected_frames: selectedFrames.map(frame => ({
|
||||
path: frame.path,
|
||||
time: frame.time,
|
||||
base64_image: frame.base64Image
|
||||
})),
|
||||
api_key: apiKey
|
||||
path: frame.path,
|
||||
time: frame.time,
|
||||
base64_image: frame.base64Image
|
||||
})),
|
||||
api_key: apiKey,
|
||||
visual_prompt: visualPrompt,
|
||||
subtitle_prompt: subtitlePrompt
|
||||
}
|
||||
});
|
||||
console.log('Transcription completed with full response:', transcriptionResult);
|
||||
|
|
@ -324,6 +343,10 @@ function App() {
|
|||
onClose={() => setIsSettingsOpen(false)}
|
||||
apiKey={apiKey}
|
||||
onApiKeyChange={setApiKey}
|
||||
visualPrompt={visualPrompt}
|
||||
subtitlePrompt={subtitlePrompt}
|
||||
onVisualPromptChange={setVisualPrompt}
|
||||
onSubtitlePromptChange={setSubtitlePrompt}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -6,11 +6,51 @@ interface SettingsProps {
|
|||
onClose: () => void;
|
||||
apiKey: string;
|
||||
onApiKeyChange: (key: string) => void;
|
||||
visualPrompt: string;
|
||||
subtitlePrompt: string;
|
||||
onVisualPromptChange: (prompt: string) => void;
|
||||
onSubtitlePromptChange: (prompt: string) => void;
|
||||
}
|
||||
|
||||
const DEFAULT_API_KEY = 'AIzaSyAF825tPTh77oL0knsGFEyvsN0iPUO_bXc';
|
||||
export const DEFAULT_API_KEY = 'AIzaSyAF825tPTh77oL0knsGFEyvsN0iPUO_bXc';
|
||||
export const DEFAULT_VISUAL_PROMPT = `Analyze this video frame from timestamp {} and provide a visual description focusing on:
|
||||
1. The visual setup and environment
|
||||
2. The people present, their appearance, and positioning
|
||||
3. Any relevant visual context or background details
|
||||
4. Do not include details about the individuals' hands
|
||||
|
||||
export const Settings: React.FC<SettingsProps> = ({ isOpen, onClose, apiKey, onApiKeyChange }) => {
|
||||
Format the description in clear, concise paragraphs that would be helpful for DeafBlind readers to understand the visual context. Focus on spatial relationships and important visual details that contribute to understanding the scene. Use maximum of 200 words and do not include your own thoughts-- just provide the visual description alone.`;
|
||||
|
||||
export const DEFAULT_SUBTITLE_PROMPT = `I will provide you with timestamped scene descriptions and subtitle content. Create a chronological narrative that combines these elements with these strict rules:
|
||||
|
||||
Required Format Rules:
|
||||
1. Use ONLY the exact dialogue lines from the subtitle content - do not add, modify, or create new dialogue but feel free to turn them into paragraphs provided that content of exact words are not modified.
|
||||
2. For the first scene description, MOVE it to the beginning of the narration. For the rest of the scenes, ensure that they are located according to their exact timestamps when they occur in the dialogue flow.
|
||||
3. Keep all dialogue in strict chronological order and to be quoted verbatim
|
||||
4. For multiple speakers, add speaker identification before their lines until the next speaker's dialogue lines. If there is only one speaker, do not add a speaker identifier.
|
||||
5. Include speaking manner (e.g., "warmly", "firmly") only when clearly implied by the subtitle text
|
||||
6. Use paragraph breaks to separate different scenes if there is more than one scene
|
||||
7. Ensure that there are no timestamps in the output including for the scenes
|
||||
|
||||
Critical Requirements:
|
||||
- Do not invent or modify any dialogue
|
||||
- Only use the provided subtitle text verbatim
|
||||
- Scene descriptions should be inserted exactly where their timestamps occur except for the first scene which is to start at the beginning of the narration
|
||||
- Maintain precise chronological order of all elements
|
||||
- Keep your thoughts and ideas to yourself
|
||||
|
||||
Format the output as a flowing narrative that preserves all original dialogue while weaving in the visual context at the appropriate moments as like it's a novel.`;
|
||||
|
||||
export const Settings: React.FC<SettingsProps> = ({
|
||||
isOpen,
|
||||
onClose,
|
||||
apiKey,
|
||||
onApiKeyChange,
|
||||
visualPrompt,
|
||||
subtitlePrompt,
|
||||
onVisualPromptChange,
|
||||
onSubtitlePromptChange
|
||||
}) => {
|
||||
const [testing, setTesting] = useState(false);
|
||||
const [testResult, setTestResult] = useState<string | null>(null);
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
|
|
@ -40,10 +80,18 @@ export const Settings: React.FC<SettingsProps> = ({ isOpen, onClose, apiKey, onA
|
|||
setDisplayValue('*'.repeat(apiKey.length));
|
||||
};
|
||||
|
||||
const resetToDefault = () => {
|
||||
const resetApiKeyToDefault = () => {
|
||||
onApiKeyChange(DEFAULT_API_KEY);
|
||||
};
|
||||
|
||||
const resetVisualPromptToDefault = () => {
|
||||
onVisualPromptChange(DEFAULT_VISUAL_PROMPT);
|
||||
};
|
||||
|
||||
const resetSubtitlePromptToDefault = () => {
|
||||
onSubtitlePromptChange(DEFAULT_SUBTITLE_PROMPT);
|
||||
};
|
||||
|
||||
const testApiKey = async () => {
|
||||
setTesting(true);
|
||||
setTestResult(null);
|
||||
|
|
@ -104,7 +152,7 @@ export const Settings: React.FC<SettingsProps> = ({ isOpen, onClose, apiKey, onA
|
|||
|
||||
{apiKey !== DEFAULT_API_KEY && (
|
||||
<button
|
||||
onClick={resetToDefault}
|
||||
onClick={resetApiKeyToDefault}
|
||||
className="inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md shadow-sm text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
||||
>
|
||||
Reset to Default
|
||||
|
|
@ -117,9 +165,65 @@ export const Settings: React.FC<SettingsProps> = ({ isOpen, onClose, apiKey, onA
|
|||
{testResult}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mt-6 space-y-4">
|
||||
<div className="space-y-2">
|
||||
<label className="block text-sm font-medium text-gray-700">
|
||||
Visual Description Prompt
|
||||
</label>
|
||||
<div className="relative">
|
||||
<textarea
|
||||
value={visualPrompt}
|
||||
onChange={(e) => onVisualPromptChange(e.target.value)}
|
||||
rows={4}
|
||||
className="w-full px-3 py-2 rounded-md border border-gray-300 focus:ring-blue-500 focus:border-blue-500 sm:text-sm font-mono resize-y"
|
||||
placeholder="Enter prompt for visual description"
|
||||
spellCheck={false}
|
||||
/>
|
||||
<div className="absolute bottom-2 right-2 text-xs text-gray-500">
|
||||
{visualPrompt.length} characters
|
||||
</div>
|
||||
</div>
|
||||
{visualPrompt !== DEFAULT_VISUAL_PROMPT && (
|
||||
<button
|
||||
onClick={resetVisualPromptToDefault}
|
||||
className="inline-flex items-center px-3 py-1 border border-gray-300 text-xs font-medium rounded-md shadow-sm text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
||||
>
|
||||
Reset to Default
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<label className="block text-sm font-medium text-gray-700">
|
||||
Subtitle Narrative Prompt
|
||||
</label>
|
||||
<div className="relative">
|
||||
<textarea
|
||||
value={subtitlePrompt}
|
||||
onChange={(e) => onSubtitlePromptChange(e.target.value)}
|
||||
rows={4}
|
||||
className="w-full px-3 py-2 rounded-md border border-gray-300 focus:ring-blue-500 focus:border-blue-500 sm:text-sm font-mono resize-y"
|
||||
placeholder="Enter prompt for subtitle narrative"
|
||||
spellCheck={false}
|
||||
/>
|
||||
<div className="absolute bottom-2 right-2 text-xs text-gray-500">
|
||||
{subtitlePrompt.length} characters
|
||||
</div>
|
||||
</div>
|
||||
{subtitlePrompt !== DEFAULT_SUBTITLE_PROMPT && (
|
||||
<button
|
||||
onClick={resetSubtitlePromptToDefault}
|
||||
className="inline-flex items-center px-3 py-1 border border-gray-300 text-xs font-medium rounded-md shadow-sm text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
||||
>
|
||||
Reset to Default
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-6 flex justify-end">
|
||||
<div className="mt-6 flex justify-end border-t border-gray-200 pt-4">
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="px-4 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-blue-500 hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue