Chan Meng
Update app.py
e1f685d
import streamlit as st
import random
import json
import os
from dotenv import load_dotenv
import requests
# ๅŠ ่ฝฝ็Žฏๅขƒๅ˜้‡
load_dotenv()
# ๅฎšไน‰ๅˆ†็ฑป่กจๆƒ…ๅˆ—่กจ
EMOJI_CATEGORIES = {
"่กจๆƒ…ไธŽๆƒ…็ปช": [
"๐Ÿ˜€", "๐Ÿ˜ƒ", "๐Ÿ˜„", "๐Ÿ˜", "๐Ÿ˜…", "๐Ÿ˜‚", "๐Ÿคฃ", "๐Ÿ˜Š", "๐Ÿ˜‡", "๐Ÿ™‚", "๐Ÿ˜‰", "๐Ÿ˜Œ",
"๐Ÿ˜", "๐Ÿฅฐ", "๐Ÿ˜˜", "๐Ÿ˜—", "๐Ÿ˜™", "๐Ÿ˜š", "๐Ÿ˜‹", "๐Ÿ˜›", "๐Ÿ˜", "๐Ÿ˜œ", "๐Ÿคช", "๐Ÿคจ",
"๐Ÿง", "๐Ÿค“", "๐Ÿ˜Ž", "๐Ÿคฉ", "๐Ÿฅณ", "๐Ÿ˜", "๐Ÿ˜’", "๐Ÿ˜ž", "๐Ÿ˜”", "๐Ÿ˜Ÿ", "๐Ÿ˜•", "๐Ÿ™"
],
"ๅŠจ็‰ฉ": [
"๐Ÿถ", "๐Ÿฑ", "๐Ÿญ", "๐Ÿน", "๐Ÿฐ", "๐ŸฆŠ", "๐Ÿป", "๐Ÿผ", "๐Ÿจ", "๐Ÿฏ", "๐Ÿฆ", "๐Ÿฎ",
"๐Ÿท", "๐Ÿธ", "๐Ÿต", "๐Ÿ”", "๐Ÿง", "๐Ÿฆ", "๐Ÿฆ†", "๐Ÿฆ…", "๐Ÿฆ‰", "๐Ÿฆ‡", "๐Ÿบ", "๐Ÿ—"
],
"ๆค็‰ฉ": [
"๐ŸŒธ", "๐Ÿ’ฎ", "๐ŸŒน", "๐ŸŒบ", "๐ŸŒป", "๐ŸŒผ", "๐ŸŒท", "๐ŸŒฑ", "๐ŸŒฒ", "๐ŸŒณ", "๐ŸŒด", "๐ŸŒต",
"๐ŸŒพ", "๐ŸŒฟ", "โ˜˜๏ธ", "๐Ÿ€", "๐Ÿ", "๐Ÿ‚", "๐Ÿƒ", "๐Ÿชด", "๐ŸŽ‹", "๐ŸŽ"
],
"้ฃŸ็‰ฉ": [
"๐ŸŽ", "๐Ÿ", "๐ŸŠ", "๐Ÿ‹", "๐ŸŒ", "๐Ÿ‰", "๐Ÿ‡", "๐Ÿ“", "๐Ÿซ", "๐Ÿˆ", "๐Ÿ’", "๐Ÿ‘",
"๐Ÿฅญ", "๐Ÿ", "๐Ÿฅฅ", "๐Ÿฅ", "๐Ÿ…", "๐Ÿ†", "๐Ÿฅ‘", "๐Ÿฅฆ", "๐Ÿฅฌ", "๐Ÿฅ’", "๐ŸŒถ๏ธ", "๐Ÿซ‘",
"๐Ÿฅ•", "๐Ÿง„", "๐Ÿง…", "๐Ÿฅ”", "๐Ÿ ", "๐Ÿฅ", "๐Ÿฅฏ", "๐Ÿž", "๐Ÿฅ–", "๐Ÿฅจ", "๐Ÿง€", "๐Ÿฅš",
"๐Ÿณ", "๐Ÿฅ“", "๐Ÿฅฉ", "๐Ÿ—", "๐Ÿ–", "๐Ÿฆด", "๐ŸŒญ", "๐Ÿ”", "๐ŸŸ", "๐Ÿ•", "๐Ÿซ“", "๐Ÿฅช"
],
"ๆดปๅŠจไธŽ่ฟๅŠจ": [
"โšฝ", "๐Ÿ€", "๐Ÿˆ", "โšพ", "๐ŸฅŽ", "๐ŸŽพ", "๐Ÿ", "๐Ÿ‰", "๐Ÿฅ", "๐ŸŽฑ", "๐Ÿช€", "๐Ÿ“",
"๐Ÿธ", "๐Ÿ’", "๐Ÿ‘", "๐Ÿฅ", "๐Ÿ", "๐Ÿชƒ", "๐Ÿฅ…", "โ›ณ", "๐Ÿช", "๐Ÿน", "๐ŸŽฃ", "๐Ÿคฟ"
],
"ไบค้€šๅทฅๅ…ท": [
"๐Ÿš—", "๐Ÿš•", "๐Ÿš™", "๐ŸšŒ", "๐ŸšŽ", "๐ŸŽ๏ธ", "๐Ÿš“", "๐Ÿš‘", "๐Ÿš’", "๐Ÿš", "๐Ÿ›ป", "๐Ÿšš",
"๐Ÿš›", "๐Ÿšœ", "๐Ÿ›ต", "๐Ÿ๏ธ", "๐Ÿšฒ", "๐Ÿ›ด", "๐Ÿš”", "๐Ÿš", "๐Ÿš˜", "๐Ÿš–", "โœˆ๏ธ", "๐Ÿš€"
],
"ๅœฐ็‚นไธŽๅปบ็ญ‘": [
"๐Ÿ ", "๐Ÿก", "๐Ÿข", "๐Ÿฃ", "๐Ÿค", "๐Ÿฅ", "๐Ÿฆ", "๐Ÿจ", "๐Ÿฉ", "๐Ÿช", "๐Ÿซ", "๐Ÿฌ",
"๐Ÿญ", "๐Ÿฏ", "๐Ÿฐ", "๐Ÿ’’", "๐Ÿ—ผ", "๐Ÿ—ฝ", "โ›ช", "๐Ÿ•Œ", "๐Ÿ•", "โ›ฉ๏ธ", "๐Ÿ•‹", "โ›ฒ"
],
"็‰ฉๅ“ไธŽ็ฌฆๅท": [
"๐Ÿ“ฑ", "๐Ÿ’ป", "โŒจ๏ธ", "๐Ÿ–ฅ๏ธ", "๐Ÿ–จ๏ธ", "๐Ÿ–ฑ๏ธ", "๐Ÿ–ฒ๏ธ", "๐Ÿ“ท", "๐Ÿ“ธ", "๐Ÿ“น", "๐ŸŽฅ", "๐Ÿ“ฝ๏ธ",
"๐Ÿ“บ", "๐Ÿ“ป", "๐ŸŽ™๏ธ", "๐ŸŽš๏ธ", "๐ŸŽ›๏ธ", "๐Ÿงญ", "โฑ๏ธ", "โฒ๏ธ", "โฐ", "๐Ÿ•ฐ๏ธ", "๐Ÿ“ก", "๐Ÿ”‹",
"๐Ÿ“š", "๐Ÿ“–", "๐Ÿ†", "๐ŸŽฎ", "๐ŸŽฒ", "๐ŸŽญ", "๐ŸŽจ", "๐ŸŽช", "๐ŸŽŸ๏ธ", "๐ŸŽซ", "๐ŸŽ—๏ธ", "๐Ÿท๏ธ"
]
}
# ๅฎšไน‰ๆ•ฐๆฎๆ–‡ไปถ่ทฏๅพ„
DATA_FILE = "stories_data.json"
HUGGINGFACE_API_TOKEN = os.getenv("HUGGINGFACE_API_TOKEN")
API_URL = "https://api-inference.huggingface.co/models/HuggingFaceH4/zephyr-7b-beta"
def query_huggingface(payload):
"""่ฐƒ็”จHugging Face API"""
headers = {
"Authorization": f"Bearer {HUGGINGFACE_API_TOKEN}",
"Content-Type": "application/json"
}
simplified_payload = {
"inputs": payload["inputs"],
"parameters": {
"max_new_tokens": 250,
"temperature": 0.7,
"top_p": 0.9,
"do_sample": True,
"return_full_text": False
}
}
try:
response = requests.post(API_URL, headers=headers, json=simplified_payload, timeout=60)
if response.status_code != 200:
st.error(f"API call failed, status code: {response.status_code}")
return None
result = response.json()
return result
except Exception as e:
st.error(f"API request error: {str(e)}")
return None
def generate_story_with_ai(emojis):
"""Generate story using AI"""
emoji_text = ' '.join(emojis)
prompt = f"""Create a short story (100-150 words) using these emojis: {emoji_text}
Instructions:
1. Write a coherent story that naturally incorporates the given emojis
2. The story must be suitable for all ages and have a clear structure:
- Beginning: Introduce the main character and setting
- Middle: Present a small challenge or interesting situation
- End: Resolve the situation with a satisfying conclusion
3. Important rules:
- Write as one continuous narrative without any section markers
- Do not use labels like 'Story event:' or 'Story resolution:'
- Ensure the story has a proper ending (no cliffhangers)
- Keep sentences complete (no trailing thoughts)
- Maintain a consistent tone throughout
4. Example flow (do not copy this exactly):
"Character encounters situation โ†’ faces challenge โ†’ resolves it โ†’ learns or achieves something"
Begin the story with:
Once upon a sunny day,"""
try:
with st.spinner('Creating story...'):
response = query_huggingface({"inputs": prompt})
if response and isinstance(response, list) and len(response) > 0:
story = response[0].get('generated_text', '').strip()
story = story.replace(prompt, '').strip()
if not story:
st.error("Failed to generate story. Please try again.")
return None
# ๆธ…็†ๆ‰€ๆœ‰ๅฏ่ƒฝ็š„็ซ ่Š‚ๆ ‡่ฎฐๅ’Œๆ•…ไบ‹ๆ ‡็ญพ
markers_to_remove = [
'Story event:', 'Story resolution:', 'Story middle:',
'Story end:', 'Story summary:', 'Story continuation:',
'Story ending:', 'Story begins:', 'Story continues:',
'Story concludes:', 'Beginning:', 'Middle:', 'End:',
'Continuation:', 'Ending:', 'Event:', 'Resolution:',
'Finally:', 'In conclusion:', 'The end:', 'Summary:',
'Next:', 'Then:', 'After that:', 'Eventually:'
]
# ็งป้™คๆ‰€ๆœ‰ๆ ‡่ฎฐ
for marker in markers_to_remove:
story = story.replace(marker, '')
# ๆธ…็†ๅคšไฝ™็š„็ฉบ่กŒๅ’Œ็ฉบๆ ผ
story = '\n'.join(line for line in story.split('\n') if line.strip())
story = ' '.join(story.split())
# ๆฃ€ๆŸฅๅนถไฟฎๅคไธๅฎŒๆ•ด็š„็ป“ๅฐพ
incomplete_endings = ('and', 'but', 'or', 'so', 'while', 'as', 'then', 'when', '...')
while story.endswith(incomplete_endings) or story.rstrip()[-1] not in '.!?':
story = story.rsplit(' ', 1)[0].rstrip()
if not story:
break
# ็กฎไฟๆ•…ไบ‹ๆœ‰้€‚ๅฝ“็š„็ป“ๅฐพๆ ‡็‚น
if story and story[-1] not in '.!?':
story += '.'
final_story = f"Once upon a sunny day, {story}\n\n(Emojis used: {emoji_text})"
return final_story
st.error("Failed to generate story. Please try again.")
return None
except Exception as e:
st.error(f"Error generating story: {str(e)}")
return None
def load_stories():
"""ไปŽๆ–‡ไปถๅŠ ่ฝฝๆ•…ไบ‹ๆ•ฐๆฎ"""
if os.path.exists(DATA_FILE):
try:
with open(DATA_FILE, 'r', encoding='utf-8') as f:
return json.load(f)
except Exception as e:
st.error(f"Error loading data: {str(e)}")
return []
return []
def save_stories_to_file(stories):
"""ไฟๅญ˜ๆ•…ไบ‹ๆ•ฐๆฎๅˆฐๆ–‡ไปถ"""
try:
with open(DATA_FILE, 'w', encoding='utf-8') as f:
json.dump(stories, f, ensure_ascii=False, indent=2)
except Exception as e:
st.error(f"Error saving data: {str(e)}")
# ๅˆๅง‹ๅŒ–ๆˆ–ๅŠ ่ฝฝๆ•…ไบ‹ๆ•ฐๆฎ
if 'stories' not in st.session_state:
st.session_state.stories = load_stories()
def save_story(story):
"""ไฟๅญ˜ๆ–ฐๆ•…ไบ‹ๅนถๆ›ดๆ–ฐๆ–‡ไปถ"""
st.session_state.stories.append({"story": story, "votes": 0})
save_stories_to_file(st.session_state.stories)
def update_votes():
"""ๆ›ดๆ–ฐๆ–‡ไปถไธญ็š„ๆŠ•็ฅจๆ•ฐๆฎ"""
save_stories_to_file(st.session_state.stories)
def main():
st.set_page_config(page_title="Emoji Story Generator", page_icon="๐Ÿ“š")
st.title("Emoji Story Generator")
# Initialize session state for selected emojis
if 'selected_emojis' not in st.session_state:
st.session_state.selected_emojis = []
# Create tab layout
ENGLISH_CATEGORIES = {
"Faces & Emotions": EMOJI_CATEGORIES["่กจๆƒ…ไธŽๆƒ…็ปช"],
"Animals": EMOJI_CATEGORIES["ๅŠจ็‰ฉ"],
"Plants": EMOJI_CATEGORIES["ๆค็‰ฉ"],
"Food": EMOJI_CATEGORIES["้ฃŸ็‰ฉ"],
"Activities & Sports": EMOJI_CATEGORIES["ๆดปๅŠจไธŽ่ฟๅŠจ"],
"Transportation": EMOJI_CATEGORIES["ไบค้€šๅทฅๅ…ท"],
"Places & Buildings": EMOJI_CATEGORIES["ๅœฐ็‚นไธŽๅปบ็ญ‘"],
"Objects & Symbols": EMOJI_CATEGORIES["็‰ฉๅ“ไธŽ็ฌฆๅท"]
}
tabs = st.tabs(list(ENGLISH_CATEGORIES.keys()))
# Display emojis in each tab
for tab, (category, emojis) in zip(tabs, ENGLISH_CATEGORIES.items()):
with tab:
st.write(f"Select {category}:")
cols = st.columns(8)
for i, emoji in enumerate(emojis):
if cols[i % 8].button(emoji, key=f"{category}_{emoji}"):
if emoji not in st.session_state.selected_emojis:
if len(st.session_state.selected_emojis) < 5:
st.session_state.selected_emojis.append(emoji)
else:
st.warning("Maximum 5 emojis allowed!")
# Display selected emojis
if st.session_state.selected_emojis:
st.write("---")
st.write("Selected emojis:", " ".join(st.session_state.selected_emojis))
col1, col2 = st.columns([1, 4])
with col1:
if st.button("Clear Selection"):
st.session_state.selected_emojis = []
st.rerun()
with col2:
if st.button("Generate Story"):
story = generate_story_with_ai(st.session_state.selected_emojis)
if story:
save_story(story)
st.write("Generated Story:")
st.write(story)
st.success("Story saved!")
else:
st.write("Please select at least one emoji.")
# Display saved stories
if st.session_state.stories:
st.markdown("---")
st.header("Generated Stories")
sorted_stories = sorted(st.session_state.stories,
key=lambda x: x['votes'],
reverse=True)
for idx, story_data in enumerate(sorted_stories):
col1, col2 = st.columns([4, 1])
with col1:
st.write(f"{idx + 1}. {story_data['story']} (Likes: {story_data['votes']})")
with col2:
if st.button(f"๐Ÿ‘", key=f"vote_{idx}"):
story_data['votes'] += 1
update_votes()
st.success("Liked!")
st.rerun()
if __name__ == "__main__":
main()