Using Flask
Browse files- README.md +1 -1
- app.py +83 -248
- modules/dataset.py +0 -19
- modules/inference.py +0 -11
- requirements.txt +4 -8
- static/script.js +0 -47
- static/style.css +0 -37
- templates/home.html +0 -85
- templates/index.html +97 -70
- templates/login.html +0 -27
    	
        README.md
    CHANGED
    
    | @@ -1,5 +1,5 @@ | |
| 1 | 
             
            ---
         | 
| 2 | 
            -
            title:  | 
| 3 | 
             
            colorFrom: blue
         | 
| 4 | 
             
            colorTo: blue
         | 
| 5 | 
             
            sdk: gradio
         | 
|  | |
| 1 | 
             
            ---
         | 
| 2 | 
            +
            title: Utilities
         | 
| 3 | 
             
            colorFrom: blue
         | 
| 4 | 
             
            colorTo: blue
         | 
| 5 | 
             
            sdk: gradio
         | 
    	
        app.py
    CHANGED
    
    | @@ -1,253 +1,88 @@ | |
| 1 | 
            -
            from  | 
| 2 | 
            -
            from  | 
| 3 | 
            -
            import  | 
| 4 | 
            -
             | 
| 5 | 
            -
             | 
| 6 | 
            -
            import  | 
| 7 | 
            -
            import  | 
| 8 | 
            -
            import  | 
| 9 | 
            -
            import  | 
| 10 | 
            -
             | 
| 11 | 
            -
            import  | 
| 12 | 
             
            from datetime import datetime as dt
         | 
| 13 | 
            -
            from datetime import timedelta | 
| 14 | 
            -
            from  | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
            #  | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
| 43 | 
            -
             | 
| 44 | 
            -
             | 
| 45 | 
            -
             | 
| 46 | 
            -
             | 
| 47 | 
            -
             | 
| 48 | 
            -
             | 
| 49 | 
            -
             | 
| 50 | 
            -
             | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| 53 | 
            -
             | 
| 54 | 
            -
             | 
| 55 | 
            -
             | 
| 56 | 
            -
             | 
| 57 | 
            -
             | 
| 58 | 
            -
             | 
| 59 | 
            -
             | 
| 60 | 
            -
             | 
| 61 | 
            -
             | 
| 62 | 
            -
                 | 
| 63 | 
            -
             | 
| 64 | 
            -
                 | 
| 65 | 
            -
             | 
| 66 | 
            -
             | 
| 67 | 
            -
             | 
| 68 | 
            -
             | 
| 69 | 
            -
                 | 
| 70 | 
            -
             | 
| 71 | 
            -
             | 
| 72 | 
            -
            def process_complete_callback(retcode, **kwargs):
         | 
| 73 | 
            -
                if retcode == 0:
         | 
| 74 | 
            -
                    print("FFmpeg process completed successfully!")
         | 
| 75 | 
            -
                else:
         | 
| 76 | 
            -
                    print("FFmpeg process encountered an error.")
         | 
| 77 | 
            -
             | 
| 78 | 
            -
            def transcribe_audio(latest_file, time_counter):
         | 
| 79 | 
            -
                print('transcribing ', latest_file)
         | 
| 80 | 
            -
                segments, info = wmodel.transcribe(f"{latest_file}", beam_size=beamsize) # beamsize is 2.
         | 
| 81 | 
            -
                text = ''
         | 
| 82 | 
            -
             | 
| 83 | 
            -
                for segment in segments:
         | 
| 84 | 
            -
                    text += segment.text
         | 
| 85 | 
            -
                transcribed = text.replace('\n', ' ').replace('  ', ' ')
         | 
| 86 | 
            -
                if time_counter%5  == 0: 
         | 
| 87 | 
            -
                    transcribed_sents = transcribed.split('. ') # Get the first fullstop break and append to previous para, before adding time code
         | 
| 88 | 
            -
                    transcribed = transcribed_sents[0] + '\nTime ' + str((dt.now(timezone.utc) + timedelta(hours=local_tz)).strftime('%H:%M:%S')) + '\n' + '. '.join(transcribed_sents[1:])
         | 
| 89 | 
            -
             | 
| 90 | 
            -
                time_counter += 1
         | 
| 91 | 
            -
                return transcribed, time_counter
         | 
| 92 | 
            -
             | 
| 93 | 
            -
            def save_audio(youtube_url):
         | 
| 94 | 
            -
                global stream_process, recording, mp3_extraction_process
         | 
| 95 | 
            -
                try:
         | 
| 96 | 
            -
                    streams = streamlink.streams(youtube_url)
         | 
| 97 | 
            -
                    #if "audio" not in streams:
         | 
| 98 | 
            -
                    #    raise Exception("No audio stream found.")
         | 
| 99 | 
            -
                    
         | 
| 100 | 
            -
                    stream_url = streams["144p"].url
         | 
| 101 | 
            -
                    time_counter = 0
         | 
| 102 | 
            -
                    while recording:
         | 
| 103 | 
            -
                        # Save audio only into mp3 files
         | 
| 104 | 
            -
             | 
| 105 | 
            -
                        saved_mp3 = f"mp3/audio_{int(time.time())}.mp3"
         | 
| 106 | 
            -
                        mp3_extraction_process = (
         | 
| 107 | 
            -
                            ffmpeg
         | 
| 108 | 
            -
                            .input(stream_url, t=30)
         | 
| 109 | 
            -
                            .audio
         | 
| 110 | 
            -
                            # TODO - change destination url to relevant url
         | 
| 111 | 
            -
                            .output(saved_mp3)
         | 
| 112 | 
            -
                            .overwrite_output()
         | 
| 113 | 
            -
                            .global_args('-loglevel', 'panic')
         | 
| 114 | 
            -
                            .run_async()
         | 
| 115 | 
            -
                            )
         | 
| 116 | 
            -
                        
         | 
| 117 | 
            -
                        print('pid', mp3_extraction_process.pid)
         | 
| 118 | 
            -
                        # write the pid to pid_file
         | 
| 119 | 
            -
                        with open(pid_file, 'w') as f: f.write(str(mp3_extraction_process.pid))
         | 
| 120 | 
            -
                        
         | 
| 121 | 
            -
                        # If there is more than one mp3 file in the folder, transcribe the one that is not being written to
         | 
| 122 | 
            -
                        mp3files = [f for f in os.listdir('mp3') if f.endswith('.mp3')]
         | 
| 123 | 
            -
                        if len(mp3files) < 2: 
         | 
| 124 | 
            -
                            print('Sleeping for 30s as only one mp3 file in folder')
         | 
| 125 | 
            -
                            time.sleep(30)            
         | 
| 126 | 
            -
                        else: 
         | 
| 127 | 
            -
                            starttime = time.time()
         | 
| 128 | 
            -
                            file_to_transcribe = [f for f in mp3files if f != os.path.basename(saved_mp3)][0]
         | 
| 129 | 
            -
                            print('Working on ', file_to_transcribe)
         | 
| 130 | 
            -
                            transcribed, time_counter = transcribe_audio(f'mp3/{file_to_transcribe}', time_counter)
         | 
| 131 | 
            -
                            os.remove(f'mp3/{file_to_transcribe}')
         | 
| 132 | 
            -
             | 
| 133 | 
            -
                            update_gdoc(transcribed, gdoc_id)
         | 
| 134 | 
            -
                            with open(local_transcript, 'a', encoding='utf-8', errors='ignore') as f: f.write(transcribed)
         | 
| 135 | 
            -
                            
         | 
| 136 | 
            -
                            elapsed_time = time.time() - starttime
         | 
| 137 | 
            -
                            print('Time to transcribe:', elapsed_time, 'seconds')
         | 
| 138 | 
            -
                            if elapsed_time < 30: 
         | 
| 139 | 
            -
                                print(f'Sleeping for {30-elapsed_time} as there are more than one mp3 files in folder')
         | 
| 140 | 
            -
                                time.sleep(30-elapsed_time)
         | 
| 141 | 
            -
                        #time.sleep(30)
         | 
| 142 | 
            -
             | 
| 143 | 
            -
                except Exception as e:
         | 
| 144 | 
            -
                    recording = False
         | 
| 145 | 
            -
                    print('exception', str(e))
         | 
| 146 | 
            -
                    return str(e)
         | 
| 147 | 
            -
             | 
| 148 | 
            -
            @app.route("/start_process", methods=["POST"])
         | 
| 149 | 
            -
            def start_process():
         | 
| 150 | 
            -
                if not os.path.isfile(local_transcript):
         | 
| 151 | 
            -
                    global recording, stream_process
         | 
| 152 | 
            -
                    with open(local_transcript, 'a', encoding='utf-8', errors='ignore') as f: f.write('') # Create the local transcript file, which is used as a check to prevent multiple recordings
         | 
| 153 | 
            -
             | 
| 154 | 
            -
                    youtube_url = request.form.get("url")
         | 
| 155 | 
            -
                    if not youtube_url:
         | 
| 156 | 
            -
                        return jsonify({"message": "Please provide a valid YouTube URL."}), 400
         | 
| 157 | 
            -
             | 
| 158 | 
            -
                    if recording:
         | 
| 159 | 
            -
                        return jsonify({"message": "A recording is already in progress."}), 400
         | 
| 160 | 
            -
                    
         | 
| 161 | 
            -
                    print('In start process')
         | 
| 162 | 
            -
                    recording = True
         | 
| 163 | 
            -
                    stream_process = threading.Thread(target=save_audio, args=(youtube_url,))
         | 
| 164 | 
            -
                    stream_process.start()
         | 
| 165 | 
            -
             | 
| 166 | 
            -
                    return jsonify({"message": "Recording started."}), 200
         | 
| 167 |  | 
| 168 | 
            -
                 | 
| 169 | 
            -
             | 
| 170 | 
            -
             | 
| 171 | 
            -
             | 
| 172 | 
            -
             | 
| 173 | 
            -
             | 
| 174 | 
            -
             | 
| 175 | 
            -
             | 
| 176 | 
            -
             | 
| 177 | 
            -
                 | 
| 178 | 
            -
                 | 
| 179 | 
            -
                 | 
| 180 | 
            -
                 | 
| 181 | 
            -
                mp3_extraction_process.terminate()
         | 
| 182 | 
            -
                mp3_extraction_process = None
         | 
| 183 | 
            -
                for f in os.listdir('mp3/'): os.remove(os.path.join('mp3/', f))
         | 
| 184 | 
            -
                if os.path.isfile(local_transcript): os.remove(local_transcript)
         | 
| 185 | 
            -
                # check if pid_file exists, get the pid inside it and convert to int, and use os.kill to kill it
         | 
| 186 | 
            -
                if os.path.isfile(pid_file): 
         | 
| 187 | 
            -
                    with open(pid_file, 'r') as f: pid = int(f.read())
         | 
| 188 | 
            -
                    try: 
         | 
| 189 | 
            -
                        os.kill(pid, 9) # For linux
         | 
| 190 | 
            -
                        print("Process terminated successfully in Linux.")
         | 
| 191 | 
            -
                    except: 
         | 
| 192 | 
            -
                        try: 
         | 
| 193 | 
            -
                            process = subprocess.Popen(["taskkill", "/F", "/PID", str(pid)], stdout=subprocess.PIPE, stderr=subprocess.PIPE) # For Windows
         | 
| 194 | 
            -
                            process.communicate()
         | 
| 195 | 
            -
                            print("Process terminated successfully in Windows.")
         | 
| 196 | 
            -
                        except Exception as e:
         | 
| 197 | 
            -
                            print("Error:", e) 
         | 
| 198 | 
            -
                    os.remove(pid_file)
         | 
| 199 | 
            -
             | 
| 200 | 
            -
                return jsonify({"message": "Recording stopped."}), 200
         | 
| 201 | 
            -
             | 
| 202 | 
            -
            @app.route('/google/')
         | 
| 203 | 
            -
            def google():
         | 
| 204 | 
            -
                CONF_URL = 'https://accounts.google.com/.well-known/openid-configuration'
         | 
| 205 | 
            -
                oauth.register(
         | 
| 206 | 
            -
                    name='google',
         | 
| 207 | 
            -
                    client_id=GOOGLE_CLIENT_ID,
         | 
| 208 | 
            -
                    client_secret=GOOGLE_CLIENT_SECRET,
         | 
| 209 | 
            -
                    server_metadata_url=CONF_URL,
         | 
| 210 | 
            -
                    client_kwargs={"scope": "openid email profile"}
         | 
| 211 | 
            -
                )
         | 
| 212 | 
            -
             | 
| 213 | 
            -
                # Redirect to google_auth function/page
         | 
| 214 | 
            -
                redirect_uri = url_for('google_auth', _external=True)
         | 
| 215 | 
            -
                session['nonce'] = generate_token()
         | 
| 216 | 
            -
                return oauth.google.authorize_redirect(redirect_uri, nonce=session['nonce'])
         | 
| 217 | 
            -
             | 
| 218 | 
            -
            @app.route('/google/auth/')
         | 
| 219 | 
            -
            def google_auth():
         | 
| 220 | 
            -
                token = oauth.google.authorize_access_token()
         | 
| 221 | 
            -
                user = oauth.google.parse_id_token(token, nonce=session['nonce'])
         | 
| 222 | 
            -
                session['user'] = user
         | 
| 223 | 
            -
                print('USER', user)
         | 
| 224 | 
            -
                # Redirect to home if login successful
         | 
| 225 | 
            -
                return redirect('/home')
         | 
| 226 | 
            -
             | 
| 227 | 
            -
            def is_not_logged_in():
         | 
| 228 | 
            -
                return session.get('user') is None or session.get('nonce') is None
         | 
| 229 | 
            -
             | 
| 230 | 
            -
            # decorator to check if user is logged in, used for protected URLs
         | 
| 231 | 
            -
            def login_required(f):
         | 
| 232 | 
            -
                @wraps(f)
         | 
| 233 | 
            -
                def decorated_function(*args, **kwargs):
         | 
| 234 | 
            -
                    if is_not_logged_in():
         | 
| 235 | 
            -
                        return redirect('/login')
         | 
| 236 | 
            -
                    return f(*args, **kwargs)
         | 
| 237 | 
            -
                return decorated_function
         | 
| 238 | 
            -
             | 
| 239 | 
            -
            @app.route("/home")
         | 
| 240 | 
            -
            @login_required
         | 
| 241 | 
            -
            def home():
         | 
| 242 | 
            -
                return render_template("home.html")
         | 
| 243 | 
            -
             | 
| 244 | 
            -
            @app.route("/", methods=["GET"])
         | 
| 245 | 
            -
            @app.route("/login", methods=["GET"])
         | 
| 246 | 
            -
            def login():
         | 
| 247 | 
            -
                if not is_not_logged_in():
         | 
| 248 | 
            -
                    return redirect("/home")
         | 
| 249 | 
            -
                #return render_template("login.html")
         | 
| 250 | 
            -
                return render_template("home.html")
         | 
| 251 |  | 
| 252 | 
             
            if __name__ == "__main__":
         | 
| 253 | 
             
                app.run(host="0.0.0.0", debug=True, port=7860)
         | 
|  | |
| 1 | 
            +
            from flask import Flask, render_template, request, jsonify
         | 
| 2 | 
            +
            from qdrant_client import QdrantClient
         | 
| 3 | 
            +
            from qdrant_client import models
         | 
| 4 | 
            +
            import torch.nn.functional as F
         | 
| 5 | 
            +
            import torch
         | 
| 6 | 
            +
            from torch import Tensor
         | 
| 7 | 
            +
            from transformers import AutoTokenizer, AutoModel
         | 
| 8 | 
            +
            from qdrant_client.models import Batch, PointStruct
         | 
| 9 | 
            +
            from pickle import load, dump
         | 
| 10 | 
            +
            import numpy as np
         | 
| 11 | 
            +
            import os, time, sys
         | 
| 12 | 
             
            from datetime import datetime as dt
         | 
| 13 | 
            +
            from datetime import timedelta
         | 
| 14 | 
            +
            from datetime import timezone
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            app = Flask(__name__)
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            # Initialize Qdrant Client and other required settings
         | 
| 19 | 
            +
            qdrant_api_key = os.environ.get("qdrant_api_key")
         | 
| 20 | 
            +
            qdrant_url = os.environ.get("qdrant_url")
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            client = QdrantClient(url=qdrant_url, port=443, api_key=qdrant_api_key, prefer_grpc=False)
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            def average_pool(last_hidden_states: Tensor,
         | 
| 27 | 
            +
                             attention_mask: Tensor) -> Tensor:
         | 
| 28 | 
            +
                last_hidden = last_hidden_states.masked_fill(~attention_mask[..., None].bool(), 0.0)
         | 
| 29 | 
            +
                return last_hidden.sum(dim=1) / attention_mask.sum(dim=1)[..., None]
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            tokenizer = AutoTokenizer.from_pretrained('intfloat/e5-base-v2')
         | 
| 32 | 
            +
            model = AutoModel.from_pretrained('intfloat/e5-base-v2').to(device)
         | 
| 33 | 
            +
             | 
| 34 | 
            +
            def e5embed(query):
         | 
| 35 | 
            +
              batch_dict = tokenizer(query, max_length=512, padding=True, truncation=True, return_tensors='pt')
         | 
| 36 | 
            +
              batch_dict = {k: v.to(device) for k, v in batch_dict.items()}
         | 
| 37 | 
            +
              outputs = model(**batch_dict)
         | 
| 38 | 
            +
              embeddings = average_pool(outputs.last_hidden_state, batch_dict['attention_mask'])
         | 
| 39 | 
            +
              embeddings = F.normalize(embeddings, p=2, dim=1)
         | 
| 40 | 
            +
              embeddings = embeddings.cpu().detach().numpy().flatten().tolist()
         | 
| 41 | 
            +
              return embeddings
         | 
| 42 | 
            +
             | 
| 43 | 
            +
            @app.route("/")
         | 
| 44 | 
            +
            def index():
         | 
| 45 | 
            +
                return render_template("index.html")
         | 
| 46 | 
            +
             | 
| 47 | 
            +
            @app.route("/search", methods=["POST"])
         | 
| 48 | 
            +
            def search():
         | 
| 49 | 
            +
                query = request.form["query"]
         | 
| 50 | 
            +
                topN = 200  # Define your topN value
         | 
| 51 | 
            +
             | 
| 52 | 
            +
             | 
| 53 | 
            +
                print('QUERY: ',query)
         | 
| 54 | 
            +
                if query.strip().startswith('tilc:'):
         | 
| 55 | 
            +
                    collection_name = 'tils'
         | 
| 56 | 
            +
                    qvector = "context"
         | 
| 57 | 
            +
                    query = query.replace('tilc:', '')
         | 
| 58 | 
            +
                elif query.strip().startswith('til:'):
         | 
| 59 | 
            +
                    collection_name = 'tils'
         | 
| 60 | 
            +
                    qvector = "title"
         | 
| 61 | 
            +
                    query = query.replace('til:', '')
         | 
| 62 | 
            +
                else: collection_name = 'jks'
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                timh = time.time()
         | 
| 65 | 
            +
                sq = e5embed(query)    
         | 
| 66 | 
            +
                print('EMBEDDING TIME: ', time.time() - timh)
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                timh = time.time()
         | 
| 69 | 
            +
                if collection_name == "jks": results = client.search(collection_name=collection_name, query_vector=sq, with_payload=True, limit=topN)
         | 
| 70 | 
            +
                else: results = client.search(collection_name=collection_name, query_vector=(qvector, sq), with_payload=True, limit=100)
         | 
| 71 | 
            +
                print('SEARCH TIME: ', time.time() - timh)
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 72 |  | 
| 73 | 
            +
                print(results[0].payload['text'].split('\n'))
         | 
| 74 | 
            +
                try: 
         | 
| 75 | 
            +
                    results = [{"text": x.payload['text'], "date": str(int(x.payload['date'])), "id": x.id} for x in results]  # Implement your Qdrant search here     
         | 
| 76 | 
            +
                    return jsonify(results)
         | 
| 77 | 
            +
                except:
         | 
| 78 | 
            +
                    return jsonify([])
         | 
| 79 | 
            +
             | 
| 80 | 
            +
            @app.route("/delete_joke", methods=["POST"])
         | 
| 81 | 
            +
            def delete_joke():
         | 
| 82 | 
            +
                joke_id = request.form["id"]
         | 
| 83 | 
            +
                print('Deleting joke no', joke_id)
         | 
| 84 | 
            +
                client.delete(collection_name="jks", points_selector=models.PointIdsList(points=[int(joke_id)],),)
         | 
| 85 | 
            +
                return jsonify({"deleted": True})
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 86 |  | 
| 87 | 
             
            if __name__ == "__main__":
         | 
| 88 | 
             
                app.run(host="0.0.0.0", debug=True, port=7860)
         | 
    	
        modules/dataset.py
    DELETED
    
    | @@ -1,19 +0,0 @@ | |
| 1 | 
            -
            from datasets import load_dataset
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            dataset = load_dataset("go_emotions", split="train")
         | 
| 4 | 
            -
             | 
| 5 | 
            -
            emotions = dataset.info.features['labels'].feature.names
         | 
| 6 | 
            -
             | 
| 7 | 
            -
            def query_emotion(start, end):
         | 
| 8 | 
            -
                rows = dataset[start:end]
         | 
| 9 | 
            -
                texts, labels = [rows[k] for k in rows.keys()]
         | 
| 10 | 
            -
             | 
| 11 | 
            -
                observations = []
         | 
| 12 | 
            -
             | 
| 13 | 
            -
                for i, text in enumerate(texts):
         | 
| 14 | 
            -
                    observations.append({
         | 
| 15 | 
            -
                        "text": text,
         | 
| 16 | 
            -
                        "emotion": emotions[labels[i]],
         | 
| 17 | 
            -
                    })
         | 
| 18 | 
            -
             | 
| 19 | 
            -
                return observations
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
    	
        modules/inference.py
    DELETED
    
    | @@ -1,11 +0,0 @@ | |
| 1 | 
            -
            from transformers import T5Tokenizer, T5ForConditionalGeneration
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            tokenizer = T5Tokenizer.from_pretrained("t5-small")
         | 
| 4 | 
            -
            model = T5ForConditionalGeneration.from_pretrained("t5-small")
         | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 7 | 
            -
            def infer_t5(input):
         | 
| 8 | 
            -
                input_ids = tokenizer(input, return_tensors="pt").input_ids
         | 
| 9 | 
            -
                outputs = model.generate(input_ids)
         | 
| 10 | 
            -
             | 
| 11 | 
            -
                return tokenizer.decode(outputs[0], skip_special_tokens=True)
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
    	
        requirements.txt
    CHANGED
    
    | @@ -1,9 +1,5 @@ | |
| 1 | 
            -
             | 
| 2 | 
            -
             | 
| 3 | 
            -
             | 
| 4 | 
            -
            faster-whisper
         | 
| 5 | 
            -
            requests
         | 
| 6 | 
            -
            ffmpeg-python
         | 
| 7 | 
            -
            Authlib
         | 
| 8 | 
             
            flask
         | 
| 9 | 
            -
            Werkzeug
         | 
|  | |
| 1 | 
            +
            transformers
         | 
| 2 | 
            +
            torch
         | 
| 3 | 
            +
            qdrant-client
         | 
|  | |
|  | |
|  | |
|  | |
| 4 | 
             
            flask
         | 
| 5 | 
            +
            Werkzeug
         | 
    	
        static/script.js
    DELETED
    
    | @@ -1,47 +0,0 @@ | |
| 1 | 
            -
            $(document).ready(function () {
         | 
| 2 | 
            -
              let recording = false;
         | 
| 3 | 
            -
             | 
| 4 | 
            -
              $("#startBtn").click(function () {
         | 
| 5 | 
            -
                const youtubeUrl = $("#urlInput").val().trim();
         | 
| 6 | 
            -
                if (youtubeUrl === "") {
         | 
| 7 | 
            -
                  showMessage("Please enter a valid YouTube Livestream URL.", "danger");
         | 
| 8 | 
            -
                  return;
         | 
| 9 | 
            -
                }
         | 
| 10 | 
            -
             | 
| 11 | 
            -
                // Call the start_process route in Flask
         | 
| 12 | 
            -
                $.ajax({
         | 
| 13 | 
            -
                  type: "POST",
         | 
| 14 | 
            -
                  url: "/start_process",
         | 
| 15 | 
            -
                  data: { url: youtubeUrl },
         | 
| 16 | 
            -
                  success: function (data) {
         | 
| 17 | 
            -
                    showMessage(data.message, "success");
         | 
| 18 | 
            -
                    recording = true;
         | 
| 19 | 
            -
                  },
         | 
| 20 | 
            -
                  error: function (xhr, status, error) {
         | 
| 21 | 
            -
                    showMessage("Error: " + xhr.responseText, "danger");
         | 
| 22 | 
            -
                  },
         | 
| 23 | 
            -
                });
         | 
| 24 | 
            -
              });
         | 
| 25 | 
            -
             | 
| 26 | 
            -
              $("#stopBtn").click(function () {
         | 
| 27 | 
            -
                showMessage("Stopping transcription. This may take upto 30 sec.", "success");
         | 
| 28 | 
            -
                // Call the stop_process route in Flask
         | 
| 29 | 
            -
                $.ajax({
         | 
| 30 | 
            -
                  type: "POST",
         | 
| 31 | 
            -
                  url: "/stop_process",
         | 
| 32 | 
            -
                  success: function (data) {
         | 
| 33 | 
            -
                    showMessage(data.message, "success");
         | 
| 34 | 
            -
                    recording = false;
         | 
| 35 | 
            -
                  },
         | 
| 36 | 
            -
                  error: function (xhr, status, error) {
         | 
| 37 | 
            -
                    showMessage("Error: " + xhr.responseText, "danger");
         | 
| 38 | 
            -
                  },
         | 
| 39 | 
            -
                });
         | 
| 40 | 
            -
              });
         | 
| 41 | 
            -
             | 
| 42 | 
            -
              function showMessage(message, type) {
         | 
| 43 | 
            -
                $("#message").html(
         | 
| 44 | 
            -
                  `<div class="alert alert-${type}" role="alert">${message}</div>`
         | 
| 45 | 
            -
                );
         | 
| 46 | 
            -
              }
         | 
| 47 | 
            -
            });
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
    	
        static/style.css
    DELETED
    
    | @@ -1,37 +0,0 @@ | |
| 1 | 
            -
            #container {
         | 
| 2 | 
            -
              width: 600px;
         | 
| 3 | 
            -
              margin: 0 auto;
         | 
| 4 | 
            -
              text-align: center;
         | 
| 5 | 
            -
            }
         | 
| 6 | 
            -
             | 
| 7 | 
            -
            #urlInput {
         | 
| 8 | 
            -
              width: 500px;
         | 
| 9 | 
            -
            }
         | 
| 10 | 
            -
             | 
| 11 | 
            -
            button {
         | 
| 12 | 
            -
              margin: 10px;
         | 
| 13 | 
            -
            }
         | 
| 14 | 
            -
             | 
| 15 | 
            -
            #login {
         | 
| 16 | 
            -
              display: flex;
         | 
| 17 | 
            -
              justify-content: center;
         | 
| 18 | 
            -
              flex-direction: row;
         | 
| 19 | 
            -
            }
         | 
| 20 | 
            -
             | 
| 21 | 
            -
            #loginButton {
         | 
| 22 | 
            -
              display: flex;
         | 
| 23 | 
            -
              background-color: rgb(255, 255, 255);
         | 
| 24 | 
            -
              justify-content: center;
         | 
| 25 | 
            -
              align-items: center;
         | 
| 26 | 
            -
              width: fit-content;
         | 
| 27 | 
            -
              padding: 10px 30px;
         | 
| 28 | 
            -
              box-shadow: 1px 1px 1px 1px rgb(170, 170, 170);
         | 
| 29 | 
            -
              border-radius: 15px;
         | 
| 30 | 
            -
              border: 1px solid rgb(170, 170, 170);
         | 
| 31 | 
            -
            }
         | 
| 32 | 
            -
             | 
| 33 | 
            -
            #loginButtonText {
         | 
| 34 | 
            -
              justify-content: center;
         | 
| 35 | 
            -
              padding: 10px;
         | 
| 36 | 
            -
              color: rgb(85, 85, 85);
         | 
| 37 | 
            -
            }
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
    	
        templates/home.html
    DELETED
    
    | @@ -1,85 +0,0 @@ | |
| 1 | 
            -
            <!DOCTYPE html>
         | 
| 2 | 
            -
            <html>
         | 
| 3 | 
            -
             | 
| 4 | 
            -
            <head>
         | 
| 5 | 
            -
              <title>YouTube Livestream Audio Recorder</title>
         | 
| 6 | 
            -
              <!-- Add necessary CSS and jQuery libraries -->
         | 
| 7 | 
            -
              <style>
         | 
| 8 | 
            -
                body {
         | 
| 9 | 
            -
                        font-family: Roboto, sans-serif;
         | 
| 10 | 
            -
                        margin: 0;
         | 
| 11 | 
            -
                        padding: 0;
         | 
| 12 | 
            -
            			height: 100%;
         | 
| 13 | 
            -
                }
         | 
| 14 | 
            -
             | 
| 15 | 
            -
                #container {
         | 
| 16 | 
            -
                  width: 600px;
         | 
| 17 | 
            -
                  margin: 0 auto;
         | 
| 18 | 
            -
                  text-align: center;
         | 
| 19 | 
            -
                }
         | 
| 20 | 
            -
             | 
| 21 | 
            -
                #url {
         | 
| 22 | 
            -
                  width: 500px;
         | 
| 23 | 
            -
                }
         | 
| 24 | 
            -
             | 
| 25 | 
            -
                button {
         | 
| 26 | 
            -
                  margin: 10px;
         | 
| 27 | 
            -
                }
         | 
| 28 | 
            -
             | 
| 29 | 
            -
                .row, h2 {
         | 
| 30 | 
            -
                        display: flex;
         | 
| 31 | 
            -
                        align-items: center;
         | 
| 32 | 
            -
                        margin: 10px;
         | 
| 33 | 
            -
                }
         | 
| 34 | 
            -
             | 
| 35 | 
            -
                select, button {
         | 
| 36 | 
            -
                        padding: 5px;
         | 
| 37 | 
            -
                        border: 1px solid #ccc;
         | 
| 38 | 
            -
                        border-radius: 5px;
         | 
| 39 | 
            -
                }
         | 
| 40 | 
            -
             | 
| 41 | 
            -
                input {
         | 
| 42 | 
            -
                        padding: 5px;
         | 
| 43 | 
            -
                        border: 1px solid #ccc;
         | 
| 44 | 
            -
                        border-radius: 5px;
         | 
| 45 | 
            -
                        width: 500px;
         | 
| 46 | 
            -
                }
         | 
| 47 | 
            -
             | 
| 48 | 
            -
                label, #message {
         | 
| 49 | 
            -
                        margin: 0px 5px 0px 10px;
         | 
| 50 | 
            -
                }
         | 
| 51 | 
            -
             | 
| 52 | 
            -
                button {
         | 
| 53 | 
            -
                        background-color: #2196f3;
         | 
| 54 | 
            -
                        color: white;
         | 
| 55 | 
            -
                        cursor: pointer;
         | 
| 56 | 
            -
                        margin: 0px 0px 0px 3px;
         | 
| 57 | 
            -
                }
         | 
| 58 | 
            -
             | 
| 59 | 
            -
                    button:hover {
         | 
| 60 | 
            -
                        background-color: #1976d2;
         | 
| 61 | 
            -
                }
         | 
| 62 | 
            -
              </style>
         | 
| 63 | 
            -
            </head>
         | 
| 64 | 
            -
             | 
| 65 | 
            -
            <body>
         | 
| 66 | 
            -
              <div class="container">
         | 
| 67 | 
            -
                <h2>Search & Transcribing Utilities</h2>
         | 
| 68 | 
            -
                <div class="mb-3 row">
         | 
| 69 | 
            -
                  <label for="urlInput" class="form-label">Enter YouTube Livestream URL:</label>
         | 
| 70 | 
            -
                  <input type="text" class="form-control" id="urlInput"
         | 
| 71 | 
            -
                    placeholder="e.g., https://www.youtube.com/watch?v=YOUR_STREAM_ID">
         | 
| 72 | 
            -
                
         | 
| 73 | 
            -
                <button class="btn btn-primary" id="startBtn">Start</button>
         | 
| 74 | 
            -
                <button class="btn btn-danger" id="stopBtn">Stop</button>
         | 
| 75 | 
            -
                <div id="message"></div>
         | 
| 76 | 
            -
              </div>
         | 
| 77 | 
            -
             | 
| 78 | 
            -
              <!-- Add necessary jQuery library -->
         | 
| 79 | 
            -
              <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
         | 
| 80 | 
            -
              <!-- Add custom script for handling button clicks -->
         | 
| 81 | 
            -
              <script src="{{ url_for('static', filename='script.js') }}"></script>
         | 
| 82 | 
            -
             | 
| 83 | 
            -
            </body>
         | 
| 84 | 
            -
             | 
| 85 | 
            -
            </html>
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
    	
        templates/index.html
    CHANGED
    
    | @@ -1,85 +1,112 @@ | |
| 1 | 
             
            <!DOCTYPE html>
         | 
| 2 | 
            -
            <html>
         | 
| 3 | 
            -
             | 
| 4 | 
             
            <head>
         | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
                 | 
| 9 | 
            -
             | 
| 10 | 
            -
                         | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
                  text-align: center;
         | 
| 19 | 
            -
                }
         | 
| 20 | 
            -
             | 
| 21 | 
            -
                #url {
         | 
| 22 | 
            -
                  width: 500px;
         | 
| 23 | 
            -
                }
         | 
| 24 | 
            -
             | 
| 25 | 
            -
                button {
         | 
| 26 | 
            -
                  margin: 10px;
         | 
| 27 | 
            -
                }
         | 
| 28 | 
            -
             | 
| 29 | 
            -
                .row, h2 {
         | 
| 30 | 
             
                        display: flex;
         | 
|  | |
| 31 | 
             
                        align-items: center;
         | 
| 32 | 
            -
             | 
| 33 | 
            -
                }
         | 
| 34 |  | 
| 35 | 
            -
             | 
| 36 | 
            -
                         | 
| 37 | 
            -
                         | 
| 38 | 
            -
             | 
| 39 | 
            -
                }
         | 
| 40 |  | 
| 41 | 
            -
             | 
| 42 | 
            -
                         | 
| 43 | 
            -
                         | 
| 44 | 
            -
                        border | 
| 45 | 
            -
                         | 
| 46 | 
            -
             | 
|  | |
|  | |
| 47 |  | 
| 48 | 
            -
             | 
| 49 | 
            -
                        margin:  | 
| 50 | 
            -
             | 
| 51 |  | 
| 52 | 
            -
             | 
| 53 | 
            -
                         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 54 | 
             
                        color: white;
         | 
|  | |
|  | |
| 55 | 
             
                        cursor: pointer;
         | 
| 56 | 
            -
                        margin:  | 
| 57 | 
            -
             | 
| 58 | 
            -
             | 
| 59 | 
            -
                    button:hover {
         | 
| 60 | 
            -
                        background-color: #1976d2;
         | 
| 61 | 
            -
                }
         | 
| 62 | 
            -
              </style>
         | 
| 63 | 
             
            </head>
         | 
| 64 | 
            -
             | 
| 65 | 
             
            <body>
         | 
| 66 | 
            -
             | 
| 67 | 
            -
                < | 
| 68 | 
            -
             | 
| 69 | 
            -
             | 
| 70 | 
            -
             | 
| 71 | 
            -
             | 
| 72 | 
            -
                
         | 
| 73 | 
            -
                <button class="btn btn-primary" id="startBtn">Start</button>
         | 
| 74 | 
            -
                <button class="btn btn-danger" id="stopBtn">Stop</button>
         | 
| 75 | 
            -
                <div id="message"></div>
         | 
| 76 | 
            -
              </div>
         | 
| 77 | 
            -
             | 
| 78 | 
            -
              <!-- Add necessary jQuery library -->
         | 
| 79 | 
            -
              <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
         | 
| 80 | 
            -
              <!-- Add custom script for handling button clicks -->
         | 
| 81 | 
            -
              <script src="{{ url_for('static', filename='script.js') }}"></script>
         | 
| 82 |  | 
| 83 | 
            -
             | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 84 |  | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 85 | 
             
            </html>
         | 
|  | |
| 1 | 
             
            <!DOCTYPE html>
         | 
| 2 | 
            +
            <html lang="en">
         | 
|  | |
| 3 | 
             
            <head>
         | 
| 4 | 
            +
                <meta charset="UTF-8">
         | 
| 5 | 
            +
                <title>Joke Search</title>
         | 
| 6 | 
            +
                <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
         | 
| 7 | 
            +
                <style>
         | 
| 8 | 
            +
                    body {
         | 
| 9 | 
            +
                        font-family: Arial, sans-serif;
         | 
| 10 | 
            +
                    }
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                    h1 {
         | 
| 13 | 
            +
                        text-align: center;
         | 
| 14 | 
            +
                    }
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                    #search-container {
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 17 | 
             
                        display: flex;
         | 
| 18 | 
            +
                        justify-content: center;
         | 
| 19 | 
             
                        align-items: center;
         | 
| 20 | 
            +
                    }
         | 
|  | |
| 21 |  | 
| 22 | 
            +
                    #query {
         | 
| 23 | 
            +
                        width: 70%;
         | 
| 24 | 
            +
                        padding: 10px;
         | 
| 25 | 
            +
                    }
         | 
|  | |
| 26 |  | 
| 27 | 
            +
                    #search {
         | 
| 28 | 
            +
                        background-color: #4c72af;
         | 
| 29 | 
            +
                        color: white;
         | 
| 30 | 
            +
                        border: none;
         | 
| 31 | 
            +
                        padding: 10px 20px;
         | 
| 32 | 
            +
                        cursor: pointer;
         | 
| 33 | 
            +
                        margin-left: 10px; /* Add margin to separate the query bar and button */
         | 
| 34 | 
            +
                    }
         | 
| 35 |  | 
| 36 | 
            +
                    #results {
         | 
| 37 | 
            +
                        margin: 20px;
         | 
| 38 | 
            +
                    }
         | 
| 39 |  | 
| 40 | 
            +
                    .result {
         | 
| 41 | 
            +
                        border: 1px solid #ccc;
         | 
| 42 | 
            +
                        padding: 10px;
         | 
| 43 | 
            +
                        margin: 10px 0;
         | 
| 44 | 
            +
                    }
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                    .delete {
         | 
| 47 | 
            +
                        background-color: #ff0000;
         | 
| 48 | 
             
                        color: white;
         | 
| 49 | 
            +
                        border: none;
         | 
| 50 | 
            +
                        padding: 5px 10px;
         | 
| 51 | 
             
                        cursor: pointer;
         | 
| 52 | 
            +
                        margin: 0 10px;
         | 
| 53 | 
            +
                    }
         | 
| 54 | 
            +
                </style>
         | 
|  | |
|  | |
|  | |
|  | |
| 55 | 
             
            </head>
         | 
|  | |
| 56 | 
             
            <body>
         | 
| 57 | 
            +
                <h1>Joke Search</h1>
         | 
| 58 | 
            +
                <div id="search-container">
         | 
| 59 | 
            +
                    <input type="text" id="query" placeholder="Search...">
         | 
| 60 | 
            +
                    <button id="search">Search</button>
         | 
| 61 | 
            +
                </div>
         | 
| 62 | 
            +
                <div id="results"></div>
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 63 |  | 
| 64 | 
            +
                <script>
         | 
| 65 | 
            +
                    $(document).ready(function () {
         | 
| 66 | 
            +
                        function performSearch() {
         | 
| 67 | 
            +
                            var query = $("#query").val();
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                            $.post("/search", { query: query }, function (data) {
         | 
| 70 | 
            +
                                var results = $("#results");
         | 
| 71 | 
            +
                                results.empty();
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                                data.forEach(function (result) {
         | 
| 74 | 
            +
                                    var resultElement = $("<div class='result'>" +
         | 
| 75 | 
            +
                                        "<p>" + result.text + "</p>" +
         | 
| 76 | 
            +
                                        "<small>Date: " + result.date + "</small>" +
         | 
| 77 | 
            +
                                        "<button class='delete' data-id='" + result.id + "'>Delete</button>" +
         | 
| 78 | 
            +
                                        "</div>");
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                                    results.append(resultElement);
         | 
| 81 |  | 
| 82 | 
            +
                                    resultElement.find(".delete").on("click", function () {
         | 
| 83 | 
            +
                                        var id = $(this).data("id");
         | 
| 84 | 
            +
                                        var resultButton = $(this);
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                                        $.post("/delete_joke", { id: id }, function (data) {
         | 
| 87 | 
            +
                                            // Handle the delete response if needed
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                                            if (data.deleted) {
         | 
| 90 | 
            +
                                                // Replace the button with "DELETED!" text
         | 
| 91 | 
            +
                                                resultButton.replaceWith("<p class='deleted-text'>DELETED!</p>");
         | 
| 92 | 
            +
                                            }
         | 
| 93 | 
            +
                                        });
         | 
| 94 | 
            +
                                    });
         | 
| 95 | 
            +
                                });
         | 
| 96 | 
            +
                            });
         | 
| 97 | 
            +
                        }
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                        $("#search").on("click", function () {
         | 
| 100 | 
            +
                            performSearch();
         | 
| 101 | 
            +
                        });
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                        $("#query").on("keydown", function (event) {
         | 
| 104 | 
            +
                            if (event.key === "Enter") {
         | 
| 105 | 
            +
                                event.preventDefault(); // Prevent form submission
         | 
| 106 | 
            +
                                performSearch();
         | 
| 107 | 
            +
                            }
         | 
| 108 | 
            +
                        });
         | 
| 109 | 
            +
                    });
         | 
| 110 | 
            +
                </script>
         | 
| 111 | 
            +
            </body>
         | 
| 112 | 
             
            </html>
         | 
    	
        templates/login.html
    DELETED
    
    | @@ -1,27 +0,0 @@ | |
| 1 | 
            -
            <!DOCTYPE html>
         | 
| 2 | 
            -
            <html lang="en">
         | 
| 3 | 
            -
             | 
| 4 | 
            -
            <head>
         | 
| 5 | 
            -
                <meta charset="UTF-8">
         | 
| 6 | 
            -
                <meta name="viewport" content="width=device-width, initial-scale=1.0">
         | 
| 7 | 
            -
                <link rel="preconnect" href="https://fonts.googleapis.com">
         | 
| 8 | 
            -
                <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
         | 
| 9 | 
            -
                <link href="https://fonts.googleapis.com/css2?family=Poppins&display=swap" rel="stylesheet">
         | 
| 10 | 
            -
                <link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='style.css') }}">
         | 
| 11 | 
            -
                <title>Flask app</title>
         | 
| 12 | 
            -
            </head>
         | 
| 13 | 
            -
             | 
| 14 | 
            -
            <body>
         | 
| 15 | 
            -
                <div id="login">
         | 
| 16 | 
            -
                    <a href="google/" id="loginButton" style="text-decoration:none;">
         | 
| 17 | 
            -
                        <img id="google"
         | 
| 18 | 
            -
                            src="https://upload.wikimedia.org/wikipedia/commons/thumb/5/53/Google_%22G%22_Logo.svg/2048px-Google_%22G%22_Logo.svg.png"
         | 
| 19 | 
            -
                            alt="Google" style="width:50px;height:50px;">
         | 
| 20 | 
            -
                        <div id="loginButtonText">
         | 
| 21 | 
            -
                            Login with Google
         | 
| 22 | 
            -
                        </div>
         | 
| 23 | 
            -
                    </a>
         | 
| 24 | 
            -
                </div>
         | 
| 25 | 
            -
            </body>
         | 
| 26 | 
            -
             | 
| 27 | 
            -
            </html>
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  |