Spaces:
Sleeping
Sleeping
| # | |
| import base64 | |
| import os | |
| from datetime import datetime | |
| from openai import OpenAI | |
| import gradio as gr | |
| import oci | |
| # === OpenAI API Setup === | |
| openai_api_key = os.environ.get("OPENAI_API_KEY") | |
| if not openai_api_key: | |
| raise ValueError("OPENAI_API_KEY environment variable is not set.") | |
| client = OpenAI(api_key=openai_api_key) | |
| # === OCI Object Storage Setup === | |
| oci_config = { | |
| "user": os.environ.get("OCI_USER"), | |
| "tenancy": os.environ.get("OCI_TENANCY"), | |
| "fingerprint": os.environ.get("OCI_FINGERPRINT"), | |
| "region": os.environ.get("OCI_REGION"), | |
| "key_content": os.environ.get("OCI_PRIVATE_KEY") | |
| } | |
| namespace = os.environ.get("OCI_NAMESPACE") | |
| bucket_name = os.environ.get("OCI_BUCKET_NAME") | |
| try: | |
| object_storage = oci.object_storage.ObjectStorageClient(oci_config) | |
| except Exception as e: | |
| print("Failed to initialize OCI Object Storage client:", e) | |
| # === Prompts === | |
| system_prompt = ( | |
| "You are a detail-oriented assistant that specializes in transcribing and polishing " | |
| "handwritten notes from images. Your goal is to turn rough, casual, or handwritten " | |
| "content into clean, structured, and professional-looking text that sounds like it " | |
| "was written by a human—not an AI. You do not include icons, emojis, or suggest next " | |
| "steps unless explicitly instructed." | |
| ) | |
| user_prompt_template = ( | |
| "You will receive an image of handwritten notes. Transcribe the content accurately, " | |
| "correcting any spelling or grammar issues. Then, organize it clearly with headings, " | |
| "bullet points, and proper formatting. Maintain the original intent and voice of the " | |
| "author, but enhance readability and flow. Do not add embellishments or AI-style phrasing." | |
| ) | |
| # === Encode uploaded bytes === | |
| def encode_image_to_base64(file_bytes): | |
| return base64.b64encode(file_bytes).decode("utf-8") | |
| # === Upload transcription result to OCI === | |
| def upload_to_object_storage(user_name, text): | |
| timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") | |
| filename = f"{user_name.replace(' ', '_')}_{timestamp}.txt" | |
| object_storage.put_object( | |
| namespace_name=namespace, | |
| bucket_name=bucket_name, | |
| object_name=filename, | |
| put_object_body=text.encode("utf-8") | |
| ) | |
| return filename | |
| # === List files in object storage === | |
| def list_object_store(): | |
| try: | |
| objects = object_storage.list_objects(namespace, bucket_name) | |
| return "\n".join([obj.name for obj in objects.data.objects]) | |
| except Exception as e: | |
| return f"Failed to list objects: {str(e)}" | |
| # === Transcription logic === | |
| def transcribe_image(file_bytes, user_name): | |
| if not file_bytes: | |
| return "No image uploaded." | |
| encoded = encode_image_to_base64(file_bytes) | |
| image_url = f"data:image/jpeg;base64,{encoded}" | |
| response = client.chat.completions.create( | |
| model="gpt-4-turbo", | |
| messages=[ | |
| {"role": "system", "content": system_prompt}, | |
| {"role": "user", "content": [ | |
| {"type": "text", "text": user_prompt_template}, | |
| {"type": "image_url", "image_url": {"url": image_url}} | |
| ]} | |
| ], | |
| max_tokens=1500 | |
| ) | |
| timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") | |
| result = f"🗓️ Transcribed on: {timestamp}\n\n{response.choices[0].message.content}" | |
| upload_to_object_storage(user_name, result) | |
| return result | |
| # === Gradio Interface === | |
| with gr.Blocks() as app: | |
| gr.Markdown("## Handwritten Note Transcriber\nUpload a handwritten note image for professional transcription and auto-upload to OCI Object Storage.") | |
| with gr.Row(): | |
| user_dropdown = gr.Dropdown( | |
| choices=["Jim Goodwin", "Zahabiya Ali rampurawala", "Keith Gauvin"], | |
| label="Who is uploading this?" | |
| ) | |
| input_file = gr.File(label="Upload image", type="binary", file_types=[".jpg", ".jpeg", ".png"]) | |
| output_text = gr.Textbox(label="Transcription Output", lines=30) | |
| input_file.change(fn=transcribe_image, inputs=[input_file, user_dropdown], outputs=output_text) | |
| gr.Button("List Object Store").click(fn=list_object_store, outputs=gr.Textbox(label="Object Store Contents")) | |
| # === Launch App === | |
| if __name__ == "__main__": | |
| app.launch(share=True) |